diff options
Diffstat (limited to 'application/palemoon/base/content/browser.js')
-rw-r--r-- | application/palemoon/base/content/browser.js | 7440 |
1 files changed, 0 insertions, 7440 deletions
diff --git a/application/palemoon/base/content/browser.js b/application/palemoon/base/content/browser.js deleted file mode 100644 index 7615bc92a..000000000 --- a/application/palemoon/base/content/browser.js +++ /dev/null @@ -1,7440 +0,0 @@ -# -*- Mode: javascript; 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/. - -var Ci = Components.interfaces; -var Cu = Components.utils; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource:///modules/RecentWindow.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Task", - "resource://gre/modules/Task.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu", - "resource:///modules/CharsetMenu.jsm"); - -const nsIWebNavigation = Ci.nsIWebNavigation; -const gToolbarInfoSeparators = ["|", "-"]; - -var gLastBrowserCharset = null; -var gPrevCharset = null; -var gProxyFavIcon = null; -var gLastValidURLStr = ""; -var gInPrintPreviewMode = false; -var gContextMenu = null; // nsContextMenu instance -var gMultiProcessBrowser = false; - -#ifndef XP_MACOSX -var gEditUIVisible = true; -#endif - -[ - ["gBrowser", "content"], - ["gNavToolbox", "navigator-toolbox"], - ["gURLBar", "urlbar"], - ["gNavigatorBundle", "bundle_browser"] -].forEach(function (elementGlobal) { - var [name, id] = elementGlobal; - window.__defineGetter__(name, function () { - var element = document.getElementById(id); - if (!element) - return null; - delete window[name]; - return window[name] = element; - }); - window.__defineSetter__(name, function (val) { - delete window[name]; - return window[name] = val; - }); -}); - -// Smart getter for the findbar. If you don't wish to force the creation of -// the findbar, check gFindBarInitialized first. -var gFindBarInitialized = false; -XPCOMUtils.defineLazyGetter(window, "gFindBar", function() { - let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; - let findbar = document.createElementNS(XULNS, "findbar"); - findbar.id = "FindToolbar"; - - let browserBottomBox = document.getElementById("browser-bottombox"); - browserBottomBox.insertBefore(findbar, browserBottomBox.firstChild); - - // Force a style flush to ensure that our binding is attached. - findbar.clientTop; - findbar.browser = gBrowser.mCurrentBrowser; - window.gFindBarInitialized = true; - return findbar; -}); - -XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils", - "resource://gre/modules/BrowserUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "gPrefService", function() { - return Services.prefs; -}); - -this.__defineGetter__("AddonManager", function() { - let tmp = {}; - Cu.import("resource://gre/modules/AddonManager.jsm", tmp); - return this.AddonManager = tmp.AddonManager; -}); -this.__defineSetter__("AddonManager", function (val) { - delete this.AddonManager; - return this.AddonManager = val; -}); - -XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", - "resource://gre/modules/PluralForm.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "AboutHomeUtils", - "resource:///modules/AboutHomeUtils.jsm"); - -#ifdef MOZ_SERVICES_SYNC -XPCOMUtils.defineLazyModuleGetter(this, "Weave", - "resource://services-sync/main.js"); -#endif - -XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () { - let tmp = {}; - Cu.import("resource:///modules/PopupNotifications.jsm", tmp); - try { - return new tmp.PopupNotifications(gBrowser, - document.getElementById("notification-popup"), - document.getElementById("notification-popup-box")); - } catch (ex) { - Cu.reportError(ex); - return null; - } -}); - -XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", - "resource://gre/modules/PageThumbs.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "gBrowserNewTabPreloader", - "resource:///modules/BrowserNewTabPreloader.jsm", "BrowserNewTabPreloader"); - -XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", - "resource://gre/modules/PrivateBrowsingUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "FormValidationHandler", - "resource:///modules/FormValidationHandler.jsm"); - -var gInitialPages = [ - "about:blank", - "about:newtab", - "about:home", - "about:privatebrowsing", - "about:sessionrestore", - "about:logopage" -]; - -#include browser-addons.js -#include browser-feeds.js -#include browser-fullScreen.js -#include browser-fullZoom.js -#include browser-places.js -#include browser-plugins.js -#include browser-tabPreviews.js -#include browser-thumbnails.js -#include browser-uacompat.js - -#ifdef MOZ_WEBRTC -#include browser-webrtcUI.js -#endif - -#include browser-gestureSupport.js - -#ifdef MOZ_SERVICES_SYNC -#include browser-syncui.js -#endif - -XPCOMUtils.defineLazyGetter(this, "Win7Features", function () { -#ifdef XP_WIN - const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1"; - if (WINTASKBAR_CONTRACTID in Cc && - Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) { - let AeroPeek = Cu.import("resource:///modules/WindowsPreviewPerTab.jsm", {}).AeroPeek; - return { - onOpenWindow: function () { - AeroPeek.onOpenWindow(window); - }, - onCloseWindow: function () { - AeroPeek.onCloseWindow(window); - } - }; - } -#endif - return null; -}); - -XPCOMUtils.defineLazyGetter(this, "PageMenu", function() { - let tmp = {}; - Cu.import("resource:///modules/PageMenu.jsm", tmp); - return new tmp.PageMenu(); -}); - -/** -* We can avoid adding multiple load event listeners and save some time by adding -* one listener that calls all real handlers. -*/ -function pageShowEventHandlers(persisted) { - charsetLoadListener(); - XULBrowserWindow.asyncUpdateUI(); - - // The PluginClickToPlay events are not fired when navigating using the - // BF cache. |persisted| is true when the page is loaded from the - // BF cache, so this code reshows the notification if necessary. - if (persisted) - gPluginHandler.reshowClickToPlayNotification(); -} - -function UpdateBackForwardCommands(aWebNavigation) { - var backBroadcaster = document.getElementById("Browser:Back"); - var forwardBroadcaster = document.getElementById("Browser:Forward"); - - // Avoid setting attributes on broadcasters if the value hasn't changed! - // Remember, guys, setting attributes on elements is expensive! They - // get inherited into anonymous content, broadcast to other widgets, etc.! - // Don't do it if the value hasn't changed! - dwh - - var backDisabled = backBroadcaster.hasAttribute("disabled"); - var forwardDisabled = forwardBroadcaster.hasAttribute("disabled"); - if (backDisabled == aWebNavigation.canGoBack) { - if (backDisabled) - backBroadcaster.removeAttribute("disabled"); - else - backBroadcaster.setAttribute("disabled", true); - } - - if (forwardDisabled == aWebNavigation.canGoForward) { - if (forwardDisabled) - forwardBroadcaster.removeAttribute("disabled"); - else - forwardBroadcaster.setAttribute("disabled", true); - } -} - -/** - * Click-and-Hold implementation for the Back and Forward buttons - * XXXmano: should this live in toolbarbutton.xml? - */ -function SetClickAndHoldHandlers() { - var timer; - - function openMenu(aButton) { - cancelHold(aButton); - aButton.firstChild.hidden = false; - aButton.open = true; - } - - function mousedownHandler(aEvent) { - if (aEvent.button != 0 || - aEvent.currentTarget.open || - aEvent.currentTarget.disabled) - return; - - // Prevent the menupopup from opening immediately - aEvent.currentTarget.firstChild.hidden = true; - - aEvent.currentTarget.addEventListener("mouseout", mouseoutHandler, false); - aEvent.currentTarget.addEventListener("mouseup", mouseupHandler, false); - timer = setTimeout(openMenu, 500, aEvent.currentTarget); - } - - function mouseoutHandler(aEvent) { - let buttonRect = aEvent.currentTarget.getBoundingClientRect(); - if (aEvent.clientX >= buttonRect.left && - aEvent.clientX <= buttonRect.right && - aEvent.clientY >= buttonRect.bottom) - openMenu(aEvent.currentTarget); - else - cancelHold(aEvent.currentTarget); - } - - function mouseupHandler(aEvent) { - cancelHold(aEvent.currentTarget); - } - - function cancelHold(aButton) { - clearTimeout(timer); - aButton.removeEventListener("mouseout", mouseoutHandler, false); - aButton.removeEventListener("mouseup", mouseupHandler, false); - } - - function clickHandler(aEvent) { - if (aEvent.button == 0 && - aEvent.target == aEvent.currentTarget && - !aEvent.currentTarget.open && - !aEvent.currentTarget.disabled) { - let cmdEvent = document.createEvent("xulcommandevent"); - cmdEvent.initCommandEvent("command", true, true, window, 0, - aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey, - aEvent.metaKey, null); - aEvent.currentTarget.dispatchEvent(cmdEvent); - } - } - - function _addClickAndHoldListenersOnElement(aElm) { - aElm.addEventListener("mousedown", mousedownHandler, true); - aElm.addEventListener("click", clickHandler, true); - } - - // Bug 414797: Clone unified-back-forward-button's context menu into both the - // back and the forward buttons. - var unifiedButton = document.getElementById("unified-back-forward-button"); - if (unifiedButton && !unifiedButton._clickHandlersAttached) { - unifiedButton._clickHandlersAttached = true; - - let popup = document.getElementById("backForwardMenu").cloneNode(true); - popup.removeAttribute("id"); - // Prevent the context attribute on unified-back-forward-button from being - // inherited. - popup.setAttribute("context", ""); - - let backButton = document.getElementById("back-button"); - backButton.setAttribute("type", "menu"); - backButton.appendChild(popup); - _addClickAndHoldListenersOnElement(backButton); - - let forwardButton = document.getElementById("forward-button"); - popup = popup.cloneNode(true); - forwardButton.setAttribute("type", "menu"); - forwardButton.appendChild(popup); - _addClickAndHoldListenersOnElement(forwardButton); - } -} - -const gSessionHistoryObserver = { - observe: function(subject, topic, data) - { - if (topic != "browser:purge-session-history") - return; - - var backCommand = document.getElementById("Browser:Back"); - backCommand.setAttribute("disabled", "true"); - var fwdCommand = document.getElementById("Browser:Forward"); - fwdCommand.setAttribute("disabled", "true"); - - // Hide session restore button on about:home - window.messageManager.broadcastAsyncMessage("Browser:HideSessionRestoreButton"); - - if (gURLBar) { - // Clear undo history of the URL bar - gURLBar.editor.transactionManager.clear() - } - } -}; - -var gFindBarSettings = { - messageName: "Findbar:Keypress", - prefName: "accessibility.typeaheadfind", - findAsYouType: null, - - init: function() { - window.messageManager.addMessageListener(this.messageName, this); - - gPrefService.addObserver(this.prefName, this, false); - this.writeFindAsYouType(); - }, - - uninit: function() { - window.messageManager.removeMessageListener(this.messageName, this); - - try { - gPrefService.removeObserver(this.prefName, this); - } catch (ex) { - Cu.reportError(ex); - } - }, - - observe: function(aSubject, aTopic, aData) { - if (aTopic != "nsPref:changed") { - return; - } - - this.writeFindAsYouType(); - }, - - writeFindAsYouType: function() { - this.findAsYouType = gPrefService.getBoolPref(this.prefName); - }, - - receiveMessage: function(aMessage) { - switch (aMessage.name) { - case this.messageName: - // If the find bar for chrome window's context is not yet alive, - // only initialize it if there's a possibility FindAsYouType - // will be used. - // There's no point in doing it for most random keypresses. - if (!gFindBarInitialized && aMessage.data.shouldFastFind) { - let shouldFastFind = this.findAsYouType; - if (!shouldFastFind) { - // Please keep in sync with toolkit/content/widgets/findbar.xml - const FAYT_LINKS_KEY = "'"; - const FAYT_TEXT_KEY = "/"; - let charCode = aMessage.data.fakeEvent.charCode; - let key = charCode ? String.fromCharCode(charCode) : null; - shouldFastFind = key == FAYT_LINKS_KEY || key == FAYT_TEXT_KEY; - } - if (shouldFastFind) { - // Make sure we return the result. - return gFindBar.receiveMessage(aMessage); - } - } - break; - } - } -}; - -var gURLBarSettings = { - prefSuggest: "browser.urlbar.suggest.", - /* - For searching in the source code: - browser.urlbar.suggest.bookmark - browser.urlbar.suggest.history - browser.urlbar.suggest.openpage - */ - prefSuggests: [ - "bookmark", - "history", - "openpage" - ], - prefKeyword: "keyword.enabled", - - observe: function(aSubject, aTopic, aData) { - if (aTopic != "nsPref:changed") - return; - - this.writePlaceholder(); - }, - - writePlaceholder: function() { - if (!gURLBar) { - return; - } - - let attribute = "placeholder"; - let prefs = this.prefSuggests.map(pref => { - return this.prefSuggest + pref; - }); - prefs.push(this.prefKeyword); - let placeholderDefault = prefs.some(pref => { - return gPrefService.getBoolPref(pref); - }); - - if (placeholderDefault) { - gURLBar.setAttribute( - attribute, gNavigatorBundle.getString("urlbar.placeholder")); - } else { - gURLBar.setAttribute( - attribute, gNavigatorBundle.getString("urlbar.placeholderURLOnly")); - } - } -}; - -/** - * Given a starting docshell and a URI to look up, find the docshell the URI - * is loaded in. - * @param aDocument - * A document to find instead of using just a URI - this is more specific. - * @param aDocShell - * The doc shell to start at - * @param aSoughtURI - * The URI that we're looking for - * @returns The doc shell that the sought URI is loaded in. Can be in - * subframes. - */ -function findChildShell(aDocument, aDocShell, aSoughtURI) { - aDocShell.QueryInterface(Components.interfaces.nsIWebNavigation); - aDocShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor); - var doc = aDocShell.getInterface(Components.interfaces.nsIDOMDocument); - if ((aDocument && doc == aDocument) || - (aSoughtURI && aSoughtURI.spec == aDocShell.currentURI.spec)) - return aDocShell; - - var node = aDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeItem); - for (var i = 0; i < node.childCount; ++i) { - var docShell = node.getChildAt(i); - docShell = findChildShell(aDocument, docShell, aSoughtURI); - if (docShell) - return docShell; - } - return null; -} - -var gPopupBlockerObserver = { - _reportButton: null, - - onReportButtonClick: function (aEvent) - { - if (aEvent.button != 0 || aEvent.target != this._reportButton) - return; - - document.getElementById("blockedPopupOptions") - .openPopup(this._reportButton, "after_end", 0, 2, false, false, aEvent); - }, - - handleEvent: function (aEvent) - { - if (aEvent.originalTarget != gBrowser.selectedBrowser) - return; - - if (!this._reportButton && gURLBar) - this._reportButton = document.getElementById("page-report-button"); - - if (!gBrowser.selectedBrowser.blockedPopups || - !gBrowser.selectedBrowser.blockedPopups.length) { - // Hide the icon in the location bar (if the location bar exists) - if (gURLBar) - this._reportButton.hidden = true; - return; - } - - if (gURLBar) - this._reportButton.hidden = false; - - // Only show the notification again if we've not already shown it. Since - // notifications are per-browser, we don't need to worry about re-adding - // it. - if (!gBrowser.selectedBrowser.blockedPopups.reported) { - if (gPrefService.getBoolPref("privacy.popups.showBrowserMessage")) { - var brandBundle = document.getElementById("bundle_brand"); - var brandShortName = brandBundle.getString("brandShortName"); - var popupCount = gBrowser.selectedBrowser.blockedPopups.length; - var popupButtonText = gNavigatorBundle.getString("popupWarningButton"); - var popupButtonAccesskey = gNavigatorBundle.getString("popupWarningButton.accesskey"); - var messageBase = gNavigatorBundle.getString("popupWarning.message"); - var message = PluralForm.get(popupCount, messageBase) - .replace("#1", brandShortName) - .replace("#2", popupCount); - - var notificationBox = gBrowser.getNotificationBox(); - var notification = notificationBox.getNotificationWithValue("popup-blocked"); - if (notification) { - notification.label = message; - } - else { - var buttons = [{ - label: popupButtonText, - accessKey: popupButtonAccesskey, - popup: "blockedPopupOptions", - callback: null - }]; - - const priority = notificationBox.PRIORITY_WARNING_MEDIUM; - notificationBox.appendNotification(message, "popup-blocked", - "chrome://browser/skin/Info.png", - priority, buttons); - } - } - - // Record the fact that we've reported this blocked popup, so we don't - // show it again. - gBrowser.selectedBrowser.blockedPopups.reported = true; - } - }, - - toggleAllowPopupsForSite: function (aEvent) - { - var pm = Services.perms; - var shouldBlock = aEvent.target.getAttribute("block") == "true"; - var perm = shouldBlock ? pm.DENY_ACTION : pm.ALLOW_ACTION; - pm.add(gBrowser.currentURI, "popup", perm); - - gBrowser.getNotificationBox().removeCurrentNotification(); - }, - - fillPopupList: function (aEvent) - { - // XXXben - rather than using |currentURI| here, which breaks down on multi-framed sites - // we should really walk the blockedPopups and create a list of "allow for <host>" - // menuitems for the common subset of hosts present in the report, this will - // make us frame-safe. - // - // XXXjst - Note that when this is fixed to work with multi-framed sites, - // also back out the fix for bug 343772 where - // nsGlobalWindow::CheckOpenAllow() was changed to also - // check if the top window's location is whitelisted. - let browser = gBrowser.selectedBrowser; - var uri = browser.currentURI; - var blockedPopupAllowSite = document.getElementById("blockedPopupAllowSite"); - try { - blockedPopupAllowSite.removeAttribute("hidden"); - - var pm = Services.perms; - if (pm.testPermission(uri, "popup") == pm.ALLOW_ACTION) { - // Offer an item to block popups for this site, if a whitelist entry exists - // already for it. - let blockString = gNavigatorBundle.getFormattedString("popupBlock", [uri.host || uri.spec]); - blockedPopupAllowSite.setAttribute("label", blockString); - blockedPopupAllowSite.setAttribute("block", "true"); - } - else { - // Offer an item to allow popups for this site - let allowString = gNavigatorBundle.getFormattedString("popupAllow", [uri.host || uri.spec]); - blockedPopupAllowSite.setAttribute("label", allowString); - blockedPopupAllowSite.removeAttribute("block"); - } - } - catch (e) { - blockedPopupAllowSite.setAttribute("hidden", "true"); - } - - if (PrivateBrowsingUtils.isWindowPrivate(window)) - blockedPopupAllowSite.setAttribute("disabled", "true"); - else - blockedPopupAllowSite.removeAttribute("disabled"); - - let blockedPopupDontShowMessage = document.getElementById("blockedPopupDontShowMessage"); - let showMessage = gPrefService.getBoolPref("privacy.popups.showBrowserMessage"); - blockedPopupDontShowMessage.setAttribute("checked", !showMessage); - if (aEvent.target.anchorNode.id == "page-report-button") { - aEvent.target.anchorNode.setAttribute("open", "true"); - blockedPopupDontShowMessage.setAttribute("label", gNavigatorBundle.getString("popupWarningDontShowFromLocationbar")); - } else { - blockedPopupDontShowMessage.setAttribute("label", gNavigatorBundle.getString("popupWarningDontShowFromMessage")); - } - - let blockedPopupsSeparator = - document.getElementById("blockedPopupsSeparator"); - blockedPopupsSeparator.setAttribute("hidden", true); - - gBrowser.selectedBrowser.retrieveListOfBlockedPopups().then(blockedPopups => { - let foundUsablePopupURI = false; - if (blockedPopups) { - for (let i = 0; i < blockedPopups.length; i++) { - let blockedPopup = blockedPopups[i]; - - // popupWindowURI will be null if the file picker popup is blocked. - // xxxdz this should make the option say "Show file picker" and do it (Bug 590306) - if (!blockedPopup.popupWindowURIspec) - continue; - - var popupURIspec = blockedPopup.popupWindowURIspec; - - // Sometimes the popup URI that we get back from the blockedPopup - // isn't useful (for instance, netscape.com's popup URI ends up - // being "http://www.netscape.com", which isn't really the URI of - // the popup they're trying to show). This isn't going to be - // useful to the user, so we won't create a menu item for it. - if (popupURIspec == "" || popupURIspec == "about:blank" || - popupURIspec == "<self>" || - popupURIspec == uri.spec) - continue; - - // Because of the short-circuit above, we may end up in a situation - // in which we don't have any usable popup addresses to show in - // the menu, and therefore we shouldn't show the separator. However, - // since we got past the short-circuit, we must've found at least - // one usable popup URI and thus we'll turn on the separator later. - foundUsablePopupURI = true; - - var menuitem = document.createElement("menuitem"); - var label = gNavigatorBundle.getFormattedString("popupShowPopupPrefix", - [popupURIspec]); - menuitem.setAttribute("label", label); - menuitem.setAttribute("oncommand", "gPopupBlockerObserver.showBlockedPopup(event);"); - menuitem.setAttribute("popupReportIndex", i); - menuitem.popupReportBrowser = browser; - aEvent.target.appendChild(menuitem); - } - } - - // Show the separator if we added any - // showable popup addresses to the menu. - if (foundUsablePopupURI) - blockedPopupsSeparator.removeAttribute("hidden"); - }, null); - }, - - onPopupHiding: function (aEvent) { - if (aEvent.target.anchorNode.id == "page-report-button") - aEvent.target.anchorNode.removeAttribute("open"); - - let item = aEvent.target.lastChild; - while (item && item.getAttribute("observes") != "blockedPopupsSeparator") { - let next = item.previousSibling; - item.parentNode.removeChild(item); - item = next; - } - }, - - showBlockedPopup: function (aEvent) - { - var target = aEvent.target; - var popupReportIndex = target.getAttribute("popupReportIndex"); - let browser = target.popupReportBrowser; - browser.unblockPopup(popupReportIndex); - }, - - editPopupSettings: function () - { - var host = ""; - try { - host = gBrowser.currentURI.host; - } - catch (e) { } - - var bundlePreferences = document.getElementById("bundle_preferences"); - var params = { blockVisible : false, - sessionVisible : false, - allowVisible : true, - prefilledHost : host, - permissionType : "popup", - windowTitle : bundlePreferences.getString("popuppermissionstitle"), - introText : bundlePreferences.getString("popuppermissionstext") }; - var existingWindow = Services.wm.getMostRecentWindow("Browser:Permissions"); - if (existingWindow) { - existingWindow.initWithParams(params); - existingWindow.focus(); - } - else - window.openDialog("chrome://browser/content/preferences/permissions.xul", - "_blank", "resizable,dialog=no,centerscreen", params); - }, - - dontShowMessage: function () - { - var showMessage = gPrefService.getBoolPref("privacy.popups.showBrowserMessage"); - gPrefService.setBoolPref("privacy.popups.showBrowserMessage", !showMessage); - gBrowser.getNotificationBox().removeCurrentNotification(); - } -}; - -const gXSSObserver = { - - observe: function (aSubject, aTopic, aData) - { - - // Don't do anything if the notification is disabled. - if (!gPrefService.getBoolPref("security.xssfilter.displayWarning")) - return; - - // Parse incoming XSS array - aSubject.QueryInterface(Ci.nsIArray); - var policy = aSubject.queryElementAt(0, Ci.nsISupportsString).data; - var content = aSubject.queryElementAt(1, Ci.nsISupportsString).data; - var domain = aSubject.queryElementAt(2, Ci.nsISupportsString).data; - var url = aSubject.queryElementAt(3, Ci.nsISupportsCString).data; - var blockMode = aSubject.queryElementAt(4, Ci.nsISupportsPRBool).data; - - // If it is a block mode event, do not display the infobar - if (blockMode) - return; - - var nb = gBrowser.getNotificationBox(); - const priority = nb.PRIORITY_WARNING_MEDIUM; - - var buttons = [{ - label: 'View Unsafe Content', - accessKey: 'V', - popup: null, - callback: function () { - alert(content); - } - }]; - - if (domain !== "") - buttons.push({ - label: 'Add Domain Exception', - accessKey: 'A', - popup: null, - callback: function () { - let whitelist = gPrefService.getCharPref("security.xssfilter.whitelist"); - if (whitelist != "") { - whitelist = whitelist + "," + domain; - } else { - whitelist = domain; - } - // Write the updated whitelist. Since this is observed by the XSS filter, - // it will automatically sync to the back-end and update immediately. - gPrefService.setCharPref("security.xssfilter.whitelist", whitelist); - // After setting this, we automatically reload the page. - BrowserReloadSkipCache(); - } - }); - - nb.appendNotification("The XSS Filter has detected a potential XSS attack. Type: " + - policy, 'popup-blocked', 'chrome://browser/skin/Info.png', - priority, buttons); - } -}; - -var gBrowserInit = { - delayedStartupFinished: false, - - onLoad: function() { - gMultiProcessBrowser = gPrefService.getBoolPref("browser.tabs.remote"); - - var mustLoadSidebar = false; - - Cc["@mozilla.org/eventlistenerservice;1"] - .getService(Ci.nsIEventListenerService) - .addSystemEventListener(gBrowser, "click", contentAreaClick, true); - - gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver, false); - - // Note that the XBL binding is untrusted - gBrowser.addEventListener("PluginBindingAttached", gPluginHandler, true, true); - gBrowser.addEventListener("PluginCrashed", gPluginHandler, true); - gBrowser.addEventListener("PluginOutdated", gPluginHandler, true); - gBrowser.addEventListener("PluginInstantiated", gPluginHandler, true); - gBrowser.addEventListener("PluginRemoved", gPluginHandler, true); - - Services.obs.addObserver(gPluginHandler.pluginCrashed, "plugin-crashed", false); - - window.addEventListener("AppCommand", HandleAppCommandEvent, true); - - // These routines add message listeners. They must run before - // loading the frame script to ensure that we don't miss any - // message sent between when the frame script is loaded and when - // the listener is registered. -#ifdef MOZ_DEVTOOLS - DevToolsTheme.init(); -#endif - gFindBarSettings.init(); - - messageManager.loadFrameScript("chrome://browser/content/content.js", true); - messageManager.loadFrameScript("chrome://browser/content/content-sessionStore.js", true); - - // initialize observers and listeners - // and give C++ access to gBrowser - XULBrowserWindow.init(); - window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIXULWindow) - .XULBrowserWindow = window.XULBrowserWindow; - window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = - new nsBrowserAccess(); - - // set default character set if provided - // window.arguments[1]: character set (string) - if ("arguments" in window && window.arguments.length > 1 && window.arguments[1]) { - if (window.arguments[1].startsWith("charset=")) { - var arrayArgComponents = window.arguments[1].split("="); - if (arrayArgComponents) { - //we should "inherit" the charset menu setting in a new window - //TFE FIXME: this is now a wrappednative and can't be set this way. - //getMarkupDocumentViewer().defaultCharacterSet = arrayArgComponents[1]; - } - } - } - - // Manually hook up session and global history for the first browser - // so that we don't have to load global history before bringing up a - // window. - // Wire up session and global history before any possible - // progress notifications for back/forward button updating - gBrowser.webNavigation.sessionHistory = Cc["@mozilla.org/browser/shistory;1"]. - createInstance(Ci.nsISHistory); - Services.obs.addObserver(gBrowser.browsers[0], "browser:purge-session-history", false); - - // remove the disablehistory attribute so the browser cleans up, as - // though it had done this work itself - gBrowser.browsers[0].removeAttribute("disablehistory"); - - // enable global history - try { - if (!gMultiProcessBrowser) - gBrowser.docShell.useGlobalHistory = true; - } catch(ex) { - Cu.reportError("Places database may be locked: " + ex); - } - - // hook up UI through progress listener - gBrowser.addProgressListener(window.XULBrowserWindow); - gBrowser.addTabsProgressListener(window.TabsProgressListener); - - // setup our common DOMLinkAdded listener - gBrowser.addEventListener("DOMLinkAdded", DOMLinkHandler, false); - - // setup our MozApplicationManifest listener - gBrowser.addEventListener("MozApplicationManifest", - OfflineApps, false); - - // setup simple gestures support - gGestureSupport.init(true); - - // setup history swipe animation - gHistorySwipeAnimation.init(); - - if (window.opener && !window.opener.closed) { - let openerSidebarBox = window.opener.document.getElementById("sidebar-box"); - // If the opener had a sidebar, open the same sidebar in our window. - // The opener can be the hidden window too, if we're coming from the state - // where no windows are open, and the hidden window has no sidebar box. - if (openerSidebarBox && !openerSidebarBox.hidden) { - let sidebarCmd = openerSidebarBox.getAttribute("sidebarcommand"); - let sidebarCmdElem = document.getElementById(sidebarCmd); - - // dynamically generated sidebars will fail this check. - if (sidebarCmdElem) { - let sidebarBox = document.getElementById("sidebar-box"); - let sidebarTitle = document.getElementById("sidebar-title"); - - sidebarTitle.setAttribute( - "value", window.opener.document.getElementById("sidebar-title").getAttribute("value")); - sidebarBox.setAttribute("width", openerSidebarBox.boxObject.width); - - sidebarBox.setAttribute("sidebarcommand", sidebarCmd); - // Note: we're setting 'src' on sidebarBox, which is a <vbox>, not on - // the <browser id="sidebar">. This lets us delay the actual load until - // delayedStartup(). - sidebarBox.setAttribute( - "src", window.opener.document.getElementById("sidebar").getAttribute("src")); - mustLoadSidebar = true; - - sidebarBox.hidden = false; - document.getElementById("sidebar-splitter").hidden = false; - sidebarCmdElem.setAttribute("checked", "true"); - } - } - } - else { - let box = document.getElementById("sidebar-box"); - if (box.hasAttribute("sidebarcommand")) { - let commandID = box.getAttribute("sidebarcommand"); - if (commandID) { - let command = document.getElementById(commandID); - if (command) { - mustLoadSidebar = true; - box.hidden = false; - document.getElementById("sidebar-splitter").hidden = false; - command.setAttribute("checked", "true"); - } - else { - // Remove the |sidebarcommand| attribute, because the element it - // refers to no longer exists, so we should assume this sidebar - // panel has been uninstalled. (249883) - box.removeAttribute("sidebarcommand"); - } - } - } - } - - // Certain kinds of automigration rely on this notification to complete their - // tasks BEFORE the browser window is shown. - Services.obs.notifyObservers(null, "browser-window-before-show", ""); - - // Set a sane starting width/height for all resolutions on new profiles. - if (!document.documentElement.hasAttribute("width")) { - let defaultWidth; - let defaultHeight; - - // Very small: maximize the window - // Portrait : use about full width and 3/4 height, to view entire pages - // at once (without being obnoxiously tall) - // Widescreen: use about half width, to suggest side-by-side page view - // Otherwise : use 3/4 height and width - if (screen.availHeight <= 600) { - document.documentElement.setAttribute("sizemode", "maximized"); - defaultWidth = 610; - defaultHeight = 450; - } - else { - if (screen.availWidth <= screen.availHeight) { - defaultWidth = screen.availWidth * .9; - defaultHeight = screen.availHeight * .75; - } - else if (screen.availWidth >= 2048) { - defaultWidth = (screen.availWidth / 2) - 20; - defaultHeight = screen.availHeight - 10; - } - else { - defaultWidth = screen.availWidth * .75; - defaultHeight = screen.availHeight * .75; - } - -#ifdef MOZ_WIDGET_GTK2 - // On X, we're not currently able to account for the size of the window - // border. Use 28px as a guess (titlebar + bottom window border) - defaultHeight -= 28; -#endif - } - document.documentElement.setAttribute("width", defaultWidth); - document.documentElement.setAttribute("height", defaultHeight); - } - - if (!gShowPageResizers) - document.getElementById("status-bar").setAttribute("hideresizer", "true"); - - if (!window.toolbar.visible) { - // adjust browser UI for popups - if (gURLBar) { - gURLBar.setAttribute("readonly", "true"); - gURLBar.setAttribute("enablehistory", "false"); - } - goSetCommandEnabled("cmd_newNavigatorTab", false); - } - -#ifdef MENUBAR_CAN_AUTOHIDE - updateAppButtonDisplay(); -#endif - - // Misc. inits. - CombinedStopReload.init(); - allTabs.readPref(); - TabsOnTop.init(); - AudioIndicator.init(); - gPrivateBrowsingUI.init(); - TabsInTitlebar.init(); - retrieveToolbarIconsizesFromTheme(); - ToolbarIconColor.init(); - UserAgentCompatibility.init(); - -#ifdef XP_WIN - if (window.matchMedia("(-moz-os-version: windows-win8)").matches && - window.matchMedia("(-moz-windows-default-theme)").matches) { - let windows8WindowFrameColor = Cu.import("resource:///modules/Windows8WindowFrameColor.jsm", {}).Windows8WindowFrameColor; - - var windowFrameColor; - windowFrameColor = windows8WindowFrameColor.get_win8(); - - // Formula from Microsoft's UWP guideline. - let backgroundLuminance = (windowFrameColor[0] * 2 + - windowFrameColor[1] * 5 + - windowFrameColor[2]) / 8; - if (backgroundLuminance <= 128) { - document.documentElement.setAttribute("darkwindowframe", "true"); - } - } -#endif - - // Wait until chrome is painted before executing code not critical to making the window visible - this._boundDelayedStartup = this._delayedStartup.bind(this, mustLoadSidebar); - window.addEventListener("MozAfterPaint", this._boundDelayedStartup); - - this._loadHandled = true; - }, - - _cancelDelayedStartup: function () { - window.removeEventListener("MozAfterPaint", this._boundDelayedStartup); - this._boundDelayedStartup = null; - }, - - _delayedStartup: function(mustLoadSidebar) { - let tmp = {}; - - this._cancelDelayedStartup(); - - let uriToLoad = this._getUriToLoad(); - var isLoadingBlank = isBlankPageURL(uriToLoad); - - // This pageshow listener needs to be registered before we may call - // swapBrowsersAndCloseOther() to receive pageshow events fired by that. - gBrowser.addEventListener("pageshow", function(event) { - // Filter out events that are not about the document load we are interested in - if (content && event.target == content.document) - setTimeout(pageShowEventHandlers, 0, event.persisted); - }, true); - - if (uriToLoad && uriToLoad != "about:blank") { - if (uriToLoad instanceof Ci.nsISupportsArray) { - let count = uriToLoad.Count(); - let specs = []; - for (let i = 0; i < count; i++) { - let urisstring = uriToLoad.GetElementAt(i).QueryInterface(Ci.nsISupportsString); - specs.push(urisstring.data); - } - - // This function throws for certain malformed URIs, so use exception handling - // so that we don't disrupt startup - try { - gBrowser.loadTabs(specs, false, true); - } catch (e) {} - } - else if (uriToLoad instanceof XULElement) { - // swap the given tab with the default about:blank tab and then close - // the original tab in the other window. - - // Stop the about:blank load - gBrowser.stop(); - // make sure it has a docshell - gBrowser.docShell; - - gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad); - } - // window.arguments[2]: referrer (nsIURI | string) - // [3]: postData (nsIInputStream) - // [4]: allowThirdPartyFixup (bool) - // [5]: referrerPolicy (int) - // [6]: originPrincipal (nsIPrincipal) - // [7]: triggeringPrincipal (nsIPrincipal) - else if (window.arguments.length >= 3) { - let referrerURI = window.arguments[2]; - if (typeof(referrerURI) == "string") { - try { - referrerURI = makeURI(referrerURI); - } catch (e) { - referrerURI = null; - } - } - let referrerPolicy = (window.arguments[5] != undefined ? - window.arguments[5] : Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT); - loadURI(uriToLoad, referrerURI, window.arguments[3] || null, - window.arguments[4] || false, referrerPolicy, - // pass the origin principal (if any) and force its use to create - // an initial about:blank viewer if present: - window.arguments[6], !!window.arguments[6], window.arguments[7]); - window.focus(); - } - // Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3. - // Such callers expect that window.arguments[0] is handled as a single URI. - else - loadOneOrMoreURIs(uriToLoad); - } - - Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false); - Services.obs.addObserver(gXPInstallObserver, "addon-install-disabled", false); - Services.obs.addObserver(gXPInstallObserver, "addon-install-started", false); - Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false); - Services.obs.addObserver(gXPInstallObserver, "addon-install-origin-blocked", false); - Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false); - Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false); - Services.obs.addObserver(gXSSObserver, "xss-on-violate-policy", false); - - gPrefService.addObserver(gURLBarSettings.prefSuggest, gURLBarSettings, false); - gPrefService.addObserver(gURLBarSettings.prefKeyword, gURLBarSettings, false); - - gURLBarSettings.writePlaceholder(); - - BrowserOffline.init(); - OfflineApps.init(); - IndexedDBPromptHelper.init(); - AddonManager.addAddonListener(AddonsMgrListener); -#ifdef MOZ_WEBRTC - WebrtcIndicator.init(); -#endif - - // Ensure login manager is up and running. - Services.logins; - - if (mustLoadSidebar) { - let sidebar = document.getElementById("sidebar"); - let sidebarBox = document.getElementById("sidebar-box"); - sidebar.setAttribute("src", sidebarBox.getAttribute("src")); - } - - UpdateUrlbarSearchSplitterState(); - - if (!isLoadingBlank || !focusAndSelectUrlBar()) - gBrowser.selectedBrowser.focus(); - - gNavToolbox.customizeDone = BrowserToolboxCustomizeDone; - gNavToolbox.customizeChange = BrowserToolboxCustomizeChange; - - // Set up Sanitize Item - this._initializeSanitizer(); - - // Enable/Disable auto-hide tabbar - gBrowser.tabContainer.updateVisibility(); - - gPrefService.addObserver(gHomeButton.prefDomain, gHomeButton, false); - - var homeButton = document.getElementById("home-button"); - gHomeButton.updateTooltip(homeButton); - gHomeButton.updatePersonalToolbarStyle(homeButton); - - // BiDi UI - gBidiUI = isBidiEnabled(); - if (gBidiUI) { - document.getElementById("documentDirection-separator").hidden = false; - document.getElementById("documentDirection-swap").hidden = false; - document.getElementById("textfieldDirection-separator").hidden = false; - document.getElementById("textfieldDirection-swap").hidden = false; - } - - // Setup click-and-hold gestures access to the session history - // menus if global click-and-hold isn't turned on - if (!Services.prefs.getBoolPref("ui.click_hold_context_menus", false)) - SetClickAndHoldHandlers(); - - // Initialize the full zoom setting. - // We do this before the session restore service gets initialized so we can - // apply full zoom settings to tabs restored by the session restore service. - FullZoom.init(); - - // Bug 666804 - NetworkPrioritizer support for e10s - if (!gMultiProcessBrowser) { - let NP = {}; - Cu.import("resource:///modules/NetworkPrioritizer.jsm", NP); - NP.trackBrowserWindow(window); - } - - // initialize the session-restore service (in case it's not already running) - let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); - let ssPromise = ss.init(window); - - PlacesToolbarHelper.init(); - - ctrlTab.readPref(); - gPrefService.addObserver(ctrlTab.prefName, ctrlTab, false); - gPrefService.addObserver(allTabs.prefName, allTabs, false); - - // Initialize the download manager some time after the app starts so that - // auto-resume downloads begin (such as after crashing or quitting with - // active downloads) and speeds up the first-load of the download manager UI. - // If the user manually opens the download manager before the timeout, the - // downloads will start right away, and getting the service again won't hurt. - setTimeout(function() { - try { - Cu.import("resource:///modules/DownloadsCommon.jsm", {}) - .DownloadsCommon.initializeAllDataLinks(); - Cu.import("resource:///modules/DownloadsTaskbar.jsm", {}) - .DownloadsTaskbar.registerIndicator(window); - } catch(ex) { - Cu.reportError(ex); - } - }, 10000); - - // Load the Login Manager data from disk off the main thread, some time - // after startup. If the data is required before the timeout, for example - // because a restored page contains a password field, it will be loaded on - // the main thread, and this initialization request will be ignored. - setTimeout(function() { - try { - Services.logins; - } catch (ex) { - Cu.reportError(ex); - } - }, 3000); - - // The object handling the downloads indicator is also initialized here in the - // delayed startup function, but the actual indicator element is not loaded - // unless there are downloads to be displayed. - DownloadsButton.initializeIndicator(); - -#ifndef XP_MACOSX - updateEditUIVisibility(); - let placesContext = document.getElementById("placesContext"); - placesContext.addEventListener("popupshowing", updateEditUIVisibility, false); - placesContext.addEventListener("popuphiding", updateEditUIVisibility, false); -#endif - -#ifdef MOZ_PERSONAS - gBrowser.mPanelContainer.addEventListener("InstallBrowserTheme", LightWeightThemeWebInstaller, false, true); - gBrowser.mPanelContainer.addEventListener("PreviewBrowserTheme", LightWeightThemeWebInstaller, false, true); - gBrowser.mPanelContainer.addEventListener("ResetBrowserThemePreview", LightWeightThemeWebInstaller, false, true); -#endif - - // Bug 666808 - AeroPeek support for e10s - if (!gMultiProcessBrowser) { - if (Win7Features) - Win7Features.onOpenWindow(); - } - - // called when we go into full screen, even if initiated by a web page script - window.addEventListener("fullscreen", onFullScreen, true); - - // Called when we enter DOM full-screen mode. Note we can already be in browser - // full-screen mode when we enter DOM full-screen mode. - window.addEventListener("MozDOMFullscreen:NewOrigin", onMozEnteredDomFullscreen, true); - - if (window.fullScreen) - onFullScreen(); - if (document.mozFullScreen) - onMozEnteredDomFullscreen(); - -#ifdef MOZ_SERVICES_SYNC - // initialize the sync UI - gSyncUI.init(); -#endif - - gBrowserThumbnails.init(); - - setUrlAndSearchBarWidthForConditionalForwardButton(); - window.addEventListener("resize", function resizeHandler(event) { - if (event.target == window) - setUrlAndSearchBarWidthForConditionalForwardButton(); - }); - - // Enable Error Console? - let consoleEnabled = gPrefService.getBoolPref("devtools.errorconsole.enabled"); - if (consoleEnabled) { - let cmd = document.getElementById("Tools:ErrorConsole"); - cmd.removeAttribute("disabled"); - cmd.removeAttribute("hidden"); - } - -#ifdef MENUBAR_CAN_AUTOHIDE - // If the user (or the locale) hasn't enabled the top-level "Character - // Encoding" menu via the "browser.menu.showCharacterEncoding" preference, - // hide it. - if ("true" != gPrefService.getComplexValue("browser.menu.showCharacterEncoding", - Ci.nsIPrefLocalizedString).data) - document.getElementById("appmenu_charsetMenu").hidden = true; -#endif - - let appMenuButton = document.getElementById("appmenu-button"); - let appMenuPopup = document.getElementById("appmenu-popup"); - if (appMenuButton && appMenuPopup) { - let appMenuOpening = null; - appMenuButton.addEventListener("mousedown", function(event) { - if (event.button == 0) - appMenuOpening = new Date(); - }, false); - appMenuPopup.addEventListener("popupshown", function(event) { - if (event.target != appMenuPopup || !appMenuOpening) - return; - let duration = new Date() - appMenuOpening; - appMenuOpening = null; - }, false); - } - - window.addEventListener("mousemove", MousePosTracker, false); - window.addEventListener("dragover", MousePosTracker, false); - - // End startup crash tracking after a delay to catch crashes while restoring - // tabs and to postpone saving the pref to disk. - try { - const startupCrashEndDelay = 30 * 1000; - setTimeout(Services.startup.trackStartupCrashEnd, startupCrashEndDelay); - } catch (ex) { - Cu.reportError("Could not end startup crash tracking: " + ex); - } - - ssPromise.then(() =>{ - // Bail out if the window has been closed in the meantime. - if (window.closed) { - return; - } - if ("TabView" in window) { - TabView.init(); - } - // XXX: do we still need this?... - setTimeout(function () { BrowserChromeTest.markAsReady(); }, 0); - }); - - this.delayedStartupFinished = true; - - Services.obs.notifyObservers(window, "browser-delayed-startup-finished", ""); - }, - - // Returns the URI(s) to load at startup. - _getUriToLoad: function () { - // window.arguments[0]: URI to load (string), or an nsISupportsArray of - // nsISupportsStrings to load, or a xul:tab of - // a tabbrowser, which will be replaced by this - // window (for this case, all other arguments are - // ignored). - if (!window.arguments || !window.arguments[0]) - return null; - - let uri = window.arguments[0]; - let sessionStartup = Cc["@mozilla.org/browser/sessionstartup;1"] - .getService(Ci.nsISessionStartup); - let defaultArgs = Cc["@mozilla.org/browser/clh;1"] - .getService(Ci.nsIBrowserHandler) - .defaultArgs; - - // If the given URI matches defaultArgs (the default homepage) we want - // to block its load if we're going to restore a session anyway. - if (uri == defaultArgs && sessionStartup.willOverrideHomepage) - return null; - - return uri; - }, - - onUnload: function() { - // In certain scenarios it's possible for unload to be fired before onload, - // (e.g. if the window is being closed after browser.js loads but before the - // load completes). In that case, there's nothing to do here. - if (!this._loadHandled) - return; - - // First clean up services initialized in gBrowserInit.onLoad (or those whose - // uninit methods don't depend on the services having been initialized). - - allTabs.uninit(); - - CombinedStopReload.uninit(); - - gGestureSupport.init(false); - - gHistorySwipeAnimation.uninit(); - - FullScreen.cleanup(); - - Services.obs.removeObserver(gPluginHandler.pluginCrashed, "plugin-crashed"); - - try { - gBrowser.removeProgressListener(window.XULBrowserWindow); - gBrowser.removeTabsProgressListener(window.TabsProgressListener); - } catch (ex) { - } - - BookmarkingUI.uninit(); - - TabsOnTop.uninit(); - - AudioIndicator.uninit(); - - TabsInTitlebar.uninit(); - - ToolbarIconColor.uninit(); - -#ifdef MOZ_DEVTOOLS - DevToolsTheme.uninit(); -#endif - gFindBarSettings.uninit(); - - UserAgentCompatibility.uninit(); - - var enumerator = Services.wm.getEnumerator(null); - enumerator.getNext(); - if (!enumerator.hasMoreElements()) { - document.persist("sidebar-box", "sidebarcommand"); - document.persist("sidebar-box", "width"); - document.persist("sidebar-box", "src"); - document.persist("sidebar-title", "value"); - } - - // Now either cancel delayedStartup, or clean up the services initialized from - // it. - if (this._boundDelayedStartup) { - this._cancelDelayedStartup(); - } else { - if (Win7Features) - Win7Features.onCloseWindow(); - - gPrefService.removeObserver(ctrlTab.prefName, ctrlTab); - gPrefService.removeObserver(allTabs.prefName, allTabs); - ctrlTab.uninit(); - if ("TabView" in window) { - TabView.uninit(); - } - gBrowserThumbnails.uninit(); - FullZoom.destroy(); - - Services.obs.removeObserver(gSessionHistoryObserver, "browser:purge-session-history"); - Services.obs.removeObserver(gXPInstallObserver, "addon-install-disabled"); - Services.obs.removeObserver(gXPInstallObserver, "addon-install-started"); - Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked"); - Services.obs.removeObserver(gXPInstallObserver, "addon-install-origin-blocked"); - Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed"); - Services.obs.removeObserver(gXPInstallObserver, "addon-install-complete"); - Services.obs.removeObserver(gXSSObserver, "xss-on-violate-policy"); - - try { - gPrefService.removeObserver(gURLBarSettings.prefSuggest, gURLBarSettings); - gPrefService.removeObserver(gURLBarSettings.prefKeyword, gURLBarSettings); - } catch (ex) { - Cu.reportError(ex); - } - - try { - gPrefService.removeObserver(gHomeButton.prefDomain, gHomeButton); - } catch (ex) { - Cu.reportError(ex); - } - - BrowserOffline.uninit(); - OfflineApps.uninit(); - IndexedDBPromptHelper.uninit(); - AddonManager.removeAddonListener(AddonsMgrListener); - } - - // Final window teardown, do this last. - window.XULBrowserWindow.destroy(); - window.XULBrowserWindow = null; - window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIXULWindow) - .XULBrowserWindow = null; - window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = null; - }, - -#ifdef XP_MACOSX - // nonBrowserWindowStartup(), nonBrowserWindowDelayedStartup(), and - // nonBrowserWindowShutdown() are used for non-browser windows in - // macBrowserOverlay - nonBrowserWindowStartup: function() { - // Disable inappropriate commands / submenus - var disabledItems = ['Browser:SavePage', - 'Browser:SendLink', 'cmd_pageSetup', 'cmd_print', 'cmd_find', 'cmd_findAgain', - 'viewToolbarsMenu', 'viewSidebarMenuMenu', 'Browser:Reload', - 'viewFullZoomMenu', 'pageStyleMenu', 'charsetMenu', 'View:PageSource', 'View:FullScreen', - 'viewHistorySidebar', 'Browser:AddBookmarkAs', 'Browser:BookmarkAllTabs', - 'View:PageInfo', 'Browser:ToggleAddonBar']; - var element; - - for (let disabledItem of disabledItems) { - element = document.getElementById(disabledItem); - if (element) - element.setAttribute("disabled", "true"); - } - - // If no windows are active (i.e. we're the hidden window), disable the close, minimize - // and zoom menu commands as well - if (window.location.href == "chrome://browser/content/hiddenWindow.xul") { - var hiddenWindowDisabledItems = ['cmd_close', 'minimizeWindow', 'zoomWindow']; - for (let hiddenWindowDisabledItem of hiddenWindowDisabledItems) { - element = document.getElementById(hiddenWindowDisabledItem); - if (element) - element.setAttribute("disabled", "true"); - } - - // also hide the window-list separator - element = document.getElementById("sep-window-list"); - element.setAttribute("hidden", "true"); - - // Setup the dock menu. - let dockMenuElement = document.getElementById("menu_mac_dockmenu"); - if (dockMenuElement != null) { - let nativeMenu = Cc["@mozilla.org/widget/standalonenativemenu;1"] - .createInstance(Ci.nsIStandaloneNativeMenu); - - try { - nativeMenu.init(dockMenuElement); - - let dockSupport = Cc["@mozilla.org/widget/macdocksupport;1"] - .getService(Ci.nsIMacDockSupport); - dockSupport.dockMenu = nativeMenu; - } - catch (e) { - } - } - } - - if (PrivateBrowsingUtils.permanentPrivateBrowsing) { - document.getElementById("macDockMenuNewWindow").hidden = true; - } - - this._delayedStartupTimeoutId = setTimeout(this.nonBrowserWindowDelayedStartup.bind(this), 0); - }, - - nonBrowserWindowDelayedStartup: function() { - this._delayedStartupTimeoutId = null; - - // initialise the offline listener - BrowserOffline.init(); - - // Set up Sanitize Item - this._initializeSanitizer(); - - // initialize the private browsing UI - gPrivateBrowsingUI.init(); - -#ifdef MOZ_SERVICES_SYNC - // initialize the sync UI - gSyncUI.init(); -#endif - }, - - nonBrowserWindowShutdown: function() { - // If nonBrowserWindowDelayedStartup hasn't run yet, we have no work to do - - // just cancel the pending timeout and return; - if (this._delayedStartupTimeoutId) { - clearTimeout(this._delayedStartupTimeoutId); - return; - } - - BrowserOffline.uninit(); - }, -#endif - - _initializeSanitizer: function() { - const kDidSanitizeDomain = "privacy.sanitize.didShutdownSanitize"; - if (gPrefService.prefHasUserValue(kDidSanitizeDomain)) { - gPrefService.clearUserPref(kDidSanitizeDomain); - // We need to persist this preference change, since we want to - // check it at next app start even if the browser exits abruptly - gPrefService.savePrefFile(null); - } - - /** - * Migrate Firefox 3.0 privacy.item prefs under one of these conditions: - * - * a) User has customized any privacy.item prefs - * b) privacy.sanitize.sanitizeOnShutdown is set - */ - if (!gPrefService.getBoolPref("privacy.sanitize.migrateFx3Prefs")) { - let itemBranch = gPrefService.getBranch("privacy.item."); - let itemArray = itemBranch.getChildList(""); - - // See if any privacy.item prefs are set - let doMigrate = itemArray.some(function (name) itemBranch.prefHasUserValue(name)); - // Or if sanitizeOnShutdown is set - if (!doMigrate) - doMigrate = gPrefService.getBoolPref("privacy.sanitize.sanitizeOnShutdown"); - - if (doMigrate) { - let cpdBranch = gPrefService.getBranch("privacy.cpd."); - let clearOnShutdownBranch = gPrefService.getBranch("privacy.clearOnShutdown."); - for (let name of itemArray) { - try { - // don't migrate password or offlineApps clearing in the CRH dialog since - // there's no UI for those anymore. They default to false. bug 497656 - if (name != "passwords" && name != "offlineApps") - cpdBranch.setBoolPref(name, itemBranch.getBoolPref(name)); - clearOnShutdownBranch.setBoolPref(name, itemBranch.getBoolPref(name)); - } - catch(e) { - Cu.reportError("Exception thrown during privacy pref migration: " + e); - } - } - } - - gPrefService.setBoolPref("privacy.sanitize.migrateFx3Prefs", true); - } - }, -} - - -/* Legacy global init functions */ -var BrowserStartup = gBrowserInit.onLoad.bind(gBrowserInit); -var BrowserShutdown = gBrowserInit.onUnload.bind(gBrowserInit); -#ifdef XP_MACOSX -var nonBrowserWindowStartup = gBrowserInit.nonBrowserWindowStartup.bind(gBrowserInit); -var nonBrowserWindowDelayedStartup = gBrowserInit.nonBrowserWindowDelayedStartup.bind(gBrowserInit); -var nonBrowserWindowShutdown = gBrowserInit.nonBrowserWindowShutdown.bind(gBrowserInit); -#endif - -function HandleAppCommandEvent(evt) { - switch (evt.command) { - case "Back": - BrowserBack(); - break; - case "Forward": - BrowserForward(); - break; - case "Reload": - BrowserReloadSkipCache(); - break; - case "Stop": - if (XULBrowserWindow.stopCommand.getAttribute("disabled") != "true") - BrowserStop(); - break; - case "Search": - BrowserSearch.webSearch(); - break; - case "Bookmarks": - toggleSidebar('viewBookmarksSidebar'); - break; - case "Home": - BrowserHome(); - break; - case "New": - BrowserOpenTab(); - break; - case "Close": - BrowserCloseTabOrWindow(); - break; - case "Find": - gFindBar.onFindCommand(); - break; - case "Help": - openHelpLink('firefox-help'); - break; - case "Open": - BrowserOpenFileWindow(); - break; - case "Print": - PrintUtils.print(); - break; - case "Save": - saveDocument(window.content.document); - break; - case "SendMail": - MailIntegration.sendLinkForWindow(window.content); - break; - default: - return; - } - evt.stopPropagation(); - evt.preventDefault(); -} - -function gotoHistoryIndex(aEvent) { - let index = aEvent.target.getAttribute("index"); - if (!index) - return false; - - let where = whereToOpenLink(aEvent); - - if (where == "current") { - // Normal click. Go there in the current tab and update session history. - - try { - gBrowser.gotoIndex(index); - } - catch(ex) { - return false; - } - return true; - } - // Modified click. Go there in a new tab/window. - - duplicateTabIn(gBrowser.selectedTab, where, index - gBrowser.sessionHistory.index); - return true; -} - -function BrowserForward(aEvent) { - let where = whereToOpenLink(aEvent, false, true); - - if (where == "current") { - try { - gBrowser.goForward(); - } - catch(ex) { - } - } - else { - duplicateTabIn(gBrowser.selectedTab, where, 1); - } -} - -function BrowserBack(aEvent) { - let where = whereToOpenLink(aEvent, false, true); - - if (where == "current") { - try { - gBrowser.goBack(); - } - catch(ex) { - } - } - else { - duplicateTabIn(gBrowser.selectedTab, where, -1); - } -} - -function BrowserHandleBackspace() -{ - switch (gPrefService.getIntPref("browser.backspace_action")) { - case 0: - BrowserBack(); - break; - case 1: - goDoCommand("cmd_scrollPageUp"); - break; - } -} - -function BrowserHandleShiftBackspace() -{ - switch (gPrefService.getIntPref("browser.backspace_action")) { - case 0: - BrowserForward(); - break; - case 1: - goDoCommand("cmd_scrollPageDown"); - break; - } -} - -function BrowserStop() { - const stopFlags = nsIWebNavigation.STOP_ALL; - gBrowser.webNavigation.stop(stopFlags); -} - -function BrowserReloadOrDuplicate(aEvent) { - var backgroundTabModifier = aEvent.button == 1 || -#ifdef XP_MACOSX - aEvent.metaKey; -#else - aEvent.ctrlKey; -#endif - if (aEvent.shiftKey && !backgroundTabModifier) { - BrowserReloadSkipCache(); - return; - } - - let where = whereToOpenLink(aEvent, false, true); - if (where == "current") - BrowserReload(); - else - duplicateTabIn(gBrowser.selectedTab, where); -} - -function BrowserReload() { - const reloadFlags = nsIWebNavigation.LOAD_FLAGS_NONE; - BrowserReloadWithFlags(reloadFlags); -} - -function BrowserReloadSkipCache() { - // Bypass proxy and cache. - const reloadFlags = nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE; - BrowserReloadWithFlags(reloadFlags); -} - -var BrowserHome = BrowserGoHome; -function BrowserGoHome(aEvent) { - if (aEvent && "button" in aEvent && - aEvent.button == 2) // right-click: do nothing - return; - - var homePage = gHomeButton.getHomePage(); - var where = whereToOpenLink(aEvent, false, true); - var urls; - - // Home page should open in a new tab when current tab is an app tab - if (where == "current" && - gBrowser && - gBrowser.selectedTab.pinned) - where = "tab"; - - // openUILinkIn in utilityOverlay.js doesn't handle loading multiple pages - switch (where) { - case "current": - loadOneOrMoreURIs(homePage); - break; - case "tabshifted": - case "tab": - urls = homePage.split("|"); - var loadInBackground = Services.prefs.getBoolPref("browser.tabs.loadBookmarksInBackground", false); - gBrowser.loadTabs(urls, loadInBackground); - break; - case "window": - OpenBrowserWindow(); - break; - } -} - -function loadOneOrMoreURIs(aURIString) -{ -#ifdef XP_MACOSX - // we're not a browser window, pass the URI string to a new browser window - if (window.location.href != getBrowserURL()) - { - window.openDialog(getBrowserURL(), "_blank", "all,dialog=no", aURIString); - return; - } -#endif - // This function throws for certain malformed URIs, so use exception handling - // so that we don't disrupt startup - try { - gBrowser.loadTabs(aURIString.split("|"), false, true); - } - catch (e) { - } -} - -function focusAndSelectUrlBar() { - if (gURLBar) { - if (window.fullScreen) - FullScreen.showNavToolbox(); - - gURLBar.select(); - if (document.activeElement == gURLBar.inputField) - return true; - } - return false; -} - -function openLocation() { - if (focusAndSelectUrlBar()) - return; - -#ifdef XP_MACOSX - if (window.location.href != getBrowserURL()) { - var win = getTopWin(); - if (win) { - // If there's an open browser window, it should handle this command - win.focus() - win.openLocation(); - } - else { - // If there are no open browser windows, open a new one - win = window.openDialog("chrome://browser/content/", "_blank", - "chrome,all,dialog=no", BROWSER_NEW_TAB_URL); - win.addEventListener("load", openLocationCallback, false); - } - return; - } -#endif - openDialog("chrome://browser/content/openLocation.xul", "_blank", - "chrome,modal,titlebar", window); -} - -function openLocationCallback() -{ - // make sure the DOM is ready - setTimeout(function() { this.openLocation(); }, 0); -} - -function BrowserOpenTab() -{ - openUILinkIn(BROWSER_NEW_TAB_URL, "tab"); -} - -/* Called from the openLocation dialog. This allows that dialog to instruct - its opener to open a new window and then step completely out of the way. - Anything less byzantine is causing horrible crashes, rather believably, - though oddly only on Linux. */ -function delayedOpenWindow(chrome, flags, href, postData) -{ - // The other way to use setTimeout, - // setTimeout(openDialog, 10, chrome, "_blank", flags, url), - // doesn't work here. The extra "magic" extra argument setTimeout adds to - // the callback function would confuse gBrowserInit.onLoad() by making - // window.arguments[1] be an integer instead of null. - setTimeout(function() { openDialog(chrome, "_blank", flags, href, null, null, postData); }, 10); -} - -/* Required because the tab needs time to set up its content viewers and get the load of - the URI kicked off before becoming the active content area. */ -function delayedOpenTab(aUrl, aReferrer, aCharset, aPostData, aAllowThirdPartyFixup) -{ - gBrowser.loadOneTab(aUrl, { - referrerURI: aReferrer, - charset: aCharset, - postData: aPostData, - inBackground: false, - allowThirdPartyFixup: aAllowThirdPartyFixup}); -} - -var gLastOpenDirectory = { - _lastDir: null, - get path() { - if (!this._lastDir || !this._lastDir.exists()) { - try { - this._lastDir = gPrefService.getComplexValue("browser.open.lastDir", - Ci.nsILocalFile); - if (!this._lastDir.exists()) - this._lastDir = null; - } - catch(e) {} - } - return this._lastDir; - }, - set path(val) { - try { - if (!val || !val.isDirectory()) - return; - } catch(e) { - return; - } - this._lastDir = val.clone(); - - // Don't save the last open directory pref inside the Private Browsing mode - if (!PrivateBrowsingUtils.isWindowPrivate(window)) - gPrefService.setComplexValue("browser.open.lastDir", Ci.nsILocalFile, - this._lastDir); - }, - reset: function() { - this._lastDir = null; - } -}; - -function BrowserOpenFileWindow() -{ - // Get filepicker component. - try { - const nsIFilePicker = Ci.nsIFilePicker; - let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); - let fpCallback = function fpCallback_done(aResult) { - if (aResult == nsIFilePicker.returnOK) { - try { - if (fp.file) { - gLastOpenDirectory.path = - fp.file.parent.QueryInterface(Ci.nsILocalFile); - } - } catch (ex) { - } - openUILinkIn(fp.fileURL.spec, "current"); - } - }; - - fp.init(window, gNavigatorBundle.getString("openFile"), - nsIFilePicker.modeOpen); - fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText | - nsIFilePicker.filterImages | nsIFilePicker.filterXML | - nsIFilePicker.filterHTML); - fp.displayDirectory = gLastOpenDirectory.path; - fp.open(fpCallback); - } catch (ex) { - } -} - -function BrowserCloseTabOrWindow() { -#ifdef XP_MACOSX - // If we're not a browser window, just close the window - if (window.location.href != getBrowserURL()) { - closeWindow(true); - return; - } -#endif - - // If the current tab is the last one, this will close the window. - gBrowser.removeCurrentTab({animate: true}); -} - -function BrowserTryToCloseWindow() -{ - if (WindowIsClosing()) - window.close(); // WindowIsClosing does all the necessary checks -} - -function loadURI(uri, referrer, postData, allowThirdPartyFixup, referrerPolicy, - originPrincipal, forceAboutBlankViewerInCurrent, - triggeringPrincipal) { - if (postData === undefined) - postData = null; - - var flags = nsIWebNavigation.LOAD_FLAGS_NONE; - if (allowThirdPartyFixup) { - flags |= nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; - flags |= nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS; - } - - try { - gBrowser.loadURIWithFlags(uri, { - flags: flags, - referrerURI: referrer, - referrerPolicy: referrerPolicy, - postData: postData, - originPrincipal: originPrincipal, - triggeringPrincipal: triggeringPrincipal, - forceAboutBlankViewerInCurrent: forceAboutBlankViewerInCurrent, - }); - } catch (e) {} -} - -/** - * Given a urlbar value, discerns between URIs, keywords and aliases. - * - * @param url - * The urlbar value. - * @param callback (optional, deprecated) - * The callback function invoked when done. This parameter is - * deprecated, please use the Promise that is returned. - * - * @return Promise<{ postData, url, mayInheritPrincipal }> - */ -function getShortcutOrURIAndPostData(url, callback = null) { - if (callback) { - Deprecated.warning("Please use the Promise returned by " + - "getShortcutOrURIAndPostData() instead of passing a " + - "callback", - "https://bugzilla.mozilla.org/show_bug.cgi?id=1100294"); - } - - return Task.spawn(function* () { - let mayInheritPrincipal = false; - let postData = null; - let shortcutURL = null; - let keyword = url; - let param = ""; - - let offset = url.indexOf(" "); - if (offset > 0) { - keyword = url.substr(0, offset); - param = url.substr(offset + 1); - } - - let engine = Services.search.getEngineByAlias(keyword); - if (engine) { - let submission = engine.getSubmission(param, null, "keyword"); - postData = submission.postData; - return { postData: submission.postData, url: submission.uri.spec, - mayInheritPrincipal }; - } - - let entry = yield PlacesUtils.keywords.fetch(keyword); - if (entry) { - shortcutURL = entry.url.href; - postData = entry.postData; - } - - if (!shortcutURL) { - return { postData, url, mayInheritPrincipal }; - } - - let escapedPostData = ""; - if (postData) - escapedPostData = unescape(postData); - - if (/%s/i.test(shortcutURL) || /%s/i.test(escapedPostData)) { - let charset = ""; - const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/; - let matches = shortcutURL.match(re); - - if (matches) { - [, shortcutURL, charset] = matches; - } else { - let uri; - try { - // makeURI() throws if URI is invalid. - uri = makeURI(shortcutURL); - } catch (ex) {} - - if (uri) { - // Try to get the saved character-set. - // Will return an empty string if character-set is not found. - charset = yield PlacesUtils.getCharsetForURI(uri); - } - } - - // encodeURIComponent produces UTF-8, and cannot be used for other charsets. - // escape() works in those cases, but it doesn't uri-encode +, @, and /. - // Therefore we need to manually replace these ASCII characters by their - // encodeURIComponent result, to match the behavior of nsEscape() with - // url_XPAlphas - let encodedParam = ""; - if (charset && charset != "UTF-8") - encodedParam = escape(convertFromUnicode(charset, param)). - replace(/[+@\/]+/g, encodeURIComponent); - else // Default charset is UTF-8 - encodedParam = encodeURIComponent(param); - - shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param); - - if (/%s/i.test(escapedPostData)) // POST keyword - postData = getPostDataStream(escapedPostData, param, encodedParam, - "application/x-www-form-urlencoded"); - - // This URL came from a bookmark, so it's safe to let it inherit the current - // document's principal. - mayInheritPrincipal = true; - - return { postData, url: shortcutURL, mayInheritPrincipal }; - } - - if (param) { - // This keyword doesn't take a parameter, but one was provided. Just return - // the original URL. - postData = null; - - return { postData, url, mayInheritPrincipal }; - } - - // This URL came from a bookmark, so it's safe to let it inherit the current - // document's principal. - mayInheritPrincipal = true; - - return { postData, url: shortcutURL, mayInheritPrincipal }; - }).then(data => { - if (callback) { - callback(data); - } - - return data; - }); -} - -function getPostDataStream(aStringData, aKeyword, aEncKeyword, aType) { - var dataStream = Cc["@mozilla.org/io/string-input-stream;1"]. - createInstance(Ci.nsIStringInputStream); - aStringData = aStringData.replace(/%s/g, aEncKeyword).replace(/%S/g, aKeyword); - dataStream.data = aStringData; - - var mimeStream = Cc["@mozilla.org/network/mime-input-stream;1"]. - createInstance(Ci.nsIMIMEInputStream); - mimeStream.addHeader("Content-Type", aType); - mimeStream.addContentLength = true; - mimeStream.setData(dataStream); - return mimeStream.QueryInterface(Ci.nsIInputStream); -} - -function getLoadContext() { - return window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsILoadContext); -} - -function readFromClipboard() -{ - var url; - - try { - // Create transferable that will transfer the text. - var trans = Components.classes["@mozilla.org/widget/transferable;1"] - .createInstance(Components.interfaces.nsITransferable); - trans.init(getLoadContext()); - - trans.addDataFlavor("text/unicode"); - - // If available, use selection clipboard, otherwise global one - if (Services.clipboard.supportsSelectionClipboard()) - Services.clipboard.getData(trans, Services.clipboard.kSelectionClipboard); - else - Services.clipboard.getData(trans, Services.clipboard.kGlobalClipboard); - - var data = {}; - var dataLen = {}; - trans.getTransferData("text/unicode", data, dataLen); - - if (data) { - data = data.value.QueryInterface(Components.interfaces.nsISupportsString); - url = data.data.substring(0, dataLen.value / 2); - } - } catch (ex) { - } - - return url; -} - -function BrowserViewSourceOfDocument(aArgsOrDocument) -{ - let args; - - if (aArgsOrDocument instanceof Document) { - let doc = aArgsOrDocument; - - let requestor = doc.defaultView - .QueryInterface(Ci.nsIInterfaceRequestor); - let browser = requestor.getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .chromeEventHandler; - let outerWindowID = requestor.getInterface(Ci.nsIDOMWindowUtils) - .outerWindowID; - let URL = browser.currentURI.spec; - args = { browser, outerWindowID, URL }; - } else { - args = aArgsOrDocument; - } - - let viewInternal = () => { - top.gViewSourceUtils.viewSource(args); - } - - // Check if external view source is enabled. If so, try it. If it fails, - // fallback to internal view source. - if (Services.prefs.getBoolPref("view_source.editor.external")) { - top.gViewSourceUtils - .openInExternalEditor(args, null, null, null, result => { - if (!result) { - viewInternal(); - } - }); - } else { - // Display using internal view source - viewInternal(); - } -} - -// doc - document to use for source, or null for this window's document -// initialTab - name of the initial tab to display, or null for the first tab -// imageElement - image to load in the Media Tab of the Page Info window; can be null/omitted -function BrowserPageInfo(doc, initialTab, imageElement) { - var args = {doc: doc, initialTab: initialTab, imageElement: imageElement}; - var windows = Services.wm.getEnumerator("Browser:page-info"); - - var documentURL = doc ? doc.location : window.content.document.location; - - // Check for windows matching the url - while (windows.hasMoreElements()) { - var currentWindow = windows.getNext(); - if (currentWindow.document.documentElement.getAttribute("relatedUrl") == documentURL) { - currentWindow.focus(); - currentWindow.resetPageInfo(args); - return currentWindow; - } - } - - // We didn't find a matching window, so open a new one. - return openDialog("chrome://browser/content/pageinfo/pageInfo.xul", "", - "chrome,toolbar,dialog=no,resizable", args); -} - -function URLBarSetURI(aURI) { - var value = gBrowser.userTypedValue; - var valid = false; - - if (value == null) { - let uri = aURI || gBrowser.currentURI; - // Strip off "wyciwyg://" and passwords for the location bar - try { - uri = Services.uriFixup.createExposableURI(uri); - } catch (e) {} - - // Replace initial page URIs with an empty string - // only if there's no opener (bug 370555). - // Bug 863515 - Make content.opener checks work in electrolysis. - if (gInitialPages.indexOf(uri.spec) != -1) - value = !gMultiProcessBrowser && content.opener ? uri.spec : ""; - else - value = losslessDecodeURI(uri); - - valid = !isBlankPageURL(uri.spec); - } - - let isDifferentValidValue = valid && value != gURLBar.value; - gURLBar.value = value; - gURLBar.valueIsTyped = !valid; - if (isDifferentValidValue) { - gURLBar.selectionStart = gURLBar.selectionEnd = 0; - } - - SetPageProxyState(valid ? "valid" : "invalid"); -} - -function losslessDecodeURI(aURI) { - let scheme = aURI.scheme; - let decodeASCIIOnly = !(/(https|http|file|ftp)/i.test(scheme)); - - var value = aURI.spec; - - // Try to decode as UTF-8 if there's no encoding sequence that we would break. - if (!/%25(?:3B|2F|3F|3A|40|26|3D|2B|24|2C|23)/i.test(value)) { - if (decodeASCIIOnly) { - // This only decodes ASCII characters (hex) 20-7e, except 25 (%). - // This avoids both cases stipulated below (%-related issues, and \r, \n - // and \t, which would be %0d, %0a and %09, respectively) as well as any - // non-US-ascii characters. - value = value.replace(/%(2[0-4]|2[6-9a-f]|[3-6][0-9a-f]|7[0-9a-e])/g, decodeURI); - } else { - try { - value = decodeURI(value) - // 1. decodeURI decodes %25 to %, which creates unintended - // encoding sequences. Re-encode it, unless it's part of - // a sequence that survived decodeURI, i.e. one for: - // ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#' - // (RFC 3987 section 3.2) - // 2. Re-encode whitespace so that it doesn't get eaten away - // by the location bar (bug 410726). - .replace(/%(?!3B|2F|3F|3A|40|26|3D|2B|24|2C|23)|[\r\n\t]/ig, - encodeURIComponent); - } catch (e) {} - } - } - - // Encode invisible characters (C0/C1 control characters, U+007F [DEL], - // U+00A0 [no-break space], line and paragraph separator, - // object replacement character) (bug 452979, bug 909264) - value = value.replace(/[\u0000-\u001f\u007f-\u00a0\u2028\u2029\ufffc]/g, - encodeURIComponent); - - // Encode default ignorable characters (bug 546013) - // except ZWNJ (U+200C) and ZWJ (U+200D) (bug 582186). - // This includes all bidirectional formatting characters. - // (RFC 3987 sections 3.2 and 4.1 paragraph 6) - value = value.replace(/[\u00ad\u034f\u115f-\u1160\u17b4-\u17b5\u180b-\u180d\u200b\u200e-\u200f\u202a-\u202e\u2060-\u206f\u3164\ufe00-\ufe0f\ufeff\uffa0\ufff0-\ufff8]|\ud834[\udd73-\udd7a]|[\udb40-\udb43][\udc00-\udfff]/g, - encodeURIComponent); - return value; -} - -function UpdateUrlbarSearchSplitterState() -{ - var splitter = document.getElementById("urlbar-search-splitter"); - var urlbar = document.getElementById("urlbar-container"); - var searchbar = document.getElementById("search-container"); - var stop = document.getElementById("stop-button"); - - var ibefore = null; - if (urlbar && searchbar) { - if (urlbar.nextSibling == searchbar || - urlbar.getAttribute("combined") && - stop && stop.nextSibling == searchbar) - ibefore = searchbar; - else if (searchbar.nextSibling == urlbar) - ibefore = urlbar; - } - - if (ibefore) { - if (!splitter) { - splitter = document.createElement("splitter"); - splitter.id = "urlbar-search-splitter"; - splitter.setAttribute("resizebefore", "flex"); - splitter.setAttribute("resizeafter", "flex"); - splitter.setAttribute("skipintoolbarset", "true"); - splitter.className = "chromeclass-toolbar-additional"; - } - urlbar.parentNode.insertBefore(splitter, ibefore); - } else if (splitter) - splitter.parentNode.removeChild(splitter); -} - -function setUrlAndSearchBarWidthForConditionalForwardButton() { - // Workaround for bug 694084: Showing/hiding the conditional forward button resizes - // the search bar when the url/search bar splitter hasn't been used. - var urlbarContainer = document.getElementById("urlbar-container"); - var searchbarContainer = document.getElementById("search-container"); - if (!urlbarContainer || - !searchbarContainer || - urlbarContainer.hasAttribute("width") || - searchbarContainer.hasAttribute("width") || - urlbarContainer.parentNode != searchbarContainer.parentNode) - return; - urlbarContainer.style.width = searchbarContainer.style.width = ""; - var urlbarWidth = urlbarContainer.clientWidth; - var searchbarWidth = searchbarContainer.clientWidth; - urlbarContainer.style.width = urlbarWidth + "px"; - searchbarContainer.style.width = searchbarWidth + "px"; -} - -function UpdatePageProxyState() -{ - if (gURLBar && gURLBar.value != gLastValidURLStr) - SetPageProxyState("invalid"); -} - -function SetPageProxyState(aState) -{ - BookmarkingUI.onPageProxyStateChanged(aState); - - if (!gURLBar) - return; - - if (!gProxyFavIcon) - gProxyFavIcon = document.getElementById("page-proxy-favicon"); - - gURLBar.setAttribute("pageproxystate", aState); - gProxyFavIcon.setAttribute("pageproxystate", aState); - - // the page proxy state is set to valid via OnLocationChange, which - // gets called when we switch tabs. - if (aState == "valid") { - gLastValidURLStr = gURLBar.value; - gURLBar.addEventListener("input", UpdatePageProxyState, false); - PageProxySetIcon(gBrowser.getIcon()); - } else if (aState == "invalid") { - gURLBar.removeEventListener("input", UpdatePageProxyState, false); - PageProxyClearIcon(); - } -} - -function PageProxySetIcon (aURL) -{ - if (!gProxyFavIcon) - return; - - if (gBrowser.selectedBrowser.contentDocument instanceof ImageDocument) { - // PageProxyClearIcon(); - gProxyFavIcon.setAttribute("src", "chrome://browser/skin/imagedocument.png"); - return; - } - - if (!aURL) - PageProxyClearIcon(); - else if (gProxyFavIcon.getAttribute("src") != aURL) - gProxyFavIcon.setAttribute("src", aURL); -} - -function PageProxyClearIcon () -{ - gProxyFavIcon.removeAttribute("src"); -} - - -function PageProxyClickHandler(aEvent) -{ - if (aEvent.button == 1 && gPrefService.getBoolPref("middlemouse.paste")) - middleMousePaste(aEvent); -} - -/** - * Handle load of some pages (about:*) so that we can make modifications - * to the DOM for unprivileged pages. - */ -function BrowserOnAboutPageLoad(doc) { - - /* === about:home === */ - - if (doc.documentURI.toLowerCase() == "about:home") { - if (!PrivateBrowsingUtils.isWindowPrivate(window)) { - let wrapper = {}; - Cu.import("resource:///modules/sessionstore/SessionStore.jsm", wrapper); - let ss = wrapper.SessionStore; - ss.promiseInitialized.then(function() { - if (ss.canRestoreLastSession) { - doc.getElementById("launcher").setAttribute("session", "true"); - } - }).then(null, function onError(x) { - Cu.reportError("Error in SessionStore init while processing 'about:home': " + x); - }); - } - - // Inject search engine and snippets URL. - let docElt = doc.documentElement; - if (AboutHomeUtils.showKnowYourRights) { - docElt.setAttribute("showKnowYourRights", "true"); - // Set pref to indicate we've shown the notification. - let currentVersion = Services.prefs.getIntPref("browser.rights.version"); - Services.prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true); - } - - function updateSearchEngine() { - let engine = AboutHomeUtils.defaultSearchEngine; - docElt.setAttribute("searchEngineName", engine.name); - docElt.setAttribute("searchEnginePostData", engine.postDataString || ""); - docElt.setAttribute("searchEngineURL", engine.searchURL); - } - Services.search.init(updateSearchEngine); - - // Listen for the event that's triggered when the user changes search engine. - // At this point we simply reload about:home to reflect the change. - Services.obs.addObserver(updateSearchEngine, "browser-search-engine-modified", false); - - // Remove the observer when the page is reloaded or closed. - doc.defaultView.addEventListener("pagehide", function removeObserver() { - doc.defaultView.removeEventListener("pagehide", removeObserver); - Services.obs.removeObserver(updateSearchEngine, "browser-search-engine-modified"); - }, false); - } - - /* === about:newtab === */ - - if (doc.documentURI.toLowerCase() == "about:newtab") { - - let docElt = doc.documentElement; - - function updateSearchEngine() { - let engine = AboutHomeUtils.defaultSearchEngine; - docElt.setAttribute("searchEngineName", engine.name); - docElt.setAttribute("searchEnginePostData", engine.postDataString || ""); - docElt.setAttribute("searchEngineURL", engine.searchURL); - } - Services.search.init(updateSearchEngine); - - // Listen for the event that's triggered when the user changes search engine. - // At this point we simply reload about:newtab to reflect the change. - Services.obs.addObserver(updateSearchEngine, "browser-search-engine-modified", false); - - // Remove the observer when the page is reloaded or closed. - doc.defaultView.addEventListener("pagehide", function removeObserver() { - doc.defaultView.removeEventListener("pagehide", removeObserver); - Services.obs.removeObserver(updateSearchEngine, "browser-search-engine-modified"); - }, false); - } - -} - -/** - * Handle command events bubbling up from error page content - */ -var BrowserOnClick = { - handleEvent: function BrowserOnClick_handleEvent(aEvent) { - if (!aEvent.isTrusted || // Don't trust synthetic events - aEvent.button == 2 || aEvent.target.localName != "button") { - return; - } - - let originalTarget = aEvent.originalTarget; - let ownerDoc = originalTarget.ownerDocument; - - // If the event came from an ssl error page, it is probably either the "Add - // Exception…" or "Get me out of here!" button - if (ownerDoc.documentURI.startsWith("about:certerror")) { - this.onAboutCertError(originalTarget, ownerDoc); - } - else if (ownerDoc.documentURI.startsWith("about:neterror")) { - this.onAboutNetError(originalTarget, ownerDoc); - } - else if (ownerDoc.documentURI.toLowerCase() == "about:home") { - this.onAboutHome(originalTarget, ownerDoc); - } - }, - - onAboutCertError: function BrowserOnClick_onAboutCertError(aTargetElm, aOwnerDoc) { - let elmId = aTargetElm.getAttribute("id"); - let isTopFrame = (aOwnerDoc.defaultView.parent === aOwnerDoc.defaultView); - - switch (elmId) { - case "exceptionDialogButton": - let params = { exceptionAdded : false }; - - try { - switch (Services.prefs.getIntPref("browser.ssl_override_behavior")) { - case 2 : // Pre-fetch & pre-populate - params.prefetchCert = true; - case 1 : // Pre-populate - params.location = aOwnerDoc.location.href; - } - } catch (e) { - Components.utils.reportError("Couldn't get ssl_override pref: " + e); - } - - 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) { - aOwnerDoc.location.reload(); - } - break; - - case "getMeOutOfHereButton": - getMeOutOfHere(); - break; - - case "technicalContent": - break; - - case "expertContent": - break; - - } - }, - - onAboutNetError: function BrowserOnClick_onAboutNetError(aTargetElm, aOwnerDoc) { - let elmId = aTargetElm.getAttribute("id"); - if (elmId != "errorTryAgain" || !/e=netOffline/.test(aOwnerDoc.documentURI)) - return; - Services.io.offline = false; - }, - - onAboutHome: function BrowserOnClick_onAboutHome(aTargetElm, aOwnerDoc) { - let elmId = aTargetElm.getAttribute("id"); - - switch (elmId) { - case "restorePreviousSession": - let ss = Cc["@mozilla.org/browser/sessionstore;1"]. - getService(Ci.nsISessionStore); - if (ss.canRestoreLastSession) { - ss.restoreLastSession(); - } - aOwnerDoc.getElementById("launcher").removeAttribute("session"); - break; - - case "downloads": - BrowserDownloadsUI(); - break; - - case "bookmarks": - PlacesCommandHook.showPlacesOrganizer("AllBookmarks"); - break; - - case "history": - PlacesCommandHook.showPlacesOrganizer("History"); - break; - - case "addons": - BrowserOpenAddonsMgr(); - break; - - case "sync": - openPreferences("paneSync"); - break; - - case "settings": - openPreferences(); - 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() { - try { - let toBlank = Services.prefs.getBoolPref("browser.escape_to_blank"); - if (toBlank) { - content.location = "about:logopage"; - return; - } - } catch(e) { - Components.utils.reportError("Couldn't get escape pref: " + e); - } - // Get the start page from the *default* pref branch, not the user's - var prefs = Services.prefs.getDefaultBranch(null); - var url = BROWSER_NEW_TAB_URL; - try { - url = prefs.getComplexValue("browser.startup.homepage", - Ci.nsIPrefLocalizedString).data; - // If url is a pipe-delimited set of pages, just take the first one. - if (url.includes("|")) - url = url.split("|")[0]; - } catch(e) { - Components.utils.reportError("Couldn't get homepage pref: " + e); - } - content.location = url; -} - -function BrowserFullScreen() -{ - window.fullScreen = !window.fullScreen; -} - -function onFullScreen() { - FullScreen.toggle(); -} - -function onMozEnteredDomFullscreen(event) { - FullScreen.enterDomFullscreen(event); -} - -function getWebNavigation() -{ - return gBrowser.webNavigation; -} - -function BrowserReloadWithFlags(reloadFlags) { - - // Reset DOS mitigation for auth prompts when user initiates a reload. - let browser = gBrowser.selectedBrowser; - delete browser.authPromptCounter; - - /* First, we'll try to use the session history object to reload so - * that framesets are handled properly. If we're in a special - * window (such as view-source) that has no session history, fall - * back on using the web navigation's reload method. - */ - - var webNav = gBrowser.webNavigation; - try { - var sh = webNav.sessionHistory; - if (sh) - webNav = sh.QueryInterface(nsIWebNavigation); - } catch (e) { - } - - try { - webNav.reload(reloadFlags); - } catch (e) { - } -} - -var PrintPreviewListener = { - _printPreviewTab: null, - _tabBeforePrintPreview: null, - - getPrintPreviewBrowser: function () { - if (!this._printPreviewTab) { - this._tabBeforePrintPreview = gBrowser.selectedTab; - this._printPreviewTab = gBrowser.loadOneTab("about:blank", - { inBackground: false }); - gBrowser.selectedTab = this._printPreviewTab; - } - return gBrowser.getBrowserForTab(this._printPreviewTab); - }, - getSourceBrowser: function () { - return this._tabBeforePrintPreview ? - this._tabBeforePrintPreview.linkedBrowser : gBrowser.selectedBrowser; - }, - getNavToolbox: function () { - return gNavToolbox; - }, - onEnter: function () { - // We might have accidentally switched tabs since the user invoked print - // preview - if (gBrowser.selectedTab != this._printPreviewTab) { - gBrowser.selectedTab = this._printPreviewTab; - } - gInPrintPreviewMode = true; - this._toggleAffectedChrome(); - }, - onExit: function () { - gBrowser.selectedTab = this._tabBeforePrintPreview; - this._tabBeforePrintPreview = null; - gInPrintPreviewMode = false; - this._toggleAffectedChrome(); - gBrowser.removeTab(this._printPreviewTab); - this._printPreviewTab = null; - }, - _toggleAffectedChrome: function () { - gNavToolbox.collapsed = gInPrintPreviewMode; - - if (gInPrintPreviewMode) - this._hideChrome(); - else - this._showChrome(); - - if (this._chromeState.sidebarOpen) - toggleSidebar(this._sidebarCommand); - -#ifdef MENUBAR_CAN_AUTOHIDE - updateAppButtonDisplay(); -#endif - }, - _hideChrome: function () { - this._chromeState = {}; - - var sidebar = document.getElementById("sidebar-box"); - this._chromeState.sidebarOpen = !sidebar.hidden; - this._sidebarCommand = sidebar.getAttribute("sidebarcommand"); - - var notificationBox = gBrowser.getNotificationBox(); - this._chromeState.notificationsOpen = !notificationBox.notificationsHidden; - notificationBox.notificationsHidden = true; - - document.getElementById("sidebar").setAttribute("src", "about:blank"); - var addonBar = document.getElementById("addon-bar"); - this._chromeState.addonBarOpen = !addonBar.collapsed; - addonBar.collapsed = true; - gBrowser.updateWindowResizers(); - - this._chromeState.findOpen = gFindBarInitialized && !gFindBar.hidden; - if (gFindBarInitialized) - gFindBar.close(); - - var globalNotificationBox = document.getElementById("global-notificationbox"); - this._chromeState.globalNotificationsOpen = !globalNotificationBox.notificationsHidden; - globalNotificationBox.notificationsHidden = true; - - this._chromeState.syncNotificationsOpen = false; - var syncNotifications = document.getElementById("sync-notifications"); - if (syncNotifications) { - this._chromeState.syncNotificationsOpen = !syncNotifications.notificationsHidden; - syncNotifications.notificationsHidden = true; - } - }, - _showChrome: function () { - if (this._chromeState.notificationsOpen) - gBrowser.getNotificationBox().notificationsHidden = false; - - if (this._chromeState.addonBarOpen) { - document.getElementById("addon-bar").collapsed = false; - gBrowser.updateWindowResizers(); - } - - if (this._chromeState.findOpen) - gFindBar.open(); - - if (this._chromeState.globalNotificationsOpen) - document.getElementById("global-notificationbox").notificationsHidden = false; - - if (this._chromeState.syncNotificationsOpen) - document.getElementById("sync-notifications").notificationsHidden = false; - } -} - -function getMarkupDocumentViewer() -{ - return gBrowser.markupDocumentViewer; -} - -// This function is obsolete. Newer code should use <tooltip page="true"/> instead. -function FillInHTMLTooltip(tipElement) -{ - document.getElementById("aHTMLTooltip").fillInPageTooltip(tipElement); -} - -var browserDragAndDrop = { - canDropLink: function (aEvent) Services.droppedLinkHandler.canDropLink(aEvent, true), - - dragOver: function (aEvent) - { - if (this.canDropLink(aEvent)) { - aEvent.preventDefault(); - } - }, - - dropLinks: function (aEvent, aDisallowInherit) { - return Services.droppedLinkHandler.dropLinks(aEvent, aDisallowInherit); - } -}; - -var homeButtonObserver = { - onDrop: function (aEvent) - { - // disallow setting home pages that inherit the principal - let links = browserDragAndDrop.dropLinks(aEvent, true); - if (links.length) { - setTimeout(openHomeDialog, 0, links.map(link => link.url).join("|")); - } - }, - - onDragOver: function (aEvent) - { - browserDragAndDrop.dragOver(aEvent); - aEvent.dropEffect = "link"; - }, - onDragExit: function (aEvent) - { - } -} - -function openHomeDialog(aURL) -{ - var promptTitle = gNavigatorBundle.getString("droponhometitle"); - var promptMsg; - if (aURL.includes("|")) { - promptMsg = gNavigatorBundle.getString("droponhomemsgMultiple"); - } else { - promptMsg = gNavigatorBundle.getString("droponhomemsg"); - } - - var pressedVal = Services.prompt.confirmEx(window, promptTitle, promptMsg, - Services.prompt.STD_YES_NO_BUTTONS, - null, null, null, null, {value:0}); - - if (pressedVal == 0) { - try { - var homepageStr = Components.classes["@mozilla.org/supports-string;1"] - .createInstance(Components.interfaces.nsISupportsString); - homepageStr.data = aURL; - gPrefService.setComplexValue("browser.startup.homepage", - Components.interfaces.nsISupportsString, homepageStr); - } catch (ex) { - dump("Failed to set the home page.\n"+ex+"\n"); - } - } -} - -var bookmarksButtonObserver = { - onDrop: function (aEvent) - { - let name = { }; - let url = browserDragAndDrop.drop(aEvent, name); - try { - PlacesUIUtils.showBookmarkDialog({ action: "add" - , type: "bookmark" - , uri: makeURI(url) - , title: name - , hiddenRows: [ "description" - , "location" - , "loadInSidebar" - , "keyword" ] - }, window); - } catch(ex) { } - }, - - onDragOver: function (aEvent) - { - browserDragAndDrop.dragOver(aEvent); - aEvent.dropEffect = "link"; - }, - - onDragExit: function (aEvent) - { - } -} - -var newTabButtonObserver = { - onDragOver: function (aEvent) - { - browserDragAndDrop.dragOver(aEvent); - }, - - onDragExit: function (aEvent) - { - }, - - onDrop: function (aEvent) - { - let links = browserDragAndDrop.dropLinks(aEvent); - Task.spawn(function*() { - for (let link of links) { - let data = yield getShortcutOrURIAndPostData(link.url); - if (data.url) { - // allow third-party services to fixup this URL - openNewTabWith(data.url, null, data.postData, aEvent, true); - } - } - }); - } -} - -var newWindowButtonObserver = { - onDragOver: function (aEvent) - { - browserDragAndDrop.dragOver(aEvent); - }, - onDragExit: function (aEvent) - { - }, - onDrop: function (aEvent) - { - let links = browserDragAndDrop.dropLinks(aEvent); - Task.spawn(function*() { - for (let link of links) { - let data = yield getShortcutOrURIAndPostData(link.url); - if (data.url) { - // allow third-party services to fixup this URL - openNewWindowWith(data.url, null, data.postData, true); - } - } - }); - } -} - -const DOMLinkHandler = { - handleEvent: function (event) { - switch (event.type) { - case "DOMLinkAdded": - this.onLinkAdded(event); - break; - } - }, - getLinkIconURI: function(aLink) { - let targetDoc = aLink.ownerDocument; - var uri = makeURI(aLink.href, targetDoc.characterSet); - - // Verify that the load of this icon is legal. - // Some error or special pages can load their favicon. - // To be on the safe side, only allow chrome:// favicons. - var isAllowedPage = [ - /^about:neterror\?/, - /^about:blocked\?/, - /^about:certerror\?/, - /^about:home$/, - ].some(function (re) re.test(targetDoc.documentURI)); - - if (!isAllowedPage || !uri.schemeIs("chrome")) { - var ssm = Services.scriptSecurityManager; - try { - ssm.checkLoadURIWithPrincipal(targetDoc.nodePrincipal, uri, - Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); - } catch(e) { - return null; - } - } - - try { - var contentPolicy = Cc["@mozilla.org/layout/content-policy;1"]. - getService(Ci.nsIContentPolicy); - } catch(e) { - return null; // Refuse to load if we can't do a security check. - } - - // Security says okay, now ask content policy - if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE, - uri, targetDoc.documentURIObject, - aLink, aLink.type, null) - != Ci.nsIContentPolicy.ACCEPT) - return null; - - try { - uri.userPass = ""; - } catch(e) { - // some URIs are immutable - } - return uri; - }, - onLinkAdded: function (event) { - var link = event.originalTarget; - var rel = link.rel && link.rel.toLowerCase(); - if (!link || !link.ownerDocument || !rel || !link.href) - return; - - var feedAdded = false; - var iconAdded = false; - var searchAdded = false; - var rels = {}; - for (let relString of rel.split(/\s+/)) - rels[relString] = true; - - for (let relVal in rels) { - switch (relVal) { - case "feed": - case "alternate": - if (!feedAdded) { - if (!rels.feed && rels.alternate && rels.stylesheet) - break; - - if (isValidFeed(link, link.ownerDocument.nodePrincipal, "feed" in rels)) { - FeedHandler.addFeed(link, link.ownerDocument); - feedAdded = true; - } - } - break; - case "icon": - if (!iconAdded) { - if (!gPrefService.getBoolPref("browser.chrome.site_icons")) - break; - - var uri = this.getLinkIconURI(link); - if (!uri) - break; - - if (gBrowser.isFailedIcon(uri)) - break; - - var browserIndex = gBrowser.getBrowserIndexForDocument(link.ownerDocument); - // no browser? no favicon. - if (browserIndex == -1) - break; - - let tab = gBrowser.tabs[browserIndex]; - gBrowser.setIcon(tab, uri.spec, link.ownerDocument.nodePrincipal); - iconAdded = true; - } - break; - case "search": - if (!searchAdded) { - var type = link.type && link.type.toLowerCase(); - type = type.replace(/^\s+|\s*(?:;.*)?$/g, ""); - - if (type == "application/opensearchdescription+xml" && link.title && - /^(?:https?|ftp):/i.test(link.href) && - !PrivateBrowsingUtils.isWindowPrivate(window)) { - var engine = { title: link.title, href: link.href }; - Services.search.init(function () { - BrowserSearch.addEngine(engine, link.ownerDocument); - }); - searchAdded = true; - } - } - break; - } - } - } -} - -const BrowserSearch = { - addEngine: function(engine, targetDoc) { - if (!this.searchBar) - return; - - var browser = gBrowser.getBrowserForDocument(targetDoc); - // ignore search engines from subframes (see bug 479408) - if (!browser) - return; - - // Check to see whether we've already added an engine with this title - if (browser.engines) { - if (browser.engines.some(function (e) e.title == engine.title)) - return; - } - - // Append the URI and an appropriate title to the browser data. - // Use documentURIObject in the check for shouldLoadFavIcon so that we - // do the right thing with about:-style error pages. Bug 453442 - var iconURL = null; - if (gBrowser.shouldLoadFavIcon(targetDoc.documentURIObject)) - iconURL = targetDoc.documentURIObject.prePath + "/favicon.ico"; - - var hidden = false; - // If this engine (identified by title) is already in the list, add it - // to the list of hidden engines rather than to the main list. - // XXX This will need to be changed when engines are identified by URL; - // see bug 335102. - if (Services.search.getEngineByName(engine.title)) - hidden = true; - - var engines = (hidden ? browser.hiddenEngines : browser.engines) || []; - - engines.push({ uri: engine.href, - title: engine.title, - icon: iconURL }); - - if (hidden) - browser.hiddenEngines = engines; - else - browser.engines = engines; - }, - - /** - * Gives focus to the search bar, if it is present on the toolbar, or loads - * the default engine's search form otherwise. For Mac, opens a new window - * or focuses an existing window, if necessary. - */ - webSearch: function BrowserSearch_webSearch() { -#ifdef XP_MACOSX - if (window.location.href != getBrowserURL()) { - var win = getTopWin(); - if (win) { - // If there's an open browser window, it should handle this command - win.focus(); - win.BrowserSearch.webSearch(); - } else { - // If there are no open browser windows, open a new one - var observer = function observer(subject, topic, data) { - if (subject == win) { - BrowserSearch.webSearch(); - Services.obs.removeObserver(observer, "browser-delayed-startup-finished"); - } - } - win = window.openDialog(getBrowserURL(), "_blank", - "chrome,all,dialog=no", "about:blank"); - Services.obs.addObserver(observer, "browser-delayed-startup-finished", false); - } - return; - } -#endif - var searchBar = this.searchBar; - if (searchBar && window.fullScreen) - FullScreen.showNavToolbox(); - if (searchBar) - searchBar.select(); - if (!searchBar || document.activeElement != searchBar.textbox.inputField) - openUILinkIn(Services.search.defaultEngine.searchForm, "current"); - }, - - /** - * Loads a search results page, given a set of search terms. Uses the current - * engine if the search bar is visible, or the default engine otherwise. - * - * @param searchText - * The search terms to use for the search. - * - * @param useNewTab - * Boolean indicating whether or not the search should load in a new - * tab. - * - * @param purpose [optional] - * A string meant to indicate the context of the search request. This - * allows the search service to provide a different nsISearchSubmission - * depending on e.g. where the search is triggered in the UI. - * - * @return string Name of the search engine used to perform a search or null - * if a search was not performed. - */ - loadSearch: function BrowserSearch_search(searchText, useNewTab, purpose) { - var engine; - - // If the search bar is visible, use the current engine, otherwise, fall - // back to the default engine. - if (isElementVisible(this.searchBar)) - engine = Services.search.currentEngine; - else - engine = Services.search.defaultEngine; - - var submission = engine.getSubmission(searchText, null, purpose); // HTML response - - // getSubmission can return null if the engine doesn't have a URL - // with a text/html response type. This is unlikely (since - // SearchService._addEngineToStore() should fail for such an engine), - // but let's be on the safe side. - if (!submission) { - return null; - } - - let inBackground = Services.prefs.getBoolPref("browser.search.context.loadInBackground"); - openLinkIn(submission.uri.spec, - useNewTab ? "tab" : "current", - { postData: submission.postData, - inBackground: inBackground, - relatedToCurrent: true }); - - return engine.name; - }, - - /** - * Perform a search initiated from the context menu. - * - * This should only be called from the context menu. See - * BrowserSearch.loadSearch for the preferred API. - */ - loadSearchFromContext: function (terms) { - let engine = BrowserSearch.loadSearch(terms, true, "contextmenu"); - }, - - /** - * Returns the search bar element if it is present in the toolbar, null otherwise. - */ - get searchBar() { - return document.getElementById("searchbar"); - }, - - loadAddEngines: function BrowserSearch_loadAddEngines() { - var newWindowPref = gPrefService.getIntPref("browser.link.open_newwindow"); - var where = newWindowPref == 3 ? "tab" : "window"; - var searchEnginesURL = formatURL("browser.search.searchEnginesURL", true); - openUILinkIn(searchEnginesURL, where); - }, -}; - -XPCOMUtils.defineConstant(this, "BrowserSearch", BrowserSearch); - -function FillHistoryMenu(aParent) { - // Lazily add the hover listeners on first showing and never remove them - if (!aParent.hasStatusListener) { - // Show history item's uri in the status bar when hovering, and clear on exit - aParent.addEventListener("DOMMenuItemActive", function(aEvent) { - // Only the current page should have the checked attribute, so skip it - if (!aEvent.target.hasAttribute("checked")) - XULBrowserWindow.setOverLink(aEvent.target.getAttribute("uri")); - }, false); - aParent.addEventListener("DOMMenuItemInactive", function() { - XULBrowserWindow.setOverLink(""); - }, false); - - aParent.hasStatusListener = true; - } - - // Remove old entries if any - var children = aParent.childNodes; - for (var i = children.length - 1; i >= 0; --i) { - if (children[i].hasAttribute("index")) - aParent.removeChild(children[i]); - } - - var webNav = gBrowser.webNavigation; - var sessionHistory = webNav.sessionHistory; - - var count = sessionHistory.count; - if (count <= 1) // don't display the popup for a single item - return false; - - const MAX_HISTORY_MENU_ITEMS = 15; - var index = sessionHistory.index; - var half_length = Math.floor(MAX_HISTORY_MENU_ITEMS / 2); - var start = Math.max(index - half_length, 0); - var end = Math.min(start == 0 ? MAX_HISTORY_MENU_ITEMS : index + half_length + 1, count); - if (end == count) - start = Math.max(count - MAX_HISTORY_MENU_ITEMS, 0); - - var tooltipBack = gNavigatorBundle.getString("tabHistory.goBack"); - var tooltipCurrent = gNavigatorBundle.getString("tabHistory.current"); - var tooltipForward = gNavigatorBundle.getString("tabHistory.goForward"); - - for (var j = end - 1; j >= start; j--) { - let item = document.createElement("menuitem"); - let entry = sessionHistory.getEntryAtIndex(j, false); - let uri = entry.URI.spec; - - item.setAttribute("uri", uri); - item.setAttribute("label", entry.title || uri); - item.setAttribute("index", j); - - if (j != index) { - PlacesUtils.favicons.getFaviconURLForPage(entry.URI, function (aURI) { - if (aURI) { - let iconURL = PlacesUtils.favicons.getFaviconLinkForIcon(aURI).spec; - item.style.listStyleImage = "url(" + iconURL + ")"; - } - }); - } - - if (j < index) { - item.className = "unified-nav-back menuitem-iconic menuitem-with-favicon"; - item.setAttribute("tooltiptext", tooltipBack); - } else if (j == index) { - item.setAttribute("type", "radio"); - item.setAttribute("checked", "true"); - item.className = "unified-nav-current"; - item.setAttribute("tooltiptext", tooltipCurrent); - } else { - item.className = "unified-nav-forward menuitem-iconic menuitem-with-favicon"; - item.setAttribute("tooltiptext", tooltipForward); - } - - aParent.appendChild(item); - } - return true; -} - -function addToUrlbarHistory(aUrlToAdd) { - if (!PrivateBrowsingUtils.isWindowPrivate(window) && - aUrlToAdd && - !aUrlToAdd.includes(" ") && - !/[\x00-\x1F]/.test(aUrlToAdd)) - PlacesUIUtils.markPageAsTyped(aUrlToAdd); -} - -function toJavaScriptConsole() -{ - toOpenWindowByType("global:console", "chrome://global/content/console.xul"); -} - -function BrowserDownloadsUI() -{ - if (PrivateBrowsingUtils.isWindowPrivate(window)) { - openUILinkIn("about:downloads", "tab"); - } else { - PlacesCommandHook.showPlacesOrganizer("Downloads"); - } -} - -function toOpenWindowByType(inType, uri, features) -{ - var topWindow = Services.wm.getMostRecentWindow(inType); - - if (topWindow) - topWindow.focus(); - else if (features) - window.open(uri, "_blank", features); - else - window.open(uri, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar"); -} - -function OpenBrowserWindow(options) -{ - function newDocumentShown(doc, topic, data) { - if (topic == "document-shown" && - doc != document && - doc.defaultView == win) { - Services.obs.removeObserver(newDocumentShown, "document-shown"); - } - }; - Services.obs.addObserver(newDocumentShown, "document-shown", false); - - var charsetArg = new String(); - var handler = Components.classes["@mozilla.org/browser/clh;1"] - .getService(Components.interfaces.nsIBrowserHandler); - var defaultArgs = handler.defaultArgs; - var wintype = document.documentElement.getAttribute('windowtype'); - - var extraFeatures = ""; - if (options && options.private) { - extraFeatures = ",private"; - if (!PrivateBrowsingUtils.permanentPrivateBrowsing) { - // Force the new window to load about:privatebrowsing instead of the default home page - defaultArgs = "about:privatebrowsing"; - } - } else { - extraFeatures = ",non-private"; - } - - // if and only if the current window is a browser window and it has a document with a character - // set, then extract the current charset menu setting from the current document and use it to - // initialize the new browser window... - var win; - if (window && (wintype == "navigator:browser") && window.content && window.content.document) - { - var DocCharset = window.content.document.characterSet; - charsetArg = "charset="+DocCharset; - - //we should "inherit" the charset menu setting in a new window - win = window.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no" + extraFeatures, defaultArgs, charsetArg); - } - else // forget about the charset information. - { - win = window.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no" + extraFeatures, defaultArgs); - } - - return win; -} - -var gCustomizeSheet = false; -function BrowserCustomizeToolbar() { - // Disable the toolbar context menu items - var menubar = document.getElementById("main-menubar"); - for (let childNode of menubar.childNodes) - childNode.setAttribute("disabled", true); - - var cmd = document.getElementById("cmd_CustomizeToolbars"); - cmd.setAttribute("disabled", "true"); - - var splitter = document.getElementById("urlbar-search-splitter"); - if (splitter) - splitter.parentNode.removeChild(splitter); - - CombinedStopReload.uninit(); - - PlacesToolbarHelper.customizeStart(); - BookmarkingUI.customizeStart(); - DownloadsButton.customizeStart(); - - TabsInTitlebar.allowedBy("customizing-toolbars", false); - - var customizeURL = "chrome://global/content/customizeToolbar.xul"; - gCustomizeSheet = Services.prefs.getBoolPref("toolbar.customization.usesheet", false); - - if (gCustomizeSheet) { - let sheetFrame = document.createElement("iframe"); - let panel = document.getElementById("customizeToolbarSheetPopup"); - sheetFrame.id = "customizeToolbarSheetIFrame"; - sheetFrame.toolbox = gNavToolbox; - sheetFrame.panel = panel; - sheetFrame.setAttribute("style", panel.getAttribute("sheetstyle")); - panel.appendChild(sheetFrame); - - // 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"; - gNavToolbox.addEventListener("beforecustomization", function onBeforeCustomization() { - gNavToolbox.removeEventListener("beforecustomization", onBeforeCustomization, false); - panel.style.removeProperty("visibility"); - }, false); - - sheetFrame.setAttribute("src", customizeURL); - - panel.openPopup(gNavToolbox, "after_start", 0, 0); - } else { - window.openDialog(customizeURL, - "CustomizeToolbar", - "chrome,titlebar,toolbar,location,resizable,dependent", - gNavToolbox); - } -} - -function BrowserToolboxCustomizeDone(aToolboxChanged) { - if (gCustomizeSheet) { - document.getElementById("customizeToolbarSheetPopup").hidePopup(); - let iframe = document.getElementById("customizeToolbarSheetIFrame"); - iframe.parentNode.removeChild(iframe); - } - - // Update global UI elements that may have been added or removed - if (aToolboxChanged) { - gURLBar = document.getElementById("urlbar"); - - gProxyFavIcon = document.getElementById("page-proxy-favicon"); - gHomeButton.updateTooltip(); - gIdentityHandler._cacheElements(); - window.XULBrowserWindow.init(); - -#ifndef XP_MACOSX - updateEditUIVisibility(); -#endif - - // Hacky: update the PopupNotifications' object's reference to the iconBox, - // if it already exists, since it may have changed if the URL bar was - // added/removed. - if (!window.__lookupGetter__("PopupNotifications")) - PopupNotifications.iconBox = document.getElementById("notification-popup-box"); - } - - PlacesToolbarHelper.customizeDone(); - BookmarkingUI.customizeDone(); - DownloadsButton.customizeDone(); - - // The url bar splitter state is dependent on whether stop/reload - // and the location bar are combined, so we need this ordering - CombinedStopReload.init(); - UpdateUrlbarSearchSplitterState(); - setUrlAndSearchBarWidthForConditionalForwardButton(); - - // Update the urlbar - if (gURLBar) { - gURLBarSettings.writePlaceholder(); - URLBarSetURI(); - XULBrowserWindow.asyncUpdateUI(); - BookmarkingUI.updateStarState(); - } - - TabsInTitlebar.allowedBy("customizing-toolbars", true); - - // Re-enable parts of the UI we disabled during the dialog - var menubar = document.getElementById("main-menubar"); - for (let childNode of menubar.childNodes) - childNode.setAttribute("disabled", false); - var cmd = document.getElementById("cmd_CustomizeToolbars"); - cmd.removeAttribute("disabled"); - - // make sure to re-enable click-and-hold - if (!Services.prefs.getBoolPref("ui.click_hold_context_menus", false)) - SetClickAndHoldHandlers(); - - gBrowser.selectedBrowser.focus(); -} - -function BrowserToolboxCustomizeChange(aType) { - switch (aType) { - case "iconsize": - case "mode": - retrieveToolbarIconsizesFromTheme(); - break; - default: - gHomeButton.updatePersonalToolbarStyle(); - BookmarkingUI.customizeChange(); - allTabs.readPref(); - } -} - -/** - * Allows themes to override the "iconsize" attribute on toolbars. - */ -function retrieveToolbarIconsizesFromTheme() { - function retrieveToolbarIconsize(aToolbar) { - if (aToolbar.localName != "toolbar") - return; - - // The theme indicates that it wants to override the "iconsize" attribute - // by specifying a special value for the "counter-reset" property on the - // toolbar. A custom property cannot be used because getComputedStyle can - // only return the values of standard CSS properties. - let counterReset = getComputedStyle(aToolbar).counterReset; - if (counterReset == "smallicons 0") - aToolbar.setAttribute("iconsize", "small"); - else if (counterReset == "largeicons 0") - aToolbar.setAttribute("iconsize", "large"); - } - - Array.forEach(gNavToolbox.childNodes, retrieveToolbarIconsize); - gNavToolbox.externalToolbars.forEach(retrieveToolbarIconsize); -} - -/** - * Update the global flag that tracks whether or not any edit UI (the Edit menu, - * edit-related items in the context menu, and edit-related toolbar buttons - * is visible, then update the edit commands' enabled state accordingly. We use - * this flag to skip updating the edit commands on focus or selection changes - * when no UI is visible to improve performance (including pageload performance, - * since focus changes when you load a new page). - * - * If UI is visible, we use goUpdateGlobalEditMenuItems to set the commands' - * enabled state so the UI will reflect it appropriately. - * - * If the UI isn't visible, we enable all edit commands so keyboard shortcuts - * still work and just lazily disable them as needed when the user presses a - * shortcut. - * - * This doesn't work on Mac, since Mac menus flash when users press their - * keyboard shortcuts, so edit UI is essentially always visible on the Mac, - * and we need to always update the edit commands. Thus on Mac this function - * is a no op. - */ -function updateEditUIVisibility() -{ -#ifndef XP_MACOSX - let editMenuPopupState = document.getElementById("menu_EditPopup").state; - let contextMenuPopupState = document.getElementById("contentAreaContextMenu").state; - let placesContextMenuPopupState = document.getElementById("placesContext").state; -#ifdef MENUBAR_CAN_AUTOHIDE - let appMenuPopupState = document.getElementById("appmenu-popup").state; -#endif - - // The UI is visible if the Edit menu is opening or open, if the context menu - // is open, or if the toolbar has been customized to include the Cut, Copy, - // or Paste toolbar buttons. - gEditUIVisible = editMenuPopupState == "showing" || - editMenuPopupState == "open" || - contextMenuPopupState == "showing" || - contextMenuPopupState == "open" || - placesContextMenuPopupState == "showing" || - placesContextMenuPopupState == "open" || -#ifdef MENUBAR_CAN_AUTOHIDE - appMenuPopupState == "showing" || - appMenuPopupState == "open" || -#endif - document.getElementById("cut-button") || - document.getElementById("copy-button") || - document.getElementById("paste-button") ? true : false; - - // If UI is visible, update the edit commands' enabled state to reflect - // whether or not they are actually enabled for the current focus/selection. - if (gEditUIVisible) - goUpdateGlobalEditMenuItems(); - - // Otherwise, enable all commands, so that keyboard shortcuts still work, - // then lazily determine their actual enabled state when the user presses - // a keyboard shortcut. - else { - goSetCommandEnabled("cmd_undo", true); - goSetCommandEnabled("cmd_redo", true); - goSetCommandEnabled("cmd_cut", true); - goSetCommandEnabled("cmd_copy", true); - goSetCommandEnabled("cmd_paste", true); - goSetCommandEnabled("cmd_selectAll", true); - goSetCommandEnabled("cmd_delete", true); - goSetCommandEnabled("cmd_switchTextDirection", true); - } -#endif -} - -/** - * Makes the Character Encoding menu enabled or disabled as appropriate. - * To be called when the View menu or the app menu is opened. - */ -function updateCharacterEncodingMenuState() -{ - let charsetMenu = document.getElementById("charsetMenu"); - let appCharsetMenu = document.getElementById("appmenu_charsetMenu"); - let appDevCharsetMenu = - document.getElementById("appmenu_developer_charsetMenu"); - // gBrowser is null on Mac when the menubar shows in the context of - // non-browser windows. The above elements may be null depending on - // what parts of the menubar are present. E.g. no app menu on Mac. - if (gBrowser && - gBrowser.docShell && - gBrowser.docShell.mayEnableCharacterEncodingMenu) { - if (charsetMenu) { - charsetMenu.removeAttribute("disabled"); - } - if (appCharsetMenu) { - appCharsetMenu.removeAttribute("disabled"); - } - if (appDevCharsetMenu) { - appDevCharsetMenu.removeAttribute("disabled"); - } - } else { - if (charsetMenu) { - charsetMenu.setAttribute("disabled", "true"); - } - if (appCharsetMenu) { - appCharsetMenu.setAttribute("disabled", "true"); - } - if (appDevCharsetMenu) { - appDevCharsetMenu.setAttribute("disabled", "true"); - } - } -} - -var XULBrowserWindow = { - // Stored Status, Link and Loading values - status: "", - defaultStatus: "", - overLink: "", - startTime: 0, - statusText: "", - isBusy: false, -/* Pale Moon: Don't hide navigation controls and toolbars for "special" pages. SBaD, M! - inContentWhitelist: ["about:addons", "about:downloads", "about:permissions", - "about:sync-progress"],*/ - inContentWhitelist: [], - - QueryInterface: function (aIID) { - if (aIID.equals(Ci.nsIWebProgressListener) || - aIID.equals(Ci.nsIWebProgressListener2) || - aIID.equals(Ci.nsISupportsWeakReference) || - aIID.equals(Ci.nsIXULBrowserWindow) || - aIID.equals(Ci.nsISupports)) - return this; - throw Cr.NS_NOINTERFACE; - }, - - get stopCommand () { - delete this.stopCommand; - return this.stopCommand = document.getElementById("Browser:Stop"); - }, - get reloadCommand () { - delete this.reloadCommand; - return this.reloadCommand = document.getElementById("Browser:Reload"); - }, - get statusTextField () { - delete this.statusTextField; - return this.statusTextField = document.getElementById("statusbar-display"); - }, - get isImage () { - delete this.isImage; - return this.isImage = document.getElementById("isImage"); - }, - - init: function () { - this.throbberElement = document.getElementById("navigator-throbber"); - - // Bug 666809 - SecurityUI support for e10s - if (gMultiProcessBrowser) - return; - - // Initialize the security button's state and tooltip text. Remember to reset - // _hostChanged, otherwise onSecurityChange will short circuit. - var securityUI = gBrowser.securityUI; - this._hostChanged = true; - this.onSecurityChange(null, null, securityUI.state); - }, - - destroy: function () { - // XXXjag to avoid leaks :-/, see bug 60729 - delete this.throbberElement; - delete this.stopCommand; - delete this.reloadCommand; - delete this.statusTextField; - delete this.statusText; - }, - - setJSStatus: function () { - // unsupported - }, - - setDefaultStatus: function (status) { - this.defaultStatus = status; - this.updateStatusField(); - }, - - setOverLink: function (url, anchorElt) { - // Encode bidirectional formatting characters. - // (RFC 3987 sections 3.2 and 4.1 paragraph 6) - url = url.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g, - encodeURIComponent); - - if (gURLBar && gURLBar._mayTrimURLs /* corresponds to browser.urlbar.trimURLs */) - url = trimURL(url); - - this.overLink = url; - LinkTargetDisplay.update(); - }, - - updateStatusField: function () { - var text, type, types = ["overLink"]; - if (this._busyUI) - types.push("status"); - types.push("defaultStatus"); - for (type of types) { - text = this[type]; - if (text) - break; - } - - // check the current value so we don't trigger an attribute change - // and cause needless (slow!) UI updates - if (this.statusText != text) { - let field = this.statusTextField; - field.setAttribute("previoustype", field.getAttribute("type")); - field.setAttribute("type", type); - field.label = text; - field.setAttribute("crop", type == "overLink" ? "center" : "end"); - this.statusText = text; - } - }, - - // Called before links are navigated to to allow us to retarget them if needed. - onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) { - let target = this._onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab); - return target; - }, - - _onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) { - // Don't modify non-default targets or targets that aren't in top-level app - // tab docshells (isAppTab will be false for app tab subframes). - if (originalTarget != "" || !isAppTab) - return originalTarget; - - // External links from within app tabs should always open in new tabs - // instead of replacing the app tab's page (Bug 575561) - let linkHost; - let docHost; - try { - linkHost = linkURI.host; - docHost = linkNode.ownerDocument.documentURIObject.host; - } catch(e) { - // nsIURI.host can throw for non-nsStandardURL nsIURIs. - // If we fail to get either host, just return originalTarget. - return originalTarget; - } - - if (docHost == linkHost) - return originalTarget; - - // Special case: ignore "www" prefix if it is part of host string - let [longHost, shortHost] = - linkHost.length > docHost.length ? [linkHost, docHost] : [docHost, linkHost]; - if (longHost == "www." + shortHost) - return originalTarget; - - return "_blank"; - }, - - onLinkIconAvailable: function (aIconURL) { - if (gProxyFavIcon && gBrowser.userTypedValue === null) { - PageProxySetIcon(aIconURL); // update the favicon in the URL bar - } - }, - - onProgressChange: function (aWebProgress, aRequest, - aCurSelfProgress, aMaxSelfProgress, - aCurTotalProgress, aMaxTotalProgress) { - // Do nothing. - }, - - onProgressChange64: function (aWebProgress, aRequest, - aCurSelfProgress, aMaxSelfProgress, - aCurTotalProgress, aMaxTotalProgress) { - return this.onProgressChange(aWebProgress, aRequest, - aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, - aMaxTotalProgress); - }, - - // This function fires only for the currently selected tab. - onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus) { - const nsIWebProgressListener = Ci.nsIWebProgressListener; - const nsIChannel = Ci.nsIChannel; - - if (aStateFlags & nsIWebProgressListener.STATE_START && - aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) { - - if (aRequest && aWebProgress.isTopLevel) { - // clear out feed data - gBrowser.selectedBrowser.feeds = null; - - // clear out search-engine data - gBrowser.selectedBrowser.engines = null; - } - - this.isBusy = true; - - if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) { - this._busyUI = true; - - // Turn the throbber on. - if (this.throbberElement) - this.throbberElement.setAttribute("busy", "true"); - - // XXX: This needs to be based on window activity... - this.stopCommand.removeAttribute("disabled"); - CombinedStopReload.switchToStop(); - } - } - else if (aStateFlags & nsIWebProgressListener.STATE_STOP) { - // This (thanks to the filter) is a network stop or the last - // request stop outside of loading the document, stop throbbers - // and progress bars and such - if (aRequest) { - let msg = ""; - let location; - // Get the URI either from a channel or a pseudo-object - if (aRequest instanceof nsIChannel || "URI" in aRequest) { - location = aRequest.URI; - - // For keyword URIs clear the user typed value since they will be changed into real URIs - if (location.scheme == "keyword" && aWebProgress.isTopLevel) - gBrowser.userTypedValue = null; - - if (location.spec != "about:blank") { - switch (aStatus) { - case Components.results.NS_ERROR_NET_TIMEOUT: - msg = gNavigatorBundle.getString("nv_timeout"); - break; - } - } - } - - this.status = ""; - this.setDefaultStatus(msg); - - // Disable menu entries for images, enable otherwise - if (!gMultiProcessBrowser && content.document && BrowserUtils.mimeTypeIsTextBased(content.document.contentType)) - this.isImage.removeAttribute('disabled'); - else - this.isImage.setAttribute('disabled', 'true'); - } - - this.isBusy = false; - - if (this._busyUI) { - this._busyUI = false; - - // Turn the throbber off. - if (this.throbberElement) - this.throbberElement.removeAttribute("busy"); - - this.stopCommand.setAttribute("disabled", "true"); - CombinedStopReload.switchToReload(aRequest instanceof Ci.nsIRequest); - } - } - }, - - onLocationChange: function (aWebProgress, aRequest, aLocationURI, aFlags) { - var location = aLocationURI ? aLocationURI.spec : ""; - this._hostChanged = true; - - // If displayed, hide the form validation popup. - FormValidationHandler.hidePopup(); - - let pageTooltip = document.getElementById("aHTMLTooltip"); - let tooltipNode = pageTooltip.triggerNode; - if (tooltipNode) { - // Optimise for the common case - if (aWebProgress.isTopLevel) { - pageTooltip.hidePopup(); - } - else { - for (let tooltipWindow = tooltipNode.ownerDocument.defaultView; - tooltipWindow != tooltipWindow.parent; - tooltipWindow = tooltipWindow.parent) { - if (tooltipWindow == aWebProgress.DOMWindow) { - pageTooltip.hidePopup(); - break; - } - } - } - } - - // Disable menu entries for images, enable otherwise - if (!gMultiProcessBrowser && content.document && BrowserUtils.mimeTypeIsTextBased(content.document.contentType)) - this.isImage.removeAttribute('disabled'); - else - this.isImage.setAttribute('disabled', 'true'); - - this.hideOverLinkImmediately = true; - this.setOverLink("", null); - this.hideOverLinkImmediately = false; - - // We should probably not do this if the value has changed since the user - // searched - // Update urlbar only if a new page was loaded on the primary content area - // Do not update urlbar if there was a subframe navigation - - var browser = gBrowser.selectedBrowser; - if (aWebProgress.isTopLevel) { - if ((location == "about:blank" && (gMultiProcessBrowser || !content.opener)) || - location == "") { // Second condition is for new tabs, otherwise - // reload function is enabled until tab is refreshed. - this.reloadCommand.setAttribute("disabled", "true"); - } else { - this.reloadCommand.removeAttribute("disabled"); - } - - if (gURLBar) { - URLBarSetURI(aLocationURI); - - // Update starring UI - BookmarkingUI.updateStarState(); - } - - // Show or hide browser chrome based on the whitelist - if (this.hideChromeForLocation(location)) { - document.documentElement.setAttribute("disablechrome", "true"); - } else { - let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); - if (ss.getTabValue(gBrowser.selectedTab, "appOrigin")) - document.documentElement.setAttribute("disablechrome", "true"); - else - document.documentElement.removeAttribute("disablechrome"); - } - - // Utility functions for disabling find - var shouldDisableFind = function shouldDisableFind(aDocument) { - let docElt = aDocument.documentElement; - return docElt && docElt.getAttribute("disablefastfind") == "true"; - } - - var disableFindCommands = function disableFindCommands(aDisable) { - let findCommands = [document.getElementById("cmd_find"), - document.getElementById("cmd_findAgain"), - document.getElementById("cmd_findPrevious")]; - for (let elt of findCommands) { - if (aDisable) - elt.setAttribute("disabled", "true"); - else - elt.removeAttribute("disabled"); - } - if (gFindBarInitialized) { - if (!gFindBar.hidden && aDisable) { - gFindBar.hidden = true; - this._findbarTemporarilyHidden = true; - } else if (this._findbarTemporarilyHidden && !aDisable) { - gFindBar.hidden = false; - this._findbarTemporarilyHidden = false; - } - } - }.bind(this); - - var onContentRSChange = function onContentRSChange(e) { - if (e.target.readyState != "interactive" && e.target.readyState != "complete") - return; - - e.target.removeEventListener("readystatechange", onContentRSChange); - disableFindCommands(shouldDisableFind(e.target)); - } - - // Disable find commands in documents that ask for them to be disabled. - if (!gMultiProcessBrowser && aLocationURI && - (aLocationURI.schemeIs("about") || aLocationURI.schemeIs("chrome"))) { - // Don't need to re-enable/disable find commands for same-document location changes - // (e.g. the replaceStates in about:addons) - if (!(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)) { - if (content.document.readyState == "interactive" || content.document.readyState == "complete") - disableFindCommands(shouldDisableFind(content.document)); - else { - content.document.addEventListener("readystatechange", onContentRSChange); - } - } - } else - disableFindCommands(false); - - if (gFindBarInitialized) { - if (gFindBar.findMode != gFindBar.FIND_NORMAL) { - // Close the Find toolbar if we're in old-style TAF mode - gFindBar.close(); - } - - // XXX - // See: https://github.com/MoonchildProductions/Pale-Moon/issues/364 - // An actual preference: findbar.highlightAll - /* - if (!(gPrefService.getBoolPref("accessibility.typeaheadfind.highlightallremember") || - gPrefService.getBoolPref("accessibility.typeaheadfind.highlightallbydefault"))) { - // fix bug 253793 - turn off highlight when page changes - gFindBar.getElement("highlight").checked = false; - } - */ - } - } - UpdateBackForwardCommands(gBrowser.webNavigation); - - gGestureSupport.restoreRotationState(); - - // See bug 358202, when tabs are switched during a drag operation, - // timers don't fire on windows (bug 203573) - if (aRequest) - setTimeout(function () { XULBrowserWindow.asyncUpdateUI(); }, 0); - else - this.asyncUpdateUI(); - }, - - asyncUpdateUI: function () { - FeedHandler.updateFeeds(); - }, - - hideChromeForLocation: function(aLocation) { - aLocation = aLocation.toLowerCase(); - return this.inContentWhitelist.some(function(aSpec) { - return aSpec == aLocation; - }); - }, - - onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) { - this.status = aMessage; - this.updateStatusField(); - }, - - // Properties used to cache security state used to update the UI - _state: null, - _hostChanged: false, // onLocationChange will flip this bit - - onSecurityChange: function (aWebProgress, aRequest, aState) { - // Don't need to do anything if the data we use to update the UI hasn't - // changed - if (this._state == aState && - !this._hostChanged) { -#ifdef DEBUG - try { - var contentHost = gBrowser.contentWindow.location.host; - if (this._host !== undefined && this._host != contentHost) { - Components.utils.reportError( - "ASSERTION: browser.js host is inconsistent. Content window has " + - "<" + contentHost + "> but cached host is <" + this._host + ">.\n" - ); - } - } catch (ex) {} -#endif - return; - } - this._state = aState; - -#ifdef DEBUG - try { - this._host = gBrowser.contentWindow.location.host; - } catch(ex) { - this._host = null; - } -#endif - - this._hostChanged = false; - - // aState is defined as a bitmask that may be extended in the future. - // We filter out any unknown bits before testing for known values. - const wpl = Components.interfaces.nsIWebProgressListener; - const wpl_security_bits = wpl.STATE_IS_SECURE | - wpl.STATE_IS_BROKEN | - wpl.STATE_IS_INSECURE; - var level; - - switch (this._state & wpl_security_bits) { - case wpl.STATE_IS_SECURE: - level = "high"; - break; - case wpl.STATE_IS_BROKEN: - level = "broken"; - break; - } - - if (level) { - // We don't style the Location Bar based on the the 'level' attribute - // anymore, but still set it for third-party themes. - if (gURLBar) - gURLBar.setAttribute("level", level); - } else { - if (gURLBar) - gURLBar.removeAttribute("level"); - } - - if (gMultiProcessBrowser) - return; - - // Don't pass in the actual location object, since it can cause us to - // hold on to the window object too long. Just pass in the fields we - // care about. (bug 424829) - var location = gBrowser.contentWindow.location; - var locationObj = {}; - try { - // about:blank can be used by webpages so pretend it is http - locationObj.protocol = location == "about:blank" ? "http:" : location.protocol; - locationObj.host = location.host; - locationObj.hostname = location.hostname; - locationObj.port = location.port; - } catch (ex) { - // Can sometimes throw if the URL being visited has no host/hostname, - // e.g. about:blank. The _state for these pages means we won't need these - // properties anyways, though. - } - gIdentityHandler.checkIdentity(this._state, locationObj); - }, - - // simulate all change notifications after switching tabs - onUpdateCurrentBrowser: function XWB_onUpdateCurrentBrowser(aStateFlags, aStatus, aMessage, aTotalProgress) { - if (FullZoom.updateBackgroundTabs) - FullZoom.onLocationChange(gBrowser.currentURI, true); - var nsIWebProgressListener = Components.interfaces.nsIWebProgressListener; - var loadingDone = aStateFlags & nsIWebProgressListener.STATE_STOP; - // use a pseudo-object instead of a (potentially nonexistent) channel for getting - // a correct error message - and make sure that the UI is always either in - // loading (STATE_START) or done (STATE_STOP) mode - this.onStateChange( - gBrowser.webProgress, - { URI: gBrowser.currentURI }, - loadingDone ? nsIWebProgressListener.STATE_STOP : nsIWebProgressListener.STATE_START, - aStatus - ); - // status message and progress value are undefined if we're done with loading - if (loadingDone) - return; - this.onStatusChange(gBrowser.webProgress, null, 0, aMessage); - } -}; - -var LinkTargetDisplay = { - get DELAY_SHOW() { - delete this.DELAY_SHOW; - return this.DELAY_SHOW = Services.prefs.getIntPref("browser.overlink-delay"); - }, - - DELAY_HIDE: 250, - _timer: 0, - - get _isVisible () XULBrowserWindow.statusTextField.label != "", - - update: function () { - clearTimeout(this._timer); - window.removeEventListener("mousemove", this, true); - - if (!XULBrowserWindow.overLink) { - if (XULBrowserWindow.hideOverLinkImmediately) - this._hide(); - else - this._timer = setTimeout(this._hide.bind(this), this.DELAY_HIDE); - return; - } - - if (this._isVisible) { - XULBrowserWindow.updateStatusField(); - } else { - // Let the display appear when the mouse doesn't move within the delay - this._showDelayed(); - window.addEventListener("mousemove", this, true); - } - }, - - handleEvent: function (event) { - switch (event.type) { - case "mousemove": - // Restart the delay since the mouse was moved - clearTimeout(this._timer); - this._showDelayed(); - break; - } - }, - - _showDelayed: function () { - this._timer = setTimeout(function (self) { - XULBrowserWindow.updateStatusField(); - window.removeEventListener("mousemove", self, true); - }, this.DELAY_SHOW, this); - }, - - _hide: function () { - clearTimeout(this._timer); - - XULBrowserWindow.updateStatusField(); - } -}; - -var CombinedStopReload = { - init: function () { - if (this._initialized) - return; - - var urlbar = document.getElementById("urlbar-container"); - var reload = document.getElementById("reload-button"); - var stop = document.getElementById("stop-button"); - - if (urlbar) { - if (urlbar.parentNode.getAttribute("mode") != "icons" || - !reload || urlbar.nextSibling != reload || - !stop || reload.nextSibling != stop) - urlbar.removeAttribute("combined"); - else { - urlbar.setAttribute("combined", "true"); - reload = document.getElementById("urlbar-reload-button"); - stop = document.getElementById("urlbar-stop-button"); - } - } - if (!stop || !reload || reload.nextSibling != stop) - return; - - this._initialized = true; - if (XULBrowserWindow.stopCommand.getAttribute("disabled") != "true") - reload.setAttribute("displaystop", "true"); - stop.addEventListener("click", this, false); - this.reload = reload; - this.stop = stop; - }, - - uninit: function () { - if (!this._initialized) - return; - - this._cancelTransition(); - this._initialized = false; - this.stop.removeEventListener("click", this, false); - this.reload = null; - this.stop = null; - }, - - handleEvent: function (event) { - // the only event we listen to is "click" on the stop button - if (event.button == 0 && - !this.stop.disabled) - this._stopClicked = true; - }, - - switchToStop: function () { - if (!this._initialized) - return; - - this._cancelTransition(); - this.reload.setAttribute("displaystop", "true"); - }, - - switchToReload: function (aDelay) { - if (!this._initialized) - return; - - this.reload.removeAttribute("displaystop"); - - if (!aDelay || this._stopClicked) { - this._stopClicked = false; - this._cancelTransition(); - this.reload.disabled = XULBrowserWindow.reloadCommand - .getAttribute("disabled") == "true"; - return; - } - - if (this._timer) - return; - - // Temporarily disable the reload button to prevent the user from - // accidentally reloading the page when intending to click the stop button - this.reload.disabled = true; - this._timer = setTimeout(function (self) { - self._timer = 0; - self.reload.disabled = XULBrowserWindow.reloadCommand - .getAttribute("disabled") == "true"; - }, 650, this); - }, - - _cancelTransition: function () { - if (this._timer) { - clearTimeout(this._timer); - this._timer = 0; - } - } -}; - -var TabsProgressListener = { - onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) { - - // Attach a listener to watch for "click" events bubbling up from error - // pages and other similar page. This lets us fix bugs like 401575 which - // require error page UI to do privileged things, without letting error - // pages have any privilege themselves. - // We can't look for this during onLocationChange since at that point the - // document URI is not yet the about:-uri of the error page. - - let doc = gMultiProcessBrowser ? null : aWebProgress.DOMWindow.document; - if (!gMultiProcessBrowser && - aStateFlags & Ci.nsIWebProgressListener.STATE_STOP && - Components.isSuccessCode(aStatus) && - doc.documentURI.startsWith("about:") && - !doc.documentURI.toLowerCase().startsWith("about:blank") && - !doc.documentElement.hasAttribute("hasBrowserHandlers")) { - // STATE_STOP may be received twice for documents, thus store an - // attribute to ensure handling it just once. - doc.documentElement.setAttribute("hasBrowserHandlers", "true"); - aBrowser.addEventListener("click", BrowserOnClick, true); - aBrowser.addEventListener("pagehide", function onPageHide(event) { - if (event.target.defaultView.frameElement) - return; - aBrowser.removeEventListener("click", BrowserOnClick, true); - aBrowser.removeEventListener("pagehide", onPageHide, true); - if (event.target.documentElement) - event.target.documentElement.removeAttribute("hasBrowserHandlers"); - }, true); - - // We also want to make changes to page UI for unprivileged about pages. - BrowserOnAboutPageLoad(doc); - } - }, - - onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI, - aFlags) { - // Filter out location changes caused by anchor navigation - // or history.push/pop/replaceState. - if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) - return; - - // Only need to call locationChange if the PopupNotifications object - // for this window has already been initialized (i.e. its getter no - // longer exists) - if (!Object.getOwnPropertyDescriptor(window, "PopupNotifications").get) - PopupNotifications.locationChange(aBrowser); - - gBrowser.getNotificationBox(aBrowser).removeTransientNotifications(); - - // Filter out location changes in sub documents. - if (aWebProgress.isTopLevel) { - // Initialize the click-to-play state. - aBrowser._clickToPlayPluginsActivated = new Map(); - aBrowser._clickToPlayAllPluginsActivated = false; - aBrowser._pluginScriptedState = gPluginHandler.PLUGIN_SCRIPTED_STATE_NONE; - - FullZoom.onLocationChange(aLocationURI, false, aBrowser); - } - }, - - onRefreshAttempted: function (aBrowser, aWebProgress, aURI, aDelay, aSameURI) { - if (gPrefService.getBoolPref("accessibility.blockautorefresh")) { - let brandBundle = document.getElementById("bundle_brand"); - let brandShortName = brandBundle.getString("brandShortName"); - let refreshButtonText = - gNavigatorBundle.getString("refreshBlocked.goButton"); - let refreshButtonAccesskey = - gNavigatorBundle.getString("refreshBlocked.goButton.accesskey"); - let message = - gNavigatorBundle.getFormattedString(aSameURI ? "refreshBlocked.refreshLabel" - : "refreshBlocked.redirectLabel", - [brandShortName]); - let docShell = aWebProgress.DOMWindow - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell); - let notificationBox = gBrowser.getNotificationBox(aBrowser); - let notification = notificationBox.getNotificationWithValue("refresh-blocked"); - if (notification) { - notification.label = message; - notification.refreshURI = aURI; - notification.delay = aDelay; - notification.docShell = docShell; - } else { - let buttons = [{ - label: refreshButtonText, - accessKey: refreshButtonAccesskey, - callback: function (aNotification, aButton) { - var refreshURI = aNotification.docShell - .QueryInterface(Ci.nsIRefreshURI); - refreshURI.forceRefreshURI(aNotification.refreshURI, - aNotification.delay, true); - } - }]; - notification = - notificationBox.appendNotification(message, "refresh-blocked", - "chrome://browser/skin/Info.png", - notificationBox.PRIORITY_INFO_MEDIUM, - buttons); - notification.refreshURI = aURI; - notification.delay = aDelay; - notification.docShell = docShell; - } - return false; - } - return true; - } -} - -function nsBrowserAccess() { } - -nsBrowserAccess.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow, Ci.nsISupports]), - - openURI: function (aURI, aOpener, aWhere, aContext) { - var newWindow = null; - var isExternal = !!(aContext & Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL); - - if (aOpener && isExternal) { - Cu.reportError("nsBrowserAccess.openURI did not expect an opener to be " + - "passed if the context is OPEN_EXTERNAL."); - throw Cr.NS_ERROR_FAILURE; - } - - if (isExternal && aURI && aURI.schemeIs("chrome")) { - dump("use -chrome command-line option to load external chrome urls\n"); - return null; - } - - if (aWhere == Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW) { - if (isExternal && - gPrefService.prefHasUserValue("browser.link.open_newwindow.override.external")) - aWhere = gPrefService.getIntPref("browser.link.open_newwindow.override.external"); - else - aWhere = gPrefService.getIntPref("browser.link.open_newwindow"); - } - - let referrer = aOpener ? makeURI(aOpener.location.href) : null; - let triggeringPrincipal = null; - let referrerPolicy = Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT; - if (aOpener && aOpener.document) { - referrerPolicy = aOpener.document.referrerPolicy; - triggeringPrincipal = aOpener.document.nodePrincipal; - } - - switch (aWhere) { - case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW : - // FIXME: Bug 408379. So how come this doesn't send the - // referrer like the other loads do? - var url = aURI ? aURI.spec : "about:blank"; - // Pass all params to openDialog to ensure that "url" isn't passed through - // loadOneOrMoreURIs, which splits based on "|" - newWindow = openDialog(getBrowserURL(), "_blank", "all,dialog=no", url, null, null, null); - break; - case Ci.nsIBrowserDOMWindow.OPEN_NEWTAB : - let win, needToFocusWin; - - // try the current window. if we're in a popup, fall back on the most recent browser window - if (window.toolbar.visible) - win = window; - else { - let isPrivate = PrivateBrowsingUtils.isWindowPrivate(aOpener || window); - win = RecentWindow.getMostRecentBrowserWindow({private: isPrivate}); - needToFocusWin = true; - } - - if (!win) { - // we couldn't find a suitable window, a new one needs to be opened. - return null; - } - - if (isExternal && (!aURI || aURI.spec == "about:blank")) { - win.BrowserOpenTab(); // this also focuses the location bar - win.focus(); - newWindow = win.content; - break; - } - - let loadInBackground = gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground"); - let openerWindow = (aContext & Ci.nsIBrowserDOMWindow.OPEN_NO_OPENER) ? null : aOpener; - - let tab = win.gBrowser.loadOneTab(aURI ? aURI.spec : "about:blank", { - triggeringPrincipal: triggeringPrincipal, - referrerURI: referrer, - referrerPolicy: referrerPolicy, - fromExternal: isExternal, - inBackground: loadInBackground, - opener: openerWindow }); - let browser = win.gBrowser.getBrowserForTab(tab); - - if (gPrefService.getBoolPref("browser.tabs.noWindowActivationOnExternal")) { - isExternal = false; // this is a hack, but it works - } - - newWindow = browser.contentWindow; - if (needToFocusWin || (!loadInBackground && isExternal)) - newWindow.focus(); - break; - default : // OPEN_CURRENTWINDOW or an illegal value - newWindow = content; - if (aURI) { - let loadflags = isExternal ? - Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL : - Ci.nsIWebNavigation.LOAD_FLAGS_NONE; - gBrowser.loadURIWithFlags(aURI.spec, { - flags: loadflags, - triggeringPrincipal: triggeringPrincipal, - referrerURI: referrer, - referrerPolicy: referrerPolicy, - }); - } - if (!gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground")) - window.focus(); - } - return newWindow; - }, - - isTabContentWindow: function (aWindow) { - return gBrowser.browsers.some(function (browser) browser.contentWindow == aWindow); - } -} - -function onViewToolbarsPopupShowing(aEvent, aInsertPoint) { - var popup = aEvent.target; - if (popup != aEvent.currentTarget) - return; - - // Empty the menu - for (var i = popup.childNodes.length-1; i >= 0; --i) { - var deadItem = popup.childNodes[i]; - if (deadItem.hasAttribute("toolbarId")) - popup.removeChild(deadItem); - } - - var firstMenuItem = aInsertPoint || popup.firstChild; - - let toolbarNodes = Array.slice(gNavToolbox.childNodes); - toolbarNodes.push(document.getElementById("addon-bar")); - - for (let toolbar of toolbarNodes) { - let toolbarName = toolbar.getAttribute("toolbarname"); - if (toolbarName) { - let menuItem = document.createElement("menuitem"); - let hidingAttribute = toolbar.getAttribute("type") == "menubar" ? - "autohide" : "collapsed"; - menuItem.setAttribute("id", "toggle_" + toolbar.id); - menuItem.setAttribute("toolbarId", toolbar.id); - menuItem.setAttribute("type", "checkbox"); - menuItem.setAttribute("label", toolbarName); - menuItem.setAttribute("checked", toolbar.getAttribute(hidingAttribute) != "true"); - if (popup.id != "appmenu_customizeMenu") - menuItem.setAttribute("accesskey", toolbar.getAttribute("accesskey")); - if (popup.id != "toolbar-context-menu") - menuItem.setAttribute("key", toolbar.getAttribute("key")); - - popup.insertBefore(menuItem, firstMenuItem); - - menuItem.addEventListener("command", onViewToolbarCommand, false); - } - } -} - -function onViewToolbarCommand(aEvent) { - var toolbarId = aEvent.originalTarget.getAttribute("toolbarId"); - var toolbar = document.getElementById(toolbarId); - var isVisible = aEvent.originalTarget.getAttribute("checked") == "true"; - setToolbarVisibility(toolbar, isVisible); -} - -function setToolbarVisibility(toolbar, isVisible) { - var hidingAttribute = toolbar.getAttribute("type") == "menubar" ? - "autohide" : "collapsed"; - - toolbar.setAttribute(hidingAttribute, !isVisible); - document.persist(toolbar.id, hidingAttribute); - - // Customizable toolbars - persist the hiding attribute. - if (toolbar.hasAttribute("customindex")) { - var toolbox = toolbar.parentNode; - var name = toolbar.getAttribute("toolbarname"); - if (toolbox.toolbarset) { - try { - // Checking all attributes starting with "toolbar". - Array.prototype.slice.call(toolbox.toolbarset.attributes, 0) - .find(x => { - if (x.name.startsWith("toolbar")) { - var toolbarInfo = x.value; - var infoSplit = toolbarInfo.split(gToolbarInfoSeparators[0]); - if (infoSplit[0] == name) { - infoSplit[1] = [ - infoSplit[1].split(gToolbarInfoSeparators[1], 1), !isVisible - ].join(gToolbarInfoSeparators[1]); - toolbox.toolbarset.setAttribute( - x.name, infoSplit.join(gToolbarInfoSeparators[0])); - document.persist(toolbox.toolbarset.id, x.name); - } - } - }); - } catch (e) { - Components.utils.reportError( - "Customizable toolbars - persist the hiding attribute: " + e); - } - } - } - - PlacesToolbarHelper.init(); - BookmarkingUI.onToolbarVisibilityChange(); - gBrowser.updateWindowResizers(); - -#ifdef MENUBAR_CAN_AUTOHIDE - updateAppButtonDisplay(); -#endif - - if (isVisible) - ToolbarIconColor.inferFromText(); -} - -var AudioIndicator = { - init: function () { - Services.prefs.addObserver(this._prefName, this, false); - this.syncUI(); - }, - - uninit: function () { - Services.prefs.removeObserver(this._prefName, this); - }, - - toggle: function () { - this.enabled = !Services.prefs.getBoolPref(this._prefName); - }, - - syncUI: function () { - document.getElementById("context_toggleMuteTab").setAttribute("hidden", this.enabled); - document.getElementById("key_toggleMute").setAttribute("disabled", this.enabled); - }, - - get enabled () { - return !Services.prefs.getBoolPref(this._prefName); - }, - - set enabled (val) { - Services.prefs.setBoolPref(this._prefName, !!val); - return val; - }, - - observe: function (subject, topic, data) { - if (topic == "nsPref:changed") - this.syncUI(); - }, - - _prefName: "browser.tabs.showAudioPlayingIcon" -} - -var TabsOnTop = { - init: function TabsOnTop_init() { - Services.prefs.addObserver(this._prefName, this, false); -// Pale Moon: Stop Being a Derp, Mozilla (#3) - // Only show the toggle UI if the user disabled tabs on top. -// if (Services.prefs.getBoolPref(this._prefName)) { -// for (let item of document.querySelectorAll("menuitem[command=cmd_ToggleTabsOnTop]")) -// item.parentNode.removeChild(item); -// } - }, - - uninit: function TabsOnTop_uninit() { - Services.prefs.removeObserver(this._prefName, this); - }, - - toggle: function () { - this.enabled = !Services.prefs.getBoolPref(this._prefName); - }, - - syncUI: function () { - let userEnabled = Services.prefs.getBoolPref(this._prefName); - let enabled = userEnabled && gBrowser.tabContainer.visible; - - document.getElementById("cmd_ToggleTabsOnTop") - .setAttribute("checked", userEnabled); - - document.documentElement.setAttribute("tabsontop", enabled); - document.getElementById("navigator-toolbox").setAttribute("tabsontop", enabled); - document.getElementById("TabsToolbar").setAttribute("tabsontop", enabled); - document.getElementById("nav-bar").setAttribute("tabsontop", enabled); - gBrowser.tabContainer.setAttribute("tabsontop", enabled); - TabsInTitlebar.allowedBy("tabs-on-top", enabled); - }, - - get enabled () { - return gNavToolbox.getAttribute("tabsontop") == "true"; - }, - - set enabled (val) { - Services.prefs.setBoolPref(this._prefName, !!val); - return val; - }, - - observe: function (subject, topic, data) { - if (topic == "nsPref:changed") - this.syncUI(); - }, - - _prefName: "browser.tabs.onTop" -} - -var TabsInTitlebar = { - init: function () { -#ifdef CAN_DRAW_IN_TITLEBAR - this._readPref(); - Services.prefs.addObserver(this._prefName, this, false); - - // Don't trust the initial value of the sizemode attribute; wait for - // the resize event (handled in tabbrowser.xml). - this.allowedBy("sizemode", false); - - this._initialized = true; -#endif - }, - - allowedBy: function (condition, allow) { -#ifdef CAN_DRAW_IN_TITLEBAR - if (allow) { - if (condition in this._disallowed) { - delete this._disallowed[condition]; - this._update(); - } - } else { - if (!(condition in this._disallowed)) { - this._disallowed[condition] = null; - this._update(); - } - } -#endif - }, - - get enabled() { - return document.documentElement.getAttribute("tabsintitlebar") == "true"; - }, - -#ifdef CAN_DRAW_IN_TITLEBAR - observe: function (subject, topic, data) { - if (topic == "nsPref:changed") - this._readPref(); - }, - - _initialized: false, - _disallowed: {}, - _prefName: "browser.tabs.drawInTitlebar", - - _readPref: function () { - this.allowedBy("pref", - Services.prefs.getBoolPref(this._prefName)); - }, - - _update: function () { - function $(id) document.getElementById(id); - function rect(ele) ele.getBoundingClientRect(); - - if (!this._initialized || window.fullScreen) - return; - - let allowed = true; - for (let something in this._disallowed) { - allowed = false; - break; - } - - if (allowed == this.enabled) - return; - - let titlebar = $("titlebar"); - - if (allowed) { - let tabsToolbar = $("TabsToolbar"); - -#ifdef MENUBAR_CAN_AUTOHIDE - let appmenuButtonBox = $("appmenu-button-container"); - this._sizePlaceholder("appmenu-button", rect(appmenuButtonBox).width); -#endif - let captionButtonsBox = $("titlebar-buttonbox"); - this._sizePlaceholder("caption-buttons", rect(captionButtonsBox).width); - - let tabsToolbarRect = rect(tabsToolbar); - let titlebarTop = rect($("titlebar-content")).top; - titlebar.style.marginBottom = - Math.min(tabsToolbarRect.top - titlebarTop, - tabsToolbarRect.height) + "px"; - - document.documentElement.setAttribute("tabsintitlebar", "true"); - - if (!this._draghandle) { - let tmp = {}; - Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp); - this._draghandle = new tmp.WindowDraggingElement(tabsToolbar); - this._draghandle.mouseDownCheck = function () { - return !this._dragBindingAlive && TabsInTitlebar.enabled; - }; - } - } else { - document.documentElement.removeAttribute("tabsintitlebar"); - - titlebar.style.marginBottom = ""; - } - - ToolbarIconColor.inferFromText(); - }, - - _sizePlaceholder: function (type, width) { - Array.forEach(document.querySelectorAll(".titlebar-placeholder[type='"+ type +"']"), - function (node) { node.width = width; }); - }, -#endif - - uninit: function () { -#ifdef CAN_DRAW_IN_TITLEBAR - this._initialized = false; - Services.prefs.removeObserver(this._prefName, this); -#endif - } -}; - -#ifdef MENUBAR_CAN_AUTOHIDE -function updateAppButtonDisplay() { - var displayAppButton = - !gInPrintPreviewMode && - window.menubar.visible && - document.getElementById("toolbar-menubar").getAttribute("autohide") == "true"; - -#ifdef CAN_DRAW_IN_TITLEBAR - document.getElementById("titlebar").hidden = !displayAppButton; - - if (displayAppButton) - document.documentElement.setAttribute("chromemargin", "0,2,2,2"); - else - document.documentElement.removeAttribute("chromemargin"); - - TabsInTitlebar.allowedBy("drawing-in-titlebar", displayAppButton); -#else - document.getElementById("appmenu-toolbar-button").hidden = - !displayAppButton; -#endif -} -#endif - -#ifdef CAN_DRAW_IN_TITLEBAR -function onTitlebarMaxClick() { - if (window.windowState == window.STATE_MAXIMIZED) - window.restore(); - else - window.maximize(); -} -#endif - -function displaySecurityInfo() -{ - BrowserPageInfo(null, "securityTab"); -} - -/** - * Opens or closes the sidebar identified by commandID. - * - * @param commandID a string identifying the sidebar to toggle; see the - * note below. (Optional if a sidebar is already open.) - * @param forceOpen boolean indicating whether the sidebar should be - * opened regardless of its current state (optional). - * @note - * We expect to find a xul:broadcaster element with the specified ID. - * The following attributes on that element may be used and/or modified: - * - id (required) the string to match commandID. The convention - * is to use this naming scheme: 'view<sidebar-name>Sidebar'. - * - sidebarurl (required) specifies the URL to load in this sidebar. - * - sidebartitle or label (in that order) specify the title to - * display on the sidebar. - * - checked indicates whether the sidebar is currently displayed. - * Note that toggleSidebar updates this attribute when - * it changes the sidebar's visibility. - * - group this attribute must be set to "sidebar". - */ -function toggleSidebar(commandID, forceOpen) { - - var sidebarBox = document.getElementById("sidebar-box"); - if (!commandID) - commandID = sidebarBox.getAttribute("sidebarcommand"); - - var sidebarBroadcaster = document.getElementById(commandID); - var sidebar = document.getElementById("sidebar"); // xul:browser - var sidebarTitle = document.getElementById("sidebar-title"); - var sidebarSplitter = document.getElementById("sidebar-splitter"); - - if (sidebarBroadcaster.getAttribute("checked") == "true") { - if (!forceOpen) { - // Replace the document currently displayed in the sidebar with about:blank - // so that we can free memory by unloading the page. We need to explicitly - // create a new content viewer because the old one doesn't get destroyed - // until about:blank has loaded (which does not happen as long as the - // element is hidden). - sidebar.setAttribute("src", "about:blank"); - sidebar.docShell.createAboutBlankContentViewer(null); - - sidebarBroadcaster.removeAttribute("checked"); - sidebarBox.setAttribute("sidebarcommand", ""); - sidebarTitle.value = ""; - sidebarBox.hidden = true; - sidebarSplitter.hidden = true; - gBrowser.selectedBrowser.focus(); - } else { - fireSidebarFocusedEvent(); - } - return; - } - - // now we need to show the specified sidebar - - // ..but first update the 'checked' state of all sidebar broadcasters - var broadcasters = document.getElementsByAttribute("group", "sidebar"); - for (let broadcaster of broadcasters) { - // skip elements that observe sidebar broadcasters and random - // other elements - if (broadcaster.localName != "broadcaster") - continue; - - if (broadcaster != sidebarBroadcaster) - broadcaster.removeAttribute("checked"); - else - sidebarBroadcaster.setAttribute("checked", "true"); - } - - sidebarBox.hidden = false; - sidebarSplitter.hidden = false; - - var url = sidebarBroadcaster.getAttribute("sidebarurl"); - var title = sidebarBroadcaster.getAttribute("sidebartitle"); - if (!title) - title = sidebarBroadcaster.getAttribute("label"); - sidebar.setAttribute("src", url); // kick off async load - sidebarBox.setAttribute("sidebarcommand", sidebarBroadcaster.id); - sidebarTitle.value = title; - - // We set this attribute here in addition to setting it on the <browser> - // element itself, because the code in gBrowserInit.onUnload persists this - // attribute, not the "src" of the <browser id="sidebar">. The reason it - // does that is that we want to delay sidebar load a bit when a browser - // window opens. See delayedStartup(). - sidebarBox.setAttribute("src", url); - - if (sidebar.contentDocument.location.href != url) - sidebar.addEventListener("load", sidebarOnLoad, true); - else // older code handled this case, so we do it too - fireSidebarFocusedEvent(); -} - -function sidebarOnLoad(event) { - var sidebar = document.getElementById("sidebar"); - sidebar.removeEventListener("load", sidebarOnLoad, true); - // We're handling the 'load' event before it bubbles up to the usual - // (non-capturing) event handlers. Let it bubble up before firing the - // SidebarFocused event. - setTimeout(fireSidebarFocusedEvent, 0); -} - -/** - * Fire a "SidebarFocused" event on the sidebar's |window| to give the sidebar - * a chance to adjust focus as needed. An additional event is needed, because - * we don't want to focus the sidebar when it's opened on startup or in a new - * window, only when the user opens the sidebar. - */ -function fireSidebarFocusedEvent() { - var sidebar = document.getElementById("sidebar"); - var event = document.createEvent("Events"); - event.initEvent("SidebarFocused", true, false); - sidebar.contentWindow.dispatchEvent(event); -} - -var gHomeButton = { - prefDomain: "browser.startup.homepage", - observe: function (aSubject, aTopic, aPrefName) - { - if (aTopic != "nsPref:changed" || aPrefName != this.prefDomain) - return; - - this.updateTooltip(); - }, - - updateTooltip: function (homeButton) - { - if (!homeButton) - homeButton = document.getElementById("home-button"); - if (homeButton) { - var homePage = this.getHomePage(); - homePage = homePage.replace(/\|/g,', '); - if (homePage.toLowerCase() == "about:home") - homeButton.setAttribute("tooltiptext", homeButton.getAttribute("aboutHomeOverrideTooltip")); - else - homeButton.setAttribute("tooltiptext", homePage); - } - }, - - getHomePage: function () - { - var url; - try { - url = gPrefService.getComplexValue(this.prefDomain, - Components.interfaces.nsIPrefLocalizedString).data; - } catch (e) { - } - - // use this if we can't find the pref - if (!url) { - var configBundle = Services.strings - .createBundle("chrome://branding/locale/browserconfig.properties"); - url = configBundle.GetStringFromName(this.prefDomain); - } - - return url; - }, - - updatePersonalToolbarStyle: function (homeButton) - { - if (!homeButton) - homeButton = document.getElementById("home-button"); - if (homeButton) - homeButton.className = homeButton.parentNode.id == "PersonalToolbar" - || homeButton.parentNode.parentNode.id == "PersonalToolbar" ? - homeButton.className.replace("toolbarbutton-1", "bookmark-item") : - homeButton.className.replace("bookmark-item", "toolbarbutton-1"); - } -}; - -/** - * Gets the selected text in the active browser. Leading and trailing - * whitespace is removed, and consecutive whitespace is replaced by a single - * space. A maximum of 150 characters will be returned, regardless of the value - * of aCharLen. - * - * @param aCharLen - * The maximum number of characters to return. - */ -function getBrowserSelection(aCharLen) { - // selections of more than 150 characters aren't useful - const kMaxSelectionLen = 150; - const charLen = Math.min(aCharLen || kMaxSelectionLen, kMaxSelectionLen); - let commandDispatcher = document.commandDispatcher; - - var focusedWindow = commandDispatcher.focusedWindow; - var selection = focusedWindow.getSelection().toString(); - // try getting a selected text in text input. - if (!selection) { - let element = commandDispatcher.focusedElement; - var isOnTextInput = function isOnTextInput(elem) { - // we avoid to return a value if a selection is in password field. - // ref. bug 565717 - return elem instanceof HTMLTextAreaElement || - (elem instanceof HTMLInputElement && elem.mozIsTextField(true)); - }; - - if (isOnTextInput(element)) { - selection = element.QueryInterface(Ci.nsIDOMNSEditableElement) - .editor.selection.toString(); - } - } - - if (selection) { - if (selection.length > charLen) { - // only use the first charLen important chars. see bug 221361 - var pattern = new RegExp("^(?:\\s*.){0," + charLen + "}"); - pattern.test(selection); - selection = RegExp.lastMatch; - } - - selection = selection.trim().replace(/\s+/g, " "); - - if (selection.length > charLen) - selection = selection.substr(0, charLen); - } - return selection; -} - -var gWebPanelURI; -function openWebPanel(aTitle, aURI) -{ - // Ensure that the web panels sidebar is open. - toggleSidebar('viewWebPanelsSidebar', true); - - // Set the title of the panel. - document.getElementById("sidebar-title").value = aTitle; - - // Tell the Web Panels sidebar to load the bookmark. - var sidebar = document.getElementById("sidebar"); - if (sidebar.docShell && sidebar.contentDocument && sidebar.contentDocument.getElementById('web-panels-browser')) { - sidebar.contentWindow.loadWebPanel(aURI); - if (gWebPanelURI) { - gWebPanelURI = ""; - sidebar.removeEventListener("load", asyncOpenWebPanel, true); - } - } - else { - // The panel is still being constructed. Attach an onload handler. - if (!gWebPanelURI) - sidebar.addEventListener("load", asyncOpenWebPanel, true); - gWebPanelURI = aURI; - } -} - -function asyncOpenWebPanel(event) -{ - var sidebar = document.getElementById("sidebar"); - if (gWebPanelURI && sidebar.contentDocument && sidebar.contentDocument.getElementById('web-panels-browser')) - sidebar.contentWindow.loadWebPanel(gWebPanelURI); - gWebPanelURI = ""; - sidebar.removeEventListener("load", asyncOpenWebPanel, true); -} - -/* - * - [ Dependencies ] --------------------------------------------------------- - * utilityOverlay.js: - * - gatherTextUnder - */ - -/** - * Extracts linkNode and href for the current click target. - * - * @param event - * The click event. - * @return [href, linkNode]. - * - * @note linkNode will be null if the click wasn't on an anchor - * element (or XLink). - */ -function hrefAndLinkNodeForClickEvent(event) -{ - function isHTMLLink(aNode) - { - // Be consistent with what nsContextMenu.js does. - return ((aNode instanceof HTMLAnchorElement && aNode.href) || - (aNode instanceof HTMLAreaElement && aNode.href) || - aNode instanceof HTMLLinkElement); - } - - let node = event.target; - while (node && !isHTMLLink(node)) { - node = node.parentNode; - } - - if (node) - return [node.href, node]; - - // If there is no linkNode, try simple XLink. - let href, baseURI; - node = event.target; - while (node && !href) { - if (node.nodeType == Node.ELEMENT_NODE && - (node.localName == "a" || - node.namespaceURI == "http://www.w3.org/1998/Math/MathML")) { - href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href"); - if (href) { - baseURI = node.baseURI; - break; - } - } - node = node.parentNode; - } - - // In case of XLink, we don't return the node we got href from since - // callers expect <a>-like elements. - return [href ? makeURLAbsolute(baseURI, href) : null, null]; -} - -/** - * Called whenever the user clicks in the content area. - * - * @param event - * The click event. - * @param isPanelClick - * Whether the event comes from a web panel. - * @note default event is prevented if the click is handled. - */ -function contentAreaClick(event, isPanelClick) -{ - if (!event.isTrusted || event.defaultPrevented || event.button == 2) - return; - - let [href, linkNode] = hrefAndLinkNodeForClickEvent(event); - if (!href) { - // Not a link, handle middle mouse navigation. - if (event.button == 1 && - gPrefService.getBoolPref("middlemouse.contentLoadURL") && - !gPrefService.getBoolPref("general.autoScroll")) { - middleMousePaste(event); - event.preventDefault(); - } - return; - } - - // This code only applies if we have a linkNode (i.e. clicks on real anchor - // elements, as opposed to XLink). - if (linkNode && event.button == 0 && - !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) { - // A Web panel's links should target the main content area. Do this - // if no modifier keys are down and if there's no target or the target - // equals _main (the IE convention) or _content (the Mozilla convention). - let target = linkNode.target; - let mainTarget = !target || target == "_content" || target == "_main"; - if (isPanelClick && mainTarget) { - // javascript and data links should be executed in the current browser. - if (linkNode.getAttribute("onclick") || - href.startsWith("javascript:") || - href.startsWith("data:")) - return; - - try { - urlSecurityCheck(href, linkNode.ownerDocument.nodePrincipal); - } - catch(ex) { - // Prevent loading unsecure destinations. - event.preventDefault(); - return; - } - - loadURI(href, null, null, false); - event.preventDefault(); - return; - } - - if (linkNode.getAttribute("rel") == "sidebar") { - // This is the Opera convention for a special link that, when clicked, - // allows to add a sidebar panel. The link's title attribute contains - // the title that should be used for the sidebar panel. - PlacesUIUtils.showBookmarkDialog({ action: "add" - , type: "bookmark" - , uri: makeURI(href) - , title: linkNode.getAttribute("title") - , loadBookmarkInSidebar: true - , hiddenRows: [ "description" - , "location" - , "keyword" ] - }, window); - event.preventDefault(); - return; - } - } - - handleLinkClick(event, href, linkNode); - - // Mark the page as a user followed link. This is done so that history can - // distinguish automatic embed visits from user activated ones. For example - // pages loaded in frames are embed visits and lost with the session, while - // visits across frames should be preserved. - try { - if (!PrivateBrowsingUtils.isWindowPrivate(window)) - PlacesUIUtils.markPageAsFollowedLink(href); - } catch (ex) { /* Skip invalid URIs. */ } -} - -/** - * Handles clicks on links. - * - * @return true if the click event was handled, false otherwise. - */ -function handleLinkClick(event, href, linkNode) { - if (event.button == 2) // right click - return false; - - var where = whereToOpenLink(event); - if (where == "current") - return false; - - var doc = event.target.ownerDocument; - - if (where == "save") { - saveURL(href, linkNode ? gatherTextUnder(linkNode) : "", null, true, - true, doc.documentURIObject, doc); - event.preventDefault(); - return true; - } - - urlSecurityCheck(href, doc.nodePrincipal); - openLinkIn(href, where, { referrerURI: doc.documentURIObject, - charset: doc.characterSet, - referrerPolicy: doc.referrerPolicy, - originPrincipal: doc.nodePrincipal, - triggeringPrincipal: doc.nodePrincipal }); - event.preventDefault(); - return true; -} - -function middleMousePaste(event) { - let clipboard = readFromClipboard(); - if (!clipboard) - return; - - // Strip embedded newlines and surrounding whitespace, to match the URL - // bar's behavior (stripsurroundingwhitespace) - clipboard = clipboard.replace(/\s*\n\s*/g, ""); - - // if it's not the current tab, we don't need to do anything because the - // browser doesn't exist. - let where = whereToOpenLink(event, true, false); - let lastLocationChange; - if (where == "current") { - lastLocationChange = gBrowser.selectedBrowser.lastLocationChange; - } - - getShortcutOrURIAndPostData(clipboard).then(data => { - try { - makeURI(data.url); - } catch (ex) { - // Not a valid URI. - return; - } - - try { - addToUrlbarHistory(data.url); - } catch (ex) { - // Things may go wrong when adding url to session history, - // but don't let that interfere with the loading of the url. - Cu.reportError(ex); - } - - if (where != "current" || - lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) { - openUILink(data.url, event, - { ignoreButton: true, - disallowInheritPrincipal: !data.mayInheritPrincipal, - initiatingDoc: event ? event.target.ownerDocument : null }); - } - }); - - event.stopPropagation(); -} - -// handleDroppedLink has the following 2 overloads: -// handleDroppedLink(event, url, name) -// handleDroppedLink(event, links) -function handleDroppedLink(event, urlOrLinks, name) -{ - let links; - if (Array.isArray(urlOrLinks)) { - links = urlOrLinks; - } else { - links = [{ url: urlOrLinks, name, type: "" }]; - } - - let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange; - - let inBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground"); - if (event.shiftKey) - inBackground = !inBackground; - - Task.spawn(function*() { - let urls = []; - let postDatas = []; - for (let link of links) { - let data = yield getShortcutOrURIAndPostData(link.url); - urls.push(data.url); - postDatas.push(data.postData); - } - if (lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) { - gBrowser.loadTabs(urls, { - inBackground, - replace: true, - allowThirdPartyFixup: false, - postDatas, - }); - } - }); - - // Keep the event from being handled by the dragDrop listeners - // built-in to goanna if they happen to be above us. - event.preventDefault(); -}; - -function MultiplexHandler(event) -{ try { - var node = event.target; - var name = node.getAttribute('name'); - - if (name == 'detectorGroup') { - BrowserCharsetReload(); - SelectDetector(event, false); - } else if (name == 'charsetGroup') { - var charset = node.getAttribute('id'); - charset = charset.substring(charset.indexOf('charset.') + 'charset.'.length); - BrowserSetForcedCharacterSet(charset); - } else if (name == 'charsetCustomize') { - //do nothing - please remove this else statement, once the charset prefs moves to the pref window - } else { - BrowserSetForcedCharacterSet(node.getAttribute('id')); - } - } catch(ex) { alert(ex); } -} - -function SelectDetector(event, doReload) -{ - var uri = event.target.getAttribute("id"); - var prefvalue = uri.substring(uri.indexOf('chardet.') + 'chardet.'.length); - if ("off" == prefvalue) { // "off" is special value to turn off the detectors - prefvalue = ""; - } - - try { - var str = Cc["@mozilla.org/supports-string;1"]. - createInstance(Ci.nsISupportsString); - - str.data = prefvalue; - gPrefService.setComplexValue("intl.charset.detector", Ci.nsISupportsString, str); - if (doReload) - window.content.location.reload(); - } - catch (ex) { - dump("Failed to set the intl.charset.detector preference.\n"); - } -} - -function BrowserSetForcedCharacterSet(aCharset) -{ - gBrowser.docShell.charset = aCharset; - // Save the forced character-set - if (!PrivateBrowsingUtils.isWindowPrivate(window)) - PlacesUtils.setCharsetForURI(getWebNavigation().currentURI, aCharset); - BrowserCharsetReload(); -} - -function BrowserCharsetReload() -{ - BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE); -} - -function charsetMenuGetElement(parent, id) { - return parent.getElementsByAttribute("id", id)[0]; -} - -function UpdateCurrentCharset(target) { - // extract the charset from DOM - var wnd = document.commandDispatcher.focusedWindow; - if ((window == wnd) || (wnd == null)) wnd = window.content; - - // Uncheck previous item - if (gPrevCharset) { - var pref_item = charsetMenuGetElement(target, "charset." + gPrevCharset); - if (pref_item) - pref_item.setAttribute('checked', 'false'); - } - - var menuitem = charsetMenuGetElement(target, "charset." + wnd.document.characterSet); - if (menuitem) { - menuitem.setAttribute('checked', 'true'); - } -} - -function UpdateCharsetDetector(target) { - var prefvalue; - - try { - prefvalue = gPrefService.getComplexValue("intl.charset.detector", Ci.nsIPrefLocalizedString).data; - } - catch (ex) {} - - if (!prefvalue) - prefvalue = "off"; - - var menuitem = charsetMenuGetElement(target, "chardet." + prefvalue); - if (menuitem) - menuitem.setAttribute("checked", "true"); -} - -function UpdateMenus(event) { - UpdateCurrentCharset(event.target); - UpdateCharsetDetector(event.target); -} - -function charsetLoadListener() { - var charset = window.content.document.characterSet; - - if (charset.length > 0 && (charset != gLastBrowserCharset)) { - gPrevCharset = gLastBrowserCharset; - gLastBrowserCharset = charset; - } -} - -var gPageStyleMenu = { - - _getAllStyleSheets: function (frameset) { - var styleSheetsArray = Array.slice(frameset.document.styleSheets); - for (let i = 0; i < frameset.frames.length; i++) { - let frameSheets = this._getAllStyleSheets(frameset.frames[i]); - styleSheetsArray = styleSheetsArray.concat(frameSheets); - } - return styleSheetsArray; - }, - - fillPopup: function (menuPopup) { - var noStyle = menuPopup.firstChild; - var persistentOnly = noStyle.nextSibling; - var sep = persistentOnly.nextSibling; - while (sep.nextSibling) - menuPopup.removeChild(sep.nextSibling); - - var styleSheets = this._getAllStyleSheets(window.content); - var currentStyleSheets = {}; - var styleDisabled = getMarkupDocumentViewer().authorStyleDisabled; - var haveAltSheets = false; - var altStyleSelected = false; - - for (let currentStyleSheet of styleSheets) { - if (!currentStyleSheet.title) - continue; - - // Skip any stylesheets whose media attribute doesn't match. - if (currentStyleSheet.media.length > 0) { - let mediaQueryList = currentStyleSheet.media.mediaText; - if (!window.content.matchMedia(mediaQueryList).matches) - continue; - } - - if (!currentStyleSheet.disabled) - altStyleSelected = true; - - haveAltSheets = true; - - let lastWithSameTitle = null; - if (currentStyleSheet.title in currentStyleSheets) - lastWithSameTitle = currentStyleSheets[currentStyleSheet.title]; - - if (!lastWithSameTitle) { - let menuItem = document.createElement("menuitem"); - menuItem.setAttribute("type", "radio"); - menuItem.setAttribute("label", currentStyleSheet.title); - menuItem.setAttribute("data", currentStyleSheet.title); - menuItem.setAttribute("checked", !currentStyleSheet.disabled && !styleDisabled); - menuItem.setAttribute("oncommand", "gPageStyleMenu.switchStyleSheet(this.getAttribute('data'));"); - menuPopup.appendChild(menuItem); - currentStyleSheets[currentStyleSheet.title] = menuItem; - } else if (currentStyleSheet.disabled) { - lastWithSameTitle.removeAttribute("checked"); - } - } - - noStyle.setAttribute("checked", styleDisabled); - persistentOnly.setAttribute("checked", !altStyleSelected && !styleDisabled); - persistentOnly.hidden = (window.content.document.preferredStyleSheetSet) ? haveAltSheets : false; - sep.hidden = (noStyle.hidden && persistentOnly.hidden) || !haveAltSheets; - }, - - _stylesheetInFrame: function (frame, title) { - return Array.some(frame.document.styleSheets, - function (stylesheet) stylesheet.title == title); - }, - - _stylesheetSwitchFrame: function (frame, title) { - var docStyleSheets = frame.document.styleSheets; - - for (let i = 0; i < docStyleSheets.length; ++i) { - let docStyleSheet = docStyleSheets[i]; - - if (docStyleSheet.title) - docStyleSheet.disabled = (docStyleSheet.title != title); - else if (docStyleSheet.disabled) - docStyleSheet.disabled = false; - } - }, - - _stylesheetSwitchAll: function (frameset, title) { - if (!title || this._stylesheetInFrame(frameset, title)) - this._stylesheetSwitchFrame(frameset, title); - - for (let i = 0; i < frameset.frames.length; i++) - this._stylesheetSwitchAll(frameset.frames[i], title); - }, - - switchStyleSheet: function (title, contentWindow) { - getMarkupDocumentViewer().authorStyleDisabled = false; - this._stylesheetSwitchAll(contentWindow || content, title); - }, - - disableStyle: function () { - getMarkupDocumentViewer().authorStyleDisabled = true; - }, -}; - -/* Legacy global page-style functions */ -var getAllStyleSheets = gPageStyleMenu._getAllStyleSheets.bind(gPageStyleMenu); -var stylesheetFillPopup = gPageStyleMenu.fillPopup.bind(gPageStyleMenu); -function stylesheetSwitchAll(contentWindow, title) { - gPageStyleMenu.switchStyleSheet(title, contentWindow); -} -function setStyleDisabled(disabled) { - if (disabled) - gPageStyleMenu.disableStyle(); -} - - -var BrowserOffline = { - _inited: false, - - ///////////////////////////////////////////////////////////////////////////// - // BrowserOffline Public Methods - init: function () - { - if (!this._uiElement) - this._uiElement = document.getElementById("workOfflineMenuitemState"); - - Services.obs.addObserver(this, "network:offline-status-changed", false); - - this._updateOfflineUI(Services.io.offline); - - this._inited = true; - }, - - uninit: function () - { - if (this._inited) { - Services.obs.removeObserver(this, "network:offline-status-changed"); - } - }, - - toggleOfflineStatus: function () - { - var ioService = Services.io; - - // Stop automatic management of the offline status - try { - ioService.manageOfflineStatus = false; - } catch (ex) { - } - - if (!ioService.offline && !this._canGoOffline()) { - this._updateOfflineUI(false); - return; - } - - ioService.offline = !ioService.offline; - }, - - ///////////////////////////////////////////////////////////////////////////// - // nsIObserver - observe: function (aSubject, aTopic, aState) - { - if (aTopic != "network:offline-status-changed") - return; - - this._updateOfflineUI(aState == "offline"); - }, - - ///////////////////////////////////////////////////////////////////////////// - // BrowserOffline Implementation Methods - _canGoOffline: function () - { - try { - var cancelGoOffline = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); - Services.obs.notifyObservers(cancelGoOffline, "offline-requested", null); - - // Something aborted the quit process. - if (cancelGoOffline.data) - return false; - } - catch (ex) { - } - - return true; - }, - - _uiElement: null, - _updateOfflineUI: function (aOffline) - { - var offlineLocked = gPrefService.prefIsLocked("network.online"); - if (offlineLocked) - this._uiElement.setAttribute("disabled", "true"); - - this._uiElement.setAttribute("checked", aOffline); - } -}; - -var OfflineApps = { - ///////////////////////////////////////////////////////////////////////////// - // OfflineApps Public Methods - init: function () - { - Services.obs.addObserver(this, "offline-cache-update-completed", false); - }, - - uninit: function () - { - Services.obs.removeObserver(this, "offline-cache-update-completed"); - }, - - handleEvent: function(event) { - if (event.type == "MozApplicationManifest") { - this.offlineAppRequested(event.originalTarget.defaultView); - } - }, - - ///////////////////////////////////////////////////////////////////////////// - // OfflineApps Implementation Methods - - // XXX: _getBrowserWindowForContentWindow and _getBrowserForContentWindow - // were taken from browser/components/feeds/src/WebContentConverter. - _getBrowserWindowForContentWindow: function(aContentWindow) { - return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem) - .rootTreeItem - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow) - .wrappedJSObject; - }, - - _getBrowserForContentWindow: function(aBrowserWindow, aContentWindow) { - // This depends on pseudo APIs of browser.js and tabbrowser.xml - aContentWindow = aContentWindow.top; - var browsers = aBrowserWindow.gBrowser.browsers; - for (let browser of browsers) { - if (browser.contentWindow == aContentWindow) - return browser; - } - // handle other browser/iframe elements that may need popupnotifications - let browser = aContentWindow - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .chromeEventHandler; - if (browser.getAttribute("popupnotificationanchor")) - return browser; - return null; - }, - - _getManifestURI: function(aWindow) { - if (!aWindow.document.documentElement) - return null; - - var attr = aWindow.document.documentElement.getAttribute("manifest"); - if (!attr) - return null; - - try { - var contentURI = makeURI(aWindow.location.href, null, null); - return makeURI(attr, aWindow.document.characterSet, contentURI); - } catch (e) { - return null; - } - }, - - // A cache update isn't tied to a specific window. Try to find - // the best browser in which to warn the user about space usage - _getBrowserForCacheUpdate: function(aCacheUpdate) { - // Prefer the current browser - var uri = this._getManifestURI(content); - if (uri && uri.equals(aCacheUpdate.manifestURI)) { - return gBrowser.selectedBrowser; - } - - var browsers = gBrowser.browsers; - for (let browser of browsers) { - uri = this._getManifestURI(browser.contentWindow); - if (uri && uri.equals(aCacheUpdate.manifestURI)) { - return browser; - } - } - - // is this from a non-tab browser/iframe? - browsers = document.querySelectorAll("iframe[popupnotificationanchor] | browser[popupnotificationanchor]"); - for (let browser of browsers) { - uri = this._getManifestURI(browser.contentWindow); - if (uri && uri.equals(aCacheUpdate.manifestURI)) { - return browser; - } - } - - return null; - }, - - _warnUsage: function(aBrowser, aURI) { - if (!aBrowser) - return; - - let mainAction = { - label: gNavigatorBundle.getString("offlineApps.manageUsage"), - accessKey: gNavigatorBundle.getString("offlineApps.manageUsageAccessKey"), - callback: OfflineApps.manage - }; - - let warnQuota = gPrefService.getIntPref("offline-apps.quota.warn"); - let message = gNavigatorBundle.getFormattedString("offlineApps.usage", - [ aURI.host, - warnQuota / 1024 ]); - - let anchorID = "indexedDB-notification-icon"; - PopupNotifications.show(aBrowser, "offline-app-usage", message, - anchorID, mainAction); - - // Now that we've warned once, prevent the warning from showing up - // again. - Services.perms.add(aURI, "offline-app", - Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN); - }, - - // XXX: duplicated in preferences/advanced.js - _getOfflineAppUsage: function (host, groups) - { - var cacheService = Cc["@mozilla.org/network/application-cache-service;1"]. - getService(Ci.nsIApplicationCacheService); - if (!groups) - groups = cacheService.getGroups(); - - var usage = 0; - for (let group of groups) { - var uri = Services.io.newURI(group, null, null); - if (uri.asciiHost == host) { - var cache = cacheService.getActiveCache(group); - usage += cache.usage; - } - } - - return usage; - }, - - _checkUsage: function(aURI) { - // if the user has already allowed excessive usage, don't bother checking - if (Services.perms.testExactPermission(aURI, "offline-app") != - Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN) { - var usage = this._getOfflineAppUsage(aURI.asciiHost); - var warnQuota = gPrefService.getIntPref("offline-apps.quota.warn"); - if (usage >= warnQuota * 1024) { - return true; - } - } - - return false; - }, - - offlineAppRequested: function(aContentWindow) { - if (!gPrefService.getBoolPref("browser.offline-apps.notify")) { - return; - } - - let browserWindow = this._getBrowserWindowForContentWindow(aContentWindow); - let browser = this._getBrowserForContentWindow(browserWindow, - aContentWindow); - - let currentURI = aContentWindow.document.documentURIObject; - - // don't bother showing UI if the user has already made a decision - if (Services.perms.testExactPermission(currentURI, "offline-app") != Services.perms.UNKNOWN_ACTION) - return; - - try { - if (gPrefService.getBoolPref("offline-apps.allow_by_default")) { - // all pages can use offline capabilities, no need to ask the user - return; - } - } catch(e) { - // this pref isn't set by default, ignore failures - } - - let host = currentURI.asciiHost; - let notificationID = "offline-app-requested-" + host; - let notification = PopupNotifications.getNotification(notificationID, browser); - - if (notification) { - notification.options.documents.push(aContentWindow.document); - } else { - let mainAction = { - label: gNavigatorBundle.getString("offlineApps.allow"), - accessKey: gNavigatorBundle.getString("offlineApps.allowAccessKey"), - callback: function() { - for (let document of notification.options.documents) { - OfflineApps.allowSite(document); - } - } - }; - let secondaryActions = [{ - label: gNavigatorBundle.getString("offlineApps.never"), - accessKey: gNavigatorBundle.getString("offlineApps.neverAccessKey"), - callback: function() { - for (let document of notification.options.documents) { - OfflineApps.disallowSite(document); - } - } - }]; - let message = gNavigatorBundle.getFormattedString("offlineApps.available", - [ host ]); - let anchorID = "indexedDB-notification-icon"; - let options= { - documents : [ aContentWindow.document ] - }; - notification = PopupNotifications.show(browser, notificationID, message, - anchorID, mainAction, - secondaryActions, options); - } - }, - - allowSite: function(aDocument) { - Services.perms.add(aDocument.documentURIObject, "offline-app", Services.perms.ALLOW_ACTION); - - // When a site is enabled while loading, manifest resources will - // start fetching immediately. This one time we need to do it - // ourselves. - this._startFetching(aDocument); - }, - - disallowSite: function(aDocument) { - Services.perms.add(aDocument.documentURIObject, "offline-app", Services.perms.DENY_ACTION); - }, - - manage: function() { - openAdvancedPreferences("networkTab"); - }, - - _startFetching: function(aDocument) { - if (!aDocument.documentElement) - return; - - var manifest = aDocument.documentElement.getAttribute("manifest"); - if (!manifest) - return; - - var manifestURI = makeURI(manifest, aDocument.characterSet, - aDocument.documentURIObject); - - var updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"]. - getService(Ci.nsIOfflineCacheUpdateService); - updateService.scheduleUpdate(manifestURI, aDocument.documentURIObject, window); - }, - - ///////////////////////////////////////////////////////////////////////////// - // nsIObserver - observe: function (aSubject, aTopic, aState) - { - if (aTopic == "offline-cache-update-completed") { - var cacheUpdate = aSubject.QueryInterface(Ci.nsIOfflineCacheUpdate); - - var uri = cacheUpdate.manifestURI; - if (OfflineApps._checkUsage(uri)) { - var browser = this._getBrowserForCacheUpdate(cacheUpdate); - if (browser) { - OfflineApps._warnUsage(browser, cacheUpdate.manifestURI); - } - } - } - } -}; - -var IndexedDBPromptHelper = { - _permissionsPrompt: "indexedDB-permissions-prompt", - _permissionsResponse: "indexedDB-permissions-response", - - _quotaPrompt: "indexedDB-quota-prompt", - _quotaResponse: "indexedDB-quota-response", - _quotaCancel: "indexedDB-quota-cancel", - - _notificationIcon: "indexedDB-notification-icon", - - init: - function IndexedDBPromptHelper_init() { - Services.obs.addObserver(this, this._permissionsPrompt, false); - Services.obs.addObserver(this, this._quotaPrompt, false); - Services.obs.addObserver(this, this._quotaCancel, false); - }, - - uninit: - function IndexedDBPromptHelper_uninit() { - Services.obs.removeObserver(this, this._permissionsPrompt); - Services.obs.removeObserver(this, this._quotaPrompt); - Services.obs.removeObserver(this, this._quotaCancel); - }, - - observe: - function IndexedDBPromptHelper_observe(subject, topic, data) { - if (topic != this._permissionsPrompt && - topic != this._quotaPrompt && - topic != this._quotaCancel) { - throw new Error("Unexpected topic!"); - } - - var requestor = subject.QueryInterface(Ci.nsIInterfaceRequestor); - - var contentWindow = requestor.getInterface(Ci.nsIDOMWindow); - var contentDocument = contentWindow.document; - var browserWindow = - OfflineApps._getBrowserWindowForContentWindow(contentWindow); - - if (browserWindow != window) { - // Must belong to some other window. - return; - } - - var browser = - OfflineApps._getBrowserForContentWindow(browserWindow, contentWindow); - - var host = contentDocument.documentURIObject.asciiHost; - - var message; - var responseTopic; - if (topic == this._permissionsPrompt) { - message = gNavigatorBundle.getFormattedString("offlineApps.available", - [ host ]); - responseTopic = this._permissionsResponse; - } - else if (topic == this._quotaPrompt) { - message = gNavigatorBundle.getFormattedString("indexedDB.usage", - [ host, data ]); - responseTopic = this._quotaResponse; - } - else if (topic == this._quotaCancel) { - responseTopic = this._quotaResponse; - } - - const hiddenTimeoutDuration = 30000; // 30 seconds - const firstTimeoutDuration = 300000; // 5 minutes - - var timeoutId; - - var observer = requestor.getInterface(Ci.nsIObserver); - - var mainAction = { - label: gNavigatorBundle.getString("offlineApps.allow"), - accessKey: gNavigatorBundle.getString("offlineApps.allowAccessKey"), - callback: function() { - clearTimeout(timeoutId); - observer.observe(null, responseTopic, - Ci.nsIPermissionManager.ALLOW_ACTION); - } - }; - - var secondaryActions = [ - { - label: gNavigatorBundle.getString("offlineApps.never"), - accessKey: gNavigatorBundle.getString("offlineApps.neverAccessKey"), - callback: function() { - clearTimeout(timeoutId); - observer.observe(null, responseTopic, - Ci.nsIPermissionManager.DENY_ACTION); - } - } - ]; - - // This will be set to the result of PopupNotifications.show() below, or to - // the result of PopupNotifications.getNotification() if this is a - // quotaCancel notification. - var notification; - - function timeoutNotification() { - // Remove the notification. - if (notification) { - notification.remove(); - } - - // Clear all of our timeout stuff. We may be called directly, not just - // when the timeout actually elapses. - clearTimeout(timeoutId); - - // And tell the page that the popup timed out. - observer.observe(null, responseTopic, - Ci.nsIPermissionManager.UNKNOWN_ACTION); - } - - var options = { - eventCallback: function(state) { - // Don't do anything if the timeout has not been set yet. - if (!timeoutId) { - return; - } - - // If the popup is being dismissed start the short timeout. - if (state == "dismissed") { - clearTimeout(timeoutId); - timeoutId = setTimeout(timeoutNotification, hiddenTimeoutDuration); - return; - } - - // If the popup is being re-shown then clear the timeout allowing - // unlimited waiting. - if (state == "shown") { - clearTimeout(timeoutId); - } - } - }; - - if (topic == this._quotaCancel) { - notification = PopupNotifications.getNotification(this._quotaPrompt, - browser); - timeoutNotification(); - return; - } - - notification = PopupNotifications.show(browser, topic, message, - this._notificationIcon, mainAction, - secondaryActions, options); - - // Set the timeoutId after the popup has been created, and use the long - // timeout value. If the user doesn't notice the popup after this amount of - // time then it is most likely not visible and we want to alert the page. - timeoutId = setTimeout(timeoutNotification, firstTimeoutDuration); - } -}; - -function WindowIsClosing() -{ - let event = document.createEvent("Events"); - event.initEvent("WindowIsClosing", true, true); - if (!window.dispatchEvent(event)) - return false; - - if (!closeWindow(false, warnAboutClosingWindow)) - return false; - - for (let browser of gBrowser.browsers) { - let ds = browser.docShell; - if (ds.contentViewer && !ds.contentViewer.permitUnload()) - return false; - } - - return true; -} - -/** - * Checks if this is the last full *browser* window around. If it is, this will - * be communicated like quitting. Otherwise, we warn about closing multiple tabs. - * @returns true if closing can proceed, false if it got cancelled. - */ -function warnAboutClosingWindow() { - // Popups aren't considered full browser windows. - let isPBWindow = PrivateBrowsingUtils.isWindowPrivate(window); - if (!isPBWindow && !toolbar.visible) - return gBrowser.warnAboutClosingTabs(gBrowser.closingTabsEnum.ALL); - - // Figure out if there's at least one other browser window around. - let e = Services.wm.getEnumerator("navigator:browser"); - let otherPBWindowExists = false; - let nonPopupPresent = false; - while (e.hasMoreElements()) { - let win = e.getNext(); - if (win != window) { - if (isPBWindow && PrivateBrowsingUtils.isWindowPrivate(win)) - otherPBWindowExists = true; - if (win.toolbar.visible) - nonPopupPresent = true; - // If the current window is not in private browsing mode we don't need to - // look for other pb windows, we can leave the loop when finding the - // first non-popup window. If however the current window is in private - // browsing mode then we need at least one other pb and one non-popup - // window to break out early. - if ((!isPBWindow || otherPBWindowExists) && nonPopupPresent) - break; - } - } - - if (isPBWindow && !otherPBWindowExists) { - let exitingCanceled = Cc["@mozilla.org/supports-PRBool;1"]. - createInstance(Ci.nsISupportsPRBool); - exitingCanceled.data = false; - Services.obs.notifyObservers(exitingCanceled, - "last-pb-context-exiting", - null); - if (exitingCanceled.data) - return false; - } - - if (nonPopupPresent) { - return isPBWindow || gBrowser.warnAboutClosingTabs(gBrowser.closingTabsEnum.ALL); - } - - let os = Services.obs; - - let closingCanceled = Cc["@mozilla.org/supports-PRBool;1"]. - createInstance(Ci.nsISupportsPRBool); - os.notifyObservers(closingCanceled, - "browser-lastwindow-close-requested", null); - if (closingCanceled.data) - return false; - - os.notifyObservers(null, "browser-lastwindow-close-granted", null); - -#ifdef XP_MACOSX - // OS X doesn't quit the application when the last window is closed, but keeps - // the session alive. Hence don't prompt users to save tabs, but warn about - // closing multiple tabs. - return isPBWindow || gBrowser.warnAboutClosingTabs(gBrowser.closingTabsEnum.ALL); -#else - return true; -#endif -} - -var MailIntegration = { - sendLinkForWindow: function (aWindow) { - this.sendMessage(aWindow.location.href, - aWindow.document.title); - }, - - sendMessage: function (aBody, aSubject) { - // generate a mailto url based on the url and the url's title - var mailtoUrl = "mailto:"; - if (aBody) { - mailtoUrl += "?body=" + encodeURIComponent(aBody); - mailtoUrl += "&subject=" + encodeURIComponent(aSubject); - } - - var uri = makeURI(mailtoUrl); - - // now pass this uri to the operating system - this._launchExternalUrl(uri); - }, - - // a generic method which can be used to pass arbitrary urls to the operating - // system. - // aURL --> a nsIURI which represents the url to launch - _launchExternalUrl: function (aURL) { - var extProtocolSvc = - Cc["@mozilla.org/uriloader/external-protocol-service;1"] - .getService(Ci.nsIExternalProtocolService); - if (extProtocolSvc) - extProtocolSvc.loadUrl(aURL); - } -}; - -function BrowserOpenAddonsMgr(aView) { - if (aView) { - let emWindow; - let browserWindow; - - var receivePong = function receivePong(aSubject, aTopic, aData) { - let browserWin = aSubject.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem) - .rootTreeItem - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow); - if (!emWindow || browserWin == window /* favor the current window */) { - emWindow = aSubject; - browserWindow = browserWin; - } - } - Services.obs.addObserver(receivePong, "EM-pong", false); - Services.obs.notifyObservers(null, "EM-ping", ""); - Services.obs.removeObserver(receivePong, "EM-pong"); - - if (emWindow) { - emWindow.loadView(aView); - browserWindow.gBrowser.selectedTab = - browserWindow.gBrowser._getTabForContentWindow(emWindow); - emWindow.focus(); - return; - } - } - - var newLoad = !switchToTabHavingURI("about:addons", true); - - if (aView) { - // This must be a new load, else the ping/pong would have - // found the window above. - Services.obs.addObserver(function observer(aSubject, aTopic, aData) { - Services.obs.removeObserver(observer, aTopic); - aSubject.loadView(aView); - }, "EM-loaded", false); - } -} - -function BrowserOpenPermissionsMgr() { - switchToTabHavingURI("about:permissions", true); -} - -function AddKeywordForSearchField() { - var node = document.popupNode; - - var charset = node.ownerDocument.characterSet; - - var docURI = makeURI(node.ownerDocument.URL, - charset); - - var formURI = makeURI(node.form.getAttribute("action"), - charset, - docURI); - - var spec = formURI.spec; - - var isURLEncoded = - (node.form.method.toUpperCase() == "POST" - && (node.form.enctype == "application/x-www-form-urlencoded" || - node.form.enctype == "")); - - var title = gNavigatorBundle.getFormattedString("addKeywordTitleAutoFill", - [node.ownerDocument.title]); - var description = PlacesUIUtils.getDescriptionFromDocument(node.ownerDocument); - - var formData = []; - - function escapeNameValuePair(aName, aValue, aIsFormUrlEncoded) { - if (aIsFormUrlEncoded) - return escape(aName + "=" + aValue); - else - return escape(aName) + "=" + escape(aValue); - } - - for (let el of node.form.elements) { - if (!el.type) // happens with fieldsets - continue; - - if (el == node) { - formData.push((isURLEncoded) ? escapeNameValuePair(el.name, "%s", true) : - // Don't escape "%s", just append - escapeNameValuePair(el.name, "", false) + "%s"); - continue; - } - - let type = el.type.toLowerCase(); - - if (((el instanceof HTMLInputElement && el.mozIsTextField(true)) || - type == "hidden" || type == "textarea") || - ((type == "checkbox" || type == "radio") && el.checked)) { - formData.push(escapeNameValuePair(el.name, el.value, isURLEncoded)); - } else if (el instanceof HTMLSelectElement && el.selectedIndex >= 0) { - for (var j=0; j < el.options.length; j++) { - if (el.options[j].selected) - formData.push(escapeNameValuePair(el.name, el.options[j].value, - isURLEncoded)); - } - } - } - - var postData; - - if (isURLEncoded) - postData = formData.join("&"); - else - spec += "?" + formData.join("&"); - - PlacesUIUtils.showBookmarkDialog({ action: "add" - , type: "bookmark" - , uri: makeURI(spec) - , title: title - , description: description - , keyword: "" - , postData: postData - , charSet: charset - , hiddenRows: [ "location" - , "description" - , "tags" - , "loadInSidebar" ] - }, window); -} - -function SwitchDocumentDirection(aWindow) { - // document.dir can also be "auto", in which case it won't change - if (aWindow.document.dir == "ltr" || aWindow.document.dir == "") { - aWindow.document.dir = "rtl"; - } else if (aWindow.document.dir == "rtl") { - aWindow.document.dir = "ltr"; - } - for (var run = 0; run < aWindow.frames.length; run++) - SwitchDocumentDirection(aWindow.frames[run]); -} - -function convertFromUnicode(charset, str) -{ - try { - var unicodeConverter = Components - .classes["@mozilla.org/intl/scriptableunicodeconverter"] - .createInstance(Components.interfaces.nsIScriptableUnicodeConverter); - unicodeConverter.charset = charset; - str = unicodeConverter.ConvertFromUnicode(str); - return str + unicodeConverter.Finish(); - } catch(ex) { - return null; - } -} - -/** - * Re-open a closed tab. - * @param aIndex - * The index of the tab (via nsSessionStore.getClosedTabData) - * @returns a reference to the reopened tab. - */ -function undoCloseTab(aIndex) { - // wallpaper patch to prevent an unnecessary blank tab (bug 343895) - var blankTabToRemove = null; - if (gBrowser.tabs.length == 1 && - !gPrefService.getBoolPref("browser.tabs.autoHide") && - isTabEmpty(gBrowser.selectedTab)) - blankTabToRemove = gBrowser.selectedTab; - - var tab = null; - var ss = Cc["@mozilla.org/browser/sessionstore;1"]. - getService(Ci.nsISessionStore); - if (ss.getClosedTabCount(window) > (aIndex || 0)) { - tab = ss.undoCloseTab(window, aIndex || 0); - - if (blankTabToRemove) - gBrowser.removeTab(blankTabToRemove); - } - - return tab; -} - -/** - * Re-open a closed window. - * @param aIndex - * The index of the window (via nsSessionStore.getClosedWindowData) - * @returns a reference to the reopened window. - */ -function undoCloseWindow(aIndex) { - let ss = Cc["@mozilla.org/browser/sessionstore;1"]. - getService(Ci.nsISessionStore); - let window = null; - if (ss.getClosedWindowCount() > (aIndex || 0)) - window = ss.undoCloseWindow(aIndex || 0); - - return window; -} - -/* - * Determines if a tab is "empty", usually used in the context of determining - * if it's ok to close the tab. - */ -function isTabEmpty(aTab) { - if (aTab.hasAttribute("busy")) - return false; - - let browser = aTab.linkedBrowser; - if (!isBlankPageURL(browser.currentURI.spec)) - return false; - - // Bug 863515 - Make content.opener checks work in electrolysis. - if (!gMultiProcessBrowser && browser.contentWindow.opener) - return false; - - if (browser.sessionHistory && browser.sessionHistory.count >= 2) - return false; - - return true; -} - -#ifdef MOZ_SERVICES_SYNC -function BrowserOpenSyncTabs() { - switchToTabHavingURI("about:sync-tabs", true); -} -#endif - -/** - * Format a URL - * eg: - * echo formatURL("https://addons.mozilla.org/%LOCALE%/%APP%/%VERSION%/"); - * > https://addons.mozilla.org/en-US/firefox/3.0a1/ - * - * Currently supported built-ins are LOCALE, APP, and any value from nsIXULAppInfo, uppercased. - */ -function formatURL(aFormat, aIsPref) { - var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter); - return aIsPref ? formatter.formatURLPref(aFormat) : formatter.formatURL(aFormat); -} - -/** - * Utility object to handle manipulations of the identity indicators in the UI - */ -var gIdentityHandler = { - // Mode strings used to control CSS display - IDENTITY_MODE_IDENTIFIED : "verifiedIdentity", // High-quality identity information - IDENTITY_MODE_DOMAIN_VERIFIED : "verifiedDomain", // Minimal SSL CA-signed domain verification - IDENTITY_MODE_UNKNOWN : "unknownIdentity", // No trusted identity information - IDENTITY_MODE_MIXED_CONTENT : "unknownIdentity mixedContent", // SSL with unauthenticated content - IDENTITY_MODE_MIXED_ACTIVE_CONTENT : "unknownIdentity mixedContent mixedActiveContent", // SSL with unauthenticated content - IDENTITY_MODE_CHROMEUI : "chromeUI", // Part of the product's UI - - // Cache the most recent SSLStatus and Location seen in checkIdentity - _lastStatus : null, - _lastLocation : null, - _mode : "unknownIdentity", - - // smart getters - get _encryptionLabel () { - delete this._encryptionLabel; - this._encryptionLabel = {}; - this._encryptionLabel[this.IDENTITY_MODE_DOMAIN_VERIFIED] = - gNavigatorBundle.getString("identity.encrypted"); - this._encryptionLabel[this.IDENTITY_MODE_IDENTIFIED] = - gNavigatorBundle.getString("identity.encrypted"); - this._encryptionLabel[this.IDENTITY_MODE_UNKNOWN] = - gNavigatorBundle.getString("identity.unencrypted"); - this._encryptionLabel[this.IDENTITY_MODE_MIXED_CONTENT] = - gNavigatorBundle.getString("identity.mixed_content"); - this._encryptionLabel[this.IDENTITY_MODE_MIXED_ACTIVE_CONTENT] = - gNavigatorBundle.getString("identity.mixed_content"); - return this._encryptionLabel; - }, - get _identityPopup () { - delete this._identityPopup; - return this._identityPopup = document.getElementById("identity-popup"); - }, - get _identityBox () { - delete this._identityBox; - return this._identityBox = document.getElementById("identity-box"); - }, - get _identityPopupContentBox () { - delete this._identityPopupContentBox; - return this._identityPopupContentBox = - document.getElementById("identity-popup-content-box"); - }, - get _identityPopupContentHost () { - delete this._identityPopupContentHost; - return this._identityPopupContentHost = - document.getElementById("identity-popup-content-host"); - }, - get _identityPopupContentOwner () { - delete this._identityPopupContentOwner; - return this._identityPopupContentOwner = - document.getElementById("identity-popup-content-owner"); - }, - get _identityPopupContentSupp () { - delete this._identityPopupContentSupp; - return this._identityPopupContentSupp = - document.getElementById("identity-popup-content-supplemental"); - }, - get _identityPopupContentVerif () { - delete this._identityPopupContentVerif; - return this._identityPopupContentVerif = - document.getElementById("identity-popup-content-verifier"); - }, - get _identityPopupEncLabel () { - delete this._identityPopupEncLabel; - return this._identityPopupEncLabel = - document.getElementById("identity-popup-encryption-label"); - }, - get _identityIconLabel () { - delete this._identityIconLabel; - return this._identityIconLabel = document.getElementById("identity-icon-label"); - }, - get _overrideService () { - delete this._overrideService; - return this._overrideService = Cc["@mozilla.org/security/certoverride;1"] - .getService(Ci.nsICertOverrideService); - }, - get _identityIconCountryLabel () { - delete this._identityIconCountryLabel; - return this._identityIconCountryLabel = document.getElementById("identity-icon-country-label"); - }, - get _identityIcon () { - delete this._identityIcon; - return this._identityIcon = document.getElementById("page-proxy-favicon"); - }, - - /** - * Rebuild cache of the elements that may or may not exist depending - * on whether there's a location bar. - */ - _cacheElements : function() { - delete this._identityBox; - delete this._identityIconLabel; - delete this._identityIconCountryLabel; - delete this._identityIcon; - this._identityBox = document.getElementById("identity-box"); - this._identityIconLabel = document.getElementById("identity-icon-label"); - this._identityIconCountryLabel = document.getElementById("identity-icon-country-label"); - this._identityIcon = document.getElementById("page-proxy-favicon"); - }, - - /** - * Handler for mouseclicks on the "More Information" button in the - * "identity-popup" panel. - */ - handleMoreInfoClick : function(event) { - displaySecurityInfo(); - event.stopPropagation(); - }, - - /** - * Helper to parse out the important parts of _lastStatus (of the SSL cert in - * particular) for use in constructing identity UI strings - */ - getIdentityData : function() { - var result = {}; - var status = this._lastStatus.QueryInterface(Components.interfaces.nsISSLStatus); - var cert = status.serverCert; - - // Human readable name of Subject - result.subjectOrg = cert.organization; - - // SubjectName fields, broken up for individual access - if (cert.subjectName) { - result.subjectNameFields = {}; - cert.subjectName.split(",").forEach(function(v) { - var field = v.split("="); - this[field[0]] = field[1]; - }, result.subjectNameFields); - - // Call out city, state, and country specifically - result.city = result.subjectNameFields.L; - result.state = result.subjectNameFields.ST; - result.country = result.subjectNameFields.C; - } - - // Human readable name of Certificate Authority - result.caOrg = cert.issuerOrganization || cert.issuerCommonName; - result.cert = cert; - - return result; - }, - - /** - * Determine the identity of the page being displayed by examining its SSL cert - * (if available) and, if necessary, update the UI to reflect this. Intended to - * be called by onSecurityChange - * - * @param PRUint32 state - * @param JS Object location that mirrors an nsLocation (i.e. has .host and - * .hostname and .port) - */ - checkIdentity : function(state, location) { - var currentStatus = gBrowser.securityUI - .QueryInterface(Components.interfaces.nsISSLStatusProvider) - .SSLStatus; - this._lastStatus = currentStatus; - this._lastLocation = location; - - let nsIWebProgressListener = Ci.nsIWebProgressListener; - if (location.protocol == "chrome:" || location.protocol == "about:") { - this.setMode(this.IDENTITY_MODE_CHROMEUI); - } else if (state & nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL) { - this.setMode(this.IDENTITY_MODE_IDENTIFIED); - } else if (state & nsIWebProgressListener.STATE_IS_SECURE) { - this.setMode(this.IDENTITY_MODE_DOMAIN_VERIFIED); - } else if (state & nsIWebProgressListener.STATE_IS_BROKEN) { - if ((state & nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT) && - gPrefService.getBoolPref("security.mixed_content.block_active_content")) { - this.setMode(this.IDENTITY_MODE_MIXED_ACTIVE_CONTENT); - } else { - this.setMode(this.IDENTITY_MODE_MIXED_CONTENT); - } - } else { - this.setMode(this.IDENTITY_MODE_UNKNOWN); - } - - // Ensure the doorhanger is shown when mixed active content is blocked. - if (state & nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT) - this.showMixedContentDoorhanger(); - }, - - /** - * Display the Mixed Content Blocker doohanger, providing an option - * to the user to override mixed content blocking - */ - showMixedContentDoorhanger : function() { - // If we've already got an active notification, bail out to avoid showing it repeatedly. - if (PopupNotifications.getNotification("mixed-content-blocked", gBrowser.selectedBrowser)) - return; - - let brandBundle = document.getElementById("bundle_brand"); - let brandShortName = brandBundle.getString("brandShortName"); - let messageString = gNavigatorBundle.getFormattedString("mixedContentBlocked.message", [brandShortName]); - let action = { - label: gNavigatorBundle.getString("mixedContentBlocked.keepBlockingButton.label"), - accessKey: gNavigatorBundle.getString("mixedContentBlocked.keepBlockingButton.accesskey"), - callback: function() { /* NOP */ } - }; - let secondaryActions = [ - { - label: gNavigatorBundle.getString("mixedContentBlocked.unblock.label"), - accessKey: gNavigatorBundle.getString("mixedContentBlocked.unblock.accesskey"), - callback: function() { - // Reload the page with the content unblocked - BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT); - } - } - ]; - let options = { - dismissed: true, - learnMoreURL: Services.urlFormatter.formatURLPref("browser.mixedcontent.warning.infoURL"), - }; - PopupNotifications.show(gBrowser.selectedBrowser, "mixed-content-blocked", - messageString, "mixed-content-blocked-notification-icon", - action, secondaryActions, options); - }, - - /** - * Return the eTLD+1 version of the current hostname - */ - getEffectiveHost : function() { - try { - let baseDomain = - Services.eTLD.getBaseDomainFromHost(this._lastLocation.hostname); - return this._IDNService.convertToDisplayIDN(baseDomain, {}); - } catch (e) { - // If something goes wrong (e.g. hostname is an IP address) just fail back - // to the full domain. - return this._lastLocation.hostname; - } - }, - - /** - * Update the UI to reflect the specified mode, which should be one of the - * IDENTITY_MODE_* constants. - */ - setMode : function(newMode) { - if (!this._identityBox) { - // No identity box means the identity box is not visible, in which - // case there's nothing to do. - return; - } - - this._identityBox.className = newMode; - this.setIdentityMessages(newMode); - - // Update the popup too, if it's open - if (this._identityPopup.state == "open") - this.setPopupMessages(newMode); - - this._mode = newMode; - }, - - /** - * Set up the messages for the primary identity UI based on the specified mode, - * and the details of the SSL cert, where applicable - * - * @param newMode The newly set identity mode. Should be one of the IDENTITY_MODE_* constants. - */ - setIdentityMessages : function(newMode) { - let icon_label = ""; - let tooltip = ""; - let icon_country_label = ""; - let icon_labels_dir = "ltr"; - - if (!this._IDNService) - this._IDNService = Cc["@mozilla.org/network/idn-service;1"] - .getService(Ci.nsIIDNService); - let punyID = gPrefService.getIntPref("browser.identity.display_punycode", 1); - - switch (newMode) { - case this.IDENTITY_MODE_DOMAIN_VERIFIED: { - let iData = this.getIdentityData(); - - let label_display = ""; - - //Pale Moon: honor browser.identity.ssl_domain_display! - switch (gPrefService.getIntPref("browser.identity.ssl_domain_display")) { - case 2 : // Show full domain - label_display = this._lastLocation.hostname; - break; - case 1 : // Show eTLD. - label_display = this.getEffectiveHost(); - } - - if (punyID >= 1) { - // Display punycode version in identity panel - icon_label = this._IDNService.convertUTF8toACE(label_display); - } else { - icon_label = label_display; - } - - // Verifier is either the CA Org, for a normal cert, or a special string - // for certs that are trusted because of a security exception. - tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier", - [iData.caOrg]); - - // Check whether this site is a security exception. XPConnect does the right - // thing here in terms of converting _lastLocation.port from string to int, but - // the overrideService doesn't like undefined ports, so make sure we have - // something in the default case (bug 432241). - // .hostname can return an empty string in some exceptional cases - - // hasMatchingOverride does not handle that, so avoid calling it. - // Updating the tooltip value in those cases isn't critical. - // FIXME: Fixing bug 646690 would probably makes this check unnecessary - if (this._lastLocation.hostname && - this._overrideService.hasMatchingOverride(this._lastLocation.hostname, - (this._lastLocation.port || 443), - iData.cert, {}, {})) - tooltip = gNavigatorBundle.getString("identity.identified.verified_by_you"); - break; } - case this.IDENTITY_MODE_IDENTIFIED: { - // If it's identified, then we can populate the dialog with credentials - let iData = this.getIdentityData(); - tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier", - [iData.caOrg]); - icon_label = iData.subjectOrg; - if (iData.country) - icon_country_label = "(" + iData.country + ")"; - - // If the organization name starts with an RTL character, then - // swap the positions of the organization and country code labels. - // The Unicode ranges reflect the definition of the UCS2_CHAR_IS_BIDI - // macro in intl/unicharutil/util/nsBidiUtils.h. When bug 218823 gets - // fixed, this test should be replaced by one adhering to the - // Unicode Bidirectional Algorithm proper (at the paragraph level). - icon_labels_dir = /^[\u0590-\u08ff\ufb1d-\ufdff\ufe70-\ufefc]/.test(icon_label) ? - "rtl" : "ltr"; - break; } - case this.IDENTITY_MODE_CHROMEUI: - break; - default: - tooltip = gNavigatorBundle.getString("identity.unknown.tooltip"); - if (punyID == 2) { - // Check for IDN and display if so... - let rawHost = this._IDNService.convertUTF8toACE(this._lastLocation.hostname); - if (this._IDNService.isACE(rawHost)) { - icon_label = rawHost; - } - } - } - - // Push the appropriate strings out to the UI - this._identityBox.tooltipText = tooltip; - this._identityIconLabel.value = icon_label; - this._identityIconCountryLabel.value = icon_country_label; - // Set cropping and direction - this._identityIconLabel.crop = icon_country_label ? "end" : "center"; - this._identityIconLabel.parentNode.style.direction = icon_labels_dir; - // Hide completely if the organization label is empty - this._identityIconLabel.parentNode.collapsed = icon_label ? false : true; - }, - - /** - * Set up the title and content messages for the identity message popup, - * based on the specified mode, and the details of the SSL cert, where - * applicable - * - * @param newMode The newly set identity mode. Should be one of the IDENTITY_MODE_* constants. - */ - setPopupMessages : function(newMode) { - - this._identityPopup.className = newMode; - this._identityPopupContentBox.className = newMode; - - // Set the static strings up front - this._identityPopupEncLabel.textContent = this._encryptionLabel[newMode]; - - // Initialize the optional strings to empty values - let supplemental = ""; - let verifier = ""; - let host = ""; - let owner = ""; - - switch (newMode) { - case this.IDENTITY_MODE_DOMAIN_VERIFIED: - host = this.getEffectiveHost(); - owner = gNavigatorBundle.getString("identity.ownerUnknown2"); - verifier = this._identityBox.tooltipText; - break; - case this.IDENTITY_MODE_IDENTIFIED: { - // If it's identified, then we can populate the dialog with credentials - let iData = this.getIdentityData(); - host = this.getEffectiveHost(); - owner = iData.subjectOrg; - verifier = this._identityBox.tooltipText; - - // Build an appropriate supplemental block out of whatever location data we have - if (iData.city) - supplemental += iData.city + "\n"; - if (iData.state && iData.country) - supplemental += gNavigatorBundle.getFormattedString("identity.identified.state_and_country", - [iData.state, iData.country]); - else if (iData.state) // State only - supplemental += iData.state; - else if (iData.country) // Country only - supplemental += iData.country; - break; } - } - - // Push the appropriate strings out to the UI - this._identityPopupContentHost.textContent = host; - this._identityPopupContentOwner.textContent = owner; - this._identityPopupContentSupp.textContent = supplemental; - this._identityPopupContentVerif.textContent = verifier; - }, - - hideIdentityPopup : function() { - this._identityPopup.hidePopup(); - }, - - /** - * Click handler for the identity-box element in primary chrome. - */ - handleIdentityButtonEvent : function(event) { - event.stopPropagation(); - - if ((event.type == "click" && event.button != 0) || - (event.type == "keypress" && event.charCode != KeyEvent.DOM_VK_SPACE && - event.keyCode != KeyEvent.DOM_VK_RETURN)) { - return; // Left click, space or enter only - } - - // Don't allow left click, space or enter if the location - // is chrome UI or the location has been modified. - if (this._mode == this.IDENTITY_MODE_CHROMEUI || - gURLBar.getAttribute("pageproxystate") != "valid") { - return; - } - - // Make sure that the display:none style we set in xul is removed now that - // the popup is actually needed - this._identityPopup.hidden = false; - - // Update the popup strings - this.setPopupMessages(this._identityBox.className); - - // Add the "open" attribute to the identity box for styling - this._identityBox.setAttribute("open", "true"); - var self = this; - this._identityPopup.addEventListener("popuphidden", function onPopupHidden(e) { - e.currentTarget.removeEventListener("popuphidden", onPopupHidden, false); - self._identityBox.removeAttribute("open"); - }, false); - - // Now open the popup, anchored off the primary chrome element - this._identityPopup.openPopup(this._identityIcon, "bottomcenter topleft"); - }, - - onPopupShown : function(event) { - document.getElementById('identity-popup-more-info-button').focus(); - }, - - onDragStart: function (event) { - if (gURLBar.getAttribute("pageproxystate") != "valid") - return; - - var value = content.location.href; - var urlString = value + "\n" + content.document.title; - var htmlString = "<a href=\"" + value + "\">" + value + "</a>"; - - var dt = event.dataTransfer; - dt.setData("text/x-moz-url", urlString); - dt.setData("text/uri-list", value); - dt.setData("text/plain", value); - dt.setData("text/html", htmlString); - dt.setDragImage(gProxyFavIcon, 16, 16); - } -}; - -function getNotificationBox(aWindow) { - var foundBrowser = gBrowser.getBrowserForDocument(aWindow.document); - if (foundBrowser) - return gBrowser.getNotificationBox(foundBrowser) - return null; -}; - -function getTabModalPromptBox(aWindow) { - var foundBrowser = gBrowser.getBrowserForDocument(aWindow.document); - if (foundBrowser) - return gBrowser.getTabModalPromptBox(foundBrowser); - return null; -}; - -/* DEPRECATED */ -function getBrowser() gBrowser; -function getNavToolbox() gNavToolbox; - -var gPrivateBrowsingUI = { - init: function PBUI_init() { - // Do nothing for normal windows - if (!PrivateBrowsingUtils.isWindowPrivate(window)) { - return; - } - - // Disable the Clear Recent History... menu item when in PB mode - // temporary fix until bug 463607 is fixed - document.getElementById("Tools:Sanitize").setAttribute("disabled", "true"); - - if (window.location.href == getBrowserURL()) { -#ifdef XP_MACOSX - if (!PrivateBrowsingUtils.permanentPrivateBrowsing) { - document.documentElement.setAttribute("drawintitlebar", true); - } -#endif - - // Adjust the window's title - let docElement = document.documentElement; - if (!PrivateBrowsingUtils.permanentPrivateBrowsing) { - docElement.setAttribute("title", - docElement.getAttribute("title_privatebrowsing")); - docElement.setAttribute("titlemodifier", - docElement.getAttribute("titlemodifier_privatebrowsing")); - } - docElement.setAttribute("privatebrowsingmode", - PrivateBrowsingUtils.permanentPrivateBrowsing ? "permanent" : "temporary"); - gBrowser.updateTitlebar(); - - if (PrivateBrowsingUtils.permanentPrivateBrowsing) { - // Adjust the New Window menu entries - [ - { normal: "menu_newNavigator", private: "menu_newPrivateWindow" }, - { normal: "appmenu_newNavigator", private: "appmenu_newPrivateWindow" }, - ].forEach(function(menu) { - let newWindow = document.getElementById(menu.normal); - let newPrivateWindow = document.getElementById(menu.private); - if (newWindow && newPrivateWindow) { - newPrivateWindow.hidden = true; - newWindow.label = newPrivateWindow.label; - newWindow.accessKey = newPrivateWindow.accessKey; - newWindow.command = newPrivateWindow.command; - } - }); - } - } - - if (gURLBar && - !PrivateBrowsingUtils.permanentPrivateBrowsing) { - // Disable switch to tab autocompletion for private windows - // (not for "Always use private browsing" mode) - gURLBar.setAttribute("autocompletesearchparam", ""); - } - } -}; - - -/** - * 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. - * If no suitable window is found, a new one will be opened. - * @return True if an existing tab was found, false otherwise - */ -function switchToTabHavingURI(aURI, aOpenNew) { - // This will switch to the tab in aWindow having aURI, if present. - function switchIfURIInWindow(aWindow) { - // Only switch to the tab if neither the source and desination window are - // private and they are not in permanent private borwsing mode - if ((PrivateBrowsingUtils.isWindowPrivate(window) || - PrivateBrowsingUtils.isWindowPrivate(aWindow)) && - !PrivateBrowsingUtils.permanentPrivateBrowsing) { - 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; - return true; - } - } - return false; - } - - // This can be passed either nsIURI or a string. - if (!(aURI instanceof Ci.nsIURI)) - aURI = Services.io.newURI(aURI, null, null); - - let isBrowserWindow = !!window.gBrowser; - - // Prioritise this window. - if (isBrowserWindow && 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) { - if (isBrowserWindow && isTabEmpty(gBrowser.selectedTab)) - gBrowser.selectedBrowser.loadURI(aURI.spec); - else - openUILinkIn(aURI.spec, "tab"); - } - - return false; -} - -function restoreLastSession() { - let ss = Cc["@mozilla.org/browser/sessionstore;1"]. - getService(Ci.nsISessionStore); - ss.restoreLastSession(); -} - -var TabContextMenu = { - contextTab: null, - _updateToggleMuteMenuItem(aTab, aConditionFn) { - ["muted", "soundplaying"].forEach(attr => { - if (!aConditionFn || aConditionFn(attr)) { - if (aTab.hasAttribute(attr)) { - aTab.toggleMuteMenuItem.setAttribute(attr, "true"); - } else { - aTab.toggleMuteMenuItem.removeAttribute(attr); - } - } - }); - }, - updateContextMenu: function updateContextMenu(aPopupMenu) { - this.contextTab = aPopupMenu.triggerNode.localName == "tab" ? - aPopupMenu.triggerNode : gBrowser.selectedTab; - let disabled = gBrowser.tabs.length == 1; - - // Enable the "Close Tab" menuitem when the window doesn't close with the last tab. - document.getElementById("context_closeTab").disabled = - disabled && gBrowser.tabContainer._closeWindowWithLastTab; - - var menuItems = aPopupMenu.getElementsByAttribute("tbattr", "tabbrowser-multiple"); - for (let menuItem of menuItems) - menuItem.disabled = disabled; - - disabled = gBrowser.visibleTabs.length == 1; - menuItems = aPopupMenu.getElementsByAttribute("tbattr", "tabbrowser-multiple-visible"); - for (let menuItem of menuItems) - menuItem.disabled = disabled; - - // Session store - document.getElementById("context_undoCloseTab").disabled = - Cc["@mozilla.org/browser/sessionstore;1"]. - getService(Ci.nsISessionStore). - getClosedTabCount(window) == 0; - - // Only one of pin/unpin should be visible - document.getElementById("context_pinTab").hidden = this.contextTab.pinned; - document.getElementById("context_unpinTab").hidden = !this.contextTab.pinned; - - // Disable "Close Tabs to the Right" if there are no tabs - // following it and hide it when the user rightclicked on a pinned - // tab. - document.getElementById("context_closeTabsToTheEnd").disabled = - gBrowser.getTabsToTheEndFrom(this.contextTab).length == 0; - document.getElementById("context_closeTabsToTheEnd").hidden = this.contextTab.pinned; - - // Disable "Close other Tabs" if there is only one unpinned tab and - // hide it when the user rightclicked on a pinned tab. - let unpinnedTabs = gBrowser.visibleTabs.length - gBrowser._numPinnedTabs; - document.getElementById("context_closeOtherTabs").disabled = unpinnedTabs <= 1; - document.getElementById("context_closeOtherTabs").hidden = this.contextTab.pinned; - - // Hide "Bookmark All Tabs" for a pinned tab. Update its state if visible. - let bookmarkAllTabs = document.getElementById("context_bookmarkAllTabs"); - bookmarkAllTabs.hidden = this.contextTab.pinned; - if (!bookmarkAllTabs.hidden) - PlacesCommandHook.updateBookmarkAllTabsCommand(); - - // Adjust the state of the toggle mute menu item. - let toggleMute = document.getElementById("context_toggleMuteTab"); - if (this.contextTab.hasAttribute("muted")) { - toggleMute.label = gNavigatorBundle.getString("unmuteTab.label"); - toggleMute.accessKey = gNavigatorBundle.getString("unmuteTab.accesskey"); - } else { - toggleMute.label = gNavigatorBundle.getString("muteTab.label"); - toggleMute.accessKey = gNavigatorBundle.getString("muteTab.accesskey"); - } - - this.contextTab.toggleMuteMenuItem = toggleMute; - this._updateToggleMuteMenuItem(this.contextTab); - - this.contextTab.addEventListener("TabAttrModified", this, false); - aPopupMenu.addEventListener("popuphiding", this, false); - }, - handleEvent(aEvent) { - switch (aEvent.type) { - case "popuphiding": - gBrowser.removeEventListener("TabAttrModified", this); - aEvent.target.removeEventListener("popuphiding", this); - break; - case "TabAttrModified": - let tab = aEvent.target; - this._updateToggleMuteMenuItem(tab, - attr => aEvent.detail.changed.indexOf(attr) >= 0); - break; - } - } -}; - -#ifdef MOZ_DEVTOOLS -// Note: Do not delete! It is used for: base/content/nsContextMenu.js -XPCOMUtils.defineLazyModuleGetter(this, "gDevTools", - "resource://devtools/client/framework/gDevTools.jsm"); -#endif - -// Prompt user to restart the browser in safe mode or normally -function restart(safeMode) -{ - let promptTitleString = null; - let promptMessageString = null; - let restartTextString = null; - if (safeMode) { - promptTitleString = "safeModeRestartPromptTitle"; - promptMessageString = "safeModeRestartPromptMessage"; - restartTextString = "safeModeRestartButton"; - } else { - promptTitleString = "restartPromptTitle"; - promptMessageString = "restartPromptMessage"; - restartTextString = "restartButton"; - } - - let flags = Ci.nsIAppStartup.eAttemptQuit; - - // Prompt the user to confirm - let promptTitle = gNavigatorBundle.getString(promptTitleString); - let brandBundle = document.getElementById("bundle_brand"); - let brandShortName = brandBundle.getString("brandShortName"); - let promptMessage = - gNavigatorBundle.getFormattedString(promptMessageString, [brandShortName]); - let restartText = gNavigatorBundle.getString(restartTextString); - let 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; - - let rv = Services.prompt.confirmEx(window, promptTitle, promptMessage, - buttonFlags, restartText, null, null, - null, {}); - - if (rv == 0) { - // Notify all windows that an application quit has been requested. - let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"] - .createInstance(Ci.nsISupportsPRBool); - Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart"); - - // Something aborted the quit process. - if (cancelQuit.data) { - return; - } - - if (safeMode) { - Services.startup.restartInSafeMode(flags); - } else { - Services.startup.quit(flags | Ci.nsIAppStartup.eRestart); - } - } -} - -/* duplicateTabIn duplicates tab in a place specified by the parameter |where|. - * - * |where| can be: - * "tab" new tab - * "tabshifted" same as "tab" but in background if default is to select new - * tabs, and vice versa - * "window" new window - * - * delta is the offset to the history entry that you want to load. - */ -function duplicateTabIn(aTab, where, delta) { - let newTab = Cc['@mozilla.org/browser/sessionstore;1'] - .getService(Ci.nsISessionStore) - .duplicateTab(window, aTab, delta); - - switch (where) { - case "window": - gBrowser.hideTab(newTab); - gBrowser.replaceTabWithWindow(newTab); - break; - case "tabshifted": - // A background tab has been opened, nothing else to do here. - break; - case "tab": - gBrowser.selectedTab = newTab; - break; - } -} - -function toggleAddonBar() { - let addonBar = document.getElementById("addon-bar"); - setToolbarVisibility(addonBar, addonBar.collapsed); -} - -XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () { -#ifdef XP_WIN - // Only show resizers on Windows 2000 and XP - return parseFloat(Services.sysinfo.getProperty("version")) < 6; -#else - return false; -#endif -}); - -var MousePosTracker = { - _listeners: [], - _x: 0, - _y: 0, - get _windowUtils() { - delete this._windowUtils; - return this._windowUtils = window.getInterface(Ci.nsIDOMWindowUtils); - }, - - addListener: function (listener) { - if (this._listeners.indexOf(listener) >= 0) - return; - - listener._hover = false; - this._listeners.push(listener); - - this._callListener(listener); - }, - - removeListener: function (listener) { - var index = this._listeners.indexOf(listener); - if (index < 0) - return; - - this._listeners.splice(index, 1); - }, - - handleEvent: function (event) { - var fullZoom = this._windowUtils.fullZoom; - this._x = event.screenX / fullZoom - window.mozInnerScreenX; - this._y = event.screenY / fullZoom - window.mozInnerScreenY; - - this._listeners.forEach(function (listener) { - try { - this._callListener(listener); - } catch (e) { - Cu.reportError(e); - } - }, this); - }, - - _callListener: function (listener) { - let rect = listener.getMouseTargetRect(); - let hover = this._x >= rect.left && - this._x <= rect.right && - this._y >= rect.top && - this._y <= rect.bottom; - - if (hover == listener._hover) - return; - - listener._hover = hover; - - if (hover) { - if (listener.onMouseEnter) - listener.onMouseEnter(); - } else { - if (listener.onMouseLeave) - listener.onMouseLeave(); - } - } -}; - -var BrowserChromeTest = { - _cb: null, - _ready: false, - markAsReady: function () { - this._ready = true; - if (this._cb) { - this._cb(); - this._cb = null; - } - }, - runWhenReady: function (cb) { - if (this._ready) - cb(); - else - this._cb = cb; - } -}; - -var ToolbarIconColor = { - init: function () { - this._initialized = true; - - window.addEventListener("activate", this); - window.addEventListener("deactivate", this); - Services.obs.addObserver(this, "lightweight-theme-styling-update", false); - gPrefService.addObserver("ui.colorChanged", this, false); - - // If the window isn't active now, we assume that it has never been active - // before and will soon become active such that inferFromText will be - // called from the initial activate event. - if (Services.focus.activeWindow == window) - this.inferFromText(); - }, - - uninit: function () { - this._initialized = false; - - window.removeEventListener("activate", this); - window.removeEventListener("deactivate", this); - Services.obs.removeObserver(this, "lightweight-theme-styling-update"); - gPrefService.removeObserver("ui.colorChanged", this); - }, - - handleEvent: function (event) { - switch (event.type) { - case "activate": - case "deactivate": - this.inferFromText(); - break; - } - }, - - observe: function (aSubject, aTopic, aData) { - switch (aTopic) { - case "lightweight-theme-styling-update": - // inferFromText needs to run after LightweightThemeConsumer.jsm's - // lightweight-theme-styling-update observer. - setTimeout(() => { this.inferFromText(); }, 0); - break; - case "nsPref:changed": - // system color change - var colorChangedPref = false; - try { - colorChangedPref = gPrefService.getBoolPref("ui.colorChanged"); - } catch(e) { } - // if pref indicates change, call inferFromText() on a small delay - if (colorChangedPref == true) - setTimeout(() => { this.inferFromText(); }, 300); - break; - default: - console.error("ToolbarIconColor: Uncaught topic " + aTopic); - } - }, - - inferFromText: function () { - if (!this._initialized) - return; - - function parseRGB(aColorString) { - let rgb = aColorString.match(/^rgba?\((\d+), (\d+), (\d+)/); - rgb.shift(); - return rgb.map(x => parseInt(x)); - } - - let toolbarSelector = "toolbar:not([collapsed=true])"; -#ifdef XP_MACOSX - toolbarSelector += ":not([type=menubar])"; -#endif - - // The getComputedStyle calls and setting the brighttext are separated in - // two loops to avoid flushing layout and making it dirty repeatedly. - - let luminances = new Map; - for (let toolbar of document.querySelectorAll(toolbarSelector)) { - let [r, g, b] = parseRGB(getComputedStyle(toolbar).color); - let luminance = (2 * r + 5 * g + b) / 8; - luminances.set(toolbar, luminance); - } - - for (let [toolbar, luminance] of luminances) { - if (luminance <= 128) - toolbar.removeAttribute("brighttext"); - else - toolbar.setAttribute("brighttext", "true"); - } - - // Clear pref if set, since we're done applying the color changes. - gPrefService.clearUserPref("ui.colorChanged"); - } -} |