/* -*- indent-tabs-mode: nil; js-indent-level: 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.importESModule( "resource://gre/modules/XPCOMUtils.sys.mjs"
); var { AppConstants } = ChromeUtils.importESModule( "resource://gre/modules/AppConstants.sys.mjs"
);
ChromeUtils.importESModule( "resource://gre/modules/MemoryNotificationDB.sys.mjs"
);
ChromeUtils.importESModule("resource://gre/modules/NotificationDB.sys.mjs");
// Bug 1894239: We will move this up to ChromeUtils.defineESModuleGetters once // the MOZ_SELECTABLE_PROFILES flag is removed
ChromeUtils.defineLazyGetter(this, "SelectableProfileService", () => { if (!AppConstants.MOZ_SELECTABLE_PROFILES) { returnnull;
} return ChromeUtils.importESModule( "resource:///modules/profiles/SelectableProfileService.sys.mjs"
).SelectableProfileService;
});
ChromeUtils.defineLazyGetter(this, "gURLBar", () => {
let urlbar = new UrlbarInput({
textbox: document.getElementById("urlbar"),
eventTelemetryCategory: "urlbar",
});
let beforeFocusOrSelect = event => { // In customize mode, the url bar is disabled. If a new tab is opened or the // user switches to a different tab, this function gets called before we've // finished leaving customize mode, and the url bar will still be disabled. // We can't focus it when it's disabled, so we need to re-run ourselves when // we've finished leaving customize mode. if (
CustomizationHandler.isCustomizing() ||
CustomizationHandler.isExitingCustomizeMode
) {
gNavToolbox.addEventListener( "aftercustomization",
() => { if (event.type == "beforeselect") {
gURLBar.select();
} else {
gURLBar.focus();
}
},
{
once: true,
}
);
event.preventDefault(); return;
}
if (window.fullScreen) {
FullScreen.showNavToolbox();
}
};
urlbar.addEventListener("beforefocus", beforeFocusOrSelect);
urlbar.addEventListener("beforeselect", beforeFocusOrSelect);
// High priority notification bars shown at the top of the window.
ChromeUtils.defineLazyGetter(this, "gNotificationBox", () => {
let securityDelayMS = Services.prefs.getIntPref( "security.notification_enable_delay"
);
returnnew MozElements.NotificationBox(element => {
element.classList.add("global-notificationbox");
element.setAttribute("notificationside", "top");
element.setAttribute("prepend-notifications", true); // We want this before the tab notifications.
document.getElementById("notifications-toolbar").prepend(element);
}, securityDelayMS);
});
ChromeUtils.defineLazyGetter(this, "PopupNotifications", () => { // eslint-disable-next-line no-shadow
let { PopupNotifications } = ChromeUtils.importESModule( "resource://gre/modules/PopupNotifications.sys.mjs"
); try { // Hide all PopupNotifications while the the address bar has focus, // including the virtual focus in the results popup, and the URL is being // edited or the page proxy state is invalid while async tab switching.
let shouldSuppress = () => { // "Blank" pages, like about:welcome, have a pageproxystate of "invalid", but // popups like CFRs should not automatically be suppressed when the address // bar has focus on these pages as it disrupts user navigation using FN+F6. // See `UrlbarInput.setURI()` where pageproxystate is set to "invalid" for // all pages that the "isBlankPageURL" method returns true for. const urlBarEdited = isBlankPageURL(gBrowser.currentURI.spec)
? gURLBar.hasAttribute("usertyping")
: gURLBar.getAttribute("pageproxystate") != "valid"; return (
(urlBarEdited && gURLBar.focused) ||
(gURLBar.getAttribute("pageproxystate") != "valid" &&
gBrowser.selectedBrowser._awaitingSetURI) ||
shouldSuppressPopupNotifications()
);
};
// Before a Popup is shown, check that its anchor is visible. // If the anchor is not visible, use one of the fallbacks. // If no fallbacks are visible, return null. const getVisibleAnchorElement = anchorElement => { // If the anchor element is present in the Urlbar, // ensure that both the anchor and page URL are visible.
gURLBar.maybeHandleRevertFromPopup(anchorElement); if (anchorElement?.checkVisibility()) { return anchorElement;
}
let fallback = [
document.getElementById("searchmode-switcher-icon"),
document.getElementById("identity-icon"),
gURLBar.querySelector(".urlbar-search-button"),
document.getElementById("remote-control-icon"),
]; return fallback.find(element => element?.checkVisibility()) ?? null;
};
var gBrowser; var gContextMenu = null; // nsContextMenu instance var gMultiProcessBrowser = window.docShell.QueryInterface(
Ci.nsILoadContext
).useRemoteTabs; var gFissionBrowser = window.docShell.QueryInterface(
Ci.nsILoadContext
).useRemoteSubframes;
var gBrowserAllowScriptsToCloseInitialTabs = false;
if (AppConstants.platform != "macosx") { var gEditUIVisible = true;
}
Object.defineProperty(this, "gReduceMotion", {
enumerable: true,
get() { returntypeof gReduceMotionOverride == "boolean"
? gReduceMotionOverride
: gReduceMotionSetting;
},
}); // Reduce motion during startup. The setting will be reset later.
let gReduceMotionSetting = true; // This is for tests to set. var gReduceMotionOverride;
// Smart getter for the findbar. If you don't wish to force the creation of // the findbar, check gFindBarInitialized first.
function shouldSuppressPopupNotifications() { // We have to hide notifications explicitly when the window is // minimized because of the effects of the "noautohide" attribute on Linux. // This can be removed once bug 545265 and bug 1320361 are fixed. // Hide popup notifications when system tab prompts are shown so they // don't cover up the prompt. return (
window.windowState == window.STATE_MINIMIZED ||
gBrowser?.selectedBrowser.hasAttribute("tabDialogShowing") ||
gDialogBox?.isOpen
);
}
async function gLazyFindCommand(cmd, ...args) {
let fb = await gFindBarPromise; // We could be closed by now, or the tab with XBL binding could have gone away: if (fb && fb[cmd]) {
fb[cmd].apply(fb, args);
}
}
// This is a stringbundle-like interface to gBrowserBundle, formerly a getter for // the "bundle_browser" element. var gNavigatorBundle = {
getString(key) { return gBrowserBundle.GetStringFromName(key);
},
getFormattedString(key, array) { return gBrowserBundle.formatStringFromName(key, array);
},
};
var gScreenshots = {
shouldScreenshotsButtonBeDisabled() { // About pages other than about:reader are not currently supported by // the screenshots extension (see Bug 1620992).
let uri = gBrowser.selectedBrowser.currentURI;
let shouldBeDisabled =
gScreenshotsDisabled ||
(!gScreenshotsComponentEnabled &&
uri.scheme === "about" &&
!uri.spec.startsWith("about:reader"));
return shouldBeDisabled;
},
};
function updateFxaToolbarMenu(enable, isInitialUpdate = false) { // We only show the Firefox Account toolbar menu if the feature is enabled and // if sync is enabled. const syncEnabled = Services.prefs.getBoolPref( "identity.fxaccounts.enabled", false
);
// To minimize the toolbar button flickering or appearing/disappearing during startup, // we use this pref to anticipate the likely FxA status. const statusGuess = !!Services.prefs.getStringPref( "identity.fxaccounts.account.device.name", ""
);
mainWindowEl.setAttribute( "fxastatus",
statusGuess ? "signed_in" : "not_configured"
);
if (enable && syncEnabled) {
mainWindowEl.setAttribute("fxatoolbarmenu", "visible");
// We have to manually update the sync state UI when toggling the FxA toolbar // because it could show an invalid icon if the user is logged in and no sync // event was performed yet. if (!isInitialUpdate) {
gSync.maybeUpdateUIState();
}
} else {
mainWindowEl.removeAttribute("fxatoolbarmenu");
}
}
function UpdateBackForwardCommands(aWebNavigation) { var backCommand = document.getElementById("Browser:Back"); var forwardCommand = document.getElementById("Browser:Forward");
// Avoid setting attributes on commands 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 = backCommand.hasAttribute("disabled"); var forwardDisabled = forwardCommand.hasAttribute("disabled"); if (backDisabled == aWebNavigation.canGoBack) { if (backDisabled) {
backCommand.removeAttribute("disabled");
} else {
backCommand.setAttribute("disabled", true);
}
}
if (forwardDisabled == aWebNavigation.canGoForward) { if (forwardDisabled) {
forwardCommand.removeAttribute("disabled");
} else {
forwardCommand.setAttribute("disabled", true);
}
}
}
function updatePrintCommands(enabled) { var printCommand = document.getElementById("cmd_print"); var printPreviewCommand = document.getElementById("cmd_printPreviewToggle");
/** * Click-and-Hold implementation for the Back and Forward buttons * XXXmano: should this live in toolbarbutton.js?
*/ function SetClickAndHoldHandlers() { // Bug 414797: Clone the back/forward buttons' context menu into both buttons.
let popup = document.getElementById("backForwardMenu").cloneNode(true);
popup.removeAttribute("id"); // Prevent the back/forward buttons' context attributes from being inherited.
popup.setAttribute("context", "");
function backForwardMenuCommand(event) {
BrowserCommands.gotoHistoryIndex(event); // event.stopPropagation is here for the cloned version // to prevent already-handled clicks on menu items from // propagating to the back or forward button.
event.stopPropagation();
}
_clickHandler(aEvent) { if (
aEvent.button == 0 &&
aEvent.target == aEvent.currentTarget &&
!aEvent.currentTarget.open &&
!aEvent.currentTarget.disabled && // When menupopup is not hidden and we receive // a click event, it means the mousedown occurred // on aEvent.currentTarget and mouseup occurred on // aEvent.currentTarget.menupopup, we don't // need to handle the click event as menupopup // handled mouseup event already.
aEvent.currentTarget.menupopup.hidden
) {
let cmdEvent = document.createEvent("xulcommandevent");
cmdEvent.initCommandEvent( "command", true, true,
window,
0,
aEvent.ctrlKey,
aEvent.altKey,
aEvent.shiftKey,
aEvent.metaKey,
0, null,
aEvent.inputSource
);
aEvent.currentTarget.dispatchEvent(cmdEvent);
// This is here to cancel the XUL default event // dom.click() triggers a command even if there is a click handler // however this can now be prevented with preventDefault().
aEvent.preventDefault();
}
},
_keypressHandler(aEvent) { if (aEvent.key == " " || aEvent.key == "Enter") {
aEvent.preventDefault(); // Normally, command events get fired for keyboard activation. However, // we've set type="menu", so that doesn't happen. Handle this the same // way we handle clicks.
aEvent.target.click();
}
},
handleEvent(e) { switch (e.type) { case"mouseout": this._mouseoutHandler(e); break; case"mousedown": this._mousedownHandler(e); break; case"click": this._clickHandler(e); break; case"mouseup": this._mouseupHandler(e); break; case"keypress": // Note that we might not be the only ones dealing with keypresses. // See bug 1921772 for more context. if (!e.defaultPrevented) { this._keypressHandler(e);
} break;
}
},
const NOTIFICATION_VALUE = "storage-pressure-notification"; if (gNotificationBox.getNotificationWithValue(NOTIFICATION_VALUE)) { // Do not display the 2nd notification when there is already one return;
}
// Don't display notification twice within the given interval. // This is because // - not to annoy user // - give user some time to clean space. // Even user sees notification and starts acting, it still takes some time. const MIN_NOTIFICATION_INTERVAL_MS = Services.prefs.getIntPref( "browser.storageManager.pressureNotification.minIntervalMS"
);
let duration = Date.now() - this._lastNotificationTime; if (duration <= MIN_NOTIFICATION_INTERVAL_MS) { return;
} this._lastNotificationTime = Date.now();
const BYTES_IN_GIGABYTE = 1073741824; const USAGE_THRESHOLD_BYTES =
BYTES_IN_GIGABYTE *
Services.prefs.getIntPref( "browser.storageManager.pressureNotification.usageThresholdGB"
);
let messageFragment = document.createDocumentFragment();
let message = document.createElement("span");
let buttons = [{ supportPage: "storage-permissions" }];
let usage = subject.QueryInterface(Ci.nsISupportsPRUint64).data; if (usage < USAGE_THRESHOLD_BYTES) { // The firefox-used space < 5GB, then warn user to free some disk space. // This is because this usage is small and not the main cause for space issue. // In order to avoid the bad and wrong impression among users that // firefox eats disk space a lot, indicate users to clean up other disk space.
document.l10n.setAttributes(message, "space-alert-under-5gb-message2");
} else { // The firefox-used space >= 5GB, then guide users to about:preferences // to clear some data stored on firefox by websites.
document.l10n.setAttributes(message, "space-alert-over-5gb-message2");
buttons.push({ "l10n-id": "space-alert-over-5gb-settings-button",
callback() { // The advanced subpanes are only supported in the old organization, which will // be removed by bug 1349689.
openPreferences("privacy-sitedata");
},
});
}
messageFragment.appendChild(message);
var gKeywordURIFixup = {
check(browser, { fixedURI, keywordProviderName, preferredURI }) { // We get called irrespective of whether we did a keyword search, or // whether the original input would be vaguely interpretable as a URL, // so figure that out first. if (
!keywordProviderName ||
!fixedURI ||
!fixedURI.host ||
UrlbarPrefs.get("browser.fixup.dns_first_for_single_words") ||
UrlbarPrefs.get("dnsResolveSingleWordsAfterSearch") == 0
) { return;
}
let contentPrincipal = browser.contentPrincipal;
// At this point we're still only just about to load this URI. // When the async DNS lookup comes back, we may be in any of these states: // 1) still on the previous URI, waiting for the preferredURI (keyword // search) to respond; // 2) at the keyword search URI (preferredURI) // 3) at some other page because the user stopped navigation. // We keep track of the currentURI to detect case (1) in the DNS lookup // callback.
let previousURI = browser.currentURI;
// now swap for a weak ref so we don't hang on to browser needlessly // even if the DNS query takes forever
let weakBrowser = Cu.getWeakReference(browser);
browser = null;
// Additionally, we need the host of the parsed url
let hostName = fixedURI.displayHost; // and the ascii-only host for the pref:
let asciiHost = fixedURI.asciiHost;
let onLookupCompleteListener = {
async onLookupComplete(request, record, status) {
let browserRef = weakBrowser.get(); if (!Components.isSuccessCode(status) || !browserRef) { return;
}
let currentURI = browserRef.currentURI; // If we're in case (3) (see above), don't show an info bar. if (
!currentURI.equals(previousURI) &&
!currentURI.equals(preferredURI)
) { return;
}
// show infobar offering to visit the host
let notificationBox = gBrowser.getNotificationBox(browserRef); if (notificationBox.getNotificationWithValue("keyword-uri-fixup")) { return;
}
let displayHostName = "http://" + hostName + "/";
let message = gNavigatorBundle.getFormattedString( "keywordURIFixup.message",
[displayHostName]
);
let yesMessage = gNavigatorBundle.getFormattedString( "keywordURIFixup.goTo",
[displayHostName]
);
let buttons = [
{
label: yesMessage,
accessKey: gNavigatorBundle.getString( "keywordURIFixup.goTo.accesskey"
),
callback() { // Do not set this preference while in private browsing. if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
let prefHost = asciiHost; // Normalize out a single trailing dot - NB: not using endsWith/lastIndexOf // because we need to be sure this last dot is the *only* dot, too. // More generally, this is used for the pref and should stay in sync with // the code in URIFixup::KeywordURIFixup . if (prefHost.indexOf(".") == prefHost.length - 1) {
prefHost = prefHost.slice(0, -1);
}
let pref = "browser.fixup.domainwhitelist." + prefHost;
Services.prefs.setBoolPref(pref, true);
}
openTrustedLinkIn(fixedURI.spec, "current");
},
},
];
let notification = await notificationBox.appendNotification( "keyword-uri-fixup",
{
label: message,
priority: notificationBox.PRIORITY_INFO_HIGH,
},
buttons
);
notification.persistence = 1;
},
};
let browser = fixupInfo.consumer?.top?.embedderElement; if (!browser || browser.ownerGlobal != window) { return;
}
this.check(browser, fixupInfo);
},
};
/* Creates a null principal using the userContextId
from the current selected tab or a passed in tab argument */ function _createNullPrincipalFromTabUserContextId(tab = gBrowser.selectedTab) {
let userContextId; if (tab.hasAttribute("usercontextid")) {
userContextId = tab.getAttribute("usercontextid");
} return Services.scriptSecurityManager.createNullPrincipal({
userContextId,
});
}
function loadOneOrMoreURIs(aURIString, aTriggeringPrincipal, aCsp) { // we're not a browser window, pass the URI string to a new browser window if (window.location.href != AppConstants.BROWSER_CHROME_URL) {
window.openDialog(
AppConstants.BROWSER_CHROME_URL, "_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,
csp: aCsp,
});
} catch (e) {}
}
function openLocation(event) { if (window.location.href == AppConstants.BROWSER_CHROME_URL) {
gURLBar.select();
gURLBar.view.autoOpen({ event }); return;
}
// If there's an open browser window, redirect the command there.
let win = URILoadingHelper.getTargetWindow(window); if (win) {
win.focus();
win.openLocation(); return;
}
// There are no open browser windows; open a new one.
window.openDialog(
AppConstants.BROWSER_CHROME_URL, "_blank", "chrome,all,dialog=no",
BROWSER_NEW_TAB_URL
);
}
var gLastOpenDirectory = {
_lastDir: null,
get path() { if (!this._lastDir || !this._lastDir.exists()) { try { this._lastDir = Services.prefs.getComplexValue( "browser.open.lastDir",
Ci.nsIFile
); if (!this._lastDir.exists()) { this._lastDir = null;
}
} catch (e) {}
} returnthis._lastDir;
},
set path(val) { try { if (!val || !val.isDirectory()) { return;
}
} catch (e) { return;
} this._lastDir = val.clone();
// Don't save the last open directory pref inside the Private Browsing mode if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
Services.prefs.setComplexValue( "browser.open.lastDir",
Ci.nsIFile, this._lastDir
);
}
},
reset() { this._lastDir = null;
},
};
function getLoadContext() { return window.docShell.QueryInterface(Ci.nsILoadContext);
}
function readFromClipboard() { var url;
try { // Create transferable that will transfer the text. var trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
Ci.nsITransferable
);
trans.init(getLoadContext());
trans.addDataFlavor("text/plain");
// If available, use selection clipboard, otherwise global one
let clipboard = Services.clipboard; if (clipboard.isClipboardTypeSupported(clipboard.kSelectionClipboard)) {
clipboard.getData(trans, clipboard.kSelectionClipboard);
} else {
clipboard.getData(trans, clipboard.kGlobalClipboard);
}
var data = {};
trans.getTransferData("text/plain", data);
if (data) {
data = data.value.QueryInterface(Ci.nsISupportsString);
url = data.data;
}
} catch (ex) {}
return url;
}
function UpdateUrlbarSearchSplitterState() { var splitter = document.getElementById("urlbar-search-splitter"); var urlbar = document.getElementById("urlbar-container"); var searchbar = document.getElementById("search-container");
if (document.documentElement.hasAttribute("customizing")) { if (splitter) {
splitter.remove();
} return;
}
// If the splitter is already in the right place, we don't need to do anything: if (
splitter &&
((splitter.nextElementSibling == searchbar &&
splitter.previousElementSibling == urlbar) ||
(splitter.nextElementSibling == urlbar &&
splitter.previousElementSibling == searchbar))
) { return;
}
let ibefore = null;
let resizebefore = "none";
let resizeafter = "none"; if (urlbar && searchbar) { if (urlbar.nextElementSibling == searchbar) {
resizeafter = "sibling";
ibefore = searchbar;
} elseif (searchbar.nextElementSibling == urlbar) {
resizebefore = "sibling";
ibefore = urlbar;
}
}
function UpdatePopupNotificationsVisibility() { // Only need to update PopupNotifications if it has already been initialized // for this window (i.e. its getter no longer exists). if (!Object.getOwnPropertyDescriptor(window, "PopupNotifications").get) { // Notify PopupNotifications that the visible anchors may have changed. This // also checks the suppression state according to the "shouldSuppress" // function defined earlier in this file.
PopupNotifications.anchorVisibilityChange();
}
// This is similar to the above, but for notifications attached to the // hamburger menu icon (such as update notifications and add-on install // notifications.)
PanelUI?.updateNotifications();
}
function PageProxyClickHandler(aEvent) { if (aEvent.button == 1 && Services.prefs.getBoolPref("middlemouse.paste")) {
middleMousePaste(aEvent);
}
}
/** * Handle command events bubbling up from error page content * or from about:newtab or from remote error pages that invoke * us via async messaging.
*/ var BrowserOnClick = {
async ignoreWarningLink(reason, blockedInfo, browsingContext) { // Add a notify bar before allowing the user to continue through to the // site, so that they don't lose track after, e.g., tab switching. // We can't use browser.contentPrincipal which is principal of about:blocked // Create one from uri with current principal origin attributes
let principal = Services.scriptSecurityManager.createContentPrincipal(
Services.io.newURI(blockedInfo.uri),
browsingContext.currentWindowGlobal.documentPrincipal.originAttributes
);
Services.perms.addFromPrincipal(
principal, "safe-browsing",
Ci.nsIPermissionManager.ALLOW_ACTION,
Ci.nsIPermissionManager.EXPIRE_SESSION
);
let title; if (reason === "malware") {
let reportUrl = gSafeBrowsing.getReportURL("MalwareMistake", blockedInfo);
title = gNavigatorBundle.getString("safebrowsing.reportedAttackSite"); // There's no button if we can not get report url, for example if the provider // of blockedInfo is not Google if (reportUrl) {
buttons[1] = {
label: gNavigatorBundle.getString( "safebrowsing.notAnAttackButton.label"
),
accessKey: gNavigatorBundle.getString( "safebrowsing.notAnAttackButton.accessKey"
),
callback() {
openTrustedLinkIn(reportUrl, "tab");
},
};
}
} elseif (reason === "phishing") {
let reportUrl = gSafeBrowsing.getReportURL("PhishMistake", blockedInfo);
title = gNavigatorBundle.getString("safebrowsing.deceptiveSite"); // There's no button if we can not get report url, for example if the provider // of blockedInfo is not Google if (reportUrl) {
buttons[1] = {
label: gNavigatorBundle.getString( "safebrowsing.notADeceptiveSiteButton.label"
),
accessKey: gNavigatorBundle.getString( "safebrowsing.notADeceptiveSiteButton.accessKey"
),
callback() {
openTrustedLinkIn(reportUrl, "tab");
},
};
}
} elseif (reason === "unwanted") {
title = gNavigatorBundle.getString("safebrowsing.reportedUnwantedSite"); // There is no button for reporting errors since Google doesn't currently // provide a URL endpoint for these reports.
} elseif (reason === "harmful") {
title = gNavigatorBundle.getString("safebrowsing.reportedHarmfulSite"); // There is no button for reporting errors since Google doesn't currently // provide a URL endpoint for these reports.
}
// Allow users to override and continue through to the site. // Note that we have to use the passed URI info and can't just // rely on the document URI, because the latter contains // additional query parameters that should be stripped.
let triggeringPrincipal =
blockedInfo.triggeringPrincipal ||
_createNullPrincipalFromTabUserContextId();
/** * Re-direct the browser to a known-safe page. This function is * used when, for example, the user browses to a known malware page * and is presented with about:blocked. The "Get me out of here!" * button should take the user to the default start page so that even * when their own homepage is infected, we can get them somewhere safe.
*/ function getMeOutOfHere(browsingContext) {
browsingContext.top.fixupAndLoadURIString(getDefaultHomePage(), {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), // Also needs to load homepage
});
}
/** * Return the default start page for the cases when the user's own homepage is * infected, so we can get them somewhere safe.
*/ function getDefaultHomePage() {
let url = BROWSER_NEW_TAB_URL; if (PrivateBrowsingUtils.isWindowPrivate(window)) { return url;
}
url = HomePage.getDefault(); // If url is a pipe-delimited set of pages, just take the first one. if (url.includes("|")) {
url = url.split("|")[0];
} return url;
}
// TODO: can we pull getPEMString in from pippki.js instead of // duplicating them here? function getPEMString(cert) { var derb64 = cert.getBase64DERString(); // Wrap the Base64 string into lines of 64 characters, // with CRLF line breaks (as specified in RFC 1421). var wrapped = derb64.replace(/(\S{64}(?!$))/g, "$1\r\n"); return ( "-----BEGIN CERTIFICATE-----\r\n" +
wrapped + "\r\n-----END CERTIFICATE-----\r\n"
);
}
var browserDragAndDrop = {
canDropLink: aEvent => Services.droppedLinkHandler.canDropLink(aEvent, true),
dragOver(aEvent) { if (this.canDropLink(aEvent)) {
aEvent.preventDefault();
}
},
var homeButtonObserver = {
onDrop(aEvent) { // disallow setting home pages that inherit the principal
let links = browserDragAndDrop.dropLinks(aEvent, true); if (links.length) {
let urls = []; for (let link of links) { if (link.url.includes("|")) {
urls.push(...link.url.split("|"));
} else {
urls.push(link.url);
}
}
if (pressedVal == 0) {
HomePage.set(aURL).catch(console.error);
}
}
var newTabButtonObserver = {
onDragOver(aEvent) {
browserDragAndDrop.dragOver(aEvent);
},
async onDrop(aEvent) {
let links = browserDragAndDrop.dropLinks(aEvent); if (
links.length >=
Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")
) { // Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(
links.length,
window
); if (!answer) { return;
}
}
let where = aEvent.shiftKey ? "tabshifted" : "tab";
let triggeringPrincipal = browserDragAndDrop.getTriggeringPrincipal(aEvent);
let csp = browserDragAndDrop.getCsp(aEvent); for (let link of links) { if (link.url) {
let data = await UrlbarUtils.getShortcutOrURIAndPostData(link.url); // Allow third-party services to fixup this URL.
openLinkIn(data.url, where, {
postData: data.postData,
allowThirdPartyFixup: true,
triggeringPrincipal,
csp,
});
}
}
},
};
var newWindowButtonObserver = {
onDragOver(aEvent) {
browserDragAndDrop.dragOver(aEvent);
},
async onDrop(aEvent) {
let links = browserDragAndDrop.dropLinks(aEvent); if (
links.length >=
Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")
) { // Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(
links.length,
window
); if (!answer) { return;
}
}
let triggeringPrincipal = browserDragAndDrop.getTriggeringPrincipal(aEvent);
let csp = browserDragAndDrop.getCsp(aEvent); for (let link of links) { if (link.url) {
let data = await UrlbarUtils.getShortcutOrURIAndPostData(link.url); // Allow third-party services to fixup this URL.
openLinkIn(data.url, "window", { // TODO fix allowInheritPrincipal // (this is required by javascript: drop to the new window) Bug 1475201
allowInheritPrincipal: true,
postData: data.postData,
allowThirdPartyFixup: true,
triggeringPrincipal,
csp,
});
}
}
},
};
delayedStartupInit() { // Asynchronously initialize the search service if necessary, to get the // current engine for working out the placeholder. this._updateURLBarPlaceholderFromDefaultEngine(
PrivateBrowsingUtils.isWindowPrivate(window), // Delay the update for this until so that we don't change it while // the user is looking at it / isn't expecting it. true
).then(() => { this._searchInitComplete = true;
});
},
observe(engine, topic, data) { // There are two kinds of search engine objects, nsISearchEngine objects and // plain { uri, title, icon } objects. `engine` in this method is the // former. The browser.engines and browser.hiddenEngines arrays are the // latter, and they're the engines offered by the the page in the browser. // // The two types of engines are currently related by their titles/names, // although that may change; see bug 335102.
let engineName = engine.wrappedJSObject.name; switch (data) { case"engine-removed": // An engine was removed from the search service. If a page is offering // the engine, then the engine needs to be added back to the corresponding // browser's offered engines. this._addMaybeOfferedEngine(engineName); break; case"engine-added": // An engine was added to the search service. If a page is offering the // engine, then the engine needs to be removed from the corresponding // browser's offered engines. this._removeMaybeOfferedEngine(engineName); break; case"engine-default": if ( this._searchInitComplete &&
!PrivateBrowsingUtils.isWindowPrivate(window)
) { this._updateURLBarPlaceholder(engineName, false);
} break; case"engine-default-private": if ( this._searchInitComplete &&
PrivateBrowsingUtils.isWindowPrivate(window)
) { this._updateURLBarPlaceholder(engineName, true);
} break;
}
},
_addMaybeOfferedEngine(engineName) {
let selectedBrowserOffersEngine = false; for (let browser of gBrowser.browsers) { for (let i = 0; i < (browser.hiddenEngines || []).length; i++) { if (browser.hiddenEngines[i].title == engineName) { if (!browser.engines) {
browser.engines = [];
}
browser.engines.push(browser.hiddenEngines[i]);
browser.hiddenEngines.splice(i, 1); if (browser == gBrowser.selectedBrowser) {
selectedBrowserOffersEngine = true;
} break;
}
}
} if (selectedBrowserOffersEngine) { this.updateOpenSearchBadge();
}
},
_removeMaybeOfferedEngine(engineName) {
let selectedBrowserOffersEngine = false; for (let browser of gBrowser.browsers) { for (let i = 0; i < (browser.engines || []).length; i++) { if (browser.engines[i].title == engineName) { if (!browser.hiddenEngines) {
browser.hiddenEngines = [];
}
browser.hiddenEngines.push(browser.engines[i]);
browser.engines.splice(i, 1); if (browser == gBrowser.selectedBrowser) {
selectedBrowserOffersEngine = true;
} break;
}
}
} if (selectedBrowserOffersEngine) { this.updateOpenSearchBadge();
}
},
/** * Initializes the urlbar placeholder to the pre-saved engine name. We do this * via a preference, to avoid needing to synchronously init the search service. * * This should be called around the time of DOMContentLoaded, so that it is * initialized quickly before the user sees anything. * * Note: If the preference doesn't exist, we don't do anything as the default * placeholder is a string which doesn't have the engine name; however, this * can be overridden using the `force` parameter. * * @param {Boolean} force If true and the preference doesn't exist, the * placeholder will be set to the default version * without an engine name ("Search or enter address").
*/
initPlaceHolder(force = false) { const prefName = "browser.urlbar.placeholderName" +
(PrivateBrowsingUtils.isWindowPrivate(window) ? ".private" : "");
let engineName = Services.prefs.getStringPref(prefName, ""); if (engineName || force) { // We can do this directly, since we know we're at DOMContentLoaded. this._setURLBarPlaceholder(engineName);
}
},
/** * This is a wrapper around '_updateURLBarPlaceholder' that uses the * appropriate default engine to get the engine name. * * @param {Boolean} isPrivate Set to true if this is a private window. * @param {Boolean} [delayUpdate] Set to true, to delay update until the * placeholder is not displayed.
*/
async _updateURLBarPlaceholderFromDefaultEngine(
isPrivate,
delayUpdate = false
) { const getDefault = isPrivate
? Services.search.getDefaultPrivate
: Services.search.getDefault;
let defaultEngine = await getDefault(); if (!this._searchInitComplete) { // If we haven't finished initialising, ensure the placeholder // preference is set for the next startup.
SearchUIUtils.updatePlaceholderNamePreference(defaultEngine, isPrivate);
} this._updateURLBarPlaceholder(defaultEngine.name, isPrivate, delayUpdate);
},
/** * Updates the URLBar placeholder for the specified engine, delaying the * update if required. This also saves the current engine name in preferences * for the next restart. * * Note: The engine name will only be displayed for built-in engines, as we * know they should have short names. * * @param {String} engineName The search engine name to use for the update. * @param {Boolean} isPrivate Set to true if this is a private window. * @param {Boolean} [delayUpdate] Set to true, to delay update until the * placeholder is not displayed.
*/
_updateURLBarPlaceholder(engineName, isPrivate, delayUpdate = false) { if (!engineName) { thrownew Error("Expected an engineName to be specified");
}
const engine = Services.search.getEngineByName(engineName); if (!engine.isAppProvided) { // Set the engine name to an empty string for non-default engines, which'll // make sure we display the default placeholder string.
engineName = "";
}
// Only delay if requested, and we're not displaying text in the URL bar // currently. if (delayUpdate && !gURLBar.value) { // Delays changing the URL Bar placeholder until the user is not going to be // seeing it, e.g. when there is a value entered in the bar, or if there is // a tab switch to a tab which has a url loaded. We delay the update until // the user is out of search mode since an alternative placeholder is used // in search mode.
let placeholderUpdateListener = () => { if (gURLBar.value && !gURLBar.searchMode) { // By the time the user has switched, they may have changed the engine // again, so we need to call this function again but with the // new engine name. // No need to await for this to finish, we're in a listener here anyway. this._updateURLBarPlaceholderFromDefaultEngine(isPrivate, false);
gURLBar.removeEventListener("input", placeholderUpdateListener);
gBrowser.tabContainer.removeEventListener( "TabSelect",
placeholderUpdateListener
);
}
};
/** * Sets the URLBar placeholder to either something based on the engine name, * or the default placeholder. * * @param {String} name The name of the engine to use, an empty string if to * use the default placeholder.
*/
_setURLBarPlaceholder(name) {
document.l10n.setAttributes(
gURLBar.inputField,
name ? "urlbar-placeholder-with-name" : "urlbar-placeholder",
name ? { name } : undefined
);
},
addEngine(browser, engine) { if (!this._searchInitComplete) {
--> --------------------
--> maximum size reached
--> --------------------
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.37Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.