Revision control

Copy as Markdown

Other Tools

/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const {AeroPeek} = ChromeUtils.import("resource:///modules/WindowsPreviewPerTab.jsm");
var {AppConstants} = ChromeUtils.import(
);
XPCOMUtils.defineLazyModuleGetters(this, {
});
XPCOMUtils.defineLazyScriptGetter(this, "gEditItemOverlay",
const REMOTESERVICE_CONTRACTID = "@mozilla.org/toolkit/remote-service;1";
const nsIWebNavigation = Ci.nsIWebNavigation;
var gPrintSettingsAreGlobal = true;
var gSavePrintSettings = true;
var gChromeState = null; // chrome state before we went into print preview
var gInPrintPreviewMode = false;
var gNavToolbox = null;
var gFindInstData;
var gURLBar = null;
var gProxyButton = null;
var gProxyFavIcon = null;
var gProxyDeck = null;
var gNavigatorBundle;
var gBrandBundle;
var gNavigatorRegionBundle;
var gLastValidURLStr = "";
var gLastValidURL = null;
var gClickSelectsAll = false;
var gClickAtEndSelects = false;
var gIgnoreFocus = false;
var gIgnoreClick = false;
// Listeners for updating zoom value in status bar
var ZoomListeners =
{
// Identifies the setting in the content prefs database.
name: "browser.content.full-zoom",
QueryInterface:
XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsIContentPrefObserver,
Ci.nsIContentPrefCallback2,
Ci.nsISupportsWeakReference,
Ci.nsISupports]),
init: function ()
{
Cc["@mozilla.org/content-pref/service;1"]
.getService(Ci.nsIContentPrefService2)
.addObserverForName(this.name, this);
Services.prefs.addObserver("browser.zoom.", this, true);
this.updateVisibility();
},
destroy: function ()
{
Cc["@mozilla.org/content-pref/service;1"]
.getService(Ci.nsIContentPrefService2)
.removeObserverForName(this.name, this);
Services.prefs.removeObserver("browser.zoom.", this);
},
observe: function (aSubject, aTopic, aData)
{
if (aTopic == "nsPref:changed"){
switch (aData) {
case "browser.zoom.siteSpecific":
updateZoomStatus();
break;
case "browser.zoom.showZoomStatusPanel":
this.updateVisibility();
break;
}
}
},
updateVisibility: function()
{
let hidden = !Services.prefs.getBoolPref("browser.zoom.showZoomStatusPanel");
document.getElementById("zoomOut-button").setAttribute('hidden', hidden);
document.getElementById("zoomIn-button").setAttribute('hidden', hidden);
document.getElementById("zoomLevel-display").setAttribute('hidden', hidden);
},
onContentPrefSet: function (aGroup, aName, aValue)
{
// Make sure zoom values loaded before updating
window.setTimeout(updateZoomStatus, 0);
},
onContentPrefRemoved: function (aGroup, aName)
{
// Make sure zoom values loaded before updating
window.setTimeout(updateZoomStatus, 0);
},
handleResult: function(aPref)
{
updateZoomStatus();
},
onLocationChange: function(aURI)
{
updateZoomStatus();
}
};
var gInitialPages = new Set([
"about:blank",
"about:privatebrowsing",
"about:sessionrestore"
]);
//cached elements
var gBrowser = null;
var gTabStripPrefListener =
{
domain: "browser.tabs.autoHide",
observe: function(subject, topic, prefName)
{
// verify that we're changing the tab browser strip auto hide pref
if (topic != "nsPref:changed")
return;
if (gBrowser.tabContainer.childNodes.length == 1 && window.toolbar.visible) {
var stripVisibility = !Services.prefs.getBoolPref(prefName);
gBrowser.setStripVisibilityTo(stripVisibility);
Services.prefs.setBoolPref("browser.tabs.forceHide", false);
}
}
};
var gHomepagePrefListener =
{
domain: "browser.startup.homepage",
observe: function(subject, topic, prefName)
{
// verify that we're changing the home page pref
if (topic != "nsPref:changed")
return;
updateHomeButtonTooltip();
}
};
var gStatusBarPopupIconPrefListener =
{
domain: "privacy.popups.statusbar_icon_enabled",
observe: function(subject, topic, prefName)
{
if (topic != "nsPref:changed" || prefName != this.domain)
return;
var popupIcon = document.getElementById("popupIcon");
if (!Services.prefs.getBoolPref(prefName))
popupIcon.hidden = true;
else if (gBrowser.getNotificationBox().popupCount)
popupIcon.hidden = false;
}
};
var gFormSubmitObserver = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver,
Ci.nsIObserver]),
panel: null,
init: function()
{
this.panel = document.getElementById("invalid-form-popup");
},
notifyInvalidSubmit: function (aFormElement, aInvalidElements)
{
// We are going to handle invalid form submission attempt by focusing the
// first invalid element and show the corresponding validation message in a
// panel attached to the element.
if (!aInvalidElements.length) {
return;
}
// Don't show the popup if the current tab doesn't contain the invalid form.
if (aFormElement.ownerDocument.defaultView.top != content) {
return;
}
let element = aInvalidElements.queryElementAt(0, Ci.nsISupports);
if (!(element instanceof HTMLInputElement ||
element instanceof HTMLTextAreaElement ||
element instanceof HTMLSelectElement ||
element instanceof HTMLButtonElement)) {
return;
}
this.panel.firstChild.textContent = element.validationMessage;
element.focus();
// If the user interacts with the element and makes it valid or leaves it,
// we want to remove the popup.
// We could check for clicks but a click already removes the popup.
function blurHandler() {
gFormSubmitObserver.panel.hidePopup();
}
function inputHandler(e) {
if (e.originalTarget.validity.valid) {
gFormSubmitObserver.panel.hidePopup();
} else {
// If the element is now invalid for a new reason, we should update the
// error message.
if (gFormSubmitObserver.panel.firstChild.textContent !=
e.originalTarget.validationMessage) {
gFormSubmitObserver.panel.firstChild.textContent =
e.originalTarget.validationMessage;
}
}
}
element.addEventListener("input", inputHandler);
element.addEventListener("blur", blurHandler);
// One event to bring them all and in the darkness bind them.
this.panel.addEventListener("popuphiding", function popupHidingHandler(aEvent) {
aEvent.target.removeEventListener("popuphiding", popupHidingHandler);
element.removeEventListener("input", inputHandler);
element.removeEventListener("blur", blurHandler);
});
this.panel.hidden = false;
var win = element.ownerDocument.defaultView;
var style = win.getComputedStyle(element, null);
var scale = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.fullZoom;
var offset = style.direction == 'rtl' ? parseInt(style.paddingRight) +
parseInt(style.borderRightWidth) :
parseInt(style.paddingLeft) +
parseInt(style.borderLeftWidth);
offset = Math.round(offset * scale);
this.panel.openPopup(element, "after_start", offset, 0);
}
};
/**
* Pref listener handler functions.
* Both functions assume that observer.domain is set to
* the pref domain we want to start/stop listening to.
*/
function addPrefListener(observer)
{
try {
Services.prefs.addObserver(observer.domain, observer);
} catch(ex) {
dump("Failed to observe prefs: " + ex + "\n");
}
}
function removePrefListener(observer)
{
try {
Services.prefs.removeObserver(observer.domain, observer);
} catch(ex) {
dump("Failed to remove pref observer: " + ex + "\n");
}
}
function addPopupPermListener(observer)
{
Services.obs.addObserver(observer, "popup-perm-close");
}
function removePopupPermListener(observer)
{
Services.obs.removeObserver(observer, "popup-perm-close");
}
function addFormSubmitObserver(observer)
{
observer.init();
Services.obs.addObserver(observer, "invalidformsubmit");
}
function removeFormSubmitObserver(observer)
{
Services.obs.removeObserver(observer, "invalidformsubmit");
}
/**
* We can avoid adding multiple load event listeners and save some time by adding
* one listener that calls all real handlers.
*/
function pageShowEventHandlers(event)
{
checkForDirectoryListing();
}
/**
* Determine whether or not the content area is displaying a page with frames,
* and if so, toggle the display of the 'save frame as' menu item.
**/
function getContentAreaFrameCount()
{
var saveFrameItem = document.getElementById("saveframe");
if (!content || !content.frames.length || !isContentFrame(document.commandDispatcher.focusedWindow))
saveFrameItem.setAttribute("hidden", "true");
else {
var autoDownload = Services.prefs.getBoolPref("browser.download.useDownloadDir");
goSetMenuValue("saveframe", autoDownload ? "valueSave" : "valueSaveAs");
saveFrameItem.removeAttribute("hidden");
}
}
function saveFrameDocument()
{
var focusedWindow = document.commandDispatcher.focusedWindow;
if (isContentFrame(focusedWindow))
saveDocument(focusedWindow.document, true);
}
function updateHomeButtonTooltip()
{
var homePage = getHomePage();
var tooltip = document.getElementById("home-button-tooltip-inner");
while (tooltip.hasChildNodes())
tooltip.lastChild.remove();
for (var i in homePage) {
var label = document.createElementNS(XUL_NS, "label");
label.setAttribute("value", homePage[i]);
tooltip.appendChild(label);
}
}
function getWebNavigation()
{
try {
return getBrowser().webNavigation;
} catch (e) {
return null;
}
}
function BrowserReloadWithFlags(reloadFlags)
{
// Reset temporary permissions on the current tab. This is done here
// because we only want to reset permissions on user reload.
SitePermissions.clearTemporaryPermissions(gBrowser.selectedBrowser);
// 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.
let webNav = getWebNavigation();
try {
let sh = webNav.sessionHistory;
if (sh)
webNav = sh.QueryInterface(Components.interfaces.nsIWebNavigation);
} catch (e) {
}
try {
webNav.reload(reloadFlags);
} catch (e) {
}
}
function toggleAffectedChrome(aHide)
{
// chrome to toggle includes:
// (*) menubar
// (*) navigation bar
// (*) personal toolbar
// (*) tab browser ``strip''
// (*) sidebar
// (*) statusbar
// (*) findbar
if (!gChromeState)
gChromeState = new Object;
var statusbar = document.getElementById("status-bar");
getNavToolbox().hidden = aHide;
var notificationBox = gBrowser.getNotificationBox();
var findbar = document.getElementById("FindToolbar")
// sidebar states map as follows:
// hidden => hide/show nothing
// collapsed => hide/show only the splitter
// shown => hide/show the splitter and the box
if (aHide)
{
// going into print preview mode
gChromeState.sidebar = SidebarGetState();
SidebarSetState("hidden");
// deal with tab browser
gBrowser.mStrip.setAttribute("moz-collapsed", "true");
// deal with the Status Bar
gChromeState.statusbarWasHidden = statusbar.hidden;
statusbar.hidden = true;
// deal with the notification box
gChromeState.notificationsWereHidden = notificationBox.notificationsHidden;
notificationBox.notificationsHidden = true;
if (findbar)
{
gChromeState.findbarWasHidden = findbar.hidden;
findbar.close();
}
else
{
gChromeState.findbarWasHidden = true;
}
gChromeState.syncNotificationsOpen = false;
var syncNotifications = document.getElementById("sync-notifications");
if (syncNotifications)
{
gChromeState.syncNotificationsOpen = !syncNotifications.notificationsHidden;
syncNotifications.notificationsHidden = true;
}
}
else
{
// restoring normal mode (i.e., leaving print preview mode)
SidebarSetState(gChromeState.sidebar);
// restore tab browser
gBrowser.mStrip.removeAttribute("moz-collapsed");
// restore the Status Bar
statusbar.hidden = gChromeState.statusbarWasHidden;
// restore the notification box
notificationBox.notificationsHidden = gChromeState.notificationsWereHidden;
if (!gChromeState.findbarWasHidden)
findbar.open();
if (gChromeState.syncNotificationsOpen)
document.getElementById("sync-notifications").notificationsHidden = false;
}
// if we are unhiding and sidebar used to be there rebuild it
if (!aHide && gChromeState.sidebar == "visible")
SidebarRebuild();
}
var PrintPreviewListener = {
_printPreviewTab: null,
_tabBeforePrintPreview: null,
getPrintPreviewBrowser: function () {
if (!this._printPreviewTab) {
this._tabBeforePrintPreview = getBrowser().selectedTab;
this._printPreviewTab = getBrowser().addTab("about:blank");
getBrowser().selectedTab = this._printPreviewTab;
}
return getBrowser().getBrowserForTab(this._printPreviewTab);
},
getSourceBrowser: function () {
return this._tabBeforePrintPreview ?
getBrowser().getBrowserForTab(this._tabBeforePrintPreview) :
getBrowser().selectedBrowser;
},
getNavToolbox: function () {
return window.getNavToolbox();
},
onEnter: function () {
gInPrintPreviewMode = true;
toggleAffectedChrome(true);
},
onExit: function () {
getBrowser().selectedTab = this._tabBeforePrintPreview;
this._tabBeforePrintPreview = null;
gInPrintPreviewMode = false;
toggleAffectedChrome(false);
getBrowser().removeTab(this._printPreviewTab, { disableUndo: true });
this._printPreviewTab = null;
}
};
function getNavToolbox()
{
if (!gNavToolbox)
gNavToolbox = document.getElementById("navigator-toolbox");
return gNavToolbox;
}
function BrowserPrintPreview()
{
PrintUtils.printPreview(PrintPreviewListener);
}
function BrowserSetCharacterSet(aEvent)
{
if (aEvent.target.hasAttribute("charset"))
getBrowser().docShell.charset = aEvent.target.getAttribute("charset");
BrowserCharsetReload();
}
function BrowserCharsetReload()
{
BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
}
function BrowserUpdateCharsetMenu(aNode)
{
var wnd = document.commandDispatcher.focusedWindow;
if (wnd.top != content)
wnd = content;
UpdateCharsetMenu(wnd.document.characterSet, aNode);
}
function EnableCharsetMenu()
{
var menuitem = document.getElementById("charsetMenu");
if (getBrowser() && getBrowser().docShell &&
getBrowser().docShell.mayEnableCharacterEncodingMenu)
menuitem.removeAttribute("disabled");
else
menuitem.setAttribute("disabled", "true");
}
function getFindInstData()
{
if (!gFindInstData) {
gFindInstData = new nsFindInstData();
gFindInstData.browser = getBrowser();
// defaults for rootSearchWindow and currentSearchWindow are fine here
}
return gFindInstData;
}
function BrowserFind()
{
findInPage(getFindInstData());
}
function BrowserFindAgain(reverse)
{
findAgainInPage(getFindInstData(), reverse);
}
function BrowserCanFindAgain()
{
return canFindAgainInPage();
}
function getMarkupDocumentViewer()
{
return getBrowser().markupDocumentViewer;
}
function getBrowser()
{
if (!gBrowser)
gBrowser = document.getElementById("content");
return gBrowser;
}
function getHomePage()
{
var URIs = [];
URIs[0] = GetLocalizedStringPref("browser.startup.homepage");
var count = Services.prefs.getIntPref("browser.startup.homepage.count");
for (var i = 1; i < count; ++i)
URIs[i] = GetLocalizedStringPref("browser.startup.homepage." + i);
return URIs;
}
function UpdateBackForwardButtons()
{
var backBroadcaster = document.getElementById("canGoBack");
var forwardBroadcaster = document.getElementById("canGoForward");
var upBroadcaster = document.getElementById("canGoUp");
var browser = getBrowser();
// 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");
var upDisabled = upBroadcaster.hasAttribute("disabled");
if (backDisabled == browser.canGoBack) {
if (backDisabled)
backBroadcaster.removeAttribute("disabled");
else
backBroadcaster.setAttribute("disabled", true);
}
if (forwardDisabled == browser.canGoForward) {
if (forwardDisabled)
forwardBroadcaster.removeAttribute("disabled");
else
forwardBroadcaster.setAttribute("disabled", true);
}
if (upDisabled != !browser.currentURI.spec.replace(/[#?].*$/, "").match(/\/[^\/]+\/./)) {
if (upDisabled)
upBroadcaster.removeAttribute("disabled");
else
upBroadcaster.setAttribute("disabled", true);
}
}
const nsIBrowserDOMWindow = Ci.nsIBrowserDOMWindow;
const nsIInterfaceRequestor = Ci.nsIInterfaceRequestor;
function nsBrowserAccess() {
}
nsBrowserAccess.prototype = {
createContentWindow(aURI, aOpener, aWhere, aFlags, aTriggeringPrincipal = null) {
return this.getContentWindowOrOpenURI(null, aOpener, aWhere, aFlags,
aTriggeringPrincipal);
},
openURI: function (aURI, aOpener, aWhere, aFlags, aTriggeringPrincipal = null) {
if (!aURI) {
Cu.reportError("openURI should only be called with a valid URI");
throw Cr.NS_ERROR_FAILURE;
}
return this.getContentWindowOrOpenURI(aURI, aOpener, aWhere, aFlags,
aTriggeringPrincipal);
},
getContentWindowOrOpenURI(aURI, aOpener, aWhere, aFlags, aTriggeringPrincipal) {
var isExternal = !!(aFlags & 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 (aWhere == nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW) {
if (isExternal)
aWhere = Services.prefs.getIntPref("browser.link.open_external");
else
aWhere = Services.prefs.getIntPref("browser.link.open_newwindow");
}
let referrer = aOpener ? aOpener.QueryInterface(nsIInterfaceRequestor)
.getInterface(nsIWebNavigation)
.currentURI : null;
let referrerPolicy = Ci.nsIHttpChannel.REFERRER_POLICY_UNSET;
if (aOpener && aOpener.document) {
referrerPolicy = aOpener.document.referrerPolicy;
}
var uri = aURI ? aURI.spec : "about:blank";
switch (aWhere) {
case nsIBrowserDOMWindow.OPEN_NEWWINDOW:
return window.openDialog(getBrowserURL(), "_blank", "all,dialog=no",
uri, null, null);
case nsIBrowserDOMWindow.OPEN_NEWTAB:
var bgLoad = Services.prefs.getBoolPref("browser.tabs.loadDivertedInBackground");
var isRelated = referrer ? true : false;
// If we have an opener, that means that the caller is expecting access
// to the nsIDOMWindow of the opened tab right away.
let userContextId = aOpener && aOpener.document
? aOpener.document.nodePrincipal.originAttributes.userContextId
: Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
let openerWindow = (aFlags & nsIBrowserDOMWindow.OPEN_NO_OPENER) ? null : aOpener;
var newTab = gBrowser.loadOneTab(uri, {triggeringPrincipal: aTriggeringPrincipal,
referrerURI: referrer,
referrerPolicy,
inBackground: bgLoad,
fromExternal: isExternal,
relatedToCurrent: isRelated,
userContextId: userContextId,
opener: openerWindow,
});
var contentWin = gBrowser.getBrowserForTab(newTab).contentWindow;
if (!bgLoad)
contentWin.focus();
return contentWin;
default:
var loadflags = isExternal ?
nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL :
nsIWebNavigation.LOAD_FLAGS_NONE;
if (!aOpener) {
if (aURI) {
gBrowser.loadURIWithFlags(aURI.spec, {
flags: loadflags,
referrerURI: referrer,
referrerPolicy,
triggeringPrincipal: aTriggeringPrincipal,
});
}
return content;
}
aOpener = aOpener.top;
if (aURI) {
try {
aOpener.QueryInterface(nsIInterfaceRequestor)
.getInterface(nsIWebNavigation)
.loadURI(uri, loadflags, referrer, null, null,
aTriggeringPrincipal);
} catch (e) {}
}
return aOpener;
}
},
isTabContentWindow: function isTabContentWindow(aWindow) {
return gBrowser.browsers.some(browser => browser.contentWindow == aWindow);
}
}
function HandleAppCommandEvent(aEvent)
{
aEvent.stopPropagation();
switch (aEvent.command) {
case "Back":
BrowserBack();
break;
case "Forward":
BrowserForward();
break;
case "Reload":
BrowserReloadSkipCache();
break;
case "Stop":
BrowserStop();
break;
case "Search":
BrowserSearch.webSearch();
break;
case "Bookmarks":
toBookmarksManager();
break;
case "Home":
BrowserHome(null);
break;
default:
break;
}
}
/* window.arguments[0]: URL(s) to load
(string, with one or more URLs separated by \n)
* [1]: character set (string)
* [2]: referrer (nsIURI)
* [3]: postData (nsIInputStream)
* [4]: allowThirdPartyFixup (bool)
*/
function Startup()
{
// init globals
gNavigatorBundle = document.getElementById("bundle_navigator");
gBrandBundle = document.getElementById("bundle_brand");
gNavigatorRegionBundle = document.getElementById("bundle_navigator_region");
gBrowser = document.getElementById("content");
gURLBar = document.getElementById("urlbar");
SetPageProxyState("invalid", null);
var webNavigation;
try {
webNavigation = getWebNavigation();
if (!webNavigation)
throw "no XBL binding for browser";
} catch (e) {
alert("Error launching browser window:" + e);
window.close(); // Give up.
return;
}
// Do all UI building here:
UpdateNavBar();
updateWindowState();
// set home button tooltip text
updateHomeButtonTooltip();
var lc = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsILoadContext);
if (lc.usePrivateBrowsing) {
gPrivate = window;
let docElement = document.documentElement;
var titlemodifier = docElement.getAttribute("titlemodifier");
if (titlemodifier)
titlemodifier += " ";
titlemodifier += docElement.getAttribute("titleprivate");
docElement.setAttribute("titlemodifier", titlemodifier);
document.title = titlemodifier;
docElement.setAttribute("privatebrowsingmode",
PrivateBrowsingUtils.permanentPrivateBrowsing ? "permanent" : "temporary");
}
// initialize observers and listeners
var xw = lc.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIXULWindow);
xw.XULBrowserWindow = window.XULBrowserWindow = new nsBrowserStatusHandler();
if (!window.content.opener &&
Services.prefs.getBoolPref("browser.doorhanger.enabled")) {
var tmp = {};
ChromeUtils.import("resource://gre/modules/PopupNotifications.jsm", tmp);
window.PopupNotifications = new tmp.PopupNotifications(
getBrowser(),
document.getElementById("notification-popup"),
document.getElementById("notification-popup-box"));
// Setting the popup notification attribute causes the XBL to bind
// and call the constructor again, so we have to destroy it first.
gBrowser.getNotificationBox().destroy();
gBrowser.setAttribute("popupnotification", "true");
// The rebind also resets popup window scrollbar visibility, so override it.
if (!(xw.chromeFlags & Ci.nsIWebBrowserChrome.CHROME_SCROLLBARS))
gBrowser.selectedBrowser.style.overflow = "hidden";
}
addPrefListener(gTabStripPrefListener);
addPrefListener(gHomepagePrefListener);
addPrefListener(gStatusBarPopupIconPrefListener);
addFormSubmitObserver(gFormSubmitObserver);
window.browserContentListener =
new nsBrowserContentListener(window, getBrowser());
// Add a capturing event listener to the content area
// (rjc note: not the entire window, otherwise we'll get sidebar pane loads too!)
// so we'll be notified when onloads complete.
var contentArea = document.getElementById("appcontent");
contentArea.addEventListener("pageshow", function callPageShowHandlers(aEvent) {
// Filter out events that are not about the document load we are interested in.
if (aEvent.originalTarget == content.document)
setTimeout(pageShowEventHandlers, 0, aEvent);
}, true);
// Set a sane starting width/height for all resolutions on new profiles.
if (!document.documentElement.hasAttribute("width")) {
var defaultHeight = screen.availHeight;
var defaultWidth= screen.availWidth;
// Create a narrower window for large or wide-aspect displays, to suggest
// side-by-side page view.
if (screen.availWidth >= 1440)
defaultWidth /= 2;
// Tweak sizes to be sure we don't grow outside the screen
defaultWidth = defaultWidth - 20;
defaultHeight = defaultHeight - 10;
// 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)
if (navigator.appVersion.includes("X11"))
defaultHeight -= 28;
// On small screens, default to maximized state
if (defaultHeight <= 600)
document.documentElement.setAttribute("sizemode", "maximized");
document.documentElement.setAttribute("width", defaultWidth);
document.documentElement.setAttribute("height", defaultHeight);
// Make sure we're safe at the left/top edge of screen
document.documentElement.setAttribute("screenX", screen.availLeft);
document.documentElement.setAttribute("screenY", screen.availTop);
}
// hook up UI through progress listener
getBrowser().addProgressListener(window.XULBrowserWindow);
// setup the search service DOMLinkAdded listener
getBrowser().addEventListener("DOMLinkAdded", BrowserSearch);
// hook up drag'n'drop
getBrowser().droppedLinkHandler = handleDroppedLink;
var uriToLoad = "";
// Check window.arguments[0]. If not null then use it for uriArray
// otherwise the new window is being called when another browser
// window already exists so use the New Window pref for uriArray
if ("arguments" in window && window.arguments.length >= 1) {
var uriArray;
if (window.arguments[0]) {
uriArray = window.arguments[0].toString().split('\n'); // stringify and split
} else {
switch (Services.prefs.getIntPref("browser.windows.loadOnNewWindow", 0))
{
default:
uriArray = ["about:blank"];
break;
case 1:
uriArray = getHomePage();
break;
case 2:
uriArray = [Services.prefs.getStringPref("browser.history.last_page_visited", "")];
break;
}
}
uriToLoad = uriArray.splice(0, 1)[0];
if (uriArray.length > 0)
window.setTimeout(function(arg) { for (var i in arg) gBrowser.addTab(arg[i]); }, 0, uriArray);
}
if (/^\s*$/.test(uriToLoad))
uriToLoad = "about:blank";
var browser = getBrowser();
if (uriToLoad != "about:blank") {
if (!gInitialPages.has(uriToLoad)) {
gURLBar.value = uriToLoad;
browser.userTypedValue = uriToLoad;
}
if ("arguments" in window && window.arguments.length >= 3) {
// window.arguments[2]: referrer (nsIURI | string)
// [3]: postData (nsIInputStream)
// [4]: allowThirdPartyFixup (bool)
// [5]: referrerPolicy (int)
// [6]: userContextId (int)
// [7]: originPrincipal (nsIPrincipal)
// [8]: triggeringPrincipal (nsIPrincipal)
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_UNSET);
let userContextId = (window.arguments[6] != undefined ?
window.arguments[6] : Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID);
loadURI(uriToLoad, referrerURI, window.arguments[3] || null,
window.arguments[4] || false, referrerPolicy, userContextId,
// pass the origin principal (if any) and force its use to create
// an initial about:blank viewer if present:
window.arguments[7], !!window.arguments[7], window.arguments[8]);
} else {
// Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3.
// Such callers expect that window.arguments[0] is handled as a single URI.
loadOneOrMoreURIs(uriToLoad, Services.scriptSecurityManager.getSystemPrincipal());
}
}
// Focus content area unless we're loading a blank or other initial
// page, or if we weren't passed any arguments. This "breaks" the
// javascript:window.open(); case where we don't get any arguments
// either, but we're loading about:blank, but focusing the content
// area is arguably correct in that case as well since the opener
// is very likely to put some content in the new window, and then
// the focus should be in the content area.
var navBar = document.getElementById("nav-bar");
if ("arguments" in window && gInitialPages.has(uriToLoad) &&
isElementVisible(gURLBar))
setTimeout(WindowFocusTimerCallback, 0, gURLBar);
else
setTimeout(WindowFocusTimerCallback, 0, content);
// hook up browser access support
window.browserDOMWindow = new nsBrowserAccess();
// hook up remote support
if (!gPrivate && REMOTESERVICE_CONTRACTID in Cc) {
var remoteService =
Cc[REMOTESERVICE_CONTRACTID]
.getService(Ci.nsIRemoteService);
remoteService.registerWindow(window);
}
// ensure login manager is loaded
Cc["@mozilla.org/login-manager;1"].getService();
// called when we go into full screen, even if it is
// initiated by a web page script
addEventListener("fullscreen", onFullScreen, true);
addEventListener("PopupCountChanged", UpdateStatusBarPopupIcon, true);
addEventListener("AppCommand", HandleAppCommandEvent, true);
addEventListener("sizemodechange", updateWindowState, false);
// does clicking on the urlbar select its contents?
gClickSelectsAll = Services.prefs.getBoolPref("browser.urlbar.clickSelectsAll");
gClickAtEndSelects = Services.prefs.getBoolPref("browser.urlbar.clickAtEndSelects");
// BiDi UI
gShowBiDi = isBidiEnabled();
if (gShowBiDi) {
document.getElementById("documentDirection-swap").hidden = false;
document.getElementById("textfieldDirection-separator").hidden = false;
document.getElementById("textfieldDirection-swap").hidden = false;
}
// Before and after callbacks for the customizeToolbar code
getNavToolbox().customizeInit = BrowserToolboxCustomizeInit;
getNavToolbox().customizeDone = BrowserToolboxCustomizeDone;
getNavToolbox().customizeChange = BrowserToolboxCustomizeChange;
PlacesToolbarHelper.init();
gBrowser.mPanelContainer.addEventListener("InstallBrowserTheme", LightWeightThemeWebInstaller, false, true);
gBrowser.mPanelContainer.addEventListener("PreviewBrowserTheme", LightWeightThemeWebInstaller, false, true);
gBrowser.mPanelContainer.addEventListener("ResetBrowserThemePreview", LightWeightThemeWebInstaller, false, true);
AeroPeek.onOpenWindow(window);
if (!gPrivate) {
// initialize the sync UI
// gSyncUI.init();
// initialize the session-restore service
setTimeout(InitSessionStoreCallback, 0);
}
ZoomListeners.init();
gBrowser.addTabsProgressListener(ZoomListeners);
window.addEventListener("MozAfterPaint", DelayedStartup);
}
// Minimal gBrowserInit shim to keep the Addon-SDK happy.
var gBrowserInit = {
delayedStartupFinished: false,
}
function DelayedStartup() {
window.removeEventListener("MozAfterPaint", DelayedStartup);
// Bug 778855 - Perf regression if we do this here. To be addressed in bug 779008.
setTimeout(function() { SafeBrowsing.init(); }, 2000);
gBrowserInit.delayedStartupFinished = true;
Services.obs.notifyObservers(window, "browser-delayed-startup-finished");
}
function UpdateNavBar()
{
var elements = getNavToolbox().getElementsByClassName("nav-bar-class");
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
element.classList.remove("nav-bar-last");
element.classList.remove("nav-bar-first");
var next = element.nextSibling;
if (!next || !next.classList.contains("nav-bar-class"))
element.classList.add("nav-bar-last");
var previous = element.previousSibling;
if (!previous || !previous.classList.contains("nav-bar-class"))
element.classList.add("nav-bar-first");
}
UpdateUrlbarSearchSplitterState();
}
function UpdateUrlbarSearchSplitterState()
{
var splitter = document.getElementById("urlbar-search-splitter");
var urlbar = document.getElementById("nav-bar-inner");
var searchbar = document.getElementById("search-container");
var ibefore = null;
if (isElementVisible(urlbar) && isElementVisible(searchbar)) {
if (searchbar.matches("#nav-bar-inner ~ #search-container"))
ibefore = searchbar;
else if (urlbar.matches("#search-container ~ #nav-bar-inner"))
ibefore = searchbar.nextSibling;
}
if (ibefore) {
splitter = document.createElement("splitter");
splitter.id = "urlbar-search-splitter";
splitter.setAttribute("resizebefore", "flex");
splitter.setAttribute("resizeafter", "flex");
splitter.setAttribute("skipintoolbarset", "true");
splitter.setAttribute("overflows", "false");
splitter.classList.add("chromeclass-toolbar-additional",
"nav-bar-class");
ibefore.parentNode.insertBefore(splitter, ibefore);
}
}
function updateWindowState()
{
getBrowser().showWindowResizer =
window.windowState == window.STATE_NORMAL &&
!isElementVisible(document.getElementById("status-bar"));
getBrowser().docShellIsActive =
window.windowState != window.STATE_MINIMIZED;
}
function InitSessionStoreCallback()
{
try {
var ss = Cc["@mozilla.org/suite/sessionstore;1"]
.getService(Ci.nsISessionStore);
ss.init(window);
//Check if we have "Deferred Session Restore"
let restoreItem = document.getElementById("historyRestoreLastSession");
if (ss.canRestoreLastSession)
restoreItem.removeAttribute("disabled");
} catch(ex) {
dump("nsSessionStore could not be initialized: " + ex + "\n");
}
}
function WindowFocusTimerCallback(element)
{
// This function is a redo of the fix for jag bug 91884.
// See Bug 97067 and Bug 89214 for details.
if (window == Services.ww.activeWindow) {
element.focus();
} else {
// set the element in command dispatcher so focus will restore properly
// when the window does become active
if (element instanceof Ci.nsIDOMWindow) {
document.commandDispatcher.focusedWindow = element;
document.commandDispatcher.focusedElement = null;
} else if (Element.isInstance(element)) {
document.commandDispatcher.focusedWindow = element.ownerDocument.defaultView;
document.commandDispatcher.focusedElement = element;
}
}
}
function Shutdown()
{
AeroPeek.onCloseWindow(window);
BookmarkingUI.uninit();
// shut down browser access support
window.browserDOMWindow = null;
getBrowser().removeEventListener("DOMLinkAdded", BrowserSearch);
try {
getBrowser().removeProgressListener(window.XULBrowserWindow);
} catch (ex) {
// Perhaps we didn't get around to adding the progress listener
}
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;
// unregister us as a pref listener
removePrefListener(gTabStripPrefListener);
removePrefListener(gHomepagePrefListener);
removePrefListener(gStatusBarPopupIconPrefListener);
removeFormSubmitObserver(gFormSubmitObserver);
window.browserContentListener.close();
}
function Translate()
{
var service = GetLocalizedStringPref("browser.translation.service");
var serviceDomain = GetLocalizedStringPref("browser.translation.serviceDomain");
var targetURI = getWebNavigation().currentURI.spec;
// if we're already viewing a translated page, then just reload
if (targetURI.includes(serviceDomain))
BrowserReload();
else {
loadURI(encodeURI(service) + encodeURIComponent(targetURI));
}
}
function GetTypePermFromId(aId)
{
// Get type and action from splitting id, first is type, second is action.
var [type, action] = aId.split("_");
var perm = "ACCESS_" + action.toUpperCase();
return [type, Ci.nsICookiePermission[perm]];
}
// Determine current state and check/uncheck the appropriate menu items.
function CheckPermissionsMenu(aType, aNode)
{
var currentPerm = Services.perms.testPermission(getBrowser().currentURI, aType);
var items = aNode.getElementsByAttribute("name", aType);
for (let item of items) {
// Get type and perm from id.
var [type, perm] = GetTypePermFromId(item.id);
item.setAttribute("checked", perm == currentPerm);
}
}
// Perform a Cookie, Image or Popup action.
function CookieImagePopupAction(aElement)
{
var uri = getBrowser().currentURI;
// Get type and perm from id.
var [type, perm] = GetTypePermFromId(aElement.id);
if (Services.perms.testPermission(uri, type) == perm)
return;
Services.perms.add(uri, type, perm);
Services.prompt.alert(window, aElement.getAttribute("title"),
aElement.getAttribute("msg"));
}
function OpenSessionHistoryIn(aWhere, aDelta, aTab)
{
var win = aWhere == "window" ? null : window;
aTab = aTab || getBrowser().selectedTab;
var tab = Cc["@mozilla.org/suite/sessionstore;1"]
.getService(Ci.nsISessionStore)
.duplicateTab(win, aTab, aDelta, true);
var loadInBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
switch (aWhere) {
case "tabfocused":
// forces tab to be focused
loadInBackground = true;
// fall through
case "tabshifted":
loadInBackground = !loadInBackground;
// fall through
case "tab":
if (!loadInBackground) {
getBrowser().selectedTab = tab;
window.content.focus();
}
}
}
/* Firefox compatibility shim *
* 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
* "tabfocused" same as "tab" but override any background preferences and
* focus the new tab
* "window" new window
*
* delta is the offset to the history entry that you want to load.
*/
function duplicateTabIn(aTab, aWhere, aDelta)
{
OpenSessionHistoryIn(aWhere, aDelta, aTab);
}
function gotoHistoryIndex(aEvent)
{
var index = aEvent.target.getAttribute("index");
if (!index)
return false;
var where = whereToOpenLink(aEvent);
if (where == "current") {
// Normal click. Go there in the current tab and update session history.
try {
getWebNavigation().gotoIndex(index);
}
catch(ex) {
return false;
}
}
else {
// Modified click. Go there in a new tab/window. Include session history.
var delta = index - getWebNavigation().sessionHistory.index;
OpenSessionHistoryIn(where, delta);
}
return true;
}
function BrowserBack(aEvent)
{
var where = whereToOpenLink(aEvent, false, true);
if (where == "current") {
try {
getBrowser().goBack();
}
catch(ex) {}
}
else {
OpenSessionHistoryIn(where, -1);
}
}
function BrowserHandleBackspace()
{
switch (Services.prefs.getIntPref("browser.backspace_action")) {
case 0:
BrowserBack();
break;
case 1:
goDoCommand("cmd_scrollPageUp");
break;
}
}
function BrowserForward(aEvent)
{
var where = whereToOpenLink(aEvent, false, true);
if (where == "current") {
try {
getBrowser().goForward();
}
catch(ex) {
}
}
else {
OpenSessionHistoryIn(where, 1);
}
}
function BrowserUp()
{
loadURI(getBrowser().currentURI.spec.replace(/[#?].*$/, "").replace(/\/[^\/]*.$/, "/"));
}
function BrowserHandleShiftBackspace()
{
switch (Services.prefs.getIntPref("browser.backspace_action")) {
case 0:
BrowserForward();
break;
case 1:
goDoCommand("cmd_scrollPageDown");
break;
}
}
function BrowserBackMenu(event)
{
return FillHistoryMenu(event.target, "back");
}
function BrowserForwardMenu(event)
{
return FillHistoryMenu(event.target, "forward");
}
function BrowserStop()
{
try {
const stopFlags = nsIWebNavigation.STOP_ALL;
getWebNavigation().stop(stopFlags);
}
catch(ex) {
}
}
function BrowserReload(aEvent)
{
var where = whereToOpenLink(aEvent, false, true);
if (where == "current")
BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_NONE);
else if (where == null && aEvent.shiftKey)
BrowserReloadSkipCache();
else
OpenSessionHistoryIn(where, 0);
}
function BrowserReloadSkipCache()
{
// Bypass proxy and cache.
const reloadFlags = nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
BrowserReloadWithFlags(reloadFlags);
}
function BrowserHome(aEvent)
{
var homePage = getHomePage();
var where = whereToOpenLink(aEvent, false, true);
openUILinkArrayIn(homePage, where);
}
var BrowserSearch = {
handleEvent: function (event) { // "DOMLinkAdded" event
var link = event.originalTarget;
var isSearch = /(?:^|\s)search(?:\s|$)/i.test(link.rel) && link.title &&
/^(https?|ftp):/i.test(link.href) &&
/(?:^|\s)application\/opensearchdescription\+xml(?:;?.*)$/i.test(link.type);
if (isSearch) {
this.addEngine(link, link.ownerDocument);
}
},
addEngine: function(engine, targetDoc) {
if (!this.searchBar)
return;
var browser = getBrowser().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(e => e.title == engine.title))
return;
}
// Append the URI and an appropriate title to the browser data.
// Use documentURIObject in the check so that we do the right
// thing with about:-style error pages. Bug 453442
var iconURL = null;
var aURI = targetDoc.documentURIObject;
try {
aURI = Services.uriFixup.createExposableURI(aURI);
} catch (e) {
}
if (aURI && ("schemeIs" in aURI) &&
(aURI.schemeIs("http") || aURI.schemeIs("https")))
iconURL = getBrowser().buildFavIconString(aURI);
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;
if (browser == getBrowser().selectedBrowser)
this.updateSearchButton();
}
},
/**
* Update the browser UI to show whether or not additional engines are
* available when a page is loaded or the user switches tabs to a page that
* has search engines.
*/
updateSearchButton: function() {
var searchBar = this.searchBar;
// The search bar binding might not be applied even though the element is
// in the document (e.g. when the navigation toolbar is hidden), so check
// for .searchButton specifically.
if (!searchBar || !searchBar.searchButton)
return;
searchBar.updateSearchButton();
},
/**
* Gives focus to the search bar, if it is present on the toolbar, or to the
* search sidebar, if it is open, 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() {
if (!gBrowser) {
var win = getTopWin();
if (win) {
// If there's an open browser window, it should handle this command
win.focus();
win.BrowserSearch.webSearch();
return;
}
// If there are no open browser windows, open a new one
function webSearchCallback() {
// This needs to be in a timeout so that we don't end up refocused
// in the url bar
setTimeout(BrowserSearch.webSearch, 0);
}
win = window.openDialog(getBrowserURL(), "_blank",
"chrome,all,dialog=no", "about:blank");
win.addEventListener("load", webSearchCallback);
return;
}
if (isElementVisible(this.searchBar)) {
this.searchBar.select();
this.searchBar.focus();
} else if (this.searchSidebar) {
this.searchSidebar.focus();
} else {
loadURI(Services.search.defaultEngine.searchForm);
window.content.focus();
}
},
/**
* 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 aSearchText
* The search terms to use for the search.
*
* @param [optional] aNewWindowOrTab
* A boolean if set causes the search to load in a new window or tab
* (depending on "browser.search.openintab"). Otherwise the search
* loads in the current tab.
*
* @param [optional] aEvent
* The event object passed from the caller.
*/
loadSearch: function BrowserSearch_search(aSearchText, aNewWindowOrTab, aEvent) {
var engine;
// If the search bar is visible, use the current engine, otherwise, fall
// back to the default engine.
if (isElementVisible(this.searchBar) ||
this.searchSidebar)
engine = Services.search.currentEngine;
else
engine = Services.search.defaultEngine;
var submission = engine.getSubmission(aSearchText); // 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 you change the code here, remember to make the corresponding
// changes in suite/mailnews/mailWindowOverlay.js->MsgOpenSearch
if (!submission)
return;
if (aNewWindowOrTab) {
let newTabPref = Services.prefs.getBoolPref("browser.search.opentabforcontextsearch");
let where = newTabPref ? aEvent && aEvent.shiftKey ? "tabshifted" : "tab" : "window";
openUILinkIn(submission.uri.spec, where, null, submission.postData);
if (where == "window")
return;
} else {
loadURI(submission.uri.spec, null, submission.postData, false);
window.content.focus();
}
},
/**
* Returns the search bar element if it is present in the toolbar, null otherwise.
*/
get searchBar() {
return document.getElementById("searchbar");
},
/**
* Returns the search sidebar textbox if the search sidebar is present in
* the sidebar and selected, null otherwise.
*/
get searchSidebar() {
if (sidebarObj.never_built)
return null;
var panel = sidebarObj.panels.get_panel_from_id("urn:sidebar:panel:search");
return panel && isElementVisible(panel.get_iframe()) &&
panel.get_iframe()
.contentDocument.getElementById("sidebar-search-text");
},
loadAddEngines: function BrowserSearch_loadAddEngines() {
loadAddSearchEngines(); // for compatibility
},
/**
* Reveal the search sidebar panel.
*/
revealSidebar: function BrowserSearch_revealSidebar() {
// first lets check if the search panel will be shown at all
// by checking the sidebar datasource to see if there is an entry
// for the search panel, and if it is excluded for navigator or not
var searchPanelExists = false;
var myPanel = document.getElementById("urn:sidebar:panel:search");
if (myPanel) {
var panel = sidebarObj.panels.get_panel_from_header_node(myPanel);
searchPanelExists = !panel.is_excluded();
} else if (sidebarObj.never_built) {
// XXXsearch: in theory, this should work when the sidebar isn't loaded,
// in practice, it fails as sidebarObj.datasource_uri isn't defined
try {
var datasource = RDF.GetDataSourceBlocking(sidebarObj.datasource_uri);
var aboutValue = RDF.GetResource("urn:sidebar:panel:search");
// check if the panel is even in the list by checking for its content
var contentProp = RDF.GetResource("http://home.netscape.com/NC-rdf#content");
var content = datasource.GetTarget(aboutValue, contentProp, true);
if (content instanceof Ci.nsIRDFLiteral) {
// the search panel entry exists, now check if it is excluded
// for navigator
var excludeProp = RDF.GetResource("http://home.netscape.com/NC-rdf#exclude");
var exclude = datasource.GetTarget(aboutValue, excludeProp, true);
if (exclude instanceof Ci.nsIRDFLiteral) {
searchPanelExists = !exclude.Value.includes("navigator:browser");
} else {
// panel exists and no exclude set
searchPanelExists = true;
}
}
} catch (e) {
searchPanelExists = false;
}
}
if (searchPanelExists) {
// make sure the sidebar is open, else SidebarSelectPanel() will fail
if (sidebar_is_hidden())
SidebarShowHide();
if (sidebar_is_collapsed())
SidebarExpandCollapse();
var searchPanel = document.getElementById("urn:sidebar:panel:search");
if (searchPanel)
SidebarSelectPanel(searchPanel, true, true); // lives in sidebarOverlay.js
}
}
}
function QualifySearchTerm()
{
// If the text in the URL bar is the same as the currently loaded
// page's URL then treat this as an empty search term. This way
// the user is taken to the search page where s/he can enter a term.
if (gBrowser.userTypedValue !== null)
return gURLBar.value;
return "";
}
function BrowserOpenWindow()
{
//opens a window where users can select a web location to open
var params = { action: gPrivate ? "4" : "0", url: "" };
"chrome,modal,titlebar", params);
getShortcutOrURIAndPostData(params.url).then(data => {
switch (params.action) {
case "0": // current window
loadURI(data.url, null, data.postData, true);
break;
case "1": // new window
openDialog(getBrowserURL(), "_blank", "all,dialog=no", data.url, null, null,
data.postData, true);
break;
case "2": // edit
editPage(data.url);
break;
case "3": // new tab
gBrowser.selectedTab = gBrowser.addTab(data.url,
{allowThirdPartyFixup: true,
postData: data.postData});
break;
case "4": // private
openNewPrivateWith(params.url);
break;
}
});
}
function BrowserOpenTab()
{
if (!gInPrintPreviewMode) {
var uriToLoad;
var tabPref = Services.prefs.getIntPref("browser.tabs.loadOnNewTab", 0);
switch (tabPref)
{
default:
uriToLoad = "about:blank";
break;
case 1:
uriToLoad = GetLocalizedStringPref("browser.startup.homepage");
break;
case 2:
uriToLoad = Services.prefs.getStringPref("browser.history.last_page_visited", "");
break;
}
if (!gBrowser) {
var win = getTopWin();
if (win) {
// If there's an open browser window, it should handle this command
win.focus();
win.BrowserOpenTab();
return;
}
// If there are no open browser windows, open a new one
openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no", uriToLoad);
return;
}
if (tabPref == 2)
OpenSessionHistoryIn("tabfocused", 0);
else
gBrowser.selectedTab = gBrowser.addTab(uriToLoad);
if (uriToLoad == "about:blank" && isElementVisible(gURLBar))
setTimeout(WindowFocusTimerCallback, 0, gURLBar);
else
setTimeout(WindowFocusTimerCallback, 0, content);
}
}
function BrowserOpenSyncTabs()
{
switchToTabHavingURI("about:sync-tabs", true);
}
// Class for saving the last directory and filter Index in the prefs.
// Used for open file and upload file.
class RememberLastDir {
// The pref names are constructed from the prefix parameter in the constructor.
// The pref names should not be changed later.
constructor(prefPrefix) {
this._prefLastDir = prefPrefix + ".lastDir";
this._prefFilterIndex = prefPrefix + ".filterIndex";
this._lastDir = null;
this._lastFilterIndex = null;
}
get path() {
if (!this._lastDir || !this._lastDir.exists()) {
try {
this._lastDir = Services.prefs.getComplexValue(this._prefLastDir,
Ci.nsIFile);
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 (!gPrivate) {
Services.prefs.setComplexValue(this._prefLastDir,
Ci.nsIFile,
this._lastDir);
}
}
get filterIndex() {
if (!this._lastFilterIndex) {
// use a pref to remember the filterIndex selected by the user.
this._lastFilterIndex =
Services.prefs.getIntPref(this._prefFilterIndex, 0);
}
return this._lastFilterIndex;
}
set filterIndex(val) {
// If the default is picked the filter is null.
this._lastFilterIndex = val ? val : 0;
// Don't save the last filter index inside the Private Browsing mode
if (!gPrivate) {
Services.prefs.setIntPref(this._prefFilterIndex,
this._lastFilterIndex);
}
}
// This is currently not used.
reset() {
this._lastDir = null;
this._lastFilterIndex = null;
}
}
var gLastOpenDirectory;
function BrowserOpenFileWindow() {
if (!gLastOpenDirectory) {
gLastOpenDirectory = new RememberLastDir("browser.open");
};
// 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 {
// Set last path and file index only if file is ok.
if (fp.file) {
gLastOpenDirectory.filterIndex = fp.filterIndex;
gLastOpenDirectory.path =
fp.file.parent.QueryInterface(Ci.nsIFile);
}
} 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.filterIndex = gLastOpenDirectory.filterIndex;
fp.displayDirectory = gLastOpenDirectory.path;
fp.open(fpCallback);
} catch (ex) {
}
}
function updateCloseItems()
{
var browser = getBrowser();
var hideCloseWindow = Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab") &&
(!browser || browser.tabContainer.childNodes.length <= 1);
document.getElementById("menu_closeWindow").hidden = hideCloseWindow;
var closeItem = document.getElementById("menu_close");
if (hideCloseWindow) {
closeItem.setAttribute("label", gNavigatorBundle.getString("tabs.close.label"));
closeItem.setAttribute("accesskey", gNavigatorBundle.getString("tabs.close.accesskey"));
} else {
closeItem.setAttribute("label", gNavigatorBundle.getString("tabs.closeTab.label"));
closeItem.setAttribute("accesskey", gNavigatorBundle.getString("tabs.closeTab.accesskey"));
}
var hideClose = !browser || !browser.getStripVisibility();
document.getElementById("menu_closeOtherTabs").hidden = hideClose;
if (!hideClose)
document.getElementById("cmd_closeOtherTabs").disabled = hideCloseWindow;
hideClose = !browser ||
(browser.getTabsToTheEndFrom(browser.mCurrentTab).length == 0);
document.getElementById("menu_closeTabsToTheEnd").hidden = hideClose;
if (!hideClose)
document.getElementById("cmd_closeTabsToTheEnd").disabled = hideClose;
}
function updateRecentMenuItems()
{
var browser = getBrowser();
var ss = Cc["@mozilla.org/suite/sessionstore;1"]
.getService(Ci.nsISessionStore);
var recentTabsItem = document.getElementById("menu_recentTabs");
recentTabsItem.setAttribute("disabled", !browser || browser.getUndoList().length == 0);
var recentWindowsItem = document.getElementById("menu_recentWindows");
recentWindowsItem.setAttribute("disabled", ss.getClosedWindowCount() == 0);
}
function updateRecentTabs(menupopup)
{
var browser = getBrowser();
while (menupopup.hasChildNodes())
menupopup.lastChild.remove();
var list = browser.getUndoList();
for (var i = 0; i < list.length; i++) {
var menuitem = document.createElement("menuitem");
var label = list[i];
if (i < 9) {
label = gNavigatorBundle.getFormattedString("tabs.recentlyClosed.format", [i + 1, label]);
menuitem.setAttribute("accesskey", i + 1);
}
if (i == 0)
menuitem.setAttribute("key", "key_restoreTab");
menuitem.setAttribute("label", label);
menuitem.setAttribute("value", i);
menupopup.appendChild(menuitem);
}
}
function updateRecentWindows(menupopup)
{
var ss = Cc["@mozilla.org/suite/sessionstore;1"]
.getService(Ci.nsISessionStore);
while (menupopup.hasChildNodes())
menupopup.lastChild.remove();
var undoItems = JSON.parse(ss.getClosedWindowData());
for (var i = 0; i < undoItems.length; i++) {
var menuitem = document.createElement("menuitem");
var label = undoItems[i].title;
if (i < 9) {
label = gNavigatorBundle.getFormattedString("windows.recentlyClosed.format", [i + 1, label]);
menuitem.setAttribute("accesskey", i + 1);
}
if (i == 0)
menuitem.setAttribute("key", "key_restoreWindow");
menuitem.setAttribute("label", label);
menuitem.setAttribute("value", i);
menupopup.appendChild(menuitem);
}
}
function undoCloseWindow(aIndex)
{
var ss = Cc["@mozilla.org/suite/sessionstore;1"]
.getService(Ci.nsISessionStore);
return ss.undoCloseWindow(aIndex);
}
function restoreLastSession() {
let ss = Cc["@mozilla.org/suite/sessionstore;1"]
.getService(Ci.nsISessionStore);
ss.restoreLastSession();
}
/*
* Determines if a tab is "empty" using isBrowserEmpty from utilityOverlay.js
*/
function isTabEmpty(aTab)
{
return isBrowserEmpty(aTab.linkedBrowser);
}
function BrowserCloseOtherTabs()
{
var browser = getBrowser();
browser.removeAllTabsBut(browser.mCurrentTab);
}
function BrowserCloseTabsToTheEnd()
{
var browser = getBrowser();
browser.removeTabsToTheEndFrom(browser.mCurrentTab);
}
function BrowserCloseTabOrWindow()
{
var browser = getBrowser();
if (browser.tabContainer.childNodes.length > 1 ||
!Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab")) {
// Just close up a tab.
browser.removeCurrentTab();
return;
}
BrowserCloseWindow();
}
function BrowserTryToCloseWindow()
{
if (WindowIsClosing())
BrowserCloseWindow();
}
function BrowserCloseWindow()
{
// This code replicates stuff in Shutdown(). It is here because
// window.screenX and window.screenY have real values. We need
// to fix this eventually but by replicating the code here, we
// provide a means of saving position (it just requires that the
// user close the window via File->Close (vs. close box).
// Get the current window position/size.
var x = window.screenX;
var y = window.screenY;
var h = window.outerHeight;
var w = window.outerWidth;
// Store these into the window attributes (for persistence).
var win = document.getElementById( "main-window" );
win.setAttribute( "x", x );
win.setAttribute( "y", y );
win.setAttribute( "height", h );
win.setAttribute( "width", w );
window.close();
}
function loadURI(uri, referrer, postData, allowThirdPartyFixup, referrerPolicy,
userContextId, originPrincipal,
forceAboutBlankViewerInCurrent, triggeringPrincipal) {
try {
openLinkIn(uri, "current",
{ referrerURI: referrer,
referrerPolicy: referrerPolicy,
postData: postData,
allowThirdPartyFixup: allowThirdPartyFixup,
userContextId: userContextId,
originPrincipal,
triggeringPrincipal,
forceAboutBlankViewerInCurrent, });
} catch (e) {}
}
function loadOneOrMoreURIs(aURIString, aTriggeringPrincipal) {
// 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;
}
// This function throws for certain malformed URIs, so use exception handling
// so that we don't disrupt startup
try {
gBrowser.loadTabs(aURIString.split("|"), {
inBackground: false,
replace: true,
triggeringPrincipal: aTriggeringPrincipal,
});
} catch (e) {
}
}
function handleURLBarCommand(aUserAction, aTriggeringEvent)
{
// Remove leading and trailing spaces first
var url = gURLBar.value.trim();
try {
addToUrlbarHistory(url);
} catch (ex) {
// Things may go wrong when adding url to the location bar history,
// but don't let that interfere with the loading of the url.
}
if (url.match(/^view-source:/)) {
gViewSourceUtils.viewSource(url.replace(/^view-source:/, ""), null, null);
return;
}
getShortcutOrURIAndPostData(url).then(data => {
// Check the pressed modifiers: (also see bug 97123)
// Modifier Mac | Modifier PC | Action
// -------------+-------------+-----------
// Command | Control | New Window/Tab
// Shift+Cmd | Shift+Ctrl | New Window/Tab behind current one
// Option | Shift | Save URL (show Filepicker)
// If false, the save modifier is Alt, which is Option on Mac.
var modifierIsShift = Services.prefs.getBoolPref("ui.key.saveLink.shift", true);
var shiftPressed = false;
var saveModifier = false; // if the save modifier was pressed
if (aTriggeringEvent && 'shiftKey' in aTriggeringEvent &&
'altKey' in aTriggeringEvent) {
saveModifier = modifierIsShift ? aTriggeringEvent.shiftKey
: aTriggeringEvent.altKey;
shiftPressed = aTriggeringEvent.shiftKey;
}
var browser = getBrowser();
// Accept both Control and Meta (=Command) as New-Window-Modifiers
if (aTriggeringEvent &&
(('ctrlKey' in aTriggeringEvent && aTriggeringEvent.ctrlKey) ||
('metaKey' in aTriggeringEvent && aTriggeringEvent.metaKey) ||
('button' in aTriggeringEvent && aTriggeringEvent.button == 1))) {
// Check if user requests Tabs instead of windows
if (Services.prefs.getBoolPref("browser.tabs.opentabfor.urlbar", false)) {
// Reset url in the urlbar
URLBarSetURI();
// Open link in new tab
var t = browser.addTab(data.url, {
postData: data.postData,
allowThirdPartyFixup: true,
});
// Focus new tab unless shift is pressed
if (!shiftPressed)
browser.selectedTab = t;
} else {
// Open a new window with the URL
var newWin = openDialog(getBrowserURL(), "_blank", "all,dialog=no", data.url,
null, null, data.postData, true);
// Reset url in the urlbar
URLBarSetURI();
// Focus old window if shift was pressed, as there's no
// way to open a new window in the background
// XXX this doesn't seem to work
if (shiftPressed) {
//newWin.blur();
content.focus();
}
}
} else if (saveModifier) {
try {
// Firstly, fixup the url so that (e.g.) "www.foo.com" works
url = Services.uriFixup.createFixupURI(data.url, Ci.nsIURIFixup.FIXUP_FLAGS_MAKE_ALTERNATE_URI).spec;
// Open filepicker to save the url
saveURL(url, null, null, false, true, null, document);
}
catch(ex) {
// XXX Do nothing for now.
// Do we want to put up an alert in the future? Mmm, l10n...
}
} else {
// No modifier was pressed, load the URL normally and
// focus the content area
loadURI(data.url, null, data.postData, true);
content.focus();
}
});
}
/**
* Given a string, will generate a more appropriate urlbar value if a Places
* keyword or a search alias is found at the beginning of it.
*
* @param url
* A string that may begin with a keyword or an alias.
*
* @return {Promise}
* @resolves { url, postData, mayInheritPrincipal }. If it's not possible
* to discern a keyword or an alias, url will be the input string.
*/
function getShortcutOrURIAndPostData(url) {
return (async function() {
let mayInheritPrincipal = false;
let postData = null;
// Split on the first whitespace.
let [keyword, param = ""] = url.trim().split(/\s(.+)/, 2);
if (!keyword) {
return { url, postData, mayInheritPrincipal };
}
let engine = Services.search.getEngineByAlias(keyword);
if (engine) {
let submission = engine.getSubmission(param, null, "keyword");
return { url: submission.uri.spec,
postData: submission.postData,
mayInheritPrincipal };
}
// A corrupt Places database could make this throw, breaking navigation
// from the location bar.
let entry = null;
try {
entry = await PlacesUtils.keywords.fetch(keyword);
} catch (ex) {
Cu.reportError(`Unable to fetch Places keyword "${keyword}": ${ex}`);
}
if (!entry || !entry.url) {
// This is not a Places keyword.
return { url, postData, mayInheritPrincipal };
}
try {
[url, postData] =
await BrowserUtils.parseUrlAndPostData(entry.url.href,
entry.postData,
param);
if (postData) {
postData = getPostDataStream(postData);
}
// Since this URL came from a bookmark, it's safe to let it inherit the
// current document's principal.
mayInheritPrincipal = true;
} catch (ex) {
// It was not possible to bind the param, just use the original url value.
}
return { url, postData, mayInheritPrincipal };
})().then(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.setData(dataStream);
return mimeStream.QueryInterface(Ci.nsIInputStream);
}
// handleDroppedLink has the following 2 overloads:
// handleDroppedLink(event, url, name, triggeringPrincipal)
// handleDroppedLink(event, links, triggeringPrincipal)
function handleDroppedLink(event, urlOrLinks, nameOrTriggeringPrincipal, triggeringPrincipal)
{
let links;
if (Array.isArray(urlOrLinks)) {
links = urlOrLinks;
triggeringPrincipal = nameOrTriggeringPrincipal;
} else {
links = [{ url: urlOrLinks, nameOrTriggeringPrincipal, type: "" }];
}
let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
// Usually blank for SeaMonkey.
let userContextId = gBrowser.selectedBrowser.getAttribute("usercontextid");
// event is null if links are dropped in content process.
// inBackground should be false, as it's loading into current browser.
let inBackground = false;
if (event) {
inBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
if (event.shiftKey)
inBackground = !inBackground;
}
(async function() {
let urls = [];
let postDatas = [];
for (let link of links) {
let data = await 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,
userContextId,
triggeringPrincipal,
});
}
})();
// If links are dropped in content process, event.preventDefault() should be
// called in content process.
if (event) {
// Keep the event from being handled by the dragDrop listeners
// built-in to gecko if they happen to be above us.
event.preventDefault();
}
}
function readFromClipboard()
{
var url;
try {
// Get the clipboard.
const clipboard = Services.clipboard;
// Create a transferable that will transfer the text.
var trans = Cc["@mozilla.org/widget/transferable;1"]
.createInstance(Ci.nsITransferable);
trans.init(null);
trans.addDataFlavor("text/unicode");
// If available, use the selection clipboard, otherwise use the global one.
if (clipboard.supportsSelectionClipboard())
clipboard.getData(trans, clipboard.kSelectionClipboard);
else
clipboard.getData(trans, clipboard.kGlobalClipboard);
var data = {};
trans.getTransferData("text/unicode", data, {});
if (data.value) {
data = data.value.QueryInterface(Ci.nsISupportsString);
url = data.data;
}
} catch (ex) {
}
return url;
}
/**
* Open the View Source dialog.
*
* @param aArgsOrDocument
* Either an object or a Document. Passing a Document is deprecated,
* and is not supported with e10s. This function will throw if
* aArgsOrDocument is a CPOW.
*
* If aArgsOrDocument is an object, that object can take the
* following properties:
*
* URL (required):
* A string URL for the page we'd like to view the source of.
* browser (optional):
* The browser containing the document that we would like to view the
* source of. This is required if outerWindowID is passed.
* outerWindowID (optional):
* The outerWindowID of the content window containing the document that
* we want to view the source of. You only need to provide this if you
* want to attempt to retrieve the document source from the network
* cache.
* lineNumber (optional):
* The line number to focus on once the source is loaded.
*/
function BrowserViewSourceOfDocument(aArgsOrDocument) {
if (aArgsOrDocument instanceof Document) {
// Deprecated API - callers should pass args object instead.
if (Cu.isCrossProcessWrapper(aArgsOrDocument)) {
throw new Error("BrowserViewSourceOfDocument cannot accept a CPOW " +
"as a document.");
}
let requestor = aArgsOrDocument.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;
aArgsOrDocument = { browser, outerWindowID, URL };
}
gViewSourceUtils.viewSource(aArgsOrDocument);
}
/**
* Opens the View Source dialog for the source loaded in the root
* top-level document of the browser.
*
* @param aBrowser
* The browser that we want to load the source of.
*/
function BrowserViewSource(aBrowser) {
gViewSourceUtils.viewSource({
browser: aBrowser,
outerWindowID: aBrowser.outerWindowID,
URL: aBrowser.currentURI.spec,
});
}
// documentURL - URL of the document to view, or null for this window's document
// initialTab - id 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
// frameOuterWindowID - the id of the frame that the context menu opened in;
// can be null/omitted
// browser - the browser containing the document we're interested in inspecting;
// can be null/omitted
function BrowserPageInfo(documentURL, initialTab, imageElement,
frameOuterWindowID, browser) {
if (documentURL instanceof HTMLDocument) {
Deprecated.warning("Please pass the location URL instead of the document " +
"to BrowserPageInfo() as the first argument.",
documentURL = documentURL.location;
}
let args = { initialTab, imageElement, frameOuterWindowID, browser };
var windows = Services.wm.getEnumerator("Browser:page-info");
documentURL = documentURL || window.gBrowser.selectedBrowser.currentURI.spec;
// Check for windows matching the url.
while (windows.hasMoreElements()) {
let win = windows.getNext();
if (win.closed) {
continue;
}
if (win.document.documentElement
.getAttribute("relatedUrl") == documentURL) {
win.focus();
win.resetPageInfo(args);
return win;
}
}
// We didn't find a matching window, so open a new one.
"_blank",
"chrome,dialog=no,resizable",
args);
}
function hiddenWindowStartup()
{
// focus the hidden window
window.focus();
// Disable menus which are not appropriate
var disabledItems = ['cmd_close', 'cmd_sendPage', 'Browser:SendLink',
'Browser:EditPage', 'Browser:SavePage', 'cmd_printSetup',
'cmd_print', 'canGoBack', 'canGoForward',
'Browser:AddBookmark', 'Browser:AddBookmarkAs',
'cmd_undo', 'cmd_redo', 'cmd_cut', 'cmd_copy',
'cmd_paste', 'cmd_delete', 'cmd_selectAll',
'cmd_findTypeText', 'cmd_findTypeLinks', 'cmd_find',
'cmd_findNext', 'cmd_findPrev', 'menu_Toolbars',
'menuitem_reload', 'menu_UseStyleSheet', 'charsetMenu',
'View:PageSource', 'View:PageInfo', 'menu_translate',
'cookie_deny', 'cookie_default', 'View:FullScreen',
'cookie_session', 'cookie_allow', 'image_deny',
'image_default', 'image_allow', 'popup_deny',
'popup_default','popup_allow', 'menu_zoom',
'cmd_minimizeWindow', 'cmd_zoomWindow'];
var broadcaster;
for (var id in disabledItems) {
broadcaster = document.getElementById(disabledItems[id]);
if (broadcaster)
broadcaster.setAttribute("disabled", "true");
}
// also hide the window list separator
var separator = document.getElementById("sep-window-list");
if (separator)
separator.setAttribute("hidden", "true");
// init string bundles
gNavigatorBundle = document.getElementById("bundle_navigator");
gNavigatorRegionBundle = document.getElementById("bundle_navigator_region");
gBrandBundle = document.getElementById("bundle_brand");
}
function checkForDirectoryListing()
{
if ( "HTTPIndex" in content &&
content.HTTPIndex instanceof Ci.nsIHTTPIndex ) {
var forced = getBrowser().docShell.forcedCharset;
if (forced) {
content.defaultCharacterset = forced;
}
}
}
function URLBarSetURI(aURI, aValid) {
var uri = aURI || getWebNavigation().currentURI;
var value;
// If the url has "wyciwyg://" as the protocol, strip it off.
// Nobody wants to see it on the urlbar for dynamically generated pages.
try {
uri = Services.uriFixup.createExposableURI(uri);
} catch (ex) {}
// Replace "about:blank" and other initial pages with an empty string
// only if there's no opener (bug 370555).
if (gInitialPages.has(uri.spec))
value = (content.opener || getWebNavigation().canGoBack) ? uri.spec : "";
else
value = losslessDecodeURI(uri);
gURLBar.value = value;
// In some cases, setting the urlBar value causes userTypedValue to
// become set because of oninput, so reset it to null.
getBrowser().userTypedValue = null;
SetPageProxyState((value && (!aURI || aValid)) ? "valid" : "invalid", uri);
}
function losslessDecodeURI(aURI) {
var value = aURI.displaySpec;
var scheme = aURI.scheme;
var decodeASCIIOnly = !["https", "http", "file", "ftp"].includes(scheme);
// 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. Ee-encode all adjacent whitespace, to prevent spoofing
// attempts where invisible characters would push part of
// the URL to overflow the location bar (bug 1395508).
.replace(/%(?!3B|2F|3F|3A|40|26|3D|2B|24|2C|23)|\s(?=\s)|\s$/ig,
encodeURIComponent);
} catch (e) {}
}
}
// Encode invisible characters (soft hyphen, zero-width space, BOM,
// line and paragraph separator, word joiner, invisible times,
// invisible separator, object replacement character,
// C0/C1 controls). (bug 452979, bug 909264)
// Encode bidirectional formatting characters.
// (RFC 3987 sections 3.2 and 4.1 paragraph 6)
// Re-encode whitespace so that it doesn't get eaten away
// by the location bar (bug 410726).
return value.replace(/[\u0000-\u001f\u007f-\u00a0\u00ad\u034f\u061c\u115f\u1160\u17b4\u17b5\u180b-\u180d\u200b\u200e\u200f\u2028-\u202e\u2060-\u206f\u3164\ufe00-\ufe0f\ufeff\uffa0\ufff0-\ufff8\ufffc]|\ud834[\udd73-\udd7a]|[\udb40-\udb43][\udc00-\udfff]/g, encodeURIComponent);
}
/**
* Use Stylesheet functions.
* Written by Tim Hill (bug 6782)
* Frameset handling by Neil Rashbrook <neil@parkwaycc.co.uk>
**/
/**
* Adds this frame's stylesheet sets to the View > Use Style submenu
*
* If the frame has no preferred stylesheet set then the "Default style"
* menuitem should be shown. Note that it defaults to checked, hidden.
*
* If this frame has a selected stylesheet set then its menuitem should
* be checked (unless the "None" style is currently selected), and the
* "Default style" menuitem should to be unchecked.
*
* The stylesheet sets may match those of other frames. In that case, the
* checkmark should be removed from sets that are not selected in this frame.
*
* @param menuPopup The submenu's popup child
* @param frame The frame whose sets are to be added
* @param styleDisabled True if the "None" style is currently selected
* @param itemPersistentOnly The "Default style" menuitem element
*/
function stylesheetFillFrame(menuPopup, frame, styleDisabled, itemPersistentOnly)
{
if (!frame.document.preferredStyleSheetSet)
itemPersistentOnly.hidden = false;
var title = frame.document.selectedStyleSheetSet;
if (title)
itemPersistentOnly.removeAttribute("checked");
var styleSheetSets = frame.document.styleSheetSets;
for (var i = 0; i < styleSheetSets.length; i++) {
var styleSheetSet = styleSheetSets[i];
var menuitem = menuPopup.getElementsByAttribute("data", styleSheetSet).item(0);
if (menuitem) {
if (styleSheetSet != title)
menuitem.removeAttribute("checked");
} else {
var menuItem = document.createElement("menuitem");
menuItem.setAttribute("type", "radio");
menuItem.setAttribute("label", styleSheetSet);
menuItem.setAttribute("data", styleSheetSet);
menuItem.setAttribute("checked", styleSheetSet == title && !styleDisabled);
menuPopup.appendChild(menuItem);
}
}
}
/**
* Adds all available stylesheet sets to the View > Use Style submenu
*
* If all frames have preferred stylesheet sets then the "Default style"
* menuitem should remain hidden, otherwise it should be shown, and
* if some frames have a selected stylesheet then the "Default style"
* menuitem should be unchecked, otherwise it should remain checked.
*
* A stylesheet set's menuitem should not be checked if the "None" style
* is currently selected. Otherwise a stylesheet set may be available in
* more than one frame. In such a case the menuitem should only be checked
* if it is selected in all frames in which it is available.
*
* @param menuPopup The submenu's popup child
* @param frameset The frameset whose sets are to be added
* @param styleDisabled True if the "None" style is currently selected
* @param itemPersistentOnly The "Default style" menuitem element
*/
function stylesheetFillAll(menuPopup, frameset, styleDisabled, itemPersistentOnly)
{
stylesheetFillFrame(menuPopup, frameset, styleDisabled, itemPersistentOnly);
for (var i = 0; i < frameset.frames.length; i++) {
stylesheetFillAll(menuPopup, frameset.frames[i], styleDisabled, itemPersistentOnly);
}
}
/**
* Populates the View > Use Style submenu with all available stylesheet sets
* @param menuPopup The submenu's popup child
*/
function stylesheetFillPopup(menuPopup)
{
/* Clear menu */
var itemPersistentOnly = menuPopup.firstChild.nextSibling;
while (itemPersistentOnly.nextSibling)
itemPersistentOnly.nextSibling.remove();
/* Reset permanent items */
var styleDisabled = getMarkupDocumentViewer().authorStyleDisabled;
menuPopup.firstChild.setAttribute("checked", styleDisabled);
itemPersistentOnly.setAttribute("checked", !styleDisabled);
itemPersistentOnly.hidden = true;
stylesheetFillAll(menuPopup, window.content, styleDisabled, itemPersistentOnly);
}
/**
* Switches all frames in a frameset to the same stylesheet set
*
* Only frames that support the given title will be switched
*
* @param frameset The frameset whose frames are to be switched
* @param title The name of the stylesheet set to switch to
*/
function stylesheetSwitchAll(frameset, title) {
if (!title || frameset.document.styleSheetSets.contains(title)) {
frameset.document.selectedStyleSheetSet = title;
}
for (var i = 0; i < frameset.frames.length; i++) {
stylesheetSwitchAll(frameset.frames[i], title);
}
}
function setStyleDisabled(disabled) {
getMarkupDocumentViewer().authorStyleDisabled = disabled;
}
function URLBarFocusHandler(aEvent)
{
if (gIgnoreFocus)
gIgnoreFocus = false;
else if (gClickSelectsAll)
gURLBar.select();
}
function URLBarMouseDownHandler(aEvent)
{
if (gURLBar.hasAttribute("focused")) {
gIgnoreClick = true;
} else {
gIgnoreFocus = true;
gIgnoreClick = false;
gURLBar.setSelectionRange(0, 0);
}
}
function URLBarClickHandler(aEvent)
{
if (!gIgnoreClick && gClickSelectsAll && gURLBar.selectionStart == gURLBar.selectionEnd)
if (gClickAtEndSelects || gURLBar.selectionStart < gURLBar.value.length)
gURLBar.select();
}
function ShowAndSelectContentsOfURLBar()
{
if (!isElementVisible(gURLBar)) {
BrowserOpenWindow();
return;
}
if (gURLBar.value)
gURLBar.select();
else
gURLBar.focus();
}
// If "ESC" is pressed in the url bar, we replace the urlbar's value with the url of the page
// and highlight it, unless it is about:blank, where we reset it to "".
function handleURLBarRevert()
{
var url = getWebNavigation().currentURI.spec;
var throbberElement = document.getElementById("navigator-throbber");
var isScrolling = gURLBar.userAction == "scrolling";
// don't revert to last valid url unless page is NOT loading
// and user is NOT key-scrolling through autocomplete list
if (!throbberElement.hasAttribute("busy") && !isScrolling) {
URLBarSetURI();
// If the value isn't empty, select it.
if (gURLBar.value)
gURLBar.select();
}
// tell widget to revert to last typed text only if the user
// was scrolling when they hit escape
return isScrolling;
}
function UpdatePageProxyState()
{
if (gURLBar.value != gLastValidURLStr)
SetPageProxyState("invalid", null);
}
function SetPageProxyState(aState, aURI)
{
if (!gProxyButton)
gProxyButton = document.getElementById("page-proxy-button");
if (!gProxyFavIcon)
gProxyFavIcon = document.getElementById("page-proxy-favicon");
if (!gProxyDeck)
gProxyDeck = document.getElementById("page-proxy-deck");
gProxyButton.setAttribute("pageproxystate", aState);
if (aState == "valid") {
gLastValidURLStr = gURLBar.value;
gURLBar.addEventListener("input", UpdatePageProxyState);
if (gBrowser.shouldLoadFavIcon(aURI)) {
var favStr = gBrowser.buildFavIconString(aURI);
if (favStr != gProxyFavIcon.src) {
gBrowser.loadFavIcon(aURI, "src", gProxyFavIcon);
gProxyDeck.selectedIndex = 0;
}
else gProxyDeck.selectedIndex = 1;
}
else {
gProxyDeck.selectedIndex = 0;
gProxyFavIcon.removeAttribute("src");
}
} else if (aState == "invalid") {
gURLBar.removeEventListener("input", UpdatePageProxyState);
gProxyDeck.selectedIndex = 0;
gProxyFavIcon.removeAttribute("src");
}
}
function handlePageProxyClick(aEvent)
{
switch (aEvent.button) {
case 0:
// bug 52784 - select location field contents
gURLBar.select();
break;
case 1:
// bug 111337 - load url/keyword from clipboard
middleMousePaste(aEvent);
break;
}
}
function updateComponentBarBroadcaster()
{
var compBarBroadcaster = document.getElementById('cmd_viewcomponentbar');
var taskBarBroadcaster = document.getElementById('cmd_viewtaskbar');
var compBar = document.getElementById('component-bar');
if (taskBarBroadcaster.getAttribute('checked') == 'true') {
compBarBroadcaster.removeAttribute('disabled');
if (compBar.getAttribute('hidden') != 'true')
compBarBroadcaster.setAttribute('checked', 'true');
}
else {
compBarBroadcaster.setAttribute('disabled', 'true');
compBarBroadcaster.removeAttribute('checked');
}
}
function updateToolbarStates(aEvent)
{
onViewToolbarsPopupShowing(aEvent);
updateComponentBarBroadcaster();
const tabbarMenuItem = document.getElementById("menuitem_showhide_tabbar");
// Make show/hide menu item reflect current state
const visibility = gBrowser.getStripVisibility();
tabbarMenuItem.setAttribute("checked", visibility);
// Don't allow the tab bar to be shown/hidden when more than one tab is open
// or when we have 1 tab and the autoHide pref is set
const disabled = gBrowser.browsers.length > 1 ||
Services.prefs.getBoolPref("browser.tabs.autoHide");
tabbarMenuItem.setAttribute("disabled", disabled);
}
function showHideTabbar()
{
const visibility = gBrowser.getStripVisibility();
Services.prefs.setBoolPref("browser.tabs.forceHide", visibility);
gBrowser.setStripVisibilityTo(!visibility);
}
function BrowserFullScreen()
{
window.fullScreen = !window.fullScreen;
}
function onFullScreen()
{
FullScreen.toggle();
}
function UpdateStatusBarPopupIcon(aEvent)
{
if (aEvent && aEvent.originalTarget != gBrowser.getNotificationBox())
return;
var showIcon = Services.prefs.getBoolPref("privacy.popups.statusbar_icon_enabled");
if (showIcon) {
var popupIcon = document.getElementById("popupIcon");
popupIcon.hidden = !gBrowser.getNotificationBox().popupCount;
}
}
function StatusbarViewPopupManager()
{
// Open Data Manager permissions pane site and type prefilled to add.
toDataManager(hostUrl() + "|permissions|add|popup");
}
function popupBlockerMenuShowing(event)
{
var separator = document.getElementById("popupMenuSeparator");
if (separator)
separator.hidden = !createShowPopupsMenu(event.target, gBrowser.selectedBrowser);
}
function WindowIsClosing()
{
var browser = getBrowser();
var cn = browser.tabContainer.childNodes;
var numtabs = cn.length;
if (!gPrivate && AppConstants.platform != "macosx" && isClosingLastBrowser()) {
let closingCanceled = Cc["@mozilla.org/supports-PRBool;1"]
.createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(closingCanceled, "browser-lastwindow-close-requested");
if (closingCanceled.data)
return false;
Services.obs.notifyObservers(null, "browser-lastwindow-close-granted");
return true;
}
var reallyClose = gPrivate ||
browser.warnAboutClosingTabs(browser.closingTabsEnum.ALL);
for (var i = 0; reallyClose && i < numtabs; ++i) {
var ds = browser.getBrowserForTab(cn[i]).docShell;
if (ds.contentViewer && !ds.contentViewer.permitUnload())
reallyClose = false;
}
return reallyClose;
}
/**
* Checks whether this is the last full *browser* window around.
* @returns true if closing last browser window, false if not.
*/
function isClosingLastBrowser() {
// Popups aren't considered full browser windows.
if (!toolbar.visible)
return false;
// Figure out if there's at least one other browser window around.
var e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
let win = e.getNext();
if (!win.closed && win != window && win.toolbar.visible)
return false;
}
return true;
}
/**
* file upload support
*/
/* This function returns the URI of the currently focused content frame
* or frameset.
*/
function getCurrentURI()
{
var focusedWindow = document.commandDispatcher.focusedWindow;
var contentFrame = isContentFrame(focusedWindow) ? focusedWindow : window.content;
var nav = contentFrame.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation);
return nav.currentURI;
}
var gLastOpenUploadDirectory;
function BrowserUploadFile()
{
if (!gLastOpenUploadDirectory) {
gLastOpenUploadDirectory = new RememberLastDir("browser.upload");
};
const nsIFilePicker = Ci.nsIFilePicker;
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
fp.init(window, gNavigatorBundle.getString("uploadFile"), nsIFilePicker.modeOpen);
fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText | nsIFilePicker.filterImages |
nsIFilePicker.filterXML | nsIFilePicker.filterHTML);
// use a pref to remember the filterIndex selected by the user.
fp.filterIndex = gLastOpenUploadDirectory.filterIndex;
// Use a pref to remember the displayDirectory selected by the user.
fp.displayDirectory = gLastOpenUploadDirectory.path;
fp.open(rv => {
if (rv != nsIFilePicker.returnOK || !fp.fileURL) {
return;
}
gLastOpenUploadDirectory.filterIndex = fp.filterIndex;
gLastOpenUploadDirectory.path = fp.file.parent.QueryInterface(Ci.nsIFile);
try {
var targetBaseURI = getCurrentURI();
// Generate the target URI. We use fileURL.file.leafName to get the
// unicode value of the target filename w/o any URI-escaped chars.
// this gives the protocol handler the best chance of generating a
// properly formatted URI spec. we pass null for the origin charset
// parameter since we want the URI to inherit the origin charset
// property from targetBaseURI.
var leafName = fp.fileURL.QueryInterface(Ci.nsIFileURL).file.leafName;
var targetURI = Services.io.newURI(leafName, null, targetBaseURI);
// ok, start uploading...
"titlebar,centerscreen,minimizable,dialog=no", fp.fileURL, targetURI);
} catch (e) {}
});
}
/* This function is called whenever the file menu is about to be displayed.
* Enable the upload menu item if appropriate. */
function updateFileUploadItem()
{
var canUpload = false;
try {
canUpload = getCurrentURI().schemeIs('ftp');
} catch (e) {}
var item = document.getElementById('Browser:UploadFile');
if (canUpload)
item.removeAttribute('disabled');
else
item.setAttribute('disabled', 'true');
}
function isBidiEnabled()
{
// first check the pref.
if (Services.prefs.getBoolPref("bidi.browser.ui", false)) {
return true;
}
// now see if the app locale is an RTL one.
const isRTL = Services.locale.isAppLocaleRTL;
if (isRTL) {
Services.prefs.setBoolPref("bidi.browser.ui", true);
}
return isRTL;
}
function SwitchDocumentDirection(aWindow)
{
aWindow.document.dir = (aWindow.document.dir == "ltr" ? "rtl" : "ltr");
for (var run = 0; run < aWindow.frames.length; run++)
SwitchDocumentDirection(aWindow.frames[run]);
}
function updateSavePageItems()
{
var autoDownload = Services.prefs
.getBoolPref("browser.download.useDownloadDir");
goSetMenuValue("savepage", autoDownload ? "valueSave" : "valueSaveAs");
}
function convertFromUnicode(charset, str)
{
try {
var unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
unicodeConverter.charset = charset;
str = unicodeConverter.ConvertFromUnicode(str);
return str + unicodeConverter.Finish();
} catch(ex) {
return null;
}
}
function getNotificationBox(aWindow)
{
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler.parentNode.wrappedJSObject;
}
function BrowserToolboxCustomizeInit()
{
SetPageProxyState("invalid", null);
toolboxCustomizeInit("main-menubar");
PlacesToolbarHelper.customizeStart();
var splitter = document.getElementById("urlbar-search-splitter");
if (splitter)
splitter.remove();
}
function BrowserToolboxCustomizeDone(aToolboxChanged)
{
toolboxCustomizeDone("main-menubar", getNavToolbox(), aToolboxChanged);
UpdateNavBar();
// Update the urlbar
var value = gBrowser.userTypedValue;
if (value == null)
URLBarSetURI();
else
gURLBar.value = value;
PlacesToolbarHelper.customizeDone();
}
function BrowserToolboxCustomizeChange(event)
{
toolboxCustomizeChange(getNavToolbox(), event);
}
var LightWeightThemeWebInstaller = {
handleEvent: function (event) {
switch (event.type) {
case "InstallBrowserTheme":
case "PreviewBrowserTheme":
case "ResetBrowserThemePreview":
// ignore requests from background tabs
if (event.target.ownerDocument.defaultView.top != content)
return;
}
switch (event.type) {
case "InstallBrowserTheme":
this._installRequest(event);
break;
case "PreviewBrowserTheme":
this._preview(event);
break;
case "ResetBrowserThemePreview":
this._resetPreview(event);
break;
case "pagehide":
case "TabSelect":
this._resetPreview();
break;
}
},
get _manager () {
delete this._manager;
return this._manager = LightweightThemeManager;
},
_installRequest: function (event) {
var node = event.target;
var data = this._getThemeFromNode(node);
if (!data)
return;
if (this._isAllowed(node)) {
this._install(data);
return;
}
this._removePreviousNotifications();
getBrowser().getNotificationBox().lwthemeInstallRequest(
node.ownerDocument.location.host,
this._install.bind(this, data));
},
_install: function (newTheme) {
this._removePreviousNotifications();
var previousTheme = this._manager.currentTheme;
this._manager.currentTheme = newTheme;
if (this._manager.currentTheme &&
this._manager.currentTheme.id == newTheme.id)
getBrowser().getNotificationBox().lwthemeInstallNotification(function() {
LightWeightThemeWebInstaller._manager.forgetUsedTheme(newTheme.id);
LightWeightThemeWebInstaller._manager.currentTheme = previousTheme;
});
else
getBrowser().getNotificationBox().lwthemeNeedsRestart(newTheme.name);
// We've already destroyed the permission notification,
// so tell the former that it's closed already.
return true;
},
_removePreviousNotifications: function () {
getBrowser().getNotificationBox().removeNotifications(
["lwtheme-install-request", "lwtheme-install-notification"]);
},
_previewWindow: null,
_preview: function (event) {
if (!this._isAllowed(event.target))
return;
var data = this._getThemeFromNode(event.target);
if (!data)
return;
this._resetPreview();
this._previewWindow = event.target.ownerDocument.defaultView;
this._previewWindow.addEventListener("pagehide", this, true);
gBrowser.tabContainer.addEventListener("TabSelect", this);
this._manager.previewTheme(data);
},
_resetPreview: function (event) {
if (!this._previewWindow ||
event && !this._isAllowed(event.target))
return;
this._previewWindow.removeEventListener("pagehide", this, true);
this._previewWindow = null;
gBrowser.tabContainer.removeEventListener("TabSelect", this);
this._manager.resetPreview();
},
_isAllowed: function (node) {
var uri = node.ownerDocument.documentURIObject;
return Services.perms.testPermission(uri, "install") == Services.perms.ALLOW_ACTION;
},
_getThemeFromNode: function (node) {
return this._manager.parseTheme(node.getAttribute("data-browsertheme"),
node.baseURI);
}
}
function AddKeywordForSearchField() {
var node = document.popupNode;
var doc = node.ownerDocument;
var charset = doc.characterSet;
var title = gNavigatorBundle.getFormattedString("addKeywordTitleAutoFill",
[doc.title]);
var description = PlacesUIUtils.getDescriptionFromDocument(doc);
var postData = null;
var form = node.form;
var spec = form.action || doc.documentURI;
function encodeNameValuePair(aName, aValue) {
return encodeURIComponent(aName) + "=" + encodeURIComponent(aValue);
}
let el = null;
let type = null;
let formData = [];
for (var i = 0; i < form.elements.length; i++) {
el = form.elements[i];
if (!el.type) // happens with fieldsets
continue;
if (el == node) {
formData.push(encodeNameValuePair(el.name, "") + "%s");
continue;
}
type = el.type;
if (((el instanceof HTMLInputElement && el.mozIsTextField(true)) ||
type == "hidden" || type == "textarea") ||
((type == "checkbox" || type == "radio") && el.checked)) {
formData.push(encodeNameValuePair(el.name, el.value));
} else if (el instanceof HTMLSelectElement && el.selectedIndex >= 0) {
for (var j = 0; j < el.options.length; j++) {
if (el.options[j].selected)
formData.push(encodeNameValuePair(el.name, el.options[j].value));
}
}
}
if (form.method == "post" &&
form.enctype == "application/x-www-form-urlencoded") {
postData = formData.join("&");
} else { // get
spec += spec.includes("?") ? "&" : "?";
spec += formData.join("&");
}
PlacesUIUtils.showMinimalAddBookmarkUI(makeURI(spec), title, description, null,
null, null, "", postData, charset);
}
function getCert()
{
var sslStatus = getBrowser().securityUI
.QueryInterface(Ci.nsISSLStatusProvider)
.SSLStatus;
return sslStatus && sslStatus.serverCert;
}
function viewCertificate()
{
var cert = getCert();
if (cert)
{
Cc["@mozilla.org/nsCertificateDialogs;1"]
.getService(Ci.nsICertificateDialogs)
.viewCert(window, cert);
}
}
function openCertManager()
{
toOpenWindowByType("mozilla:certmanager", "chrome://pippki/content/certManager.xul",
"resizable,dialog=no,centerscreen");
}
function onViewSecurityContextMenu()
{
document.getElementById("viewCertificate").disabled = !getCert();
}
function updateZoomStatus() {
let newLabel = Math.round(ZoomManager.zoom * 100) + " %";
let zoomStatusElement = document.getElementById("zoomLevel-display");
if (zoomStatusElement.getAttribute('label') != newLabel){
zoomStatusElement.setAttribute('label', newLabel);
}
}
function zoomIn() {
FullZoom.enlarge();
updateZoomStatus();
}
function zoomOut() {
FullZoom.reduce();
updateZoomStatus();
}
/**
* Determine whether or not a given focused DOMWindow is in the content area.
**/
function isContentFrame(aFocusedWindow) {
if (!aFocusedWindow)
return false;
return (aFocusedWindow.top == window.content);
}
var browserDragAndDrop = {
canDropLink: aEvent => Services.droppedLinkHandler.canDropLink(aEvent, true),
dragOver(aEvent) {
if (this.canDropLink(aEvent)) {
aEvent.preventDefault();
}
},
getTriggeringPrincipal(aEvent) {
return Services.droppedLinkHandler.getTriggeringPrincipal(aEvent);
},
dropLinks(aEvent, aDisallowInherit) {
return Services.droppedLinkHandler.dropLinks(aEvent, aDisallowInherit);
}
};