From a90a5cba08fdf6c0ceb95101c275108a152a3aed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:35:37 +0200 Subject: Merging upstream version 127.0. Signed-off-by: Daniel Baumann --- browser/base/content/appmenu-viewcache.inc.xhtml | 135 +-- browser/base/content/browser-addons.js | 110 +- browser/base/content/browser-allTabsMenu.inc.xhtml | 4 + browser/base/content/browser-allTabsMenu.js | 15 + browser/base/content/browser-box.inc.xhtml | 4 +- browser/base/content/browser-commands.js | 17 +- browser/base/content/browser-init.js | 1107 +++++++++++++++++ browser/base/content/browser-menubar.inc | 19 +- browser/base/content/browser-pageActions.js | 2 +- browser/base/content/browser-places.js | 15 +- browser/base/content/browser-sets.inc | 8 +- browser/base/content/browser-siteIdentity.js | 1 - .../base/content/browser-sitePermissionPanel.js | 3 - browser/base/content/browser-siteProtections.js | 9 +- browser/base/content/browser-sync.js | 326 +++-- browser/base/content/browser.js | 1261 +------------------- browser/base/content/browser.js.globals | 7 - browser/base/content/browser.xhtml | 3 +- browser/base/content/macWindow.inc.xhtml | 1 - browser/base/content/main-popupset.inc.xhtml | 33 +- browser/base/content/navigator-toolbox.inc.xhtml | 9 +- browser/base/content/nsContextMenu.js | 39 +- browser/base/content/popup-notifications.inc | 2 +- browser/base/content/spotlight.html | 1 + browser/base/content/tabbrowser-tabs.js | 15 +- browser/base/content/tabbrowser.css | 101 -- browser/base/content/tabbrowser.js | 314 ++++- browser/base/content/test/about/browser.toml | 1 - .../test/about/browser_aboutNetError_csp_iframe.js | 4 + .../test/about/browser_aboutNetError_xfo_iframe.js | 4 + browser/base/content/test/alerts/browser.toml | 4 - .../test/alerts/browser_notification_close.js | 25 +- .../test/alerts/browser_notification_replace.js | 66 - browser/base/content/test/contextMenu/browser.toml | 2 + .../test/contextMenu/browser_contextmenu.js | 69 ++ ...browser_contextmenu_cross_boundary_selection.js | 73 ++ .../contextMenu/browser_strip_on_share_link.js | 12 + .../test/general/browser_documentnavigation.js | 4 +- .../test/performance/browser_preferences_usage.js | 19 - .../browser_popupNotification_security_delay.js | 414 +++---- .../content/test/sidebar/browser_sidebar_adopt.js | 8 +- .../sidebar/browser_sidebar_app_locale_changed.js | 6 +- .../content/test/sidebar/browser_sidebar_keys.js | 16 +- .../content/test/sidebar/browser_sidebar_move.js | 18 +- .../test/sidebar/browser_sidebar_persist.js | 4 +- .../test/sidebar/browser_sidebar_switcher.js | 43 +- .../test/static/browser_all_files_referenced.js | 16 +- .../content/test/static/browser_parsable_css.js | 6 + .../content/test/static/browser_parsable_script.js | 1 + .../test/static/browser_sentence_case_strings.js | 2 +- .../test/sync/browser_contextmenu_sendpage.js | 57 +- browser/base/content/test/sync/browser_sync.js | 10 +- browser/base/content/test/tabPrompts/browser.toml | 2 + .../test/tabPrompts/browser_promptDelays.js | 113 ++ .../content/test/tabPrompts/browser_promptFocus.js | 3 +- browser/base/content/test/tabs/browser.toml | 4 + .../content/test/tabs/browser_blank_tab_label.js | 49 + ...rowser_multiselect_tabs_close_duplicate_tabs.js | 178 +++ .../base/content/test/tabs/browser_tab_preview.js | 94 ++ .../test/tabs/browser_visibleTabs_contextMenu.js | 19 +- .../webextensions/browser_aboutaddons_blanktab.js | 2 +- .../webextensions/browser_extension_sideloading.js | 10 +- .../browser_permissions_local_file.js | 4 +- .../browser_update_interactive_noprompt.js | 2 +- browser/base/content/test/webextensions/head.js | 2 +- browser/base/content/utilityOverlay.js | 5 - 66 files changed, 2831 insertions(+), 2101 deletions(-) create mode 100644 browser/base/content/browser-init.js delete mode 100644 browser/base/content/tabbrowser.css delete mode 100644 browser/base/content/test/alerts/browser_notification_replace.js create mode 100644 browser/base/content/test/contextMenu/browser_contextmenu_cross_boundary_selection.js create mode 100644 browser/base/content/test/tabPrompts/browser_promptDelays.js create mode 100644 browser/base/content/test/tabs/browser_blank_tab_label.js create mode 100644 browser/base/content/test/tabs/browser_multiselect_tabs_close_duplicate_tabs.js (limited to 'browser/base/content') diff --git a/browser/base/content/appmenu-viewcache.inc.xhtml b/browser/base/content/appmenu-viewcache.inc.xhtml index 6d838bd9d6..9633c7d79d 100644 --- a/browser/base/content/appmenu-viewcache.inc.xhtml +++ b/browser/base/content/appmenu-viewcache.inc.xhtml @@ -3,14 +3,11 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - + @@ -217,10 +205,10 @@ + /> + /> @@ -230,15 +218,15 @@ class="subviewbutton" data-l10n-id="appmenu-close-profile" data-l10n-args='{ "profilename": "" }' - oncommand=""/> + /> + /> + /> @@ -262,12 +250,12 @@ + /> + /> @@ -476,7 +462,7 @@ + > @@ -503,7 +489,7 @@ + /> @@ -517,7 +503,7 @@ + /> @@ -535,7 +521,7 @@ + /> + /> + /> + /> @@ -585,7 +571,7 @@ + > - - - - - + + + + + + + @@ -736,16 +717,16 @@ class="subviewbutton subviewbutton-nav" data-l10n-id="library-bookmarks-menu" closemenu="none" - oncommand="BookmarkingUI.showSubView(this);"/> + /> + /> + /> @@ -762,15 +743,29 @@ + > + > + + + + + + + + + + + #include ../../components/reportbrokensite/content/reportBrokenSitePanel.inc.xhtml diff --git a/browser/base/content/browser-addons.js b/browser/base/content/browser-addons.js index 1e97428e24..e00952b2dc 100644 --- a/browser/base/content/browser-addons.js +++ b/browser/base/content/browser-addons.js @@ -618,7 +618,6 @@ var gXPInstallObserver = { break; } case "addon-install-blocked": { - await window.ensureCustomElements("moz-support-link"); // Dismiss the progress notification. Note that this is bad if // there are multiple simultaneous installs happening, see // bug 1329884 for a longer explanation. @@ -1089,27 +1088,18 @@ var BrowserAddonUI = { return { remove: result === 0, report: checkboxState.value }; }, - async reportAddon(addonId, reportEntryPoint) { + async reportAddon(addonId, _reportEntryPoint) { let addon = addonId && (await AddonManager.getAddonByID(addonId)); if (!addon) { return; } - // Do not open an additional about:addons tab if the abuse report should be - // opened in its own tab. - if (lazy.AbuseReporter.amoFormEnabled) { - const amoUrl = lazy.AbuseReporter.getAMOFormURL({ addonId }); - window.openTrustedLinkIn(amoUrl, "tab", { - // Make sure the newly open tab is going to be focused, independently - // from general user prefs. - forceForeground: true, - }); - return; - } - - const win = await BrowserOpenAddonsMgr("addons://list/extension"); - - win.openAbuseReport({ addonId, reportEntryPoint }); + const amoUrl = lazy.AbuseReporter.getAMOFormURL({ addonId }); + window.openTrustedLinkIn(amoUrl, "tab", { + // Make sure the newly open tab is going to be focused, independently + // from general user prefs. + forceForeground: true, + }); }, async removeAddon(addonId) { @@ -1137,7 +1127,85 @@ var BrowserAddonUI = { return; } - BrowserOpenAddonsMgr("addons://detail/" + encodeURIComponent(addon.id)); + this.openAddonsMgr("addons://detail/" + encodeURIComponent(addon.id)); + }, + + /** + * Open about:addons page by given view id. + * @param {String} aView + * View id of page that will open. + * e.g. "addons://discover/" + * @param {Object} options + * { + * selectTabByViewId: If true, if there is the tab opening page having + * same view id, select the tab. Else if the current + * page is blank, load on it. Otherwise, open a new + * tab, then load on it. + * If false, if there is the tab opening + * about:addoons page, select the tab and load page + * for view id on it. Otherwise, leave the loading + * behavior to switchToTabHavingURI(). + * If no options, handles as false. + * } + * @returns {Promise} When the Promise resolves, returns window object loaded the + * view id. + */ + openAddonsMgr(aView, { selectTabByViewId = false } = {}) { + return new Promise(resolve => { + let emWindow; + let browserWindow; + + const receivePong = function (aSubject) { + const browserWin = aSubject.browsingContext.topChromeWindow; + if (!emWindow || browserWin == window /* favor the current window */) { + if ( + selectTabByViewId && + aSubject.gViewController.currentViewId !== aView + ) { + return; + } + + emWindow = aSubject; + browserWindow = browserWin; + } + }; + Services.obs.addObserver(receivePong, "EM-pong"); + Services.obs.notifyObservers(null, "EM-ping"); + Services.obs.removeObserver(receivePong, "EM-pong"); + + if (emWindow) { + if (aView && !selectTabByViewId) { + emWindow.loadView(aView); + } + let tab = browserWindow.gBrowser.getTabForBrowser( + emWindow.docShell.chromeEventHandler + ); + browserWindow.gBrowser.selectedTab = tab; + emWindow.focus(); + resolve(emWindow); + return; + } + + if (selectTabByViewId) { + const target = isBlankPageURL(gBrowser.currentURI.spec) + ? "current" + : "tab"; + openTrustedLinkIn("about:addons", target); + } else { + // This must be a new load, else the ping/pong would have + // found the window above. + switchToTabHavingURI("about:addons", true); + } + + Services.obs.addObserver(function observer(aSubject, aTopic) { + Services.obs.removeObserver(observer, aTopic); + if (aView) { + aSubject.loadView(aView); + } + aSubject.focus(); + resolve(aSubject); + }, "EM-loaded"); + }); }, }; @@ -1551,7 +1619,7 @@ var gUnifiedExtensions = { } else { viewID = "addons://list/extension"; } - await BrowserOpenAddonsMgr(viewID); + await BrowserAddonUI.openAddonsMgr(viewID); return; } } @@ -1877,8 +1945,6 @@ var gUnifiedExtensions = { supportPage = null, type = "warning", }) { - window.ensureCustomElements("moz-message-bar"); - const messageBar = document.createElement("moz-message-bar"); messageBar.setAttribute("type", type); messageBar.classList.add("unified-extensions-message-bar"); @@ -1886,8 +1952,6 @@ var gUnifiedExtensions = { messageBar.setAttribute("data-l10n-attrs", "heading, message"); if (supportPage) { - window.ensureCustomElements("moz-support-link"); - const supportUrl = document.createElement("a", { is: "moz-support-link", }); diff --git a/browser/base/content/browser-allTabsMenu.inc.xhtml b/browser/base/content/browser-allTabsMenu.inc.xhtml index 71d26288f7..1be6576605 100644 --- a/browser/base/content/browser-allTabsMenu.inc.xhtml +++ b/browser/base/content/browser-allTabsMenu.inc.xhtml @@ -9,6 +9,10 @@ class="subviewbutton" oncommand="gTabsPanel.searchTabs();" data-l10n-id="all-tabs-menu-search-tabs"/> + @@ -149,6 +160,10 @@ var gTabsPanel = { entrypoint, 1 ); + BrowserUsageTelemetry.recordInteractionEvent( + entrypoint, + "all-tabs-panel-entrypoint" + ); PanelUI.showSubView( this.kElements.allTabsView, this.allTabsButton, diff --git a/browser/base/content/browser-box.inc.xhtml b/browser/base/content/browser-box.inc.xhtml index 41258d81bb..b030891144 100644 --- a/browser/base/content/browser-box.inc.xhtml +++ b/browser/base/content/browser-box.inc.xhtml @@ -3,7 +3,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. - + diff --git a/browser/base/content/browser-commands.js b/browser/base/content/browser-commands.js index 40eb4d5baa..d80f9588cd 100644 --- a/browser/base/content/browser-commands.js +++ b/browser/base/content/browser-commands.js @@ -295,7 +295,7 @@ var BrowserCommands = { let where = "tab"; if (event) { - where = whereToOpenLink(event, false, true); + where = BrowserUtils.whereToOpenLink(event, false, true); switch (where) { case "tab": @@ -573,4 +573,19 @@ var BrowserCommands = { fullScreen() { window.fullScreen = !window.fullScreen || BrowserHandler.kiosk; }, + + downloadsUI() { + if (PrivateBrowsingUtils.isWindowPrivate(window)) { + openTrustedLinkIn("about:downloads", "tab"); + } else { + PlacesCommandHook.showPlacesOrganizer("Downloads"); + } + }, + + forceEncodingDetection() { + gBrowser.selectedBrowser.forceEncodingDetection(); + BrowserCommands.reloadWithFlags( + Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE + ); + }, }; diff --git a/browser/base/content/browser-init.js b/browser/base/content/browser-init.js new file mode 100644 index 0000000000..0717ce2138 --- /dev/null +++ b/browser/base/content/browser-init.js @@ -0,0 +1,1107 @@ +/* -*- 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/. */ + +let _resolveDelayedStartup; +var delayedStartupPromise = new Promise(resolve => { + _resolveDelayedStartup = resolve; +}); + +var gBrowserInit = { + delayedStartupFinished: false, + domContentLoaded: false, + + _tabToAdopt: undefined, + _firstContentWindowPaintDeferred: Promise.withResolvers(), + idleTasksFinished: Promise.withResolvers(), + + _setupFirstContentWindowPaintPromise() { + let lastTransactionId = window.windowUtils.lastTransactionId; + let layerTreeListener = () => { + if (this.getTabToAdopt()) { + // Need to wait until we finish adopting the tab, or we might end + // up focusing the initial browser and then losing focus when it + // gets swapped out for the tab to adopt. + return; + } + removeEventListener("MozLayerTreeReady", layerTreeListener); + let listener = e => { + if (e.transactionId > lastTransactionId) { + window.removeEventListener("MozAfterPaint", listener); + this._firstContentWindowPaintDeferred.resolve(); + } + }; + addEventListener("MozAfterPaint", listener); + }; + addEventListener("MozLayerTreeReady", layerTreeListener); + }, + + getTabToAdopt() { + if (this._tabToAdopt !== undefined) { + return this._tabToAdopt; + } + + if (window.arguments && window.XULElement.isInstance(window.arguments[0])) { + this._tabToAdopt = window.arguments[0]; + + // Clear the reference of the tab being adopted from the arguments. + window.arguments[0] = null; + } else { + // There was no tab to adopt in the arguments, set _tabToAdopt to null + // to avoid checking it again. + this._tabToAdopt = null; + } + + return this._tabToAdopt; + }, + + _clearTabToAdopt() { + this._tabToAdopt = null; + }, + + // Used to check if the new window is still adopting an existing tab as its first tab + // (e.g. from the WebExtensions internals). + isAdoptingTab() { + return !!this.getTabToAdopt(); + }, + + onBeforeInitialXULLayout() { + this._setupFirstContentWindowPaintPromise(); + + updateBookmarkToolbarVisibility(); + + // Set a sane starting width/height for all resolutions on new profiles. + if (ChromeUtils.shouldResistFingerprinting("RoundWindowSize", null)) { + // When the fingerprinting resistance is enabled, making sure that we don't + // have a maximum window to interfere with generating rounded window dimensions. + document.documentElement.setAttribute("sizemode", "normal"); + } else if (!document.documentElement.hasAttribute("width")) { + const TARGET_WIDTH = 1280; + const TARGET_HEIGHT = 1040; + let width = Math.min(screen.availWidth * 0.9, TARGET_WIDTH); + let height = Math.min(screen.availHeight * 0.9, TARGET_HEIGHT); + + document.documentElement.setAttribute("width", width); + document.documentElement.setAttribute("height", height); + + if (width < TARGET_WIDTH && height < TARGET_HEIGHT) { + document.documentElement.setAttribute("sizemode", "maximized"); + } + } + if (AppConstants.MENUBAR_CAN_AUTOHIDE) { + const toolbarMenubar = document.getElementById("toolbar-menubar"); + // set a default value + if (!toolbarMenubar.hasAttribute("autohide")) { + toolbarMenubar.setAttribute("autohide", true); + } + document.l10n.setAttributes( + toolbarMenubar, + "toolbar-context-menu-menu-bar-cmd" + ); + toolbarMenubar.setAttribute("data-l10n-attrs", "toolbarname"); + } + + // Run menubar initialization first, to avoid TabsInTitlebar code picking + // up mutations from it and causing a reflow. + AutoHideMenubar.init(); + // Update the chromemargin attribute so the window can be sized correctly. + window.TabBarVisibility.update(); + TabsInTitlebar.init(); + + new LightweightThemeConsumer(document); + + if ( + Services.prefs.getBoolPref( + "toolkit.legacyUserProfileCustomizations.windowIcon", + false + ) + ) { + document.documentElement.setAttribute("icon", "main-window"); + } + + // Call this after we set attributes that might change toolbars' computed + // text color. + ToolbarIconColor.init(); + }, + + onDOMContentLoaded() { + // This needs setting up before we create the first remote browser. + window.docShell.treeOwner + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIAppWindow).XULBrowserWindow = window.XULBrowserWindow; + window.browserDOMWindow = new nsBrowserAccess(); + + gBrowser = window._gBrowser; + delete window._gBrowser; + gBrowser.init(); + + BrowserWindowTracker.track(window); + + FirefoxViewHandler.init(); + + gNavToolbox.palette = document.getElementById( + "BrowserToolbarPalette" + ).content; + for (let area of CustomizableUI.areas) { + let type = CustomizableUI.getAreaType(area); + if (type == CustomizableUI.TYPE_TOOLBAR) { + let node = document.getElementById(area); + CustomizableUI.registerToolbarNode(node); + } + } + BrowserSearch.initPlaceHolder(); + + // Hack to ensure that the various initial pages favicon is loaded + // instantaneously, to avoid flickering and improve perceived performance. + this._callWithURIToLoad(uriToLoad => { + let url; + try { + url = Services.io.newURI(uriToLoad); + } catch (e) { + return; + } + let nonQuery = url.prePath + url.filePath; + if (nonQuery in gPageIcons) { + gBrowser.setIcon(gBrowser.selectedTab, gPageIcons[nonQuery]); + } + }); + + updateFxaToolbarMenu(gFxaToolbarEnabled, true); + + updatePrintCommands(gPrintEnabled); + + gUnifiedExtensions.init(); + + // Setting the focus will cause a style flush, it's preferable to call anything + // that will modify the DOM from within this function before this call. + this._setInitialFocus(); + + this.domContentLoaded = true; + }, + + onLoad() { + gBrowser.addEventListener("DOMUpdateBlockedPopups", gPopupBlockerObserver); + gBrowser.addEventListener( + "TranslationsParent:LanguageState", + FullPageTranslationsPanel + ); + gBrowser.addEventListener( + "TranslationsParent:OfferTranslation", + FullPageTranslationsPanel + ); + gBrowser.addTabsProgressListener(FullPageTranslationsPanel); + + window.addEventListener("AppCommand", HandleAppCommandEvent, true); + + // These routines add message listeners. They must run before + // loading the frame script to ensure that we don't miss any + // message sent between when the frame script is loaded and when + // the listener is registered. + CaptivePortalWatcher.init(); + ZoomUI.init(window); + + if (!gMultiProcessBrowser) { + // There is a Content:Click message manually sent from content. + gBrowser.tabpanels.addEventListener("click", contentAreaClick, { + capture: true, + mozSystemGroup: true, + }); + } + + // hook up UI through progress listener + gBrowser.addProgressListener(window.XULBrowserWindow); + gBrowser.addTabsProgressListener(window.TabsProgressListener); + + SidebarController.init(); + + // We do this in onload because we want to ensure the button's state + // doesn't flicker as the window is being shown. + DownloadsButton.init(); + + // Certain kinds of automigration rely on this notification to complete + // their tasks BEFORE the browser window is shown. SessionStore uses it to + // restore tabs into windows AFTER important parts like gMultiProcessBrowser + // have been initialized. + Services.obs.notifyObservers(window, "browser-window-before-show"); + + if (!window.toolbar.visible) { + // adjust browser UI for popups + gURLBar.readOnly = true; + } + + // Misc. inits. + gUIDensity.init(); + TabletModeUpdater.init(); + CombinedStopReload.ensureInitialized(); + gPrivateBrowsingUI.init(); + BrowserSearch.init(); + BrowserPageActions.init(); + if (gToolbarKeyNavEnabled) { + ToolbarKeyboardNavigator.init(); + } + + // Update UI if browser is under remote control. + gRemoteControl.updateVisualCue(); + + // If we are given a tab to swap in, take care of it before first paint to + // avoid an about:blank flash. + let tabToAdopt = this.getTabToAdopt(); + if (tabToAdopt) { + let evt = new CustomEvent("before-initial-tab-adopted", { + bubbles: true, + }); + gBrowser.tabpanels.dispatchEvent(evt); + + // Stop the about:blank load + gBrowser.stop(); + + // Remove the speculative focus from the urlbar to let the url be formatted. + gURLBar.removeAttribute("focused"); + + let swapBrowsers = () => { + try { + gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToAdopt); + } catch (e) { + console.error(e); + } + + // Clear the reference to the tab once its adoption has been completed. + this._clearTabToAdopt(); + }; + if (tabToAdopt.linkedBrowser.isRemoteBrowser) { + // For remote browsers, wait for the paint event, otherwise the tabs + // are not yet ready and focus gets confused because the browser swaps + // out while tabs are switching. + addEventListener("MozAfterPaint", swapBrowsers, { once: true }); + } else { + swapBrowsers(); + } + } + + // Wait until chrome is painted before executing code not critical to making the window visible + this._boundDelayedStartup = this._delayedStartup.bind(this); + window.addEventListener("MozAfterPaint", this._boundDelayedStartup); + + if (!PrivateBrowsingUtils.enabled) { + document.getElementById("Tools:PrivateBrowsing").hidden = true; + // Setting disabled doesn't disable the shortcut, so we just remove + // the keybinding. + document.getElementById("key_privatebrowsing").remove(); + } + + if (BrowserUIUtils.quitShortcutDisabled) { + document.getElementById("key_quitApplication").remove(); + document.getElementById("menu_FileQuitItem").removeAttribute("key"); + + PanelMultiView.getViewNode( + document, + "appMenu-quit-button2" + )?.removeAttribute("key"); + } + + this._loadHandled = true; + }, + + _cancelDelayedStartup() { + window.removeEventListener("MozAfterPaint", this._boundDelayedStartup); + this._boundDelayedStartup = null; + }, + + _delayedStartup() { + let { TelemetryTimestamps } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryTimestamps.sys.mjs" + ); + TelemetryTimestamps.add("delayedStartupStarted"); + + this._cancelDelayedStartup(); + + // Bug 1531854 - The hidden window is force-created here + // until all of its dependencies are handled. + Services.appShell.hiddenDOMWindow; + + gBrowser.addEventListener( + "PermissionStateChange", + function () { + gIdentityHandler.refreshIdentityBlock(); + gPermissionPanel.updateSharingIndicator(); + }, + true + ); + + this._handleURIToLoad(); + + Services.obs.addObserver(gIdentityHandler, "perm-changed"); + Services.obs.addObserver(gRemoteControl, "devtools-socket"); + Services.obs.addObserver(gRemoteControl, "marionette-listening"); + Services.obs.addObserver(gRemoteControl, "remote-listening"); + Services.obs.addObserver( + gSessionHistoryObserver, + "browser:purge-session-history" + ); + Services.obs.addObserver( + gStoragePressureObserver, + "QuotaManager::StoragePressure" + ); + Services.obs.addObserver(gXPInstallObserver, "addon-install-disabled"); + Services.obs.addObserver(gXPInstallObserver, "addon-install-started"); + Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked"); + Services.obs.addObserver( + gXPInstallObserver, + "addon-install-fullscreen-blocked" + ); + Services.obs.addObserver( + gXPInstallObserver, + "addon-install-origin-blocked" + ); + Services.obs.addObserver( + gXPInstallObserver, + "addon-install-policy-blocked" + ); + Services.obs.addObserver( + gXPInstallObserver, + "addon-install-webapi-blocked" + ); + Services.obs.addObserver(gXPInstallObserver, "addon-install-failed"); + Services.obs.addObserver(gXPInstallObserver, "addon-install-confirmation"); + Services.obs.addObserver(gKeywordURIFixup, "keyword-uri-fixup"); + + BrowserOffline.init(); + CanvasPermissionPromptHelper.init(); + WebAuthnPromptHelper.init(); + ContentAnalysis.initialize(document); + + // Initialize the full zoom setting. + // We do this before the session restore service gets initialized so we can + // apply full zoom settings to tabs restored by the session restore service. + FullZoom.init(); + PanelUI.init(shouldSuppressPopupNotifications); + ReportBrokenSite.init(gBrowser); + + UpdateUrlbarSearchSplitterState(); + + BookmarkingUI.init(); + BrowserSearch.delayedStartupInit(); + SearchUIUtils.init(); + gProtectionsHandler.init(); + HomePage.delayedStartup().catch(console.error); + + let safeMode = document.getElementById("helpSafeMode"); + if (Services.appinfo.inSafeMode) { + document.l10n.setAttributes(safeMode, "menu-help-exit-troubleshoot-mode"); + safeMode.setAttribute( + "appmenu-data-l10n-id", + "appmenu-help-exit-troubleshoot-mode" + ); + } + + // BiDi UI + gBidiUI = isBidiEnabled(); + if (gBidiUI) { + document.getElementById("documentDirection-separator").hidden = false; + document.getElementById("documentDirection-swap").hidden = false; + document.getElementById("textfieldDirection-separator").hidden = false; + document.getElementById("textfieldDirection-swap").hidden = false; + } + + // Setup click-and-hold gestures access to the session history + // menus if global click-and-hold isn't turned on + if (!Services.prefs.getBoolPref("ui.click_hold_context_menus", false)) { + SetClickAndHoldHandlers(); + } + + function initBackForwardButtonTooltip(tooltipId, l10nId, shortcutId) { + let shortcut = document.getElementById(shortcutId); + shortcut = ShortcutUtils.prettifyShortcut(shortcut); + + let tooltip = document.getElementById(tooltipId); + document.l10n.setAttributes(tooltip, l10nId, { shortcut }); + } + + initBackForwardButtonTooltip( + "back-button-tooltip-description", + "navbar-tooltip-back-2", + "goBackKb" + ); + + initBackForwardButtonTooltip( + "forward-button-tooltip-description", + "navbar-tooltip-forward-2", + "goForwardKb" + ); + + PlacesToolbarHelper.init(); + + ctrlTab.readPref(); + Services.prefs.addObserver(ctrlTab.prefName, ctrlTab); + + // The object handling the downloads indicator is initialized here in the + // delayed startup function, but the actual indicator element is not loaded + // unless there are downloads to be displayed. + DownloadsButton.initializeIndicator(); + + if (AppConstants.platform != "macosx") { + updateEditUIVisibility(); + let placesContext = document.getElementById("placesContext"); + placesContext.addEventListener("popupshowing", updateEditUIVisibility); + placesContext.addEventListener("popuphiding", updateEditUIVisibility); + } + + FullScreen.init(); + MenuTouchModeObserver.init(); + + if (AppConstants.MOZ_DATA_REPORTING) { + gDataNotificationInfoBar.init(); + } + + if (!AppConstants.MOZILLA_OFFICIAL) { + DevelopmentHelpers.init(); + } + + gExtensionsNotifications.init(); + + let wasMinimized = window.windowState == window.STATE_MINIMIZED; + window.addEventListener("sizemodechange", () => { + let isMinimized = window.windowState == window.STATE_MINIMIZED; + if (wasMinimized != isMinimized) { + wasMinimized = isMinimized; + UpdatePopupNotificationsVisibility(); + } + }); + + window.addEventListener("mousemove", MousePosTracker); + window.addEventListener("dragover", MousePosTracker); + + gNavToolbox.addEventListener("customizationstarting", CustomizationHandler); + gNavToolbox.addEventListener("aftercustomization", CustomizationHandler); + + SessionStore.promiseInitialized.then(() => { + // Bail out if the window has been closed in the meantime. + if (window.closed) { + return; + } + + // Enable the Restore Last Session command if needed + RestoreLastSessionObserver.init(); + + SidebarController.startDelayedLoad(); + + PanicButtonNotifier.init(); + }); + + if (BrowserHandler.kiosk) { + // We don't modify popup windows for kiosk mode + if (!gURLBar.readOnly) { + window.fullScreen = true; + } + } + + if (Services.policies.status === Services.policies.ACTIVE) { + if (!Services.policies.isAllowed("hideShowMenuBar")) { + document + .getElementById("toolbar-menubar") + .removeAttribute("toolbarname"); + } + if (!Services.policies.isAllowed("filepickers")) { + let savePageCommand = document.getElementById("Browser:SavePage"); + let openFileCommand = document.getElementById("Browser:OpenFile"); + + savePageCommand.setAttribute("disabled", "true"); + openFileCommand.setAttribute("disabled", "true"); + + document.addEventListener("FilePickerBlocked", function (event) { + let browser = event.target; + + let notificationBox = browser + .getTabBrowser() + ?.getNotificationBox(browser); + + // Prevent duplicate notifications + if ( + notificationBox && + !notificationBox.getNotificationWithValue("filepicker-blocked") + ) { + notificationBox.appendNotification("filepicker-blocked", { + label: { + "l10n-id": "filepicker-blocked-infobar", + }, + priority: notificationBox.PRIORITY_INFO_LOW, + }); + } + }); + } + let policies = Services.policies.getActivePolicies(); + if ("ManagedBookmarks" in policies) { + let managedBookmarks = policies.ManagedBookmarks; + let children = managedBookmarks.filter( + child => !("toplevel_name" in child) + ); + if (children.length) { + let managedBookmarksButton = + document.createXULElement("toolbarbutton"); + managedBookmarksButton.setAttribute("id", "managed-bookmarks"); + managedBookmarksButton.setAttribute("class", "bookmark-item"); + let toplevel = managedBookmarks.find( + element => "toplevel_name" in element + ); + if (toplevel) { + managedBookmarksButton.setAttribute( + "label", + toplevel.toplevel_name + ); + } else { + document.l10n.setAttributes( + managedBookmarksButton, + "managed-bookmarks" + ); + } + managedBookmarksButton.setAttribute("context", "placesContext"); + managedBookmarksButton.setAttribute("container", "true"); + managedBookmarksButton.setAttribute("removable", "false"); + managedBookmarksButton.setAttribute("type", "menu"); + + let managedBookmarksPopup = document.createXULElement("menupopup"); + managedBookmarksPopup.setAttribute("id", "managed-bookmarks-popup"); + managedBookmarksPopup.setAttribute( + "oncommand", + "PlacesToolbarHelper.openManagedBookmark(event);" + ); + managedBookmarksPopup.setAttribute( + "ondragover", + "event.dataTransfer.effectAllowed='none';" + ); + managedBookmarksPopup.setAttribute( + "ondragstart", + "PlacesToolbarHelper.onDragStartManaged(event);" + ); + managedBookmarksPopup.setAttribute( + "onpopupshowing", + "PlacesToolbarHelper.populateManagedBookmarks(this);" + ); + managedBookmarksPopup.setAttribute("placespopup", "true"); + managedBookmarksPopup.setAttribute("is", "places-popup"); + managedBookmarksPopup.classList.add("toolbar-menupopup"); + managedBookmarksButton.appendChild(managedBookmarksPopup); + + gNavToolbox.palette.appendChild(managedBookmarksButton); + + CustomizableUI.ensureWidgetPlacedInWindow( + "managed-bookmarks", + window + ); + + // Add button if it doesn't exist + if (!CustomizableUI.getPlacementOfWidget("managed-bookmarks")) { + CustomizableUI.addWidgetToArea( + "managed-bookmarks", + CustomizableUI.AREA_BOOKMARKS, + 0 + ); + } + } + } + } + + CaptivePortalWatcher.delayedStartup(); + + ShoppingSidebarManager.ensureInitialized(); + + SessionStore.promiseAllWindowsRestored.then(() => { + this._schedulePerWindowIdleTasks(); + document.documentElement.setAttribute("sessionrestored", "true"); + }); + + this.delayedStartupFinished = true; + _resolveDelayedStartup(); + Services.obs.notifyObservers(window, "browser-delayed-startup-finished"); + TelemetryTimestamps.add("delayedStartupFinished"); + // We've announced that delayed startup has finished. Do not add code past this point. + }, + + /** + * Resolved on the first MozLayerTreeReady and next MozAfterPaint in the + * parent process. + */ + get firstContentWindowPaintPromise() { + return this._firstContentWindowPaintDeferred.promise; + }, + + _setInitialFocus() { + let initiallyFocusedElement = document.commandDispatcher.focusedElement; + + // To prevent startup flicker, the urlbar has the 'focused' attribute set + // by default. If we are not sure the urlbar will be focused in this + // window, we need to remove the attribute before first paint. + // TODO (bug 1629956): The urlbar having the 'focused' attribute by default + // isn't a useful optimization anymore since UrlbarInput needs layout + // information to focus the urlbar properly. + let shouldRemoveFocusedAttribute = true; + + this._callWithURIToLoad(uriToLoad => { + if ( + isBlankPageURL(uriToLoad) || + uriToLoad == "about:privatebrowsing" || + this.getTabToAdopt()?.isEmpty + ) { + gURLBar.select(); + shouldRemoveFocusedAttribute = false; + return; + } + + // If the initial browser is remote, in order to optimize for first paint, + // we'll defer switching focus to that browser until it has painted. + // Otherwise use a regular promise to guarantee that mutationobserver + // microtasks that could affect focusability have run. + let promise = gBrowser.selectedBrowser.isRemoteBrowser + ? this.firstContentWindowPaintPromise + : Promise.resolve(); + + promise.then(() => { + // If focus didn't move while we were waiting, we're okay to move to + // the browser. + if ( + document.commandDispatcher.focusedElement == initiallyFocusedElement + ) { + gBrowser.selectedBrowser.focus(); + } + }); + }); + + // Delay removing the attribute using requestAnimationFrame to avoid + // invalidating styles multiple times in a row if uriToLoadPromise + // resolves before first paint. + if (shouldRemoveFocusedAttribute) { + window.requestAnimationFrame(() => { + if (shouldRemoveFocusedAttribute) { + gURLBar.removeAttribute("focused"); + } + }); + } + }, + + _handleURIToLoad() { + this._callWithURIToLoad(uriToLoad => { + if (!uriToLoad) { + // We don't check whether window.arguments[5] (userContextId) is set + // because tabbrowser.js takes care of that for the initial tab. + return; + } + + // We don't check if uriToLoad is a XULElement because this case has + // already been handled before first paint, and the argument cleared. + if (Array.isArray(uriToLoad)) { + // This function throws for certain malformed URIs, so use exception handling + // so that we don't disrupt startup + try { + gBrowser.loadTabs(uriToLoad, { + inBackground: false, + replace: true, + // See below for the semantics of window.arguments. Only the minimum is supported. + userContextId: window.arguments[5], + triggeringPrincipal: + window.arguments[8] || + Services.scriptSecurityManager.getSystemPrincipal(), + allowInheritPrincipal: window.arguments[9], + csp: window.arguments[10], + fromExternal: true, + }); + } catch (e) {} + } else if (window.arguments.length >= 3) { + // window.arguments[1]: extraOptions (nsIPropertyBag) + // [2]: referrerInfo (nsIReferrerInfo) + // [3]: postData (nsIInputStream) + // [4]: allowThirdPartyFixup (bool) + // [5]: userContextId (int) + // [6]: originPrincipal (nsIPrincipal) + // [7]: originStoragePrincipal (nsIPrincipal) + // [8]: triggeringPrincipal (nsIPrincipal) + // [9]: allowInheritPrincipal (bool) + // [10]: csp (nsIContentSecurityPolicy) + // [11]: nsOpenWindowInfo + let userContextId = + window.arguments[5] != undefined + ? window.arguments[5] + : Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID; + + let hasValidUserGestureActivation = undefined; + let fromExternal = undefined; + let globalHistoryOptions = undefined; + let triggeringRemoteType = undefined; + let forceAllowDataURI = false; + let wasSchemelessInput = false; + if (window.arguments[1]) { + if (!(window.arguments[1] instanceof Ci.nsIPropertyBag2)) { + throw new Error( + "window.arguments[1] must be null or Ci.nsIPropertyBag2!" + ); + } + + let extraOptions = window.arguments[1]; + if (extraOptions.hasKey("hasValidUserGestureActivation")) { + hasValidUserGestureActivation = extraOptions.getPropertyAsBool( + "hasValidUserGestureActivation" + ); + } + if (extraOptions.hasKey("fromExternal")) { + fromExternal = extraOptions.getPropertyAsBool("fromExternal"); + } + if (extraOptions.hasKey("triggeringSponsoredURL")) { + globalHistoryOptions = { + triggeringSponsoredURL: extraOptions.getPropertyAsACString( + "triggeringSponsoredURL" + ), + }; + if (extraOptions.hasKey("triggeringSponsoredURLVisitTimeMS")) { + globalHistoryOptions.triggeringSponsoredURLVisitTimeMS = + extraOptions.getPropertyAsUint64( + "triggeringSponsoredURLVisitTimeMS" + ); + } + } + if (extraOptions.hasKey("triggeringRemoteType")) { + triggeringRemoteType = extraOptions.getPropertyAsACString( + "triggeringRemoteType" + ); + } + if (extraOptions.hasKey("forceAllowDataURI")) { + forceAllowDataURI = + extraOptions.getPropertyAsBool("forceAllowDataURI"); + } + if (extraOptions.hasKey("wasSchemelessInput")) { + wasSchemelessInput = + extraOptions.getPropertyAsBool("wasSchemelessInput"); + } + } + + try { + openLinkIn(uriToLoad, "current", { + referrerInfo: window.arguments[2] || null, + postData: window.arguments[3] || null, + allowThirdPartyFixup: window.arguments[4] || false, + userContextId, + // pass the origin principal (if any) and force its use to create + // an initial about:blank viewer if present: + originPrincipal: window.arguments[6], + originStoragePrincipal: window.arguments[7], + triggeringPrincipal: window.arguments[8], + // TODO fix allowInheritPrincipal to default to false. + // Default to true unless explicitly set to false because of bug 1475201. + allowInheritPrincipal: window.arguments[9] !== false, + csp: window.arguments[10], + forceAboutBlankViewerInCurrent: !!window.arguments[6], + forceAllowDataURI, + hasValidUserGestureActivation, + fromExternal, + globalHistoryOptions, + triggeringRemoteType, + wasSchemelessInput, + }); + } catch (e) { + console.error(e); + } + + window.focus(); + } else { + // Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3. + // Such callers expect that window.arguments[0] is handled as a single URI. + loadOneOrMoreURIs( + uriToLoad, + Services.scriptSecurityManager.getSystemPrincipal(), + null + ); + } + }); + }, + + /** + * Use this function as an entry point to schedule tasks that + * need to run once per window after startup, and can be scheduled + * by using an idle callback. + * + * The functions scheduled here will fire from idle callbacks + * once every window has finished being restored by session + * restore, and after the equivalent only-once tasks + * have run (from _scheduleStartupIdleTasks in BrowserGlue.sys.mjs). + */ + _schedulePerWindowIdleTasks() { + // Bail out if the window has been closed in the meantime. + if (window.closed) { + return; + } + + function scheduleIdleTask(func, options) { + requestIdleCallback(function idleTaskRunner() { + if (!window.closed) { + func(); + } + }, options); + } + + scheduleIdleTask(() => { + // Initialize the Sync UI + gSync.init(); + }); + + scheduleIdleTask(() => { + // Read prefers-reduced-motion setting + let reduceMotionQuery = window.matchMedia( + "(prefers-reduced-motion: reduce)" + ); + function readSetting() { + gReduceMotionSetting = reduceMotionQuery.matches; + } + reduceMotionQuery.addListener(readSetting); + readSetting(); + }); + + scheduleIdleTask(() => { + // setup simple gestures support + gGestureSupport.init(true); + + // setup history swipe animation + gHistorySwipeAnimation.init(); + }); + + scheduleIdleTask(() => { + gBrowserThumbnails.init(); + }); + + scheduleIdleTask( + () => { + // Initialize the download manager some time after the app starts so that + // auto-resume downloads begin (such as after crashing or quitting with + // active downloads) and speeds up the first-load of the download manager UI. + // If the user manually opens the download manager before the timeout, the + // downloads will start right away, and initializing again won't hurt. + try { + DownloadsCommon.initializeAllDataLinks(); + ChromeUtils.importESModule( + "resource:///modules/DownloadsTaskbar.sys.mjs" + ).DownloadsTaskbar.registerIndicator(window); + if (AppConstants.platform == "macosx") { + ChromeUtils.importESModule( + "resource:///modules/DownloadsMacFinderProgress.sys.mjs" + ).DownloadsMacFinderProgress.register(); + } + Services.telemetry.setEventRecordingEnabled("downloads", true); + } catch (ex) { + console.error(ex); + } + }, + { timeout: 10000 } + ); + + if (Win7Features) { + scheduleIdleTask(() => Win7Features.onOpenWindow()); + } + + scheduleIdleTask(async () => { + NewTabPagePreloading.maybeCreatePreloadedBrowser(window); + }); + + scheduleIdleTask(() => { + gGfxUtils.init(); + }); + + // This should always go last, since the idle tasks (except for the ones with + // timeouts) should execute in order. Note that this observer notification is + // not guaranteed to fire, since the window could close before we get here. + scheduleIdleTask(() => { + this.idleTasksFinished.resolve(); + Services.obs.notifyObservers( + window, + "browser-idle-startup-tasks-finished" + ); + }); + + scheduleIdleTask(() => { + gProfiles.init(); + }); + }, + + // Returns the URI(s) to load at startup if it is immediately known, or a + // promise resolving to the URI to load. + get uriToLoadPromise() { + delete this.uriToLoadPromise; + return (this.uriToLoadPromise = (function () { + // window.arguments[0]: URI to load (string), or an nsIArray of + // nsISupportsStrings to load, or a xul:tab of + // a tabbrowser, which will be replaced by this + // window (for this case, all other arguments are + // ignored). + let uri = window.arguments?.[0]; + if (!uri || window.XULElement.isInstance(uri)) { + return null; + } + + let defaultArgs = BrowserHandler.defaultArgs; + + // If the given URI is different from the homepage, we want to load it. + if (uri != defaultArgs) { + AboutNewTab.noteNonDefaultStartup(); + + if (uri instanceof Ci.nsIArray) { + // Transform the nsIArray of nsISupportsString's into a JS Array of + // JS strings. + return Array.from( + uri.enumerate(Ci.nsISupportsString), + supportStr => supportStr.data + ); + } else if (uri instanceof Ci.nsISupportsString) { + return uri.data; + } + return uri; + } + + // The URI appears to be the the homepage. We want to load it only if + // session restore isn't about to override the homepage. + let willOverride = SessionStartup.willOverrideHomepage; + if (typeof willOverride == "boolean") { + return willOverride ? null : uri; + } + return willOverride.then(willOverrideHomepage => + willOverrideHomepage ? null : uri + ); + })()); + }, + + // Calls the given callback with the URI to load at startup. + // Synchronously if possible, or after uriToLoadPromise resolves otherwise. + _callWithURIToLoad(callback) { + let uriToLoad = this.uriToLoadPromise; + if (uriToLoad && uriToLoad.then) { + uriToLoad.then(callback); + } else { + callback(uriToLoad); + } + }, + + onUnload() { + gUIDensity.uninit(); + + TabsInTitlebar.uninit(); + + ToolbarIconColor.uninit(); + + // In certain scenarios it's possible for unload to be fired before onload, + // (e.g. if the window is being closed after browser.js loads but before the + // load completes). In that case, there's nothing to do here. + if (!this._loadHandled) { + return; + } + + // First clean up services initialized in gBrowserInit.onLoad (or those whose + // uninit methods don't depend on the services having been initialized). + + CombinedStopReload.uninit(); + + gGestureSupport.init(false); + + gHistorySwipeAnimation.uninit(); + + FullScreen.uninit(); + + gSync.uninit(); + + gExtensionsNotifications.uninit(); + gUnifiedExtensions.uninit(); + + try { + gBrowser.removeProgressListener(window.XULBrowserWindow); + gBrowser.removeTabsProgressListener(window.TabsProgressListener); + } catch (ex) {} + + PlacesToolbarHelper.uninit(); + + BookmarkingUI.uninit(); + + TabletModeUpdater.uninit(); + + gTabletModePageCounter.finish(); + + CaptivePortalWatcher.uninit(); + + SidebarController.uninit(); + + DownloadsButton.uninit(); + + if (gToolbarKeyNavEnabled) { + ToolbarKeyboardNavigator.uninit(); + } + + BrowserSearch.uninit(); + + NewTabPagePreloading.removePreloadedBrowser(window); + + FirefoxViewHandler.uninit(); + + // Now either cancel delayedStartup, or clean up the services initialized from + // it. + if (this._boundDelayedStartup) { + this._cancelDelayedStartup(); + } else { + if (Win7Features) { + Win7Features.onCloseWindow(); + } + Services.prefs.removeObserver(ctrlTab.prefName, ctrlTab); + ctrlTab.uninit(); + gBrowserThumbnails.uninit(); + gProtectionsHandler.uninit(); + FullZoom.destroy(); + + Services.obs.removeObserver(gIdentityHandler, "perm-changed"); + Services.obs.removeObserver(gRemoteControl, "devtools-socket"); + Services.obs.removeObserver(gRemoteControl, "marionette-listening"); + Services.obs.removeObserver(gRemoteControl, "remote-listening"); + Services.obs.removeObserver( + gSessionHistoryObserver, + "browser:purge-session-history" + ); + Services.obs.removeObserver( + gStoragePressureObserver, + "QuotaManager::StoragePressure" + ); + Services.obs.removeObserver(gXPInstallObserver, "addon-install-disabled"); + Services.obs.removeObserver(gXPInstallObserver, "addon-install-started"); + Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked"); + Services.obs.removeObserver( + gXPInstallObserver, + "addon-install-fullscreen-blocked" + ); + Services.obs.removeObserver( + gXPInstallObserver, + "addon-install-origin-blocked" + ); + Services.obs.removeObserver( + gXPInstallObserver, + "addon-install-policy-blocked" + ); + Services.obs.removeObserver( + gXPInstallObserver, + "addon-install-webapi-blocked" + ); + Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed"); + Services.obs.removeObserver( + gXPInstallObserver, + "addon-install-confirmation" + ); + Services.obs.removeObserver(gKeywordURIFixup, "keyword-uri-fixup"); + + MenuTouchModeObserver.uninit(); + BrowserOffline.uninit(); + CanvasPermissionPromptHelper.uninit(); + WebAuthnPromptHelper.uninit(); + PanelUI.uninit(); + } + + // Final window teardown, do this last. + gBrowser.destroy(); + window.XULBrowserWindow = null; + window.docShell.treeOwner + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIAppWindow).XULBrowserWindow = null; + window.browserDOMWindow = null; + }, +}; + +gBrowserInit.idleTasksFinishedPromise = gBrowserInit.idleTasksFinished.promise; diff --git a/browser/base/content/browser-menubar.inc b/browser/base/content/browser-menubar.inc index 0c8b4a1cf6..0eebfea75a 100644 --- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -140,22 +140,7 @@ - - - - - + @@ -192,7 +177,7 @@ #ifdef XP_MACOSX diff --git a/browser/base/content/browser-pageActions.js b/browser/base/content/browser-pageActions.js index 1fd1062948..fe0453160d 100644 --- a/browser/base/content/browser-pageActions.js +++ b/browser/base/content/browser-pageActions.js @@ -970,7 +970,7 @@ var BrowserPageActions = { this._contextAction = null; let viewID = "addons://detail/" + encodeURIComponent(action.extensionID); - window.BrowserOpenAddonsMgr(viewID); + window.BrowserAddonUI.openAddonsMgr(viewID); }, /** diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js index c940fade5f..404a080983 100644 --- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -55,7 +55,6 @@ var StarUI = { delete this.panel; this._createPanelIfNeeded(); var element = this._element("editBookmarkPanel"); - window.ensureCustomElements("moz-button-group"); // initially the panel is hidden // to avoid impacting startup / new window performance element.hidden = false; @@ -1378,7 +1377,7 @@ var BookmarkingUI = { this.updateLabel( "BMB_viewBookmarksSidebar", - SidebarUI.currentID == "viewBookmarksSidebar" + SidebarController.currentID == "viewBookmarksSidebar" ); this.updateLabel("BMB_viewBookmarksToolbar", !this.toolbar.collapsed); }, @@ -1999,6 +1998,13 @@ var BookmarkingUI = { case "ViewHiding": this.onPanelMenuViewHiding(aEvent); break; + case "command": + if (aEvent.target.id == "panelMenu_searchBookmarks") { + PlacesCommandHook.searchBookmarks(); + } else if (aEvent.target.id == "panelMenu_viewBookmarksToolbar") { + this.toggleBookmarksToolbar("bookmark-tools"); + } + break; } }, @@ -2026,12 +2032,15 @@ var BookmarkingUI = { panelview ); panelview.removeEventListener("ViewShowing", this); + panelview.addEventListener("command", this); }, onPanelMenuViewHiding: function BUI_onViewHiding(aEvent) { this._panelMenuView.uninit(); delete this._panelMenuView; - aEvent.target.removeEventListener("ViewHiding", this); + let panelview = aEvent.target; + panelview.removeEventListener("ViewHiding", this); + panelview.removeEventListener("command", this); }, handlePlacesEvents(aEvents) { diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc index e247f0641e..f77ce1661e 100644 --- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -91,8 +91,8 @@ - - + + @@ -276,7 +276,7 @@ + oncommand="SidebarController.toggle('viewBookmarksSidebar');"/> + oncommand="SidebarController.toggle('viewHistorySidebar');"/> diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js index 60bd4fc01c..eaed3950fe 100644 --- a/browser/base/content/browser-siteIdentity.js +++ b/browser/base/content/browser-siteIdentity.js @@ -177,7 +177,6 @@ var gIdentityHandler = { _popupInitialized: false, _initializePopup() { - window.ensureCustomElements("moz-support-link"); if (!this._popupInitialized) { let wrapper = document.getElementById("template-identity-popup"); wrapper.replaceWith(wrapper.content); diff --git a/browser/base/content/browser-sitePermissionPanel.js b/browser/base/content/browser-sitePermissionPanel.js index d977653f51..de7b2cc39a 100644 --- a/browser/base/content/browser-sitePermissionPanel.js +++ b/browser/base/content/browser-sitePermissionPanel.js @@ -14,9 +14,6 @@ var gPermissionPanel = { if (!this._popupInitialized) { let wrapper = document.getElementById("template-permission-popup"); wrapper.replaceWith(wrapper.content); - - window.ensureCustomElements("moz-support-link"); - this._popupInitialized = true; } }, diff --git a/browser/base/content/browser-siteProtections.js b/browser/base/content/browser-siteProtections.js index 043dc53b95..31b87ac7e0 100644 --- a/browser/base/content/browser-siteProtections.js +++ b/browser/base/content/browser-siteProtections.js @@ -1377,7 +1377,6 @@ var gProtectionsHandler = { let wrapper = document.getElementById("template-protections-popup"); this._protectionsPopup = wrapper.content.firstElementChild; wrapper.replaceWith(wrapper.content); - window.ensureCustomElements("moz-support-link"); this.maybeSetMilestoneCounterText(); @@ -1591,8 +1590,6 @@ var gProtectionsHandler = { // Add an observer to observe that the history has been cleared. Services.obs.addObserver(this, "browser:purge-session-history"); - - window.ensureCustomElements("moz-button-group", "moz-toggle"); }, uninit() { @@ -2601,14 +2598,14 @@ var gProtectionsHandler = { _createHeroElement(doc, message) { const messageEl = this._createElement(doc, "div"); messageEl.setAttribute("id", "protections-popup-message"); - messageEl.classList.add("whatsNew-hero-message"); + messageEl.classList.add("protections-hero-message"); const wrapperEl = this._createElement(doc, "div"); - wrapperEl.classList.add("whatsNew-message-body"); + wrapperEl.classList.add("protections-popup-message-body"); messageEl.appendChild(wrapperEl); wrapperEl.appendChild( this._createElement(doc, "h2", { - classList: "whatsNew-message-title", + classList: "protections-popup-message-title", content: message.content.title, }) ); diff --git a/browser/base/content/browser-sync.js b/browser/base/content/browser-sync.js index 065546d7b8..9aa6cc5cd4 100644 --- a/browser/base/content/browser-sync.js +++ b/browser/base/content/browser-sync.js @@ -202,10 +202,7 @@ this.SyncedTabsPanelList = class SyncedTabsPanelList { } _appendSyncClient(client, container, labelId, paginationInfo) { - let { - maxTabs = SyncedTabsPanelList.sRemoteTabsPerPage, - showInactive = false, - } = paginationInfo; + let { maxTabs = SyncedTabsPanelList.sRemoteTabsPerPage } = paginationInfo; // Create the element for the remote client. let clientItem = document.createXULElement("label"); clientItem.setAttribute("id", labelId); @@ -227,11 +224,24 @@ this.SyncedTabsPanelList = class SyncedTabsPanelList { ); label.setAttribute("class", "PanelUI-remotetabs-notabsforclient-label"); } else { - let tabs = client.tabs.filter(t => showInactive || !t.inactive); - let numInactive = client.tabs.length - tabs.length; + // We have the client obj but we need the FxA device obj so we use the clients + // engine to get us the FxA device + let device = + fxAccounts.device.recentDeviceList && + fxAccounts.device.recentDeviceList.find( + d => + d.id === Weave.Service.clientsEngine.getClientFxaDeviceId(client.id) + ); + let remoteTabCloseAvailable = + device && fxAccounts.commands.closeTab.isDeviceCompatible(device); + + let tabs = client.tabs.filter(t => !t.inactive); + let hasInactive = tabs.length != client.tabs.length; - // If this page will display all tabs, show no additional buttons. - // Otherwise, show a "Show More" button + if (hasInactive) { + container.append(this._createShowInactiveTabsElement(client, device)); + } + // If this page isn't displaying all (regular, active) tabs, show a "Show More" button. let hasNextPage = tabs.length > maxTabs; let nextPageIsLastPage = hasNextPage && @@ -248,15 +258,13 @@ this.SyncedTabsPanelList = class SyncedTabsPanelList { tabs = tabs.slice(0, maxTabs); } for (let [index, tab] of tabs.entries()) { - let tabEnt = this._createSyncedTabElement(tab, index); - container.appendChild(tabEnt); - } - if (numInactive) { - let elt = this._createShowInactiveTabsElement( - paginationInfo, - numInactive + let tabEnt = this._createSyncedTabElement( + tab, + index, + device, + remoteTabCloseAvailable ); - container.appendChild(elt); + container.appendChild(tabEnt); } if (hasNextPage) { let showAllEnt = this._createShowMoreSyncedTabsElement(paginationInfo); @@ -265,7 +273,10 @@ this.SyncedTabsPanelList = class SyncedTabsPanelList { } } - _createSyncedTabElement(tabInfo, index) { + _createSyncedTabElement(tabInfo, index, device, canCloseTabs) { + let tabContainer = document.createXULElement("hbox"); + tabContainer.setAttribute("class", "PanelUI-tabitem-container"); + let item = document.createXULElement("toolbarbutton"); let tooltipText = (tabInfo.title ? tabInfo.title + "\n" : "") + tabInfo.url; item.setAttribute("itemtype", "tab"); @@ -296,25 +307,29 @@ this.SyncedTabsPanelList = class SyncedTabsPanelList { {} ), }); - if (document.defaultView.whereToOpenLink(e) != "current") { + if (BrowserUtils.whereToOpenLink(e) != "current") { e.preventDefault(); e.stopPropagation(); } else { CustomizableUI.hidePanelForNode(item); } }); - return item; + tabContainer.appendChild(item); + // We should only add an X button next to tabs if the device + // is broadcasting that it can remotely close tabs + if (canCloseTabs) { + tabContainer.appendChild( + this._createCloseTabElement(tabInfo.url, device) + ); + } + return tabContainer; } _createShowMoreSyncedTabsElement(paginationInfo) { let showMoreItem = document.createXULElement("toolbarbutton"); showMoreItem.setAttribute("itemtype", "showmorebutton"); showMoreItem.setAttribute("closemenu", "none"); - showMoreItem.classList.add( - "subviewbutton", - "subviewbutton-nav", - "subviewbutton-nav-down" - ); + showMoreItem.classList.add("subviewbutton", "subviewbutton-nav-down"); document.l10n.setAttributes(showMoreItem, "appmenu-remote-tabs-showmore"); paginationInfo.maxTabs = Infinity; @@ -326,27 +341,56 @@ this.SyncedTabsPanelList = class SyncedTabsPanelList { return showMoreItem; } - _createShowInactiveTabsElement(paginationInfo, count) { + _createShowInactiveTabsElement(client, device) { let showItem = document.createXULElement("toolbarbutton"); - showItem.setAttribute("itemtype", "showmorebutton"); showItem.setAttribute("closemenu", "none"); - showItem.classList.add( - "subviewbutton", - "subviewbutton-nav", - "subviewbutton-nav-down" + showItem.classList.add("subviewbutton", "subviewbutton-nav"); + document.l10n.setAttributes( + showItem, + "appmenu-remote-tabs-show-inactive-tabs" ); - document.l10n.setAttributes(showItem, "appmenu-remote-tabs-showinactive"); - document.l10n.setArgs(showItem, { count }); - paginationInfo.showInactive = true; + let canClose = + device && fxAccounts.commands.closeTab.isDeviceCompatible(device); + showItem.addEventListener("click", e => { - e.preventDefault(); - e.stopPropagation(); - this._showSyncedTabs(paginationInfo); + let node = PanelMultiView.getViewNode( + document, + "PanelUI-fxa-menu-inactive-tabs" + ); + + // device name. + let label = node.querySelector("label[itemtype='client']"); + label.textContent = client.name; + + // Update the tab list. + let container = node.querySelector(".panel-subview-body"); + container.replaceChildren( + ...client.tabs + .filter(t => t.inactive) + .map((tab, index) => + this._createSyncedTabElement(tab, index, device, canClose) + ) + ); + PanelUI.showSubView("PanelUI-fxa-menu-inactive-tabs", showItem, e); }); return showItem; } + _createCloseTabElement(url, device) { + let closeBtn = document.createXULElement("image"); + closeBtn.setAttribute("class", "close-icon remotetabs-close"); + + closeBtn.addEventListener("click", function (e) { + e.stopPropagation(); + // The user could be hitting multiple tabs across multiple devices, with a few + // seconds in-between -- we should not immediately fire off pushes, so we + // add it to a queue and send in bulk at a later time + fxAccounts.commands.closeTab.enqueueTabToClose(device, url); + }); + return closeBtn; + } + destroy() { Services.obs.removeObserver(this, SyncedTabs.TOPIC_TABS_CHANGED); this.tabsList = null; @@ -384,7 +428,7 @@ var gSync = { "browser/accounts.ftl", "browser/appmenu.ftl", "browser/sync.ftl", - "toolkit/branding/accounts.ftl", + "browser/syncedTabs.ftl", ], true )); @@ -445,7 +489,7 @@ var gSync = { ); XPCOMUtils.defineLazyPreferenceGetter( this, - "PXI_TOOLBAR_ENABLED", + "FXA_CTA_MENU_ENABLED", "identity.fxaccounts.toolbar.pxiToolbarEnabled" ); }, @@ -533,10 +577,23 @@ var gSync = { let fxaPanelView = PanelMultiView.getViewNode(document, "PanelUI-fxa"); fxaPanelView.addEventListener("ViewShowing", this); fxaPanelView.addEventListener("ViewHiding", this); + fxaPanelView.addEventListener("command", this); + PanelMultiView.getViewNode( + document, + "PanelUI-fxa-menu-syncnow-button" + ).addEventListener("mouseover", this); + PanelMultiView.getViewNode( + document, + "PanelUI-fxa-menu-sendtab-not-configured-button" + ).addEventListener("command", this); + PanelMultiView.getViewNode( + document, + "PanelUI-fxa-menu-sendtab-connect-device-button" + ).addEventListener("command", this); // If the experiment is enabled, we'll need to update the panels // to show some different text to the user - if (this.PXI_TOOLBAR_ENABLED) { + if (this.FXA_CTA_MENU_ENABLED) { this.updateFxAPanel(UIState.get()); this.updateCTAPanel(); } @@ -558,6 +615,13 @@ var gSync = { handleEvent(event) { switch (event.type) { + case "mouseover": + this.refreshSyncButtonsTooltip(); + break; + case "command": { + this.onCommand(event.target); + break; + } case "ViewShowing": { this.onFxAPanelViewShowing(event.target); break; @@ -606,16 +670,61 @@ var gSync = { panelview.syncedTabsPanelList = null; }, + onCommand(button) { + switch (button.id) { + case "PanelUI-fxa-menu-sync-prefs-button": + // fall through + case "PanelUI-fxa-menu-setup-sync-button": + this.openPrefsFromFxaMenu("sync_settings", button); + break; + + case "PanelUI-fxa-menu-sendtab-connect-device-button": + // fall through + case "PanelUI-fxa-menu-connect-device-button": + this.openConnectAnotherDeviceFromFxaMenu(button); + break; + + case "fxa-manage-account-button": + this.clickFxAMenuHeaderButton(button); + break; + case "PanelUI-fxa-menu-syncnow-button": + this.doSyncFromFxaMenu(button); + break; + case "PanelUI-fxa-menu-sendtab-button": + this.showSendToDeviceViewFromFxaMenu(button); + break; + case "PanelUI-fxa-menu-account-signout-button": + this.disconnect(); + break; + case "PanelUI-fxa-menu-sync-button": + this.openPrefsFromFxaButton("sync_cta", button); + break; + case "PanelUI-fxa-menu-monitor-button": + this.openMonitorLink(button); + break; + case "PanelUI-fxa-menu-relay-button": + this.openRelayLink(button); + break; + case "PanelUI-fxa-menu-vpn-button": + this.openVPNLink(button); + break; + case "PanelUI-fxa-menu-sendtab-not-configured-button": + this.openPrefsFromFxaMenu("send_tab", button); + break; + } + }, + observe(subject, topic, data) { if (!this._initialized) { console.error("browser-sync observer called after unload: ", topic); return; } switch (topic) { - case UIState.ON_UPDATE: + case UIState.ON_UPDATE: { const state = UIState.get(); this.updateAllUI(state); break; + } case "quit-application": // Stop the animation timer on shutdown, since we can't update the UI // after this. @@ -637,7 +746,6 @@ var gSync = { this.updateSyncButtonsTooltip(state); this.updateSyncStatus(state); this.updateFxAPanel(state); - this.updateCTAPanel(state); // Ensure we have something in the device list in the background. this.ensureFxaDevices(); }, @@ -720,16 +828,6 @@ var gSync = { this.emitFxaToolbarTelemetry("send_tab", anchor); }, - showRemoteTabsFromFxaMenu(panel) { - PanelUI.showSubView("PanelUI-remotetabs", panel); - this.emitFxaToolbarTelemetry("sync_tabs", panel); - }, - - showSidebarFromFxaMenu(panel) { - SidebarUI.toggle("viewTabsSidebar"); - this.emitFxaToolbarTelemetry("sync_tabs_sidebar", panel); - }, - _populateSendTabToDevicesView(panelViewNode, reloadDevices = true) { let bodyNode = panelViewNode.querySelector(".panel-subview-body"); let panelNode = panelViewNode.closest("panel"); @@ -830,12 +928,20 @@ var gSync = { let fxaStatus = document.documentElement.getAttribute("fxastatus"); if (fxaStatus == "not_configured") { + // sign in button in app (hamburger) menu + // should take you straight to fxa sign in page + if (anchor.id == "appMenu-fxa-label2") { + this.openFxAEmailFirstPageFromFxaMenu(anchor); + PanelUI.hide(); + return; + } + // If we're signed out but have the PXI pref enabled // we should show the PXI panel instead of taking the user // straight to FxA sign-in - if (this.PXI_TOOLBAR_ENABLED) { + if (this.FXA_CTA_MENU_ENABLED) { this.updateFxAPanel(UIState.get()); - this.updateCTAPanel(); + this.updateCTAPanel(anchor); PanelUI.showSubView("PanelUI-fxa", anchor, aEvent); } else if (anchor == document.getElementById("fxa-toolbar-menu-button")) { // The fxa toolbar button doesn't have much context before the user @@ -844,20 +950,13 @@ var gSync = { this.emitFxaToolbarTelemetry("toolbar_icon", anchor); openTrustedLinkIn("about:preferences#sync", "tab"); PanelUI.hide(); - } else { - let panel = - anchor.id == "appMenu-fxa-label2" - ? PanelMultiView.getViewNode(document, "PanelUI-fxa") - : undefined; - this.openFxAEmailFirstPageFromFxaMenu(panel); - PanelUI.hide(); } return; } // If the user is signed in and we have the PXI pref enabled then add // the pxi panel to the existing toolbar - if (this.PXI_TOOLBAR_ENABLED) { - this.updateCTAPanel(); + if (this.FXA_CTA_MENU_ENABLED) { + this.updateCTAPanel(anchor); } if (!gFxaToolbarAccessed) { @@ -932,21 +1031,16 @@ var gSync = { fxaMenuAccountButtonEl.removeAttribute("closemenu"); syncSetupButtonEl.removeAttribute("hidden"); - let headerTitleL10nId = this.PXI_TOOLBAR_ENABLED - ? "appmenuitem-sign-in-account" - : "appmenuitem-fxa-sign-in"; + let headerTitleL10nId = this.FXA_CTA_MENU_ENABLED + ? "synced-tabs-fxa-sign-in" + : "appmenuitem-sign-in-account"; let headerDescription; if (state.status === UIState.STATUS_NOT_CONFIGURED) { mainWindowEl.style.removeProperty("--avatar-image-url"); - headerDescription = this.fluentStrings.formatValueSync( - "appmenu-fxa-signed-in-label" - ); - // Signed out, expeirment enabled is the only state we want to hide the - // header description, so we make it empty and check for that when setting - // the value - if (this.PXI_TOOLBAR_ENABLED) { - headerDescription = ""; - } + const headerDescString = this.FXA_CTA_MENU_ENABLED + ? "fxa-menu-sync-description" + : "appmenu-fxa-signed-in-label"; + headerDescription = this.fluentStrings.formatValueSync(headerDescString); } else if (state.status === UIState.STATUS_LOGIN_FAILED) { stateValue = "login-failed"; headerTitleL10nId = "account-disconnected2"; @@ -1020,8 +1114,8 @@ var gSync = { ).hidden = !canSendAllURIs; }, - emitFxaToolbarTelemetry(type, panel) { - if (UIState.isReady() && panel) { + emitFxaToolbarTelemetry(type, sourceElement) { + if (UIState.isReady() && sourceElement) { const state = UIState.get(); const hasAvatar = state.avatarURL && !state.avatarIsDefault; let extraOptions = { @@ -1029,10 +1123,10 @@ var gSync = { fxa_avatar: hasAvatar ? "true" : "false", }; - // When the fxa avatar panel is within the Firefox app menu, + // When the source element is within the Firefox app menu, // we emit different telemetry. let eventName = "fxa_avatar_menu"; - if (this.isPanelInsideAppMenu(panel)) { + if (this.isInsideAppMenu(sourceElement)) { eventName = "fxa_app_menu"; } @@ -1046,9 +1140,9 @@ var gSync = { } }, - isPanelInsideAppMenu(panel = undefined) { + isInsideAppMenu(sourceElement = undefined) { const appMenuPanel = document.getElementById("appMenu-popup"); - if (panel && appMenuPanel.contains(panel)) { + if (sourceElement && appMenuPanel.contains(sourceElement)) { return true; } return false; @@ -1225,10 +1319,10 @@ var gSync = { openTrustedLinkIn(url, "tab"); }, - async openConnectAnotherDeviceFromFxaMenu(panel = undefined) { - this.emitFxaToolbarTelemetry("cad", panel); + async openConnectAnotherDeviceFromFxaMenu(sourceElement = undefined) { + this.emitFxaToolbarTelemetry("cad", sourceElement); let entryPoint = "fxa_discoverability_native"; - if (this.isPanelInsideAppMenu(panel)) { + if (this.isInsideAppMenu(sourceElement)) { entryPoint = "fxa_app_menu"; } this.openConnectAnotherDevice(entryPoint); @@ -1241,7 +1335,7 @@ var gSync = { switchToTabHavingURI(url, true, { replaceQueryString: true }); }, - async clickFxAMenuHeaderButton(panel = undefined) { + async clickFxAMenuHeaderButton(sourceElement = undefined) { // Depending on the current logged in state of a user, // clicking the FxA header will either open // a sign-in page, account management page, or sync @@ -1249,16 +1343,16 @@ var gSync = { const { status } = UIState.get(); switch (status) { case UIState.STATUS_NOT_CONFIGURED: - this.openFxAEmailFirstPageFromFxaMenu(panel); + this.openFxAEmailFirstPageFromFxaMenu(sourceElement); break; case UIState.STATUS_LOGIN_FAILED: - this.openPrefsFromFxaMenu("sync_settings", panel); + this.openPrefsFromFxaMenu("sync_settings", sourceElement); break; case UIState.STATUS_NOT_VERIFIED: this.openFxAEmailFirstPage("fxa_app_menu_reverify"); break; case UIState.STATUS_SIGNED_IN: - this.openFxAManagePageFromFxaMenu(panel); + this.openFxAManagePageFromFxaMenu(sourceElement); } }, @@ -1273,10 +1367,13 @@ var gSync = { switchToTabHavingURI(url, true, { replaceQueryString: true }); }, - async openFxAEmailFirstPageFromFxaMenu(panel = undefined, extraParams = {}) { - this.emitFxaToolbarTelemetry("login", panel); + async openFxAEmailFirstPageFromFxaMenu( + sourceElement = undefined, + extraParams = {} + ) { + this.emitFxaToolbarTelemetry("login", sourceElement); let entryPoint = "fxa_discoverability_native"; - if (panel) { + if (sourceElement) { entryPoint = "fxa_toolbar_button"; } this.openFxAEmailFirstPage(entryPoint, extraParams); @@ -1287,10 +1384,10 @@ var gSync = { switchToTabHavingURI(url, true, { replaceQueryString: true }); }, - async openFxAManagePageFromFxaMenu(panel = undefined) { - this.emitFxaToolbarTelemetry("account_settings", panel); + async openFxAManagePageFromFxaMenu(sourceElement = undefined) { + this.emitFxaToolbarTelemetry("account_settings", sourceElement); let entryPoint = "fxa_discoverability_native"; - if (this.isPanelInsideAppMenu(panel)) { + if (this.isInsideAppMenu(sourceElement)) { entryPoint = "fxa_app_menu"; } this.openFxAManagePage(entryPoint); @@ -1893,9 +1990,9 @@ var gSync = { } }, - doSyncFromFxaMenu(panel) { + doSyncFromFxaMenu(sourceElement) { this.doSync(); - this.emitFxaToolbarTelemetry("sync_now", panel); + this.emitFxaToolbarTelemetry("sync_now", sourceElement); }, openPrefs(entryPoint = "syncbutton", origin = undefined) { @@ -1905,18 +2002,18 @@ var gSync = { }); }, - openPrefsFromFxaMenu(type, panel) { - this.emitFxaToolbarTelemetry(type, panel); + openPrefsFromFxaMenu(type, sourceElement) { + this.emitFxaToolbarTelemetry(type, sourceElement); let entryPoint = "fxa_discoverability_native"; - if (this.isPanelInsideAppMenu(panel)) { + if (this.isInsideAppMenu(sourceElement)) { entryPoint = "fxa_app_menu"; } this.openPrefs(entryPoint); }, - openPrefsFromFxaButton(type, panel) { + openPrefsFromFxaButton(type, sourceElement) { let entryPoint = "fxa_toolbar_button_sync"; - this.emitFxaToolbarTelemetry(type, panel); + this.emitFxaToolbarTelemetry(type, sourceElement); this.openPrefs(entryPoint); }, @@ -2049,27 +2146,24 @@ var gSync = { // This should only be shown if we have enabled the pxiPanel via // an experiment or explicitly through prefs - updateCTAPanel() { + updateCTAPanel(anchor) { const mainPanelEl = PanelMultiView.getViewNode( document, "PanelUI-fxa-cta-menu" ); - const syncCtaEl = PanelMultiView.getViewNode( - document, - "PanelUI-fxa-menu-sync-button" - ); - // If we're not in the experiment then we do not enable this at all - if (!this.PXI_TOOLBAR_ENABLED) { + // If we're not in the experiment or in the app menu (hamburger) + // do not show this CTA panel + if ( + !this.FXA_CTA_MENU_ENABLED || + (anchor && anchor.id === "appMenu-fxa-label2") + ) { // If we've previously shown this but got disabled // we should ensure we hide the panel mainPanelEl.hidden = true; return; } - // If we're already signed in an syncing, we shouldn't show the sync CTA - syncCtaEl.hidden = this.isSignedIn; - // Monitor checks let monitorPanelEl = PanelMultiView.getViewNode( document, @@ -2112,8 +2206,8 @@ var gSync = { !monitorEnabled && !relayEnabled && !vpnEnabled; mainPanelEl.hidden = false; }, - async openMonitorLink(panel) { - this.emitFxaToolbarTelemetry("monitor_cta", panel); + async openMonitorLink(sourceElement) { + this.emitFxaToolbarTelemetry("monitor_cta", sourceElement); await this.openCtaLink( FX_MONITOR_OAUTH_CLIENT_ID, new URL("https://monitor.firefox.com"), @@ -2121,8 +2215,8 @@ var gSync = { ); }, - async openRelayLink(panel) { - this.emitFxaToolbarTelemetry("relay_cta", panel); + async openRelayLink(sourceElement) { + this.emitFxaToolbarTelemetry("relay_cta", sourceElement); await this.openCtaLink( FX_RELAY_OAUTH_CLIENT_ID, new URL("https://relay.firefox.com"), @@ -2130,8 +2224,8 @@ var gSync = { ); }, - async openVPNLink(panel) { - this.emitFxaToolbarTelemetry("vpn_cta", panel); + async openVPNLink(sourceElement) { + this.emitFxaToolbarTelemetry("vpn_cta", sourceElement); await this.openCtaLink( VPN_OAUTH_CLIENT_ID, new URL("https://www.mozilla.org/en-US/products/vpn/"), diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 72753da622..5f41ca7781 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -9,6 +9,9 @@ var { XPCOMUtils } = ChromeUtils.importESModule( 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"); // lazy module getters @@ -35,8 +38,6 @@ ChromeUtils.defineESModuleGetters(this, { DownloadsCommon: "resource:///modules/DownloadsCommon.sys.mjs", E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs", ExtensionsUI: "resource:///modules/ExtensionsUI.sys.mjs", - FirefoxViewNotificationManager: - "resource:///modules/firefox-view-notification-manager.sys.mjs", HomePage: "resource:///modules/HomePage.sys.mjs", isProductURL: "chrome://global/content/shopping/ShoppingProduct.mjs", LightweightThemeConsumer: @@ -1503,1117 +1504,6 @@ function _createNullPrincipalFromTabUserContextId(tab = gBrowser.selectedTab) { }); } -let _resolveDelayedStartup; -var delayedStartupPromise = new Promise(resolve => { - _resolveDelayedStartup = resolve; -}); - -var gBrowserInit = { - delayedStartupFinished: false, - idleTasksFinishedPromise: null, - idleTaskPromiseResolve: null, - domContentLoaded: false, - - _tabToAdopt: undefined, - - _setupFirstContentWindowPaintPromise() { - let lastTransactionId = window.windowUtils.lastTransactionId; - let layerTreeListener = () => { - if (this.getTabToAdopt()) { - // Need to wait until we finish adopting the tab, or we might end - // up focusing the initial browser and then losing focus when it - // gets swapped out for the tab to adopt. - return; - } - removeEventListener("MozLayerTreeReady", layerTreeListener); - let listener = e => { - if (e.transactionId > lastTransactionId) { - window.removeEventListener("MozAfterPaint", listener); - this._firstContentWindowPaintDeferred.resolve(); - } - }; - addEventListener("MozAfterPaint", listener); - }; - addEventListener("MozLayerTreeReady", layerTreeListener); - }, - - getTabToAdopt() { - if (this._tabToAdopt !== undefined) { - return this._tabToAdopt; - } - - if (window.arguments && window.XULElement.isInstance(window.arguments[0])) { - this._tabToAdopt = window.arguments[0]; - - // Clear the reference of the tab being adopted from the arguments. - window.arguments[0] = null; - } else { - // There was no tab to adopt in the arguments, set _tabToAdopt to null - // to avoid checking it again. - this._tabToAdopt = null; - } - - return this._tabToAdopt; - }, - - _clearTabToAdopt() { - this._tabToAdopt = null; - }, - - // Used to check if the new window is still adopting an existing tab as its first tab - // (e.g. from the WebExtensions internals). - isAdoptingTab() { - return !!this.getTabToAdopt(); - }, - - onBeforeInitialXULLayout() { - this._setupFirstContentWindowPaintPromise(); - - updateBookmarkToolbarVisibility(); - - // Set a sane starting width/height for all resolutions on new profiles. - if (ChromeUtils.shouldResistFingerprinting("RoundWindowSize", null)) { - // When the fingerprinting resistance is enabled, making sure that we don't - // have a maximum window to interfere with generating rounded window dimensions. - document.documentElement.setAttribute("sizemode", "normal"); - } else if (!document.documentElement.hasAttribute("width")) { - const TARGET_WIDTH = 1280; - const TARGET_HEIGHT = 1040; - let width = Math.min(screen.availWidth * 0.9, TARGET_WIDTH); - let height = Math.min(screen.availHeight * 0.9, TARGET_HEIGHT); - - document.documentElement.setAttribute("width", width); - document.documentElement.setAttribute("height", height); - - if (width < TARGET_WIDTH && height < TARGET_HEIGHT) { - document.documentElement.setAttribute("sizemode", "maximized"); - } - } - if (AppConstants.MENUBAR_CAN_AUTOHIDE) { - const toolbarMenubar = document.getElementById("toolbar-menubar"); - // set a default value - if (!toolbarMenubar.hasAttribute("autohide")) { - toolbarMenubar.setAttribute("autohide", true); - } - document.l10n.setAttributes( - toolbarMenubar, - "toolbar-context-menu-menu-bar-cmd" - ); - toolbarMenubar.setAttribute("data-l10n-attrs", "toolbarname"); - } - - // Run menubar initialization first, to avoid TabsInTitlebar code picking - // up mutations from it and causing a reflow. - AutoHideMenubar.init(); - // Update the chromemargin attribute so the window can be sized correctly. - window.TabBarVisibility.update(); - TabsInTitlebar.init(); - - new LightweightThemeConsumer(document); - - if ( - Services.prefs.getBoolPref( - "toolkit.legacyUserProfileCustomizations.windowIcon", - false - ) - ) { - document.documentElement.setAttribute("icon", "main-window"); - } - - // Call this after we set attributes that might change toolbars' computed - // text color. - ToolbarIconColor.init(); - }, - - onDOMContentLoaded() { - // This needs setting up before we create the first remote browser. - window.docShell.treeOwner - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIAppWindow).XULBrowserWindow = window.XULBrowserWindow; - window.browserDOMWindow = new nsBrowserAccess(); - - gBrowser = window._gBrowser; - delete window._gBrowser; - gBrowser.init(); - - BrowserWindowTracker.track(window); - - FirefoxViewHandler.init(); - - gNavToolbox.palette = document.getElementById( - "BrowserToolbarPalette" - ).content; - for (let area of CustomizableUI.areas) { - let type = CustomizableUI.getAreaType(area); - if (type == CustomizableUI.TYPE_TOOLBAR) { - let node = document.getElementById(area); - CustomizableUI.registerToolbarNode(node); - } - } - BrowserSearch.initPlaceHolder(); - - // Hack to ensure that the various initial pages favicon is loaded - // instantaneously, to avoid flickering and improve perceived performance. - this._callWithURIToLoad(uriToLoad => { - let url; - try { - url = Services.io.newURI(uriToLoad); - } catch (e) { - return; - } - let nonQuery = url.prePath + url.filePath; - if (nonQuery in gPageIcons) { - gBrowser.setIcon(gBrowser.selectedTab, gPageIcons[nonQuery]); - } - }); - - updateFxaToolbarMenu(gFxaToolbarEnabled, true); - - updatePrintCommands(gPrintEnabled); - - gUnifiedExtensions.init(); - - // Setting the focus will cause a style flush, it's preferable to call anything - // that will modify the DOM from within this function before this call. - this._setInitialFocus(); - - this.domContentLoaded = true; - }, - - onLoad() { - gBrowser.addEventListener("DOMUpdateBlockedPopups", gPopupBlockerObserver); - gBrowser.addEventListener( - "TranslationsParent:LanguageState", - FullPageTranslationsPanel - ); - gBrowser.addEventListener( - "TranslationsParent:OfferTranslation", - FullPageTranslationsPanel - ); - gBrowser.addTabsProgressListener(FullPageTranslationsPanel); - - window.addEventListener("AppCommand", HandleAppCommandEvent, true); - - // These routines add message listeners. They must run before - // loading the frame script to ensure that we don't miss any - // message sent between when the frame script is loaded and when - // the listener is registered. - CaptivePortalWatcher.init(); - ZoomUI.init(window); - - if (!gMultiProcessBrowser) { - // There is a Content:Click message manually sent from content. - gBrowser.tabpanels.addEventListener("click", contentAreaClick, { - capture: true, - mozSystemGroup: true, - }); - } - - // hook up UI through progress listener - gBrowser.addProgressListener(window.XULBrowserWindow); - gBrowser.addTabsProgressListener(window.TabsProgressListener); - - SidebarUI.init(); - - // We do this in onload because we want to ensure the button's state - // doesn't flicker as the window is being shown. - DownloadsButton.init(); - - // Certain kinds of automigration rely on this notification to complete - // their tasks BEFORE the browser window is shown. SessionStore uses it to - // restore tabs into windows AFTER important parts like gMultiProcessBrowser - // have been initialized. - Services.obs.notifyObservers(window, "browser-window-before-show"); - - if (!window.toolbar.visible) { - // adjust browser UI for popups - gURLBar.readOnly = true; - } - - // Misc. inits. - gUIDensity.init(); - TabletModeUpdater.init(); - CombinedStopReload.ensureInitialized(); - gPrivateBrowsingUI.init(); - BrowserSearch.init(); - BrowserPageActions.init(); - if (gToolbarKeyNavEnabled) { - ToolbarKeyboardNavigator.init(); - } - - // Update UI if browser is under remote control. - gRemoteControl.updateVisualCue(); - - // If we are given a tab to swap in, take care of it before first paint to - // avoid an about:blank flash. - let tabToAdopt = this.getTabToAdopt(); - if (tabToAdopt) { - let evt = new CustomEvent("before-initial-tab-adopted", { - bubbles: true, - }); - gBrowser.tabpanels.dispatchEvent(evt); - - // Stop the about:blank load - gBrowser.stop(); - - // Remove the speculative focus from the urlbar to let the url be formatted. - gURLBar.removeAttribute("focused"); - - let swapBrowsers = () => { - try { - gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToAdopt); - } catch (e) { - console.error(e); - } - - // Clear the reference to the tab once its adoption has been completed. - this._clearTabToAdopt(); - }; - if (tabToAdopt.linkedBrowser.isRemoteBrowser) { - // For remote browsers, wait for the paint event, otherwise the tabs - // are not yet ready and focus gets confused because the browser swaps - // out while tabs are switching. - addEventListener("MozAfterPaint", swapBrowsers, { once: true }); - } else { - swapBrowsers(); - } - } - - // Wait until chrome is painted before executing code not critical to making the window visible - this._boundDelayedStartup = this._delayedStartup.bind(this); - window.addEventListener("MozAfterPaint", this._boundDelayedStartup); - - if (!PrivateBrowsingUtils.enabled) { - document.getElementById("Tools:PrivateBrowsing").hidden = true; - // Setting disabled doesn't disable the shortcut, so we just remove - // the keybinding. - document.getElementById("key_privatebrowsing").remove(); - } - - if (BrowserUIUtils.quitShortcutDisabled) { - document.getElementById("key_quitApplication").remove(); - document.getElementById("menu_FileQuitItem").removeAttribute("key"); - - PanelMultiView.getViewNode( - document, - "appMenu-quit-button2" - )?.removeAttribute("key"); - } - - this._loadHandled = true; - }, - - _cancelDelayedStartup() { - window.removeEventListener("MozAfterPaint", this._boundDelayedStartup); - this._boundDelayedStartup = null; - }, - - _delayedStartup() { - let { TelemetryTimestamps } = ChromeUtils.importESModule( - "resource://gre/modules/TelemetryTimestamps.sys.mjs" - ); - TelemetryTimestamps.add("delayedStartupStarted"); - - this._cancelDelayedStartup(); - - // Bug 1531854 - The hidden window is force-created here - // until all of its dependencies are handled. - Services.appShell.hiddenDOMWindow; - - gBrowser.addEventListener( - "PermissionStateChange", - function () { - gIdentityHandler.refreshIdentityBlock(); - gPermissionPanel.updateSharingIndicator(); - }, - true - ); - - this._handleURIToLoad(); - - Services.obs.addObserver(gIdentityHandler, "perm-changed"); - Services.obs.addObserver(gRemoteControl, "devtools-socket"); - Services.obs.addObserver(gRemoteControl, "marionette-listening"); - Services.obs.addObserver(gRemoteControl, "remote-listening"); - Services.obs.addObserver( - gSessionHistoryObserver, - "browser:purge-session-history" - ); - Services.obs.addObserver( - gStoragePressureObserver, - "QuotaManager::StoragePressure" - ); - Services.obs.addObserver(gXPInstallObserver, "addon-install-disabled"); - Services.obs.addObserver(gXPInstallObserver, "addon-install-started"); - Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked"); - Services.obs.addObserver( - gXPInstallObserver, - "addon-install-fullscreen-blocked" - ); - Services.obs.addObserver( - gXPInstallObserver, - "addon-install-origin-blocked" - ); - Services.obs.addObserver( - gXPInstallObserver, - "addon-install-policy-blocked" - ); - Services.obs.addObserver( - gXPInstallObserver, - "addon-install-webapi-blocked" - ); - Services.obs.addObserver(gXPInstallObserver, "addon-install-failed"); - Services.obs.addObserver(gXPInstallObserver, "addon-install-confirmation"); - Services.obs.addObserver(gKeywordURIFixup, "keyword-uri-fixup"); - - BrowserOffline.init(); - CanvasPermissionPromptHelper.init(); - WebAuthnPromptHelper.init(); - ContentAnalysis.initialize(); - - // Initialize the full zoom setting. - // We do this before the session restore service gets initialized so we can - // apply full zoom settings to tabs restored by the session restore service. - FullZoom.init(); - PanelUI.init(shouldSuppressPopupNotifications); - ReportBrokenSite.init(gBrowser); - - UpdateUrlbarSearchSplitterState(); - - BookmarkingUI.init(); - BrowserSearch.delayedStartupInit(); - SearchUIUtils.init(); - gProtectionsHandler.init(); - HomePage.delayedStartup().catch(console.error); - - let safeMode = document.getElementById("helpSafeMode"); - if (Services.appinfo.inSafeMode) { - document.l10n.setAttributes(safeMode, "menu-help-exit-troubleshoot-mode"); - safeMode.setAttribute( - "appmenu-data-l10n-id", - "appmenu-help-exit-troubleshoot-mode" - ); - } - - // BiDi UI - gBidiUI = isBidiEnabled(); - if (gBidiUI) { - document.getElementById("documentDirection-separator").hidden = false; - document.getElementById("documentDirection-swap").hidden = false; - document.getElementById("textfieldDirection-separator").hidden = false; - document.getElementById("textfieldDirection-swap").hidden = false; - } - - // Setup click-and-hold gestures access to the session history - // menus if global click-and-hold isn't turned on - if (!Services.prefs.getBoolPref("ui.click_hold_context_menus", false)) { - SetClickAndHoldHandlers(); - } - - function initBackForwardButtonTooltip(tooltipId, l10nId, shortcutId) { - let shortcut = document.getElementById(shortcutId); - shortcut = ShortcutUtils.prettifyShortcut(shortcut); - - let tooltip = document.getElementById(tooltipId); - document.l10n.setAttributes(tooltip, l10nId, { shortcut }); - } - - initBackForwardButtonTooltip( - "back-button-tooltip-description", - "navbar-tooltip-back-2", - "goBackKb" - ); - - initBackForwardButtonTooltip( - "forward-button-tooltip-description", - "navbar-tooltip-forward-2", - "goForwardKb" - ); - - PlacesToolbarHelper.init(); - - ctrlTab.readPref(); - Services.prefs.addObserver(ctrlTab.prefName, ctrlTab); - - // The object handling the downloads indicator is initialized here in the - // delayed startup function, but the actual indicator element is not loaded - // unless there are downloads to be displayed. - DownloadsButton.initializeIndicator(); - - if (AppConstants.platform != "macosx") { - updateEditUIVisibility(); - let placesContext = document.getElementById("placesContext"); - placesContext.addEventListener("popupshowing", updateEditUIVisibility); - placesContext.addEventListener("popuphiding", updateEditUIVisibility); - } - - FullScreen.init(); - MenuTouchModeObserver.init(); - - if (AppConstants.MOZ_DATA_REPORTING) { - gDataNotificationInfoBar.init(); - } - - if (!AppConstants.MOZILLA_OFFICIAL) { - DevelopmentHelpers.init(); - } - - gExtensionsNotifications.init(); - - let wasMinimized = window.windowState == window.STATE_MINIMIZED; - window.addEventListener("sizemodechange", () => { - let isMinimized = window.windowState == window.STATE_MINIMIZED; - if (wasMinimized != isMinimized) { - wasMinimized = isMinimized; - UpdatePopupNotificationsVisibility(); - } - }); - - window.addEventListener("mousemove", MousePosTracker); - window.addEventListener("dragover", MousePosTracker); - - gNavToolbox.addEventListener("customizationstarting", CustomizationHandler); - gNavToolbox.addEventListener("aftercustomization", CustomizationHandler); - - SessionStore.promiseInitialized.then(() => { - // Bail out if the window has been closed in the meantime. - if (window.closed) { - return; - } - - // Enable the Restore Last Session command if needed - RestoreLastSessionObserver.init(); - - SidebarUI.startDelayedLoad(); - - PanicButtonNotifier.init(); - }); - - if (BrowserHandler.kiosk) { - // We don't modify popup windows for kiosk mode - if (!gURLBar.readOnly) { - window.fullScreen = true; - } - } - - if (Services.policies.status === Services.policies.ACTIVE) { - if (!Services.policies.isAllowed("hideShowMenuBar")) { - document - .getElementById("toolbar-menubar") - .removeAttribute("toolbarname"); - } - if (!Services.policies.isAllowed("filepickers")) { - let savePageCommand = document.getElementById("Browser:SavePage"); - let openFileCommand = document.getElementById("Browser:OpenFile"); - - savePageCommand.setAttribute("disabled", "true"); - openFileCommand.setAttribute("disabled", "true"); - - document.addEventListener("FilePickerBlocked", function (event) { - let browser = event.target; - - let notificationBox = browser - .getTabBrowser() - ?.getNotificationBox(browser); - - // Prevent duplicate notifications - if ( - notificationBox && - !notificationBox.getNotificationWithValue("filepicker-blocked") - ) { - notificationBox.appendNotification("filepicker-blocked", { - label: { - "l10n-id": "filepicker-blocked-infobar", - }, - priority: notificationBox.PRIORITY_INFO_LOW, - }); - } - }); - } - let policies = Services.policies.getActivePolicies(); - if ("ManagedBookmarks" in policies) { - let managedBookmarks = policies.ManagedBookmarks; - let children = managedBookmarks.filter( - child => !("toplevel_name" in child) - ); - if (children.length) { - let managedBookmarksButton = - document.createXULElement("toolbarbutton"); - managedBookmarksButton.setAttribute("id", "managed-bookmarks"); - managedBookmarksButton.setAttribute("class", "bookmark-item"); - let toplevel = managedBookmarks.find( - element => "toplevel_name" in element - ); - if (toplevel) { - managedBookmarksButton.setAttribute( - "label", - toplevel.toplevel_name - ); - } else { - document.l10n.setAttributes( - managedBookmarksButton, - "managed-bookmarks" - ); - } - managedBookmarksButton.setAttribute("context", "placesContext"); - managedBookmarksButton.setAttribute("container", "true"); - managedBookmarksButton.setAttribute("removable", "false"); - managedBookmarksButton.setAttribute("type", "menu"); - - let managedBookmarksPopup = document.createXULElement("menupopup"); - managedBookmarksPopup.setAttribute("id", "managed-bookmarks-popup"); - managedBookmarksPopup.setAttribute( - "oncommand", - "PlacesToolbarHelper.openManagedBookmark(event);" - ); - managedBookmarksPopup.setAttribute( - "ondragover", - "event.dataTransfer.effectAllowed='none';" - ); - managedBookmarksPopup.setAttribute( - "ondragstart", - "PlacesToolbarHelper.onDragStartManaged(event);" - ); - managedBookmarksPopup.setAttribute( - "onpopupshowing", - "PlacesToolbarHelper.populateManagedBookmarks(this);" - ); - managedBookmarksPopup.setAttribute("placespopup", "true"); - managedBookmarksPopup.setAttribute("is", "places-popup"); - managedBookmarksPopup.classList.add("toolbar-menupopup"); - managedBookmarksButton.appendChild(managedBookmarksPopup); - - gNavToolbox.palette.appendChild(managedBookmarksButton); - - CustomizableUI.ensureWidgetPlacedInWindow( - "managed-bookmarks", - window - ); - - // Add button if it doesn't exist - if (!CustomizableUI.getPlacementOfWidget("managed-bookmarks")) { - CustomizableUI.addWidgetToArea( - "managed-bookmarks", - CustomizableUI.AREA_BOOKMARKS, - 0 - ); - } - } - } - } - - CaptivePortalWatcher.delayedStartup(); - - ShoppingSidebarManager.ensureInitialized(); - - SessionStore.promiseAllWindowsRestored.then(() => { - this._schedulePerWindowIdleTasks(); - document.documentElement.setAttribute("sessionrestored", "true"); - }); - - this.delayedStartupFinished = true; - _resolveDelayedStartup(); - Services.obs.notifyObservers(window, "browser-delayed-startup-finished"); - TelemetryTimestamps.add("delayedStartupFinished"); - // We've announced that delayed startup has finished. Do not add code past this point. - }, - - /** - * Resolved on the first MozLayerTreeReady and next MozAfterPaint in the - * parent process. - */ - get firstContentWindowPaintPromise() { - return this._firstContentWindowPaintDeferred.promise; - }, - - _setInitialFocus() { - let initiallyFocusedElement = document.commandDispatcher.focusedElement; - - // To prevent startup flicker, the urlbar has the 'focused' attribute set - // by default. If we are not sure the urlbar will be focused in this - // window, we need to remove the attribute before first paint. - // TODO (bug 1629956): The urlbar having the 'focused' attribute by default - // isn't a useful optimization anymore since UrlbarInput needs layout - // information to focus the urlbar properly. - let shouldRemoveFocusedAttribute = true; - - this._callWithURIToLoad(uriToLoad => { - if ( - isBlankPageURL(uriToLoad) || - uriToLoad == "about:privatebrowsing" || - this.getTabToAdopt()?.isEmpty - ) { - gURLBar.select(); - shouldRemoveFocusedAttribute = false; - return; - } - - // If the initial browser is remote, in order to optimize for first paint, - // we'll defer switching focus to that browser until it has painted. - // Otherwise use a regular promise to guarantee that mutationobserver - // microtasks that could affect focusability have run. - let promise = gBrowser.selectedBrowser.isRemoteBrowser - ? this.firstContentWindowPaintPromise - : Promise.resolve(); - - promise.then(() => { - // If focus didn't move while we were waiting, we're okay to move to - // the browser. - if ( - document.commandDispatcher.focusedElement == initiallyFocusedElement - ) { - gBrowser.selectedBrowser.focus(); - } - }); - }); - - // Delay removing the attribute using requestAnimationFrame to avoid - // invalidating styles multiple times in a row if uriToLoadPromise - // resolves before first paint. - if (shouldRemoveFocusedAttribute) { - window.requestAnimationFrame(() => { - if (shouldRemoveFocusedAttribute) { - gURLBar.removeAttribute("focused"); - } - }); - } - }, - - _handleURIToLoad() { - this._callWithURIToLoad(uriToLoad => { - if (!uriToLoad) { - // We don't check whether window.arguments[5] (userContextId) is set - // because tabbrowser.js takes care of that for the initial tab. - return; - } - - // We don't check if uriToLoad is a XULElement because this case has - // already been handled before first paint, and the argument cleared. - if (Array.isArray(uriToLoad)) { - // This function throws for certain malformed URIs, so use exception handling - // so that we don't disrupt startup - try { - gBrowser.loadTabs(uriToLoad, { - inBackground: false, - replace: true, - // See below for the semantics of window.arguments. Only the minimum is supported. - userContextId: window.arguments[5], - triggeringPrincipal: - window.arguments[8] || - Services.scriptSecurityManager.getSystemPrincipal(), - allowInheritPrincipal: window.arguments[9], - csp: window.arguments[10], - fromExternal: true, - }); - } catch (e) {} - } else if (window.arguments.length >= 3) { - // window.arguments[1]: extraOptions (nsIPropertyBag) - // [2]: referrerInfo (nsIReferrerInfo) - // [3]: postData (nsIInputStream) - // [4]: allowThirdPartyFixup (bool) - // [5]: userContextId (int) - // [6]: originPrincipal (nsIPrincipal) - // [7]: originStoragePrincipal (nsIPrincipal) - // [8]: triggeringPrincipal (nsIPrincipal) - // [9]: allowInheritPrincipal (bool) - // [10]: csp (nsIContentSecurityPolicy) - // [11]: nsOpenWindowInfo - let userContextId = - window.arguments[5] != undefined - ? window.arguments[5] - : Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID; - - let hasValidUserGestureActivation = undefined; - let fromExternal = undefined; - let globalHistoryOptions = undefined; - let triggeringRemoteType = undefined; - let forceAllowDataURI = false; - let wasSchemelessInput = false; - if (window.arguments[1]) { - if (!(window.arguments[1] instanceof Ci.nsIPropertyBag2)) { - throw new Error( - "window.arguments[1] must be null or Ci.nsIPropertyBag2!" - ); - } - - let extraOptions = window.arguments[1]; - if (extraOptions.hasKey("hasValidUserGestureActivation")) { - hasValidUserGestureActivation = extraOptions.getPropertyAsBool( - "hasValidUserGestureActivation" - ); - } - if (extraOptions.hasKey("fromExternal")) { - fromExternal = extraOptions.getPropertyAsBool("fromExternal"); - } - if (extraOptions.hasKey("triggeringSponsoredURL")) { - globalHistoryOptions = { - triggeringSponsoredURL: extraOptions.getPropertyAsACString( - "triggeringSponsoredURL" - ), - }; - if (extraOptions.hasKey("triggeringSponsoredURLVisitTimeMS")) { - globalHistoryOptions.triggeringSponsoredURLVisitTimeMS = - extraOptions.getPropertyAsUint64( - "triggeringSponsoredURLVisitTimeMS" - ); - } - } - if (extraOptions.hasKey("triggeringRemoteType")) { - triggeringRemoteType = extraOptions.getPropertyAsACString( - "triggeringRemoteType" - ); - } - if (extraOptions.hasKey("forceAllowDataURI")) { - forceAllowDataURI = - extraOptions.getPropertyAsBool("forceAllowDataURI"); - } - if (extraOptions.hasKey("wasSchemelessInput")) { - wasSchemelessInput = - extraOptions.getPropertyAsBool("wasSchemelessInput"); - } - } - - try { - openLinkIn(uriToLoad, "current", { - referrerInfo: window.arguments[2] || null, - postData: window.arguments[3] || null, - allowThirdPartyFixup: window.arguments[4] || false, - userContextId, - // pass the origin principal (if any) and force its use to create - // an initial about:blank viewer if present: - originPrincipal: window.arguments[6], - originStoragePrincipal: window.arguments[7], - triggeringPrincipal: window.arguments[8], - // TODO fix allowInheritPrincipal to default to false. - // Default to true unless explicitly set to false because of bug 1475201. - allowInheritPrincipal: window.arguments[9] !== false, - csp: window.arguments[10], - forceAboutBlankViewerInCurrent: !!window.arguments[6], - forceAllowDataURI, - hasValidUserGestureActivation, - fromExternal, - globalHistoryOptions, - triggeringRemoteType, - wasSchemelessInput, - }); - } catch (e) { - console.error(e); - } - - window.focus(); - } else { - // Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3. - // Such callers expect that window.arguments[0] is handled as a single URI. - loadOneOrMoreURIs( - uriToLoad, - Services.scriptSecurityManager.getSystemPrincipal(), - null - ); - } - }); - }, - - /** - * Use this function as an entry point to schedule tasks that - * need to run once per window after startup, and can be scheduled - * by using an idle callback. - * - * The functions scheduled here will fire from idle callbacks - * once every window has finished being restored by session - * restore, and after the equivalent only-once tasks - * have run (from _scheduleStartupIdleTasks in BrowserGlue.sys.mjs). - */ - _schedulePerWindowIdleTasks() { - // Bail out if the window has been closed in the meantime. - if (window.closed) { - return; - } - - function scheduleIdleTask(func, options) { - requestIdleCallback(function idleTaskRunner() { - if (!window.closed) { - func(); - } - }, options); - } - - scheduleIdleTask(() => { - // Initialize the Sync UI - gSync.init(); - }); - - scheduleIdleTask(() => { - // Read prefers-reduced-motion setting - let reduceMotionQuery = window.matchMedia( - "(prefers-reduced-motion: reduce)" - ); - function readSetting() { - gReduceMotionSetting = reduceMotionQuery.matches; - } - reduceMotionQuery.addListener(readSetting); - readSetting(); - }); - - scheduleIdleTask(() => { - // setup simple gestures support - gGestureSupport.init(true); - - // setup history swipe animation - gHistorySwipeAnimation.init(); - }); - - scheduleIdleTask(() => { - gBrowserThumbnails.init(); - }); - - scheduleIdleTask( - () => { - // Initialize the download manager some time after the app starts so that - // auto-resume downloads begin (such as after crashing or quitting with - // active downloads) and speeds up the first-load of the download manager UI. - // If the user manually opens the download manager before the timeout, the - // downloads will start right away, and initializing again won't hurt. - try { - DownloadsCommon.initializeAllDataLinks(); - ChromeUtils.importESModule( - "resource:///modules/DownloadsTaskbar.sys.mjs" - ).DownloadsTaskbar.registerIndicator(window); - if (AppConstants.platform == "macosx") { - ChromeUtils.importESModule( - "resource:///modules/DownloadsMacFinderProgress.sys.mjs" - ).DownloadsMacFinderProgress.register(); - } - Services.telemetry.setEventRecordingEnabled("downloads", true); - } catch (ex) { - console.error(ex); - } - }, - { timeout: 10000 } - ); - - if (Win7Features) { - scheduleIdleTask(() => Win7Features.onOpenWindow()); - } - - scheduleIdleTask(async () => { - NewTabPagePreloading.maybeCreatePreloadedBrowser(window); - }); - - scheduleIdleTask(() => { - gGfxUtils.init(); - }); - - // This should always go last, since the idle tasks (except for the ones with - // timeouts) should execute in order. Note that this observer notification is - // not guaranteed to fire, since the window could close before we get here. - scheduleIdleTask(() => { - this.idleTaskPromiseResolve(); - Services.obs.notifyObservers( - window, - "browser-idle-startup-tasks-finished" - ); - }); - - scheduleIdleTask(() => { - gProfiles.init(); - }); - }, - - // Returns the URI(s) to load at startup if it is immediately known, or a - // promise resolving to the URI to load. - get uriToLoadPromise() { - delete this.uriToLoadPromise; - return (this.uriToLoadPromise = (function () { - // window.arguments[0]: URI to load (string), or an nsIArray of - // nsISupportsStrings to load, or a xul:tab of - // a tabbrowser, which will be replaced by this - // window (for this case, all other arguments are - // ignored). - let uri = window.arguments?.[0]; - if (!uri || window.XULElement.isInstance(uri)) { - return null; - } - - let defaultArgs = BrowserHandler.defaultArgs; - - // If the given URI is different from the homepage, we want to load it. - if (uri != defaultArgs) { - AboutNewTab.noteNonDefaultStartup(); - - if (uri instanceof Ci.nsIArray) { - // Transform the nsIArray of nsISupportsString's into a JS Array of - // JS strings. - return Array.from( - uri.enumerate(Ci.nsISupportsString), - supportStr => supportStr.data - ); - } else if (uri instanceof Ci.nsISupportsString) { - return uri.data; - } - return uri; - } - - // The URI appears to be the the homepage. We want to load it only if - // session restore isn't about to override the homepage. - let willOverride = SessionStartup.willOverrideHomepage; - if (typeof willOverride == "boolean") { - return willOverride ? null : uri; - } - return willOverride.then(willOverrideHomepage => - willOverrideHomepage ? null : uri - ); - })()); - }, - - // Calls the given callback with the URI to load at startup. - // Synchronously if possible, or after uriToLoadPromise resolves otherwise. - _callWithURIToLoad(callback) { - let uriToLoad = this.uriToLoadPromise; - if (uriToLoad && uriToLoad.then) { - uriToLoad.then(callback); - } else { - callback(uriToLoad); - } - }, - - onUnload() { - gUIDensity.uninit(); - - TabsInTitlebar.uninit(); - - ToolbarIconColor.uninit(); - - // In certain scenarios it's possible for unload to be fired before onload, - // (e.g. if the window is being closed after browser.js loads but before the - // load completes). In that case, there's nothing to do here. - if (!this._loadHandled) { - return; - } - - // First clean up services initialized in gBrowserInit.onLoad (or those whose - // uninit methods don't depend on the services having been initialized). - - CombinedStopReload.uninit(); - - gGestureSupport.init(false); - - gHistorySwipeAnimation.uninit(); - - FullScreen.uninit(); - - gSync.uninit(); - - gExtensionsNotifications.uninit(); - gUnifiedExtensions.uninit(); - - try { - gBrowser.removeProgressListener(window.XULBrowserWindow); - gBrowser.removeTabsProgressListener(window.TabsProgressListener); - } catch (ex) {} - - PlacesToolbarHelper.uninit(); - - BookmarkingUI.uninit(); - - TabletModeUpdater.uninit(); - - gTabletModePageCounter.finish(); - - CaptivePortalWatcher.uninit(); - - SidebarUI.uninit(); - - DownloadsButton.uninit(); - - if (gToolbarKeyNavEnabled) { - ToolbarKeyboardNavigator.uninit(); - } - - BrowserSearch.uninit(); - - NewTabPagePreloading.removePreloadedBrowser(window); - - FirefoxViewHandler.uninit(); - - // Now either cancel delayedStartup, or clean up the services initialized from - // it. - if (this._boundDelayedStartup) { - this._cancelDelayedStartup(); - } else { - if (Win7Features) { - Win7Features.onCloseWindow(); - } - Services.prefs.removeObserver(ctrlTab.prefName, ctrlTab); - ctrlTab.uninit(); - gBrowserThumbnails.uninit(); - gProtectionsHandler.uninit(); - FullZoom.destroy(); - - Services.obs.removeObserver(gIdentityHandler, "perm-changed"); - Services.obs.removeObserver(gRemoteControl, "devtools-socket"); - Services.obs.removeObserver(gRemoteControl, "marionette-listening"); - Services.obs.removeObserver(gRemoteControl, "remote-listening"); - Services.obs.removeObserver( - gSessionHistoryObserver, - "browser:purge-session-history" - ); - Services.obs.removeObserver( - gStoragePressureObserver, - "QuotaManager::StoragePressure" - ); - Services.obs.removeObserver(gXPInstallObserver, "addon-install-disabled"); - Services.obs.removeObserver(gXPInstallObserver, "addon-install-started"); - Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked"); - Services.obs.removeObserver( - gXPInstallObserver, - "addon-install-fullscreen-blocked" - ); - Services.obs.removeObserver( - gXPInstallObserver, - "addon-install-origin-blocked" - ); - Services.obs.removeObserver( - gXPInstallObserver, - "addon-install-policy-blocked" - ); - Services.obs.removeObserver( - gXPInstallObserver, - "addon-install-webapi-blocked" - ); - Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed"); - Services.obs.removeObserver( - gXPInstallObserver, - "addon-install-confirmation" - ); - Services.obs.removeObserver(gKeywordURIFixup, "keyword-uri-fixup"); - - MenuTouchModeObserver.uninit(); - BrowserOffline.uninit(); - CanvasPermissionPromptHelper.uninit(); - WebAuthnPromptHelper.uninit(); - PanelUI.uninit(); - } - - // Final window teardown, do this last. - gBrowser.destroy(); - window.XULBrowserWindow = null; - window.docShell.treeOwner - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIAppWindow).XULBrowserWindow = null; - window.browserDOMWindow = null; - }, -}; - -ChromeUtils.defineLazyGetter( - gBrowserInit, - "_firstContentWindowPaintDeferred", - () => Promise.withResolvers() -); - -gBrowserInit.idleTasksFinishedPromise = new Promise(resolve => { - gBrowserInit.idleTaskPromiseResolve = resolve; -}); - function HandleAppCommandEvent(evt) { switch (evt.command) { case "Back": @@ -2634,7 +1524,7 @@ function HandleAppCommandEvent(evt) { BrowserSearch.webSearch(); break; case "Bookmarks": - SidebarUI.toggle("viewBookmarksSidebar"); + SidebarController.toggle("viewBookmarksSidebar"); break; case "Home": BrowserCommands.home(); @@ -3636,7 +2526,7 @@ const BrowserSearch = { event ) { event = getRootEvent(event); - let where = whereToOpenLink(event); + let where = BrowserUtils.whereToOpenLink(event); if (where == "current") { // override: historically search opens in new tab where = "tab"; @@ -3942,14 +2832,6 @@ function FillHistoryMenu(aParent) { return true; } -function BrowserDownloadsUI() { - if (PrivateBrowsingUtils.isWindowPrivate(window)) { - openTrustedLinkIn("about:downloads", "tab"); - } else { - PlacesCommandHook.showPlacesOrganizer("Downloads"); - } -} - function toOpenWindowByType(inType, uri, features) { var topWindow = Services.wm.getMostRecentWindow(inType); @@ -4850,7 +3732,7 @@ var XULBrowserWindow = { } } - if (TranslationsParent.isRestrictedPage(gBrowser)) { + if (TranslationsParent.isFullPageTranslationsRestrictedForPage(gBrowser)) { this._menuItemForTranslations.setAttribute("disabled", "true"); } else { this._menuItemForTranslations.removeAttribute("disabled"); @@ -5658,7 +4540,7 @@ nsBrowserAccess.prototype = { : PrivateBrowsingUtils.isWindowPrivate(window); switch (aWhere) { - case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW: + case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW: { // FIXME: Bug 408379. So how come this doesn't send the // referrer like the other loads do? var url = aURI && aURI.spec; @@ -5702,6 +4584,7 @@ nsBrowserAccess.prototype = { console.error(ex); } break; + } case Ci.nsIBrowserDOMWindow.OPEN_NEWTAB: case Ci.nsIBrowserDOMWindow.OPEN_NEWTAB_BACKGROUND: { // If we have an opener, that means that the caller is expecting access @@ -6112,7 +4995,7 @@ function setToolbarVisibility( document.documentElement.toggleAttribute(overlapAttr, false); break; case "newtab": - default: + default: { let currentURI = gBrowser?.currentURI; if (!gBrowserInit.domContentLoaded) { let uriToLoad = gBrowserInit.uriToLoadPromise; @@ -6129,6 +5012,7 @@ function setToolbarVisibility( isVisible = BookmarkingUI.isOnNewTabPage(currentURI); document.documentElement.toggleAttribute(overlapAttr, isVisible); break; + } } } @@ -6285,9 +5169,10 @@ var gUIDensity = { } let docs = [document.documentElement]; - let shouldUpdateSidebar = SidebarUI.initialized && SidebarUI.isOpen; + let shouldUpdateSidebar = + SidebarController.initialized && SidebarController.isOpen; if (shouldUpdateSidebar) { - docs.push(SidebarUI.browser.contentDocument.documentElement); + docs.push(SidebarController.browser.contentDocument.documentElement); } for (let doc of docs) { switch (mode) { @@ -6303,7 +5188,7 @@ var gUIDensity = { } } if (shouldUpdateSidebar) { - let tree = SidebarUI.browser.contentDocument.querySelector( + let tree = SidebarController.browser.contentDocument.querySelector( ".sidebar-placesTree" ); if (tree) { @@ -6540,7 +5425,7 @@ function handleLinkClick(event, href, linkNode) { return false; } - var where = whereToOpenLink(event); + var where = BrowserUtils.whereToOpenLink(event); if (where == "current") { return false; } @@ -6613,7 +5498,7 @@ function middleMousePaste(event) { // if it's not the current tab, we don't need to do anything because the // browser doesn't exist. - let where = whereToOpenLink(event, true, false); + let where = BrowserUtils.whereToOpenLink(event, true, false); let lastLocationChange; if (where == "current") { lastLocationChange = gBrowser.selectedBrowser.lastLocationChange; @@ -6727,13 +5612,6 @@ function handleDroppedLink( } } -function BrowserForceEncodingDetection() { - gBrowser.selectedBrowser.forceEncodingDetection(); - BrowserCommands.reloadWithFlags( - Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE - ); -} - var ToolbarContextMenu = { updateDownloadsAutoHide(popup) { let checkbox = document.getElementById( @@ -7628,84 +6506,6 @@ var MailIntegration = { }, }; -/** - * Open about:addons page by given view id. - * @param {String} aView - * View id of page that will open. - * e.g. "addons://discover/" - * @param {Object} options - * { - * selectTabByViewId: If true, if there is the tab opening page having - * same view id, select the tab. Else if the current - * page is blank, load on it. Otherwise, open a new - * tab, then load on it. - * If false, if there is the tab opening - * about:addoons page, select the tab and load page - * for view id on it. Otherwise, leave the loading - * behavior to switchToTabHavingURI(). - * If no options, handles as false. - * } - * @returns {Promise} When the Promise resolves, returns window object loaded the - * view id. - */ -function BrowserOpenAddonsMgr(aView, { selectTabByViewId = false } = {}) { - return new Promise(resolve => { - let emWindow; - let browserWindow; - - var receivePong = function (aSubject) { - let browserWin = aSubject.browsingContext.topChromeWindow; - if (!emWindow || browserWin == window /* favor the current window */) { - if ( - selectTabByViewId && - aSubject.gViewController.currentViewId !== aView - ) { - return; - } - - emWindow = aSubject; - browserWindow = browserWin; - } - }; - Services.obs.addObserver(receivePong, "EM-pong"); - Services.obs.notifyObservers(null, "EM-ping"); - Services.obs.removeObserver(receivePong, "EM-pong"); - - if (emWindow) { - if (aView && !selectTabByViewId) { - emWindow.loadView(aView); - } - let tab = browserWindow.gBrowser.getTabForBrowser( - emWindow.docShell.chromeEventHandler - ); - browserWindow.gBrowser.selectedTab = tab; - emWindow.focus(); - resolve(emWindow); - return; - } - - if (selectTabByViewId) { - const target = isBlankPageURL(gBrowser.currentURI.spec) - ? "current" - : "tab"; - openTrustedLinkIn("about:addons", target); - } else { - // This must be a new load, else the ping/pong would have - // found the window above. - switchToTabHavingURI("about:addons", true); - } - - Services.obs.addObserver(function observer(aSubject, aTopic) { - Services.obs.removeObserver(observer, aTopic); - if (aView) { - aSubject.loadView(aView); - } - aSubject.focus(); - resolve(aSubject); - }, "EM-loaded"); - }); -} - function AddKeywordForSearchField() { if (!gContextMenu) { throw new Error("Context menu doesn't seem to be open."); @@ -8256,7 +7056,7 @@ function safeModeRestart() { */ function duplicateTabIn(aTab, where, delta) { switch (where) { - case "window": + case "window": { let otherWin = OpenBrowserWindow({ private: PrivateBrowsingUtils.isBrowserPrivate(aTab.linkedBrowser), }); @@ -8278,6 +7078,7 @@ function duplicateTabIn(aTab, where, delta) { "browser-delayed-startup-finished" ); break; + } case "tabshifted": SessionStore.duplicateTab(window, aTab, delta); // A background tab has been opened, nothing else to do here. @@ -9125,15 +7926,14 @@ var ConfirmationHint = { * - event (DOM event): The event that triggered the feedback * - descriptionId (string): message ID of the description text * - position (string): position of the panel relative to the anchor. - * + * - l10nArgs (object): l10n arguments for the messageId. */ show(anchor, messageId, options = {}) { this._reset(); MozXULElement.insertFTLIfNeeded("toolkit/branding/brandings.ftl"); MozXULElement.insertFTLIfNeeded("browser/confirmationHints.ftl"); - document.l10n.setAttributes(this._message, messageId); - + document.l10n.setAttributes(this._message, messageId, options.l10nArgs); if (options.descriptionId) { document.l10n.setAttributes(this._description, options.descriptionId); this._description.hidden = false; @@ -9236,11 +8036,9 @@ var FirefoxViewHandler = { ChromeUtils.defineESModuleGetters(this, { SyncedTabs: "resource://services-sync/SyncedTabs.sys.mjs", }); - Services.obs.addObserver(this, "firefoxview-notification-dot-update"); }, uninit() { CustomizableUI.removeListener(this); - Services.obs.removeObserver(this, "firefoxview-notification-dot-update"); }, onWidgetRemoved(aWidgetId) { if (aWidgetId == this.BUTTON_ID && this.tab) { @@ -9293,7 +8091,7 @@ var FirefoxViewHandler = { }, handleEvent(e) { switch (e.type) { - case "TabSelect": + case "TabSelect": { const selected = e.target == this.tab; this.button?.toggleAttribute("open", selected); this.button?.setAttribute("aria-pressed", selected); @@ -9304,6 +8102,7 @@ var FirefoxViewHandler = { gBrowser.visibleTabs[0].style.MozUserFocus = e.target == this.tab ? "normal" : ""; break; + } case "TabClose": this.tab = null; gBrowser.tabContainer.removeEventListener("TabSelect", this); @@ -9314,14 +8113,6 @@ var FirefoxViewHandler = { break; } }, - observe(sub, topic, data) { - switch (topic) { - case "firefoxview-notification-dot-update": - let shouldShow = data === "true"; - this._toggleNotificationDot(shouldShow); - break; - } - }, _closeDeviceConnectedTab() { if (!TabsSetupFlowManager.didFxaTabOpen) { return; @@ -9352,11 +8143,6 @@ var FirefoxViewHandler = { _onTabForegrounded() { if (this.tab?.selected) { this.SyncedTabs.syncTabs(); - Services.obs.notifyObservers( - null, - "firefoxview-notification-dot-update", - "false" - ); } }, _recordViewIfTabSelected() { @@ -9380,7 +8166,4 @@ var FirefoxViewHandler = { } } }, - _toggleNotificationDot(shouldShow) { - this.button?.toggleAttribute("attention", shouldShow); - }, }; diff --git a/browser/base/content/browser.js.globals b/browser/base/content/browser.js.globals index 7002cd0b5b..910e0b5ca9 100644 --- a/browser/base/content/browser.js.globals +++ b/browser/base/content/browser.js.globals @@ -28,9 +28,6 @@ "gPopupBlockerObserver", "gKeywordURIFixup", "_createNullPrincipalFromTabUserContextId", - "_resolveDelayedStartup", - "delayedStartupPromise", - "gBrowserInit", "HandleAppCommandEvent", "BrowserCommands", "kSkipCacheFlags", @@ -54,7 +51,6 @@ "BrowserSearch", "CreateContainerTabMenu", "FillHistoryMenu", - "BrowserDownloadsUI", "toOpenWindowByType", "OpenBrowserWindow", "updateEditUIVisibility", @@ -85,7 +81,6 @@ "handleLinkClick", "middleMousePaste", "handleDroppedLink", - "BrowserForceEncodingDetection", "ToolbarContextMenu", "BrowserOffline", "CanvasPermissionPromptHelper", @@ -94,7 +89,6 @@ "WindowIsClosing", "warnAboutClosingWindow", "MailIntegration", - "BrowserOpenAddonsMgr", "AddKeywordForSearchField", "restoreLastClosedTabOrWindowOrSession", "undoCloseTab", @@ -135,7 +129,6 @@ "DownloadsCommon", "E10SUtils", "ExtensionsUI", - "FirefoxViewNotificationManager", "HomePage", "isProductURL", "LightweightThemeConsumer", diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index 8ef14813b1..aec0983a67 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -39,7 +39,6 @@ - - @@ -107,6 +105,7 @@