releases-comm-central/suite/browser/navigator.js

2804 строки
89 KiB
JavaScript

/* -*- 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/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/DownloadTaskbarProgress.jsm");
Components.utils.import("resource:///modules/WindowsPreviewPerTab.jsm");
__defineGetter__("PluralForm", function() {
Components.utils.import("resource://gre/modules/PluralForm.jsm");
return this.PluralForm;
});
__defineSetter__("PluralForm", function (val) {
delete this.PluralForm;
return this.PluralForm = val;
});
XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
"resource://gre/modules/SafeBrowsing.jsm");
const REMOTESERVICE_CONTRACTID = "@mozilla.org/toolkit/remote-service;1";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
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;
var gURIFixup = null;
var gInitialPages = new Set([
"about:blank",
"about:privatebrowsing",
"about:sessionrestore"
]);
//cached elements
var gBrowser = null;
const 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);
}
}
};
const 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();
}
};
const 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;
}
};
// popup window permission change listener
const gPopupPermListener = {
observe: function(subject, topic, data) {
if (topic == "popup-perm-close") {
// close the window if we're a popup and our opener's URI matches
// the URI in the notification
var popupOpenerURI = maybeInitPopupContext();
if (popupOpenerURI) {
closeURI = Services.io.newURI(data, null, null);
if (closeURI.host == popupOpenerURI.host)
window.close();
}
}
}
};
const gFormSubmitObserver = {
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIFormSubmitObserver,
Components.interfaces.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, Components.interfaces.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, false);
element.addEventListener("blur", blurHandler, false);
// One event to bring them all and in the darkness bind them.
this.panel.addEventListener("popuphiding", function popupHidingHandler(aEvent) {
aEvent.target.removeEventListener("popuphiding", popupHidingHandler, false);
element.removeEventListener("input", inputHandler, false);
element.removeEventListener("blur", blurHandler, false);
}, false);
this.panel.hidden = false;
var win = element.ownerDocument.defaultView;
var style = win.getComputedStyle(element, null);
var scale = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.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, false);
} 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", false);
}
function removePopupPermListener(observer)
{
Services.obs.removeObserver(observer, "popup-perm-close");
}
function addFormSubmitObserver(observer)
{
observer.init();
Services.obs.addObserver(observer, "invalidformsubmit", false);
}
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 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 = Components.interfaces.nsIBrowserDOMWindow;
const nsIInterfaceRequestor = Components.interfaces.nsIInterfaceRequestor;
function nsBrowserAccess() {
}
nsBrowserAccess.prototype = {
openURI: function openURI(aURI, aOpener, aWhere, aContext) {
var isExternal = aContext == nsIBrowserDOMWindow.OPEN_EXTERNAL;
if (aWhere == nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW)
if (isExternal)
aWhere = Services.prefs.getIntPref("browser.link.open_external");
else
aWhere = Services.prefs.getIntPref("browser.link.open_newwindow");
var referrer = aOpener ? aOpener.QueryInterface(nsIInterfaceRequestor)
.getInterface(nsIWebNavigation)
.currentURI : null;
var uri = aURI ? aURI.spec : "about:blank";
switch (aWhere) {
case nsIBrowserDOMWindow.OPEN_NEWWINDOW:
return window.openDialog(getBrowserURL(), "_blank", "all,dialog=no",
uri, null, referrer);
case nsIBrowserDOMWindow.OPEN_NEWTAB:
var bgLoad = Services.prefs.getBoolPref("browser.tabs.loadDivertedInBackground");
var isRelated = referrer ? true : false;
var newTab = gBrowser.loadOneTab(uri, {inBackground: bgLoad,
fromExternal: isExternal,
relatedToCurrent: isRelated,
referrerURI: referrer});
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, loadflags);
return content;
}
aOpener = aOpener.top;
if (aURI) {
try {
aOpener.QueryInterface(nsIInterfaceRequestor)
.getInterface(nsIWebNavigation)
.loadURI(uri, loadflags, referrer, null, null);
} catch (e) {}
}
return aOpener;
}
},
isTabContentWindow: function isTabContentWindow(aWindow) {
return gBrowser.browsers.some(function (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(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsILoadContext);
if (lc.usePrivateBrowsing) {
gPrivate = window;
document.documentElement.removeAttribute("windowtype");
var titlemodifier = document.documentElement.getAttribute("titlemodifier");
if (titlemodifier)
titlemodifier += " ";
titlemodifier += document.documentElement.getAttribute("titleprivate");
document.documentElement.setAttribute("titlemodifier", titlemodifier);
document.title = titlemodifier;
}
// initialize observers and listeners
var xw = lc.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIXULWindow);
xw.XULBrowserWindow = window.XULBrowserWindow = new nsBrowserStatusHandler();
if (!window.content.opener &&
Services.prefs.getBoolPref("browser.doorhanger.enabled")) {
var tmp = {};
Components.utils.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 & Components.interfaces.nsIWebBrowserChrome.CHROME_SCROLLBARS))
gBrowser.selectedBrowser.style.overflow = "hidden";
}
addPrefListener(gTabStripPrefListener);
addPrefListener(gHomepagePrefListener);
addPrefListener(gStatusBarPopupIconPrefListener);
addPopupPermListener(gPopupPermListener);
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.indexOf("X11") != -1)
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, false);
// 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 (GetIntPref("browser.windows.loadOnNewWindow", 0))
{
default:
uriArray = ["about:blank"];
break;
case 1:
uriArray = getHomePage();
break;
case 2:
uriArray = [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) {
loadURI(uriToLoad, window.arguments[2], window.arguments[3] || null,
window.arguments[4] || false, window.arguments[5] || false);
} else {
loadURI(uriToLoad);
}
}
// 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 Components.classes) {
var remoteService =
Components.classes[REMOTESERVICE_CONTRACTID]
.getService(Components.interfaces.nsIRemoteService);
remoteService.registerWindow(window);
}
// ensure login manager is loaded
Components.classes["@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) {
DownloadTaskbarProgress.onBrowserWindowLoad(window);
// initialize the sync UI
gSyncUI.init();
// initialize the session-restore service
setTimeout(InitSessionStoreCallback, 0);
}
// Bug 778855 - Perf regression if we do this here. To be addressed in bug 779008.
setTimeout(function() { SafeBrowsing.init(); }, 2000);
}
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");
}
}
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 = Components.classes["@mozilla.org/suite/sessionstore;1"]
.getService(Components.interfaces.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 Components.interfaces.nsIDOMWindow) {
document.commandDispatcher.focusedWindow = element;
document.commandDispatcher.focusedElement = null;
} else if (element instanceof Components.interfaces.nsIDOMElement) {
document.commandDispatcher.focusedWindow = element.ownerDocument.defaultView;
document.commandDispatcher.focusedElement = element;
}
}
}
function Shutdown()
{
AeroPeek.onCloseWindow(window);
PlacesStarButton.uninit();
// shut down browser access support
window.browserDOMWindow = null;
getBrowser().removeEventListener("DOMLinkAdded", BrowserSearch, false);
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(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem).treeOwner
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIXULWindow)
.XULBrowserWindow = null;
// unregister us as a pref listener
removePrefListener(gTabStripPrefListener);
removePrefListener(gHomepagePrefListener);
removePrefListener(gStatusBarPopupIconPrefListener);
removePopupPermListener(gPopupPermListener);
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.indexOf(serviceDomain) >= 0)
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, Components.interfaces.nsICookiePermission[perm]];
}
function CheckForVisibility(aEvent)
{
var uri = getBrowser().currentURI;
var policy = Services.prefs.getBoolPref("dom.disable_open_during_load");
document.getElementById("ManagePopups").hidden = !policy;
var element = document.getElementById("AllowPopups");
if (policy && (Services.perms.testPermission(uri, "popup") != Services.perms.ALLOW_ACTION))
element.removeAttribute("disabled");
else
element.setAttribute("disabled", "true");
if (!/Mac/.test(navigator.platform))
popupBlockerMenuShowing(aEvent);
}
// 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 (var i = 0; i < items.length; i++) {
var item = items[i];
// Get type and perm from id.
var [type, perm] = GetTypePermFromId(item.id);
item.setAttribute("checked", perm == currentPerm);
}
}
// Perform a Cookie or Image action.
function CookieImageAction(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 popupHost()
{
var hostPort = "";
try {
hostPort = getBrowser().currentURI.hostPort;
} catch (e) {}
return hostPort;
}
function OpenSessionHistoryIn(aWhere, aDelta, aTab)
{
var win = aWhere == "window" ? null : window;
aTab = aTab || getBrowser().selectedTab;
var tab = Components.classes["@mozilla.org/suite/sessionstore;1"]
.getService(Components.interfaces.nsISessionStore)
.duplicateTab(win, aTab, aDelta, true);
var loadInBackground = GetBoolPref("browser.tabs.loadInBackground", false);
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 SetGroupHistory(popupMenu, direction)
{
while (popupMenu.hasChildNodes())
popupMenu.lastChild.remove();
var menuItem = document.createElementNS(XUL_NS, "menuitem");
var label = gNavigatorBundle.getString("tabs.historyItem");
menuItem.setAttribute("label", label);
menuItem.setAttribute("index", direction);
popupMenu.appendChild(menuItem);
}
function BrowserBackMenu(event)
{
if (gBrowser.backBrowserGroup.length != 0) {
SetGroupHistory(event.target, "back");
return true;
}
return FillHistoryMenu(event.target, "back");
}
function BrowserForwardMenu(event)
{
if (gBrowser.forwardBrowserGroup.length != 0) {
SetGroupHistory(event.target, "forward");
return true;
}
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);
}
const 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(function (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, false);
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();
}
// should we try and open up the sidebar to show the "Search Results" panel?
if (GetBoolPref("browser.search.opensidebarsearchpanel", false))
this.revealSidebar();
},
/**
* 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 Components.interfaces.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 Components.interfaces.nsIRDFLiteral) {
searchPanelExists = (exclude.Value.indexOf("navigator:browser") < 0);
} 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 "";
}
//Note: BrowserNewEditorWindow() was moved to globalOverlay.xul and renamed to NewEditorWindow()
function BrowserOpenWindow()
{
//opens a window where users can select a web location to open
var params = { action: gPrivate ? "4" : "0", url: "" };
openDialog("chrome://communicator/content/openLocation.xul", "_blank", "chrome,modal,titlebar", params);
promiseShortcutOrURI(params.url).then(([url, postData]) => {
switch (params.action) {
case "0": // current window
loadURI(url, null, postData, true);
break;
case "1": // new window
openDialog(getBrowserURL(), "_blank", "all,dialog=no", url, null, null,
postData, true);
break;
case "2": // edit
editPage(url);
break;
case "3": // new tab
gBrowser.selectedTab = gBrowser.addTab(url, {allowThirdPartyFixup: true, postData: postData});
break;
case "4": // private
openNewPrivateWith(params.url);
break;
}
});
}
function BrowserOpenTab()
{
if (!gInPrintPreviewMode) {
var uriToLoad;
var tabPref = GetIntPref("browser.tabs.loadOnNewTab",0);
switch (tabPref)
{
default:
uriToLoad = "about:blank";
break;
case 1:
uriToLoad = GetLocalizedStringPref("browser.startup.homepage");
break;
case 2:
uriToLoad = 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);
}
/* Show file picker dialog configured for opening a file, and return
* the selected nsIFileURL instance. */
function selectFileToOpen(label, prefRoot)
{
var fileURL = null;
// Get filepicker component.
const nsIFilePicker = Components.interfaces.nsIFilePicker;
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
fp.init(window, gNavigatorBundle.getString(label), nsIFilePicker.modeOpen);
fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText | nsIFilePicker.filterImages |
nsIFilePicker.filterXML | nsIFilePicker.filterHTML);
const filterIndexPref = prefRoot + "filterIndex";
const lastDirPref = prefRoot + "dir";
// use a pref to remember the filterIndex selected by the user.
fp.filterIndex = GetIntPref(filterIndexPref, 0);
// use a pref to remember the displayDirectory selected by the user.
try {
fp.displayDirectory = Services.prefs.getComplexValue(lastDirPref,
Components.interfaces.nsILocalFile);
} catch (ex) {
}
if (fp.show() == nsIFilePicker.returnOK) {
Services.prefs.setIntPref(filterIndexPref, fp.filterIndex);
Services.prefs.setComplexValue(lastDirPref,
Components.interfaces.nsILocalFile,
fp.file.parent);
fileURL = fp.fileURL;
}
return fileURL;
}
function BrowserOpenFileWindow()
{
try {
openTopWin(selectFileToOpen("openFile", "browser.open.").spec);
} catch (e) {}
}
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 hideCloseOtherTabs = !browser || !browser.getStripVisibility();
document.getElementById("menu_closeOtherTabs").hidden = hideCloseOtherTabs;
if (!hideCloseOtherTabs)
document.getElementById("cmd_closeOtherTabs").setAttribute("disabled", hideCloseWindow);
}
function updateRecentMenuItems()
{
var browser = getBrowser();
var ss = Components.classes["@mozilla.org/suite/sessionstore;1"]
.getService(Components.interfaces.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 = Components.classes["@mozilla.org/suite/sessionstore;1"]
.getService(Components.interfaces.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 = Components.classes["@mozilla.org/suite/sessionstore;1"]
.getService(Components.interfaces.nsISessionStore);
return ss.undoCloseWindow(aIndex);
}
function restoreLastSession() {
let ss = Components.classes["@mozilla.org/suite/sessionstore;1"]
.getService(Components.interfaces.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 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, isUTF8)
{
try {
var flags = nsIWebNavigation.LOAD_FLAGS_NONE;
if (allowThirdPartyFixup) {
flags = nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
}
if (isUTF8) {
flags |= nsIWebNavigation.LOAD_FLAGS_URI_IS_UTF8;
}
if (!flags && typeof postData == "number") {
// Deal with legacy code that passes load flags in the third argument.
flags = postData;
postData = null;
}
gBrowser.loadURIWithFlags(uri, flags, referrer, null, postData);
} 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;
}
promiseShortcutOrURI(url).then(([url, postData]) => {
// 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 = 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();
var isUTF8 = browser.userTypedValue === null;
// 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 (GetBoolPref("browser.tabs.opentabfor.urlbar", false)) {
// Reset url in the urlbar
URLBarSetURI();
// Open link in new tab
var t = browser.addTab(url, {
postData: postData,
allowThirdPartyFixup: true,
isUTF8: isUTF8
});
// 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", url,
null, null, postData, true, isUTF8);
// 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
const nsIURIFixup = Components.interfaces.nsIURIFixup;
if (!gURIFixup)
gURIFixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
.getService(nsIURIFixup);
url = gURIFixup.createFixupURI(url, 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(url, null, postData, true, isUTF8);
content.focus();
}
});
}
function promiseShortcutOrURI(aURL)
{
var keyword = aURL;
var param = "";
var offset = aURL.indexOf(" ");
if (offset > 0) {
keyword = aURL.substr(0, offset);
param = aURL.substr(offset + 1);
}
var engine = Services.search.getEngineByAlias(keyword);
if (engine) {
var submission = engine.getSubmission(param);
return Promise.resolve([submission.uri.spec, submission.postData]);
}
var [shortcutURL, postData] =
PlacesUtils.getURLAndPostDataForKeyword(keyword);
if (!shortcutURL)
return Promise.resolve([aURL]);
if (postData)
postData = unescape(postData);
if (/%s/i.test(shortcutURL) || /%s/i.test(postData)) {
var charset;
const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/;
var matches = shortcutURL.match(re);
if (matches) {
shortcutURL = matches[1];
charset = Promise.resolve(matches[2]);
} else {
// Try to get the saved character-set.
try {
// makeURI throws if URI is invalid.
// Will return an empty string if character-set is not found.
charset = PlacesUtils.getCharsetForURI(makeURI(shortcutURL));
} catch (e) {
charset = Promise.resolve();
}
}
return charset.then(charset => {
// encodeURIComponent produces UTF-8, and cannot be used for other
// charsets. escape() works in those cases, but it doesn't uri-encode
// +, @, and /. Therefore we need to manually replace these ASCII
// characters by their encodeURIComponent result, to match the
// behaviour of nsEscape() with url_XPAlphas.
var encodedParam = "";
if (charset && charset != "UTF-8")
encodedParam = escape(convertFromUnicode(charset, param)).
replace(/[+@\/]+/g, encodeURIComponent);
else // Default charset is UTF-8
encodedParam = encodeURIComponent(param);
shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param);
if (/%s/i.test(postData)) { // POST keyword
var postDataStream = getPostDataStream(postData, param, encodedParam,
"application/x-www-form-urlencoded");
return [shortcutURL, postDataStream];
}
return [shortcutURL];
});
}
if (param) {
// This keyword doesn't take a parameter, but one was provided. Just return
// the original URL.
return Promise.resolve([aURL]);
}
return Promise.resolve([shortcutURL]);
}
function getPostDataStream(aStringData, aKeyword, aEncKeyword, aType)
{
var dataStream = Components.classes["@mozilla.org/io/string-input-stream;1"]
.createInstance(Components.interfaces.nsIStringInputStream);
aStringData = aStringData.replace(/%s/g, aEncKeyword).replace(/%S/g, aKeyword);
dataStream.data = aStringData;
var mimeStream = Components.classes["@mozilla.org/network/mime-input-stream;1"]
.createInstance(Components.interfaces.nsIMIMEInputStream);
mimeStream.addHeader("Content-Type", aType);
mimeStream.addContentLength = true;
mimeStream.setData(dataStream);
return mimeStream.QueryInterface(Components.interfaces.nsIInputStream);
}
function handleDroppedLink(event, url, name)
{
promiseShortcutOrURI(url).then(([uri, postData]) => {
if (uri)
loadURI(uri, null, postData, false);
});
// 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.
var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
.getService(Components.interfaces.nsIClipboard);
// Create a transferable that will transfer the text.
var trans = Components.classes["@mozilla.org/widget/transferable;1"]
.createInstance(Components.interfaces.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(Components.interfaces.nsISupportsString);
url = data.data;
}
} catch (ex) {
}
return url;
}
function BrowserViewSourceOfDocument(aDocument)
{
var pageCookie;
var webNav;
// Get the nsIWebNavigation associated with the document
try {
var win;
var ifRequestor;
// Get the DOMWindow for the requested document. If the DOMWindow
// cannot be found, then just use the content window...
//
// XXX: This is a bit of a hack...
win = aDocument.defaultView;
if (win == window) {
win = content;
}
ifRequestor = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
webNav = ifRequestor.getInterface(Components.interfaces.nsIWebNavigation);
} catch(err) {
// If nsIWebNavigation cannot be found, just get the one for the whole
// window...
webNav = getWebNavigation();
}
//
// Get the 'PageDescriptor' for the current document. This allows the
// view-source to access the cached copy of the content rather than
// refetching it from the network...
//
try{
var PageLoader = webNav.QueryInterface(Components.interfaces.nsIWebPageDescriptor);
pageCookie = PageLoader.currentDescriptor;
} catch(err) {
// If no page descriptor is available, just use the view-source URL...
}
gViewSourceUtils.viewSource(webNav.currentURI.spec, pageCookie, aDocument);
}
// doc - document to use for source, or null for the current tab
// initialTab - id of the initial tab to display, or null for the first tab
function BrowserPageInfo(doc, initialTab)
{
if (!doc)
doc = window.content.document;
var relatedUrl = doc.location.toString();
var args = {doc: doc, initialTab: initialTab};
var enumerator = Services.wm.getEnumerator("Browser:page-info");
// Check for windows matching the url
while (enumerator.hasMoreElements()) {
let win = enumerator.getNext();
if (win.document.documentElement
.getAttribute("relatedUrl") == relatedUrl) {
win.focus();
win.resetPageInfo(args);
return win;
}
}
// We didn't find a matching window, so open a new one.
return window.openDialog("chrome://navigator/content/pageinfo/pageInfo.xul",
"_blank",
"chrome,dialog=no",
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', 'AllowPopups',
'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 Components.interfaces.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.
if (!gURIFixup)
gURIFixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
.getService(Components.interfaces.nsIURIFixup);
try {
uri = gURIFixup.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.spec;
// Try to decode as UTF-8 if there's no encoding sequence that we would break.
if (!/%25(?:3B|2F|3F|3A|40|26|3D|2B|24|2C|23)/i.test(value))
try {
value = decodeURI(value)
// 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)
.replace(/%(?!3B|2F|3F|3A|40|26|3D|2B|24|2C|23)/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\udb40-\udb43\udc00-\udfff\ufe00-\ufe0f\ufeff\uffa0\ufff0-\ufff8\ufffc]|i\ud834[\udd73-\udd7a]/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 focusNextFrame(aEvent)
{
var fm = Components.classes["@mozilla.org/focus-manager;1"]
.getService(Components.interfaces.nsIFocusManager);
var dir = aEvent.shiftKey ? fm.MOVEFOCUS_BACKWARDDOC
: fm.MOVEFOCUS_FORWARDDOC;
var element = fm.moveFocus(window, null, dir, fm.FLAG_BYKEY);
if (element && element.ownerDocument == document)
ShowAndSelectContentsOfURLBar();
}
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, false);
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, false);
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()
{
var hostPort = "";
try {
hostPort = getBrowser().selectedBrowser.currentURI.hostPort;
}
catch(ex) { }
// Open Data Manager permissions pane site and type prefilled to add.
toDataManager(hostPort + "|permissions|add|popup");
}
function popupBlockerMenuShowing(event)
{
var separator = document.getElementById("popupMenuSeparator");
if (separator)
separator.hidden = !createShowPopupsMenu(event.target, gBrowser.selectedBrowser);
}
function toHistory()
{
toOpenWindowByType("history:manager", "chrome://communicator/content/history/history.xul");
}
// opener may not have been initialized by load time (chrome windows only)
// so call this function some time later.
function maybeInitPopupContext()
{
// it's not a popup with no opener
if (!window.content.opener)
return null;
try {
// are we a popup window?
const CI = Components.interfaces;
var xulwin = window
.QueryInterface(CI.nsIInterfaceRequestor)
.getInterface(CI.nsIWebNavigation)
.QueryInterface(CI.nsIDocShellTreeItem).treeOwner
.QueryInterface(CI.nsIInterfaceRequestor)
.getInterface(CI.nsIXULWindow);
if (xulwin.contextFlags &
CI.nsIWindowCreator2.PARENT_IS_LOADING_OR_RUNNING_TIMEOUT) {
// return our opener's URI
return Services.io.newURI(window.content.opener.location.href, null, null);
}
} catch(e) {
}
return null;
}
function WindowIsClosing()
{
var browser = getBrowser();
var cn = browser.tabContainer.childNodes;
var numtabs = cn.length;
var reallyClose = true;
if (!gPrivate && !/Mac/.test(navigator.platform) && isClosingLastBrowser()) {
let closingCanceled = Components.classes["@mozilla.org/supports-PRBool;1"]
.createInstance(Components.interfaces.nsISupportsPRBool);
Services.obs.notifyObservers(closingCanceled, "browser-lastwindow-close-requested", null);
if (closingCanceled.data)
return false;
Services.obs.notifyObservers(null, "browser-lastwindow-close-granted", null);
return true;
}
if (!gPrivate && numtabs > 1) {
var shouldPrompt = Services.prefs.getBoolPref("browser.tabs.warnOnClose");
if (shouldPrompt) {
//default to true: if it were false, we wouldn't get this far
var warnOnClose = {value:true};
var buttonPressed = Services.prompt.confirmEx(window,
gNavigatorBundle.getString('tabs.closeWarningTitle'),
gNavigatorBundle.getFormattedString("tabs.closeWarning", [numtabs]),
(Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0)
+ (Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1),
gNavigatorBundle.getString('tabs.closeButton'),
null, null,
gNavigatorBundle.getString('tabs.closeWarningPromptMe'),
warnOnClose);
reallyClose = (buttonPressed == 0);
//don't set the pref unless they press OK and it's false
if (reallyClose && !warnOnClose.value) {
Services.prefs.setBoolPref("browser.tabs.warnOnClose", false);
}
} //if the warn-me pref was true
} //if multiple tabs are open
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 != 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()
{
const CI = Components.interfaces;
var focusedWindow = document.commandDispatcher.focusedWindow;
var contentFrame = isContentFrame(focusedWindow) ? focusedWindow : window.content;
var nav = contentFrame.QueryInterface(CI.nsIInterfaceRequestor)
.getInterface(CI.nsIWebNavigation);
return nav.currentURI;
}
function uploadFile(fileURL)
{
const CI = Components.interfaces;
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 = fileURL.QueryInterface(CI.nsIFileURL).file.leafName;
var targetURI = Services.io.newURI(leafName, null, targetBaseURI);
// ok, start uploading...
openDialog("chrome://communicator/content/downloads/uploadProgress.xul", "",
"titlebar,centerscreen,minimizable,dialog=no", fileURL, targetURI);
}
function BrowserUploadFile()
{
try {
uploadFile(selectFileToOpen("uploadFile", "browser.upload."));
} 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()
{
var rv = false;
var systemLocale;
try {
systemLocale = Services.locale.getSystemLocale()
.getCategory("NSILOCALE_CTYPE");
rv = /^(he|ar|syr|fa|ur)-/.test(systemLocale);
} catch (e) {}
if (!rv) {
// check the overriding pref
rv = Services.prefs.getBoolPref("bidi.browser.ui");
}
return rv;
}
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 = Components
.classes["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
unicodeConverter.charset = charset;
str = unicodeConverter.ConvertFromUnicode(str);
return str + unicodeConverter.Finish();
} catch(ex) {
return null;
}
}
function getNotificationBox(aWindow)
{
return aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShell)
.chromeEventHandler.parentNode.wrappedJSObject;
}
function BrowserToolboxCustomizeInit()
{
SetPageProxyState("invalid", null);
toolboxCustomizeInit("main-menubar");
PlacesToolbarHelper.customizeStart();
}
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, false);
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, false);
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.indexOf("?") != -1 ? "&" : "?";
spec += formData.join("&");
}
PlacesUIUtils.showMinimalAddBookmarkUI(makeURI(spec), title, description, null,
null, null, "", postData, charset);
}
function getCert()
{
var sslStatus = getBrowser().securityUI
.QueryInterface(Components.interfaces.nsISSLStatusProvider)
.SSLStatus;
return sslStatus && sslStatus.serverCert;
}
function viewCertificate()
{
var cert = getCert();
if (cert)
{
Components.classes["@mozilla.org/nsCertificateDialogs;1"]
.getService(Components.interfaces.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();
}