diff options
Diffstat (limited to 'browser/base/content')
285 files changed, 4966 insertions, 4612 deletions
diff --git a/browser/base/content/aboutDialog-appUpdater.js b/browser/base/content/aboutDialog-appUpdater.js index 21bf83bc42..5a8cc0561b 100644 --- a/browser/base/content/aboutDialog-appUpdater.js +++ b/browser/base/content/aboutDialog-appUpdater.js @@ -28,7 +28,7 @@ var UPDATING_MIN_DISPLAY_TIME_MS = 1500; var gAppUpdater; -function onUnload(aEvent) { +function onUnload(_aEvent) { if (gAppUpdater) { gAppUpdater.destroy(); gAppUpdater = null; diff --git a/browser/base/content/aboutDialog.xhtml b/browser/base/content/aboutDialog.xhtml index e0fcce367a..55de242415 100644 --- a/browser/base/content/aboutDialog.xhtml +++ b/browser/base/content/aboutDialog.xhtml @@ -138,7 +138,7 @@ <label is="text-link" useoriginprincipal="true" href="about:credits" data-l10n-name="community-creditsLink"/> </description> <description class="text-blurb" id="contributeDesc" data-l10n-id="helpus"> - <label is="text-link" href="https://donate.mozilla.org/?utm_source=firefox&utm_medium=referral&utm_campaign=firefox_about&utm_content=firefox_about" data-l10n-name="helpus-donateLink"/> + <label is="text-link" href="https://foundation.mozilla.org/?form=firefox-about" data-l10n-name="helpus-donateLink"/> <label is="text-link" href="https://www.mozilla.org/contribute/?utm_source=firefox-browser&utm_medium=firefox-desktop&utm_campaign=about-dialog" data-l10n-name="helpus-getInvolvedLink"/> </description> </vbox> diff --git a/browser/base/content/appmenu-viewcache.inc.xhtml b/browser/base/content/appmenu-viewcache.inc.xhtml index 04bba182fb..9633c7d79d 100644 --- a/browser/base/content/appmenu-viewcache.inc.xhtml +++ b/browser/base/content/appmenu-viewcache.inc.xhtml @@ -3,24 +3,11 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. <html:template id="appMenu-viewCache"> - <panelview id="appMenu-mainView" class="PanelUI-subView"> - <vbox class="panel-subview-body"> - <toolbarbutton id="appMenu-whatsnew-button" - class="subviewbutton subviewbutton-iconic subviewbutton-nav" - hidden="true" - closemenu="none" - oncommand="PanelUI.showSubView('PanelUI-whatsNew', this)"/> - </vbox> - </panelview> - - <!-- This is a placeholder app menu which should be replaced with the "real" - Proton app menu before the Proton pref starts getting enabled. --> - <panelview id="appMenu-protonMainView" class="PanelUI-subView" + <panelview id="appMenu-mainView" class="PanelUI-subView" lockpanelvertical="true"> <vbox class="panel-subview-body"> - <vbox id="appMenu-proton-addon-banners"/> - <toolbarbutton id="appMenu-proton-update-banner" class="panel-banner-item subviewbutton" - oncommand="PanelUI._onBannerItemSelected(event)" + <vbox id="appMenu-addon-banners"/> + <toolbarbutton id="appMenu-update-banner" class="panel-banner-item subviewbutton" wrap="true" hidden="true"/> <toolbaritem id="appMenu-fxa-status2" @@ -29,7 +16,7 @@ <html:div id="appMenu-fxa-text" data-l10n-id="appmenu-fxa-sync-and-save-data2"/> <toolbarbutton id="appMenu-fxa-label2" class="subviewbutton" - oncommand="gSync.toggleAccountPanel(this, event)"> + > <vbox flex="1"> <label id="appMenu-header-title" crop="end"/> @@ -43,7 +30,6 @@ data-l10n-id="appmenuitem-profiles" data-l10n-args='{ "profilename": "" }' closemenu="none" - oncommand="gProfiles.updateView(this)" hidden="true"/> <toolbarseparator id="appMenu-fxa-separator" class="proton-zap"/> <toolbarbutton id="appMenu-new-tab-button2" @@ -66,12 +52,12 @@ class="subviewbutton subviewbutton-nav" data-l10n-id="library-bookmarks-menu" closemenu="none" - oncommand="BookmarkingUI.showSubView(this);"/> + /> <toolbarbutton id="appMenu-history-button" class="subviewbutton subviewbutton-nav" data-l10n-id="appmenuitem-history" closemenu="none" - oncommand="PanelUI.showSubView('PanelUI-history', this)"/> + /> <toolbarbutton id="appMenu-downloads-button" class="subviewbutton" data-l10n-id="appmenuitem-downloads" @@ -80,7 +66,6 @@ <toolbarbutton id="appMenu-passwords-button" class="subviewbutton" data-l10n-id="appmenuitem-passwords" - oncommand="LoginHelper.openPasswordManager(window, { entryPoint: 'mainmenu' })" /> <toolbarbutton id="appMenu-extensions-themes-button" class="subviewbutton" @@ -129,13 +114,6 @@ class="subviewbutton subviewbutton-iconic" data-l10n-id="appmenuitem-fullscreen" type="checkbox" -# Note that we're custom-handling this click to make sure the panel disappears -# before entering fullscreen, as it does some odd moving about on the screen -# in the middle of the fullscreen transition otherwise. - oncommand=" - this.closest('panel').hidePopup(); - setTimeout(() => BrowserFullScreen(), 0); - " tooltip="dynamic-shortcut-tooltip"> <observes element="View:FullScreen" attribute="checked"/> </toolbarbutton> @@ -147,12 +125,12 @@ #ifdef XP_MACOSX key="key_preferencesCmdMac" #endif - oncommand="openPreferences()"/> + /> <toolbarbutton id="appMenu-more-button2" class="subviewbutton subviewbutton-nav" data-l10n-id="appmenuitem-more-tools" closemenu="none" - oncommand="PanelUI.showMoreToolsPanel(this);"/> + /> <toolbarbutton id="appMenu-report-broken-site-button" class="subviewbutton subviewbutton-nav" data-l10n-id="appmenuitem-report-broken-site" @@ -163,7 +141,7 @@ class="subviewbutton subviewbutton-nav" data-l10n-id="appmenuitem-help" closemenu="none" - oncommand="PanelUI.showSubView('PanelUI-helpView', this)"/> + /> #ifndef XP_MACOSX <toolbarseparator/> <toolbarbutton id="appMenu-quit-button2" @@ -181,16 +159,16 @@ data-l10n-id="appmenu-recently-closed-tabs" class="subviewbutton subviewbutton-nav" closemenu="none" - oncommand="PanelUI.showSubView('appMenu-library-recentlyClosedTabs', this)"/> + /> <toolbarbutton id="appMenuRecentlyClosedWindows" data-l10n-id="appmenu-recently-closed-windows" class="subviewbutton subviewbutton-nav" closemenu="none" - oncommand="PanelUI.showSubView('appMenu-library-recentlyClosedWindows', this)"/> + /> <toolbarbutton id="appMenuSearchHistory" data-l10n-id="appmenu-search-history" class="subviewbutton" - oncommand="PlacesCommandHook.searchHistory()"/> + /> <toolbarbutton id="appMenu-restoreSession" data-l10n-id="appmenu-restore-session" class="subviewbutton" @@ -216,7 +194,7 @@ <toolbarbutton id="PanelUI-historyMore" class="subviewbutton panel-subview-footer-button" data-l10n-id="appmenu-manage-history" - oncommand="PlacesCommandHook.showPlacesOrganizer('History'); CustomizableUI.hidePanelForNode(this);"/> + /> </panelview> <panelview id="PanelUI-profiles" flex="1"> @@ -227,10 +205,10 @@ <hbox id="this-profile-buttons"> <toolbarbutton id="profiles-edit-this-delete-button" class="subviewbutton toolbarbutton-1" - oncommand="switchToTabHavingURI('about:profilemanager', true)"/> + /> <toolbarbutton id="profiles-delete-this-profile-button" class="subviewbutton toolbarbutton-1" - oncommand="switchToTabHavingURI('about:profilemanager', true)"/> + /> </hbox> </vbox> <toolbarseparator/> @@ -240,15 +218,15 @@ class="subviewbutton" data-l10n-id="appmenu-close-profile" data-l10n-args='{ "profilename": "" }' - oncommand=""/> + /> <toolbarbutton id="profiles-create-profile-button" class="subviewbutton" data-l10n-id="appmenu-create-profile" - oncommand="switchToTabHavingURI('about:profilemanager', true)"/> + /> <toolbarbutton id="profiles-manage-profiles-button" class="subviewbutton" data-l10n-id="appmenu-manage-profiles" - oncommand="switchToTabHavingURI('about:profilemanager', true)"/> + /> </vbox> </panelview> @@ -272,12 +250,12 @@ <toolbarbutton id="panelMenu_searchBookmarks" data-l10n-id="bookmarks-search" class="subviewbutton" - oncommand="PlacesCommandHook.searchBookmarks();"/> + /> <toolbarbutton id="panelMenu_viewBookmarksToolbar" class="subviewbutton" data-l10n-id="bookmarks-tools-toolbar-visibility-panel" data-l10n-args='{ "isVisible": false }' - oncommand="BookmarkingUI.toggleBookmarksToolbar('bookmark-tools');"/> + /> <toolbarseparator/> <html:h2 id="panelMenu_recentBookmarks" data-l10n-id="bookmarks-recent-bookmarks-panel-subheader" @@ -470,8 +448,6 @@ <toolbarbutton id="PanelUI-remotetabs-syncnow" align="center" class="subviewbutton" - oncommand="gSync.doSync();" - onmouseover="gSync.refreshSyncButtonsTooltip();" closemenu="none"> <hbox flex="1"> <image class="syncNowBtn"/> @@ -486,7 +462,7 @@ <toolbarbutton id="PanelUI-remotetabs-view-managedevices" class="subviewbutton" data-l10n-id="appmenuitem-fxa-manage-account" - oncommand="gSync.openDevicesManagementPage('syncedtabs-menupanel');"> + > <observes element="sidebar-box" attribute="positionend"/> </toolbarbutton> <toolbarseparator id="PanelUI-remotetabs-separator"/> @@ -513,7 +489,7 @@ <toolbarbutton class="PanelUI-remotetabs-button" id="PanelUI-remotetabs-tabsdisabledpane-button" data-l10n-id="appmenu-remote-tabs-opensettings" - oncommand="gSync.openPrefs('synced-tabs');"/> + /> </hbox> </vbox> </hbox> @@ -527,7 +503,7 @@ <toolbarbutton id="PanelUI-remotetabs-connect-device-button" class="PanelUI-remotetabs-button" data-l10n-id="appmenu-remote-tabs-connectdevice" - oncommand="gSync.openConnectAnotherDevice('synced-tabs');"/> + /> </vbox> </hbox> </deck> @@ -545,7 +521,7 @@ <toolbarbutton class="PanelUI-remotetabs-button" id="PanelUI-remotetabs-setupsync-button" data-l10n-id="appmenu-remote-tabs-sign-into-sync" - oncommand="gSync.openPrefs('synced-tabs');"/> + /> </vbox> <!-- When Sync is not enabled --> <vbox id="PanelUI-remotetabs-syncdisabled" @@ -558,7 +534,7 @@ <toolbarbutton class="PanelUI-remotetabs-button" id="PanelUI-remotetabs-syncdisabled-button" data-l10n-id="appmenu-remote-tabs-turn-on-sync" - oncommand="gSync.openPrefs('synced-tabs');"/> + /> </vbox> <!-- When Sync needs re-authentication --> <vbox id="PanelUI-remotetabs-reauthsync" @@ -571,7 +547,7 @@ <toolbarbutton class="PanelUI-remotetabs-button" id="PanelUI-remotetabs-reauthsync-button" data-l10n-id="appmenu-remote-tabs-sign-into-sync" - oncommand="gSync.openPrefs('synced-tabs');"/> + /> </vbox> <!-- When Sync needs verification --> <vbox id="PanelUI-remotetabs-unverified" @@ -584,7 +560,7 @@ <toolbarbutton class="PanelUI-remotetabs-button" id="PanelUI-remotetabs-unverified-button" data-l10n-id="appmenu-remote-tabs-opensettings" - oncommand="gSync.openPrefs('synced-tabs');"/> + /> </vbox> </hbox> </vbox> @@ -595,7 +571,7 @@ <toolbarbutton id="fxa-manage-account-button" align="center" class="subviewbutton" - oncommand="gSync.clickFxAMenuHeaderButton(this);"> + > <vbox flex="1"> <label id="fxa-menu-header-title" crop="end" @@ -609,8 +585,6 @@ <toolbarbutton id="PanelUI-fxa-menu-syncnow-button" align="center" class="subviewbutton" - oncommand="gSync.doSyncFromFxaMenu(this);" - onmouseover="gSync.refreshSyncButtonsTooltip();" closemenu="none"> <hbox flex="1"> <image id="PanelUI-appMenu-fxa-image-last-synced" @@ -627,43 +601,34 @@ <toolbarbutton id="PanelUI-fxa-menu-setup-sync-button" class="subviewbutton" data-l10n-id="appmenu-fxa-setup-sync" - oncommand="gSync.openPrefsFromFxaMenu('sync_settings', this);"/> + /> <!-- The `Connect Another Device` button is disabled by default until the user logs into Sync. --> <toolbarbutton id="PanelUI-fxa-menu-connect-device-button" class="subviewbutton" data-l10n-id="fxa-menu-connect-another-device" disabled="true" - oncommand="gSync.openConnectAnotherDeviceFromFxaMenu(this);"/> + /> <toolbarbutton id="PanelUI-fxa-menu-sendtab-button" class="subviewbutton subviewbutton-nav" data-l10n-id="fxa-menu-send-tab-to-device" data-l10n-args='{"tabCount":1}' closemenu="none" - oncommand="gSync.showSendToDeviceViewFromFxaMenu(this);"/> + /> <toolbarbutton id="PanelUI-fxa-menu-sync-prefs-button" class="subviewbutton" data-l10n-id="fxa-menu-sync-settings" hidden="true" - oncommand="gSync.openPrefsFromFxaMenu('sync_settings', this);"/> + /> <toolbarseparator id="PanelUI-sign-out-separator" /> <toolbarbutton id="PanelUI-fxa-menu-account-signout-button" class="subviewbutton" data-l10n-id="fxa-menu-sign-out" - oncommand="gSync.disconnect();" hidden="true"/> </vbox> <!-- updateCTAPanel will control if we show this panel --> - <vbox id="PanelUI-fxa-cta-menu"> - <toolbarbutton id="PanelUI-fxa-menu-sync-button" class="subviewbutton subviewbutton-iconic" - oncommand="gSync.openPrefsFromFxaButton('sync_cta', this);"> - <vbox flex="1"> - <label id="fxa-menu-header-title" crop="end" data-l10n-id="fxa-menu-sync-title" /> - <label id="cta-menu-header-description" crop="end" data-l10n-id="fxa-menu-sync-description" /> - </vbox> - </toolbarbutton> + <vbox id="PanelUI-fxa-cta-menu" hidden="true"> <toolbarseparator id="PanelUI-products-separator" /> - <toolbarbutton id="PanelUI-fxa-menu-monitor-button" class="subviewbutton subviewbutton-iconic" - oncommand="gSync.openMonitorLink(this)"> + <toolbarbutton id="PanelUI-fxa-menu-monitor-button" class="fxa-cta-button subviewbutton subviewbutton-iconic"> <vbox flex="1"> <hbox align="center"> <image class="PanelUI-fxa-menu-monitor-button ctaMenuLogo" role="presentation" /> @@ -672,8 +637,7 @@ <label id="cta-menu-header-description" crop="end" data-l10n-id="appmenuitem-monitor-description" /> </vbox> </toolbarbutton> - <toolbarbutton id="PanelUI-fxa-menu-relay-button" class="subviewbutton subviewbutton-iconic" - oncommand="gSync.openRelayLink(this)"> + <toolbarbutton id="PanelUI-fxa-menu-relay-button" class="fxa-cta-button subviewbutton subviewbutton-iconic"> <vbox flex="1"> <hbox align="center"> <image class="PanelUI-fxa-menu-relay-button ctaMenuLogo" role="presentation" /> @@ -682,8 +646,7 @@ <label id="cta-menu-header-description" crop="end" data-l10n-id="appmenuitem-relay-description" /> </vbox> </toolbarbutton> - <toolbarbutton id="PanelUI-fxa-menu-vpn-button" class="subviewbutton subviewbutton-iconic" - oncommand="gSync.openVPNLink(this)"> + <toolbarbutton id="PanelUI-fxa-menu-vpn-button" class="fxa-cta-button subviewbutton subviewbutton-iconic"> <vbox flex="1"> <hbox align="center"> <image class="PanelUI-fxa-menu-vpn-button ctaMenuLogo" role="presentation" /> @@ -725,7 +688,7 @@ <toolbarbutton id="PanelUI-fxa-menu-sendtab-not-configured-button" class="PanelUI-fxa-signin-button" data-l10n-id="appmenuitem-fxa-sign-in" - oncommand="gSync.openPrefsFromFxaMenu('send_tab', this);"/> + /> </vbox> </panelview> @@ -736,7 +699,15 @@ <toolbarbutton id="PanelUI-fxa-menu-sendtab-connect-device-button" class="PanelUI-fxa-signin-button" data-l10n-id="appmenu-remote-tabs-connectdevice" - oncommand="gSync.openConnectAnotherDeviceFromFxaMenu(this);"/> + /> + </vbox> + </panelview> + + <!-- This panelview holds the list of "inactive" tabs for devices --> + <panelview id="PanelUI-fxa-menu-inactive-tabs" class="PanelUI-subView PanelUI-remotetabs-clientcontainer"> + <label itemtype="client"> + </label> + <vbox class="panel-subview-body"> </vbox> </panelview> @@ -746,40 +717,17 @@ class="subviewbutton subviewbutton-nav" data-l10n-id="library-bookmarks-menu" closemenu="none" - oncommand="BookmarkingUI.showSubView(this);"/> + /> <toolbarbutton id="appMenu-library-history-button" class="subviewbutton subviewbutton-nav" data-l10n-id="appmenuitem-history" closemenu="none" - oncommand="PanelUI.showSubView('PanelUI-history', this)"/> + /> <toolbarbutton id="appMenu-library-downloads-button" class="subviewbutton" data-l10n-id="appmenuitem-downloads" - oncommand="DownloadsPanel.showDownloadsHistory();"/> - </vbox> - </panelview> - - <panelview id="PanelUI-whatsNew" class="PanelUI-subView" mainview-with-header="true"> - <hbox id="PanelUI-whatsNew-title" class="panel-header"> - <html:h1> - <html:span data-l10n-id="whatsnew-panel-header"></html:span> - </html:h1> - </hbox> - <toolbarseparator/> - <vbox class="panel-subview-body"> - <toolbaritem id="PanelUI-whatsNew-content" - orient="vertical" - smoothscroll="false"> - <html:div id="PanelUI-whatsNew-message-container" role="document"> - <!-- What's New messages will be rendered here --> - </html:div> - </toolbaritem> + /> </vbox> - <toolbarseparator/> - <checkbox id="panelMenu-toggleWhatsNew" - class="panelMenu-toggleWhatsNew-checkbox" - onclick="ToolbarPanelHub.toggleWhatsNewPref(event)" - data-l10n-id="whatsnew-panel-footer-checkbox"/> </panelview> <panelview id="reset-pbm-panel" class="PanelUI-subView" role="document"> @@ -795,15 +743,29 @@ <button id="reset-pbm-panel-cancel-button" class="footer-button" data-l10n-id="reset-pbm-panel-cancel-button" - oncommand="ResetPBMPanel.onCancel(this)"></button> + ></button> <button slot="primary" id="reset-pbm-panel-confirm-button" class="footer-button" data-l10n-id="reset-pbm-panel-confirm-button" - oncommand="ResetPBMPanel.onConfirm(this)"></button> + ></button> </html:moz-button-group> </vbox> </panelview> + <panelview id="content-analysis-panel" class="PanelUI-subView" role="document" mainview-with-header="true"> + <vbox id="content-analysis-panel-container" role="alertdialog" aria-labelledby="content-analysis-header"> + <hbox class="panel-header"> + <html:h1 id="content-analysis-header" data-l10n-id="content-analysis-panel-title"/> + </hbox> + <description id="content-analysis-panel-description"> + <html:a is="moz-support-link" + data-l10n-name="info" + class="learnMore" + support-page="data-loss-prevention"/> + </description> + </vbox> + </panelview> + #include ../../components/reportbrokensite/content/reportBrokenSitePanel.inc.xhtml </html:template> diff --git a/browser/base/content/browser-a11yUtils.js b/browser/base/content/browser-a11yUtils.js index 9bedb9238c..935ddc6a55 100644 --- a/browser/base/content/browser-a11yUtils.js +++ b/browser/base/content/browser-a11yUtils.js @@ -21,6 +21,7 @@ var A11yUtils = { * can thus hinder rather than help users if used incorrectly. * Please only use this after consultation with the Mozilla accessibility * team. + * @param {object} [options] * @param {string} [options.id] The Fluent id of the message to announce. The * ftl file must already be included in browser.xhtml. This must be * specified unless a raw message is specified instead. @@ -28,13 +29,8 @@ var A11yUtils = { * @param {string} [options.raw] The raw, already localized message to * announce. You should generally prefer a Fluent id instead, but in * rare cases, this might not be feasible. - * @param {Element} [options.source] The element with which the announcement - * is associated. This should generally be something the user can - * interact with to respond to the announcement. For example, for an - * announcement indicating that Reader View is available, this should - * be the Reader View button on the toolbar. */ - async announce({ id = null, args = {}, raw = null, source = document } = {}) { + async announce({ id = null, args = {}, raw = null } = {}) { if ((!id && !raw) || (id && raw)) { throw new Error("One of raw or id must be specified."); } diff --git a/browser/base/content/browser-addons.js b/browser/base/content/browser-addons.js index 6f50745e8d..e00952b2dc 100644 --- a/browser/base/content/browser-addons.js +++ b/browser/base/content/browser-addons.js @@ -525,7 +525,7 @@ var gXPInstallObserver = { Services.console.logMessage(consoleMsg); }, - async observe(aSubject, aTopic, aData) { + async observe(aSubject, aTopic) { var installInfo = aSubject.wrappedJSObject; var browser = installInfo.browser; @@ -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. @@ -914,9 +913,9 @@ var gXPInstallObserver = { let height = undefined; if (PopupNotifications.isPanelOpen) { - let rect = document - .getElementById("addon-progress-notification") - .getBoundingClientRect(); + let rect = window.windowUtils.getBoundsWithoutFlushing( + document.getElementById("addon-progress-notification") + ); height = rect.height; } @@ -1009,7 +1008,7 @@ var gExtensionsNotifications = { let items = 0; if (lazy.AMBrowserExtensionsImport.canCompleteOrCancelInstalls) { - this._createAddonButton("webext-imported-addons", null, evt => { + this._createAddonButton("webext-imported-addons", null, () => { lazy.AMBrowserExtensionsImport.completeInstalls(); }); items++; @@ -1022,7 +1021,7 @@ var gExtensionsNotifications = { this._createAddonButton( "webext-perms-update-menu-item", update.addon, - evt => { + () => { ExtensionsUI.showUpdate(gBrowser, update); } ); @@ -1032,7 +1031,7 @@ var gExtensionsNotifications = { if (++items > 4) { break; } - this._createAddonButton("webext-perms-sideload-menu-item", addon, evt => { + this._createAddonButton("webext-perms-sideload-menu-item", addon, () => { // We need to hide the main menu manually because the toolbarbutton is // removed immediately while processing this event, and PanelUI is // unable to identify which panel should be closed automatically. @@ -1046,16 +1045,11 @@ var gExtensionsNotifications = { var BrowserAddonUI = { async promptRemoveExtension(addon) { let { name } = addon; - let [title, btnTitle, message] = await lazy.l10n.formatValues([ + let [title, btnTitle] = await lazy.l10n.formatValues([ { id: "addon-removal-title", args: { name } }, { id: "addon-removal-button" }, - { id: "addon-removal-message", args: { name } }, ]); - if (Services.prefs.getBoolPref("prompts.windowPromptSubDialog", false)) { - message = null; - } - let { BUTTON_TITLE_IS_STRING: titleString, BUTTON_TITLE_CANCEL: titleCancel, @@ -1082,7 +1076,7 @@ var BrowserAddonUI = { let result = confirmEx( window, title, - message, + null, btnFlags, btnTitle, /* button1 */ null, @@ -1094,30 +1088,21 @@ 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, eventObject) { + async removeAddon(addonId) { let addon = addonId && (await AddonManager.getAddonByID(addonId)); if (!addon || !(addon.permissions & AddonManager.PERM_CAN_UNINSTALL)) { return; @@ -1136,13 +1121,91 @@ var BrowserAddonUI = { } }, - async manageAddon(addonId, eventObject) { + async manageAddon(addonId) { let addon = addonId && (await AddonManager.getAddonByID(addonId)); if (!addon) { 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"); + }); }, }; @@ -1556,7 +1619,7 @@ var gUnifiedExtensions = { } else { viewID = "addons://list/extension"; } - await BrowserOpenAddonsMgr(viewID); + await BrowserAddonUI.openAddonsMgr(viewID); return; } } @@ -1798,7 +1861,7 @@ var gUnifiedExtensions = { } }, - onWidgetAdded(aWidgetId, aArea, aPosition) { + onWidgetAdded(aWidgetId, aArea) { // When we pin a widget to the toolbar from a narrow window, the widget // will be overflowed directly. In this case, we do not want to change the // class name since it is going to be changed by `onWidgetOverflow()` @@ -1813,7 +1876,7 @@ var gUnifiedExtensions = { this._updateWidgetClassName(aWidgetId, inPanel); }, - onWidgetOverflow(aNode, aContainer) { + onWidgetOverflow(aNode) { // We register a CUI listener for each window so we make sure that we // handle the event for the right window here. if (window !== aNode.ownerGlobal) { @@ -1823,7 +1886,7 @@ var gUnifiedExtensions = { this._updateWidgetClassName(aNode.getAttribute("widget-id"), true); }, - onWidgetUnderflow(aNode, aContainer) { + onWidgetUnderflow(aNode) { // We register a CUI listener for each window so we make sure that we // handle the event for the right window here. if (window !== aNode.ownerGlobal) { @@ -1882,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"); @@ -1891,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"/> + <toolbarbutton id="allTabsMenu-closeDuplicateTabs" + class="subviewbutton" + oncommand="gBrowser.removeAllDuplicateTabs();" + data-l10n-id="all-tabs-menu-close-duplicate-tabs"/> <toolbarbutton id="allTabsMenu-containerTabsButton" class="subviewbutton subviewbutton-nav" closemenu="none" diff --git a/browser/base/content/browser-allTabsMenu.js b/browser/base/content/browser-allTabsMenu.js index f11d4da71d..f4b15bc9c3 100644 --- a/browser/base/content/browser-allTabsMenu.js +++ b/browser/base/content/browser-allTabsMenu.js @@ -6,6 +6,7 @@ /* eslint-env mozilla/browser-window */ ChromeUtils.defineESModuleGetters(this, { + BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.sys.mjs", TabsPanel: "resource:///modules/TabsList.sys.mjs", }); @@ -58,7 +59,7 @@ var gTabsPanel = { dropIndicator: this.dropIndicator, }); - this.allTabsView.addEventListener("ViewShowing", e => { + this.allTabsView.addEventListener("ViewShowing", () => { PanelUI._ensureShortcutsShown(this.allTabsView); let containersEnabled = @@ -72,9 +73,19 @@ var gTabsPanel = { !hasHiddenTabs; document.getElementById("allTabsMenu-hiddenTabsSeparator").hidden = !hasHiddenTabs; + + let closeDuplicateEnabled = Services.prefs.getBoolPref( + "browser.tabs.context.close-duplicate.enabled" + ); + let closeDuplicateTabsItem = document.getElementById( + "allTabsMenu-closeDuplicateTabs" + ); + closeDuplicateTabsItem.hidden = !closeDuplicateEnabled; + closeDuplicateTabsItem.disabled = + !closeDuplicateEnabled || !gBrowser.getAllDuplicateTabsToClose().length; }); - this.allTabsView.addEventListener("ViewShown", e => + this.allTabsView.addEventListener("ViewShown", () => this.allTabsView .querySelector(".all-tabs-item[selected]") ?.scrollIntoView({ block: "center" }) @@ -149,6 +160,10 @@ var gTabsPanel = { entrypoint, 1 ); + BrowserUsageTelemetry.recordInteractionEvent( + entrypoint, + "all-tabs-panel-entrypoint" + ); PanelUI.showSubView( this.kElements.allTabsView, this.allTabsButton, @@ -170,7 +185,7 @@ var gTabsPanel = { } this.allTabsView.addEventListener( "ViewShown", - e => { + () => { PanelUI.showSubView( this.kElements.hiddenTabsView, this.hiddenTabsButton diff --git a/browser/base/content/browser-box.inc.xhtml b/browser/base/content/browser-box.inc.xhtml index d445abe7e7..b030891144 100644 --- a/browser/base/content/browser-box.inc.xhtml +++ b/browser/base/content/browser-box.inc.xhtml @@ -3,6 +3,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. <hbox flex="1" id="browser"> + <html:sidebar-main id="sidebar-main" flex="1" hidden="true"></html:sidebar-main> <vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome"> <box id="sidebar-header" align="center"> <toolbarbutton id="sidebar-switcher-target" class="tabbable" aria-expanded="false"> @@ -12,7 +13,7 @@ </toolbarbutton> <image id="sidebar-throbber"/> <spacer id="sidebar-spacer"/> - <toolbarbutton id="sidebar-close" class="close-icon tabbable" data-l10n-id="sidebar-close-button" oncommand="SidebarUI.hide();"/> + <toolbarbutton id="sidebar-close" class="close-icon tabbable" data-l10n-id="sidebar-close-button" oncommand="SidebarController.hide();"/> </box> <browser id="sidebar" autoscroll="false" disablehistory="true" disablefullscreen="true" tooltip="aHTMLTooltip"/> </vbox> diff --git a/browser/base/content/browser-captivePortal.js b/browser/base/content/browser-captivePortal.js index 247f8c397f..1fd5497273 100644 --- a/browser/base/content/browser-captivePortal.js +++ b/browser/base/content/browser-captivePortal.js @@ -95,7 +95,7 @@ var CaptivePortalWatcher = { } }, - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { switch (aTopic) { case "captive-portal-login": this._captivePortalDetected(); diff --git a/browser/base/content/browser-commands.js b/browser/base/content/browser-commands.js new file mode 100644 index 0000000000..d80f9588cd --- /dev/null +++ b/browser/base/content/browser-commands.js @@ -0,0 +1,591 @@ +/* -*- 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/. */ + +/* eslint-env mozilla/browser-window */ + +"use strict"; + +var kSkipCacheFlags = + Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | + Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE; + +var BrowserCommands = { + back(aEvent) { + const where = BrowserUtils.whereToOpenLink(aEvent, false, true); + + if (where == "current") { + try { + gBrowser.goBack(); + } catch (ex) {} + } else { + duplicateTabIn(gBrowser.selectedTab, where, -1); + } + }, + + forward(aEvent) { + const where = BrowserUtils.whereToOpenLink(aEvent, false, true); + + if (where == "current") { + try { + gBrowser.goForward(); + } catch (ex) {} + } else { + duplicateTabIn(gBrowser.selectedTab, where, 1); + } + }, + + handleBackspace() { + switch (Services.prefs.getIntPref("browser.backspace_action")) { + case 0: + this.back(); + break; + case 1: + goDoCommand("cmd_scrollPageUp"); + break; + } + }, + + handleShiftBackspace() { + switch (Services.prefs.getIntPref("browser.backspace_action")) { + case 0: + this.forward(); + break; + case 1: + goDoCommand("cmd_scrollPageDown"); + break; + } + }, + + gotoHistoryIndex(aEvent) { + aEvent = BrowserUtils.getRootEvent(aEvent); + + const index = aEvent.target.getAttribute("index"); + if (!index) { + return false; + } + + const where = BrowserUtils.whereToOpenLink(aEvent); + + if (where == "current") { + // Normal click. Go there in the current tab and update session history. + + try { + gBrowser.gotoIndex(index); + } catch (ex) { + return false; + } + return true; + } + // Modified click. Go there in a new tab/window. + + const historyindex = aEvent.target.getAttribute("historyindex"); + duplicateTabIn(gBrowser.selectedTab, where, Number(historyindex)); + return true; + }, + + reloadOrDuplicate(aEvent) { + aEvent = BrowserUtils.getRootEvent(aEvent); + const accelKeyPressed = + AppConstants.platform == "macosx" ? aEvent.metaKey : aEvent.ctrlKey; + const backgroundTabModifier = aEvent.button == 1 || accelKeyPressed; + + if (aEvent.shiftKey && !backgroundTabModifier) { + this.reloadSkipCache(); + return; + } + + const where = BrowserUtils.whereToOpenLink(aEvent, false, true); + if (where == "current") { + this.reload(); + } else { + duplicateTabIn(gBrowser.selectedTab, where); + } + }, + + reload() { + if (gBrowser.currentURI.schemeIs("view-source")) { + // Bug 1167797: For view source, we always skip the cache + this.reloadSkipCache(); + return; + } + this.reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_NONE); + }, + + reloadSkipCache() { + // Bypass proxy and cache. + this.reloadWithFlags(kSkipCacheFlags); + }, + + reloadWithFlags(reloadFlags) { + const unchangedRemoteness = []; + + for (const tab of gBrowser.selectedTabs) { + const browser = tab.linkedBrowser; + const url = browser.currentURI; + const urlSpec = url.spec; + // We need to cache the content principal here because the browser will be + // reconstructed when the remoteness changes and the content prinicpal will + // be cleared after reconstruction. + const principal = tab.linkedBrowser.contentPrincipal; + if (gBrowser.updateBrowserRemotenessByURL(browser, urlSpec)) { + // If the remoteness has changed, the new browser doesn't have any + // information of what was loaded before, so we need to load the previous + // URL again. + if (tab.linkedPanel) { + loadBrowserURI(browser, url, principal); + } else { + // Shift to fully loaded browser and make + // sure load handler is instantiated. + tab.addEventListener( + "SSTabRestoring", + () => loadBrowserURI(browser, url, principal), + { once: true } + ); + gBrowser._insertBrowser(tab); + } + } else { + unchangedRemoteness.push(tab); + } + } + + if (!unchangedRemoteness.length) { + return; + } + + // Reset temporary permissions on the remaining tabs to reload. + // This is done here because we only want to reset + // permissions on user reload. + for (const tab of unchangedRemoteness) { + SitePermissions.clearTemporaryBlockPermissions(tab.linkedBrowser); + // Also reset DOS mitigations for the basic auth prompt on reload. + delete tab.linkedBrowser.authPromptAbuseCounter; + } + gIdentityHandler.hidePopup(); + gPermissionPanel.hidePopup(); + + const handlingUserInput = document.hasValidTransientUserGestureActivation; + + for (const tab of unchangedRemoteness) { + if (tab.linkedPanel) { + sendReloadMessage(tab); + } else { + // Shift to fully loaded browser and make + // sure load handler is instantiated. + tab.addEventListener("SSTabRestoring", () => sendReloadMessage(tab), { + once: true, + }); + gBrowser._insertBrowser(tab); + } + } + + function loadBrowserURI(browser, url, principal) { + browser.loadURI(url, { + flags: reloadFlags, + triggeringPrincipal: principal, + }); + } + + function sendReloadMessage(tab) { + tab.linkedBrowser.sendMessageToActor( + "Browser:Reload", + { flags: reloadFlags, handlingUserInput }, + "BrowserTab" + ); + } + }, + + stop() { + gBrowser.webNavigation.stop(Ci.nsIWebNavigation.STOP_ALL); + }, + + home(aEvent) { + if (aEvent?.button == 2) { + // right-click: do nothing + return; + } + + const homePage = HomePage.get(window); + let where = BrowserUtils.whereToOpenLink(aEvent, false, true); + + // Don't load the home page in pinned or hidden tabs (e.g. Firefox View). + if ( + where == "current" && + (gBrowser?.selectedTab.pinned || gBrowser?.selectedTab.hidden) + ) { + where = "tab"; + } + + // openTrustedLinkIn in utilityOverlay.js doesn't handle loading multiple pages + let notifyObservers; + switch (where) { + case "current": + // If we're going to load an initial page in the current tab as the + // home page, we set initialPageLoadedFromURLBar so that the URL + // bar is cleared properly (even during a remoteness flip). + if (isInitialPage(homePage)) { + gBrowser.selectedBrowser.initialPageLoadedFromUserAction = homePage; + } + loadOneOrMoreURIs( + homePage, + Services.scriptSecurityManager.getSystemPrincipal(), + null + ); + if (isBlankPageURL(homePage)) { + gURLBar.select(); + } else { + gBrowser.selectedBrowser.focus(); + } + notifyObservers = true; + aEvent?.preventDefault(); + break; + case "tabshifted": + case "tab": { + const urls = homePage.split("|"); + const loadInBackground = Services.prefs.getBoolPref( + "browser.tabs.loadBookmarksInBackground", + false + ); + // The homepage observer event should only be triggered when the homepage opens + // in the foreground. This is mostly to support the homepage changed by extension + // doorhanger which doesn't currently support background pages. This may change in + // bug 1438396. + notifyObservers = !loadInBackground; + gBrowser.loadTabs(urls, { + inBackground: loadInBackground, + triggeringPrincipal: + Services.scriptSecurityManager.getSystemPrincipal(), + csp: null, + }); + if (!loadInBackground) { + if (isBlankPageURL(homePage)) { + gURLBar.select(); + } else { + gBrowser.selectedBrowser.focus(); + } + } + aEvent?.preventDefault(); + break; + } + case "window": + // OpenBrowserWindow will trigger the observer event, so no need to do so here. + notifyObservers = false; + OpenBrowserWindow(); + aEvent?.preventDefault(); + break; + } + + if (notifyObservers) { + // A notification for when a user has triggered their homepage. This is used + // to display a doorhanger explaining that an extension has modified the + // homepage, if necessary. Observers are only notified if the homepage + // becomes the active page. + Services.obs.notifyObservers(null, "browser-open-homepage-start"); + } + }, + + openTab({ event, url } = {}) { + let werePassedURL = !!url; + url ??= BROWSER_NEW_TAB_URL; + let searchClipboard = + gMiddleClickNewTabUsesPasteboard && event?.button == 1; + + let relatedToCurrent = false; + let where = "tab"; + + if (event) { + where = BrowserUtils.whereToOpenLink(event, false, true); + + switch (where) { + case "tab": + case "tabshifted": + // When accel-click or middle-click are used, open the new tab as + // related to the current tab. + relatedToCurrent = true; + break; + case "current": + where = "tab"; + break; + } + } + + // A notification intended to be useful for modular peformance tracking + // starting as close as is reasonably possible to the time when the user + // expressed the intent to open a new tab. Since there are a lot of + // entry points, this won't catch every single tab created, but most + // initiated by the user should go through here. + // + // Note 1: This notification gets notified with a promise that resolves + // with the linked browser when the tab gets created + // Note 2: This is also used to notify a user that an extension has changed + // the New Tab page. + Services.obs.notifyObservers( + { + wrappedJSObject: new Promise(resolve => { + let options = { + relatedToCurrent, + resolveOnNewTabCreated: resolve, + }; + if (!werePassedURL && searchClipboard) { + let clipboard = readFromClipboard(); + clipboard = + UrlbarUtils.stripUnsafeProtocolOnPaste(clipboard).trim(); + if (clipboard) { + url = clipboard; + options.allowThirdPartyFixup = true; + } + } + openTrustedLinkIn(url, where, options); + }), + }, + "browser-open-newtab-start" + ); + }, + + openFileWindow() { + // Get filepicker component. + try { + const nsIFilePicker = Ci.nsIFilePicker; + const fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); + const fpCallback = function fpCallback_done(aResult) { + if (aResult == nsIFilePicker.returnOK) { + try { + if (fp.file) { + gLastOpenDirectory.path = fp.file.parent.QueryInterface( + Ci.nsIFile + ); + } + } catch (ex) {} + openTrustedLinkIn(fp.fileURL.spec, "current"); + } + }; + + fp.init( + window.browsingContext, + gNavigatorBundle.getString("openFile"), + nsIFilePicker.modeOpen + ); + fp.appendFilters( + nsIFilePicker.filterAll | + nsIFilePicker.filterText | + nsIFilePicker.filterImages | + nsIFilePicker.filterXML | + nsIFilePicker.filterHTML | + nsIFilePicker.filterPDF + ); + fp.displayDirectory = gLastOpenDirectory.path; + fp.open(fpCallback); + } catch (ex) {} + }, + + closeTabOrWindow(event) { + // If we're not a browser window, just close the window. + if (window.location.href != AppConstants.BROWSER_CHROME_URL) { + closeWindow(true); + return; + } + + // In a multi-select context, close all selected tabs + if (gBrowser.multiSelectedTabsCount) { + gBrowser.removeMultiSelectedTabs(); + return; + } + + // Keyboard shortcuts that would close a tab that is pinned select the first + // unpinned tab instead. + if ( + event && + (event.ctrlKey || event.metaKey || event.altKey) && + gBrowser.selectedTab.pinned + ) { + if (gBrowser.visibleTabs.length > gBrowser._numPinnedTabs) { + gBrowser.tabContainer.selectedIndex = gBrowser._numPinnedTabs; + } + return; + } + + // If the current tab is the last one, this will close the window. + gBrowser.removeCurrentTab({ animate: true }); + }, + + tryToCloseWindow(event) { + if (WindowIsClosing(event)) { + window.close(); + } // WindowIsClosing does all the necessary checks + }, + + /** + * Open the View Source dialog. + * + * @param args + * An object with the following properties: + * + * URL (required): + * A string URL for the page we'd like to view the source of. + * browser (optional): + * The browser containing the document that we would like to view the + * source of. This is required if outerWindowID is passed. + * outerWindowID (optional): + * The outerWindowID of the content window containing the document that + * we want to view the source of. You only need to provide this if you + * want to attempt to retrieve the document source from the network + * cache. + * lineNumber (optional): + * The line number to focus on once the source is loaded. + */ + async viewSourceOfDocument(args) { + // Check if external view source is enabled. If so, try it. If it fails, + // fallback to internal view source. + if (Services.prefs.getBoolPref("view_source.editor.external")) { + try { + await top.gViewSourceUtils.openInExternalEditor(args); + return; + } catch (data) {} + } + + let tabBrowser = gBrowser; + let preferredRemoteType; + let initialBrowsingContextGroupId; + if (args.browser) { + preferredRemoteType = args.browser.remoteType; + initialBrowsingContextGroupId = args.browser.browsingContext.group.id; + } else { + if (!tabBrowser) { + throw new Error( + "viewSourceOfDocument should be passed the " + + "subject browser if called from a window without " + + "gBrowser defined." + ); + } + // Some internal URLs (such as specific chrome: and about: URLs that are + // not yet remote ready) cannot be loaded in a remote browser. View + // source in tab expects the new view source browser's remoteness to match + // that of the original URL, so disable remoteness if necessary for this + // URL. + const oa = E10SUtils.predictOriginAttributes({ window }); + preferredRemoteType = E10SUtils.getRemoteTypeForURI( + args.URL, + gMultiProcessBrowser, + gFissionBrowser, + E10SUtils.DEFAULT_REMOTE_TYPE, + null, + oa + ); + } + + // In the case of popups, we need to find a non-popup browser window. + if (!tabBrowser || !window.toolbar.visible) { + // This returns only non-popup browser windows by default. + const browserWindow = BrowserWindowTracker.getTopWindow(); + tabBrowser = browserWindow.gBrowser; + } + + const inNewWindow = !Services.prefs.getBoolPref("view_source.tab"); + + // `viewSourceInBrowser` will load the source content from the page + // descriptor for the tab (when possible) or fallback to the network if + // that fails. Either way, the view source module will manage the tab's + // location, so use "about:blank" here to avoid unnecessary redundant + // requests. + const tab = tabBrowser.addTab("about:blank", { + relatedToCurrent: true, + inBackground: inNewWindow, + skipAnimation: inNewWindow, + preferredRemoteType, + initialBrowsingContextGroupId, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + skipLoad: true, + }); + args.viewSourceBrowser = tabBrowser.getBrowserForTab(tab); + top.gViewSourceUtils.viewSourceInBrowser(args); + + if (inNewWindow) { + tabBrowser.hideTab(tab); + tabBrowser.replaceTabWithWindow(tab); + } + }, + + /** + * Opens the View Source dialog for the source loaded in the root + * top-level document of the browser. This is really just a + * convenience wrapper around viewSourceOfDocument. + * + * @param browser + * The browser that we want to load the source of. + */ + viewSource(browser) { + this.viewSourceOfDocument({ + browser, + outerWindowID: browser.outerWindowID, + URL: browser.currentURI.spec, + }); + }, + + /** + * @param documentURL URL of the document to view, or null for this window's document + * @param initialTab name of the initial tab to display, or null for the first tab + * @param imageElement image to load in the Media Tab of the Page Info window; can be null/omitted + * @param browsingContext the browsingContext of the frame that we want to view information about; can be null/omitted + * @param browser the browser containing the document we're interested in inspecting; can be null/omitted + */ + pageInfo(documentURL, initialTab, imageElement, browsingContext, browser) { + const args = { initialTab, imageElement, browsingContext, browser }; + + documentURL = + documentURL || window.gBrowser.selectedBrowser.currentURI.spec; + + const isPrivate = PrivateBrowsingUtils.isWindowPrivate(window); + + // Check for windows matching the url + for (const currentWindow of Services.wm.getEnumerator( + "Browser:page-info" + )) { + if (currentWindow.closed) { + continue; + } + if ( + currentWindow.document.documentElement.getAttribute("relatedUrl") == + documentURL && + PrivateBrowsingUtils.isWindowPrivate(currentWindow) == isPrivate + ) { + currentWindow.focus(); + currentWindow.resetPageInfo(args); + return currentWindow; + } + } + + // We didn't find a matching window, so open a new one. + let options = "chrome,toolbar,dialog=no,resizable"; + + // Ensure the window groups correctly in the Windows taskbar + if (isPrivate) { + options += ",private"; + } + return openDialog( + "chrome://browser/content/pageinfo/pageInfo.xhtml", + "", + options, + args + ); + }, + + 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-context.inc b/browser/base/content/browser-context.inc index ff4015e3d4..3ce284a52f 100644 --- a/browser/base/content/browser-context.inc +++ b/browser/base/content/browser-context.inc @@ -439,7 +439,7 @@ oncommand="gContextMenu.viewPartialSource();"/> <menuitem id="context-viewsource" data-l10n-id="main-context-menu-view-page-source" - oncommand="BrowserViewSource(gContextMenu.browser);"/> + oncommand="BrowserCommands.viewSource(gContextMenu.browser);"/> <menuitem id="context-inspect-a11y" hidden="true" data-l10n-id="main-context-menu-inspect-a11y-properties" diff --git a/browser/base/content/browser-ctrlTab.js b/browser/base/content/browser-ctrlTab.js index d4d79a6886..e5d16e605b 100644 --- a/browser/base/content/browser-ctrlTab.js +++ b/browser/base/content/browser-ctrlTab.js @@ -284,7 +284,7 @@ var ctrlTab = { this.uninit(); } }, - observe(aSubject, aTopic, aPrefName) { + observe() { this.readPref(); }, @@ -654,7 +654,7 @@ var ctrlTab = { // tab attribute modified (i.e. label, busy, image) // update preview only if tab attribute modified in the list if ( - event.detail.changed.some((elem, ind, arr) => + event.detail.changed.some(elem => ["label", "busy", "image"].includes(elem) ) ) { diff --git a/browser/base/content/browser-data-submission-info-bar.js b/browser/base/content/browser-data-submission-info-bar.js index 26d9affb29..104414d582 100644 --- a/browser/base/content/browser-data-submission-info-bar.js +++ b/browser/base/content/browser-data-submission-info-bar.js @@ -92,7 +92,7 @@ var gDataNotificationInfoBar = { } }, - observe(subject, topic, data) { + observe(subject, topic) { switch (topic) { case "datareporting:notify-data-policy:request": let request = subject.wrappedJSObject.object; diff --git a/browser/base/content/browser-fullScreenAndPointerLock.js b/browser/base/content/browser-fullScreenAndPointerLock.js index aae596a0f7..c8794c760c 100644 --- a/browser/base/content/browser-fullScreenAndPointerLock.js +++ b/browser/base/content/browser-fullScreenAndPointerLock.js @@ -365,26 +365,19 @@ var FullScreen = { passive: true, }); - if (enterFS) { - gNavToolbox.setAttribute("inFullscreen", true); - document.documentElement.setAttribute("inFullscreen", true); - let alwaysUsesNativeFullscreen = + document.documentElement.toggleAttribute("inFullscreen", enterFS); + document.documentElement.toggleAttribute( + "macOSNativeFullscreen", + enterFS && AppConstants.platform == "macosx" && - Services.prefs.getBoolPref("full-screen-api.macos-native-full-screen"); - if ( - (alwaysUsesNativeFullscreen || !document.fullscreenElement) && - AppConstants.platform == "macosx" - ) { - document.documentElement.setAttribute("macOSNativeFullscreen", true); - } - } else { - gNavToolbox.removeAttribute("inFullscreen"); - document.documentElement.removeAttribute("inFullscreen"); - document.documentElement.removeAttribute("macOSNativeFullscreen"); - } + (Services.prefs.getBoolPref( + "full-screen-api.macos-native-full-screen" + ) || + !document.fullscreenElement) + ); if (!document.fullscreenElement) { - this._updateToolbars(enterFS); + ToolbarIconColor.inferFromText("fullscreen", enterFS); } if (enterFS) { @@ -948,22 +941,6 @@ var FullScreen = { MousePosTracker.removeListener(this); }, - - _updateToolbars(aEnterFS) { - for (let el of document.querySelectorAll( - "toolbar[fullscreentoolbar=true]" - )) { - // Set the inFullscreen attribute to allow specific styling - // in fullscreen mode - if (aEnterFS) { - el.setAttribute("inFullscreen", true); - } else { - el.removeAttribute("inFullscreen"); - } - } - - ToolbarIconColor.inferFromText("fullscreen", aEnterFS); - }, }; ChromeUtils.defineLazyGetter(FullScreen, "_permissionNotificationIDs", () => { diff --git a/browser/base/content/browser-gestureSupport.js b/browser/base/content/browser-gestureSupport.js index 0ff42f5160..6bec059789 100644 --- a/browser/base/content/browser-gestureSupport.js +++ b/browser/base/content/browser-gestureSupport.js @@ -269,7 +269,7 @@ var gGestureSupport = { gHistorySwipeAnimation.updateAnimation(aEvent.delta); }; - this._doEnd = function GS__doEnd(aEvent) { + this._doEnd = function GS__doEnd() { gHistorySwipeAnimation.swipeEndEventReceived(); this._doUpdate = function () {}; @@ -393,7 +393,7 @@ var gGestureSupport = { * @param aEvent * The continual motion update event to handle */ - _doUpdate(aEvent) {}, + _doUpdate() {}, /** * Handle gesture end events. This function will be set by _setupSwipe. @@ -401,7 +401,7 @@ var gGestureSupport = { * @param aEvent * The gesture end event to handle */ - _doEnd(aEvent) {}, + _doEnd() {}, /** * Convert the swipe gesture into a browser action based on the direction. @@ -874,7 +874,7 @@ var gHistorySwipeAnimation = { } }, - _completeFadeOut: function HSA__completeFadeOut(aEvent) { + _completeFadeOut: function HSA__completeFadeOut() { if (!this._isStoppingAnimation) { // The animation was restarted in the middle of our stopping fade out // tranistion, so don't do anything. @@ -943,7 +943,7 @@ var gHistorySwipeAnimation = { return element; }, - observe(subj, topic, data) { + observe(subj, topic) { switch (topic) { case "nsPref:changed": this._initPrefValues(); 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 66dd662137..0eebfea75a 100644 --- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -140,19 +140,7 @@ </menupopup> </menu> <menu id="viewSidebarMenuMenu" data-l10n-id="menu-view-sidebar"> - <menupopup id="viewSidebarMenu"> - <menuitem id="menu_bookmarksSidebar" - type="checkbox" - key="viewBookmarksSidebarKb" - oncommand="SidebarUI.toggle('viewBookmarksSidebar');" data-l10n-id="menu-view-bookmarks"/> - <menuitem id="menu_historySidebar" - type="checkbox" - key="key_gotoHistory" - oncommand="SidebarUI.toggle('viewHistorySidebar');" data-l10n-id="menu-view-history-button"/> - <menuitem id="menu_tabsSidebar" - type="checkbox" - class="sync-ui-item" - oncommand="SidebarUI.toggle('viewTabsSidebar');" data-l10n-id="menu-view-synced-tabs-sidebar"/> + <menupopup id="viewSidebarMenu" onpopupshowing="SidebarController.setMegalistMenubarVisibility(event);"> </menupopup> </menu> <menuseparator/> @@ -189,7 +177,7 @@ </menu> <menuitem id="repair-text-encoding" disabled="true" - oncommand="BrowserForceEncodingDetection();" + oncommand="BrowserCommands.forceEncodingDetection();" data-l10n-id="menu-view-repair-text-encoding"/> <menuseparator/> #ifdef XP_MACOSX diff --git a/browser/base/content/browser-pageActions.js b/browser/base/content/browser-pageActions.js index 1cc895434d..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); }, /** @@ -1008,7 +1008,7 @@ BrowserPageActions.bookmark = { } }, - onCommand(event, buttonNode) { + onCommand(event) { PanelMultiView.hidePopup(BrowserPageActions.panelNode); BookmarkingUI.onStarCommand(event); }, diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js index 58e61f7bf7..404a080983 100644 --- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -17,7 +17,7 @@ XPCOMUtils.defineLazyPreferenceGetter( "SHOW_OTHER_BOOKMARKS", "browser.toolbars.bookmarks.showOtherBookmarks", true, - (aPref, aPrevVal, aNewVal) => { + () => { BookmarkingUI.maybeShowOtherBookmarksFolder().then(() => { document .getElementById("PlacesToolbar") @@ -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; @@ -253,7 +252,7 @@ var StarUI = { } target.addEventListener( "popupshown", - function (event) { + function () { fn(); }, { capture: true, once: true } @@ -1174,7 +1173,7 @@ var PlacesToolbarHelper = { return null; }, - onWidgetUnderflow(aNode, aContainer) { + onWidgetUnderflow(aNode) { // The view gets broken by being removed and reinserted by the overflowable // toolbar, so we have to force an uninit and reinit. let win = aNode.ownerGlobal; @@ -1183,7 +1182,7 @@ var PlacesToolbarHelper = { } }, - onWidgetAdded(aWidgetId, aArea, aPosition) { + onWidgetAdded(aWidgetId) { if (aWidgetId == "personal-bookmarks" && !this._isCustomizing) { // It's possible (with the "Add to Menu", "Add to Toolbar" context // options) that the Places Toolbar Items have been moved without @@ -1378,7 +1377,7 @@ var BookmarkingUI = { this.updateLabel( "BMB_viewBookmarksSidebar", - SidebarUI.currentID == "viewBookmarksSidebar" + SidebarController.currentID == "viewBookmarksSidebar" ); this.updateLabel("BMB_viewBookmarksToolbar", !this.toolbar.collapsed); }, @@ -1659,13 +1658,13 @@ var BookmarkingUI = { } }, - onWidgetReset: function BUI_widgetReset(aNode, aContainer) { + onWidgetReset: function BUI_widgetReset(aNode) { if (aNode == this.button) { this._onWidgetWasMoved(); } }, - onWidgetUndoMove: function BUI_undoWidgetUndoMove(aNode, aContainer) { + onWidgetUndoMove: function BUI_undoWidgetUndoMove(aNode) { if (aNode == this.button) { this._onWidgetWasMoved(); } @@ -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) { @@ -2155,7 +2164,7 @@ var BookmarkingUI = { }); }, - onWidgetUnderflow(aNode, aContainer) { + onWidgetUnderflow(aNode) { let win = aNode.ownerGlobal; if (aNode.id != this.BOOKMARK_BUTTON_ID || win != window) { return; diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc index 090e94b684..f77ce1661e 100644 --- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -16,12 +16,12 @@ <commandset id="mainCommandSet"> <command id="cmd_newNavigator" oncommand="OpenBrowserWindow()"/> - <command id="cmd_handleBackspace" oncommand="BrowserHandleBackspace();" /> - <command id="cmd_handleShiftBackspace" oncommand="BrowserHandleShiftBackspace();" /> + <command id="cmd_handleBackspace" oncommand="BrowserCommands.handleBackspace();" /> + <command id="cmd_handleShiftBackspace" oncommand="BrowserCommands.handleShiftBackspace();" /> - <command id="cmd_newNavigatorTab" oncommand="BrowserOpenTab({ event });"/> - <command id="cmd_newNavigatorTabNoEvent" oncommand="BrowserOpenTab();"/> - <command id="Browser:OpenFile" oncommand="BrowserOpenFileWindow();"/> + <command id="cmd_newNavigatorTab" oncommand="BrowserCommands.openTab({ event });"/> + <command id="cmd_newNavigatorTabNoEvent" oncommand="BrowserCommands.openTab();"/> + <command id="Browser:OpenFile" oncommand="BrowserCommands.openFileWindow();"/> <command id="Browser:SavePage" oncommand="saveBrowser(gBrowser.selectedBrowser);"/> <command id="Browser:SendLink" @@ -32,17 +32,17 @@ <command id="cmd_printPreviewToggle" oncommand="PrintUtils.togglePrintPreview(gBrowser.selectedBrowser.browsingContext);"/> <command id="cmd_file_importFromAnotherBrowser" oncommand="MigrationUtils.showMigrationWizard(window, { entrypoint: MigrationUtils.MIGRATION_ENTRYPOINTS.FILE_MENU });"/> <command id="cmd_help_importFromAnotherBrowser" oncommand="MigrationUtils.showMigrationWizard(window, { entrypoint: MigrationUtils.MIGRATION_ENTRYPOINTS.HELP_MENU });"/> - <command id="cmd_close" oncommand="BrowserCloseTabOrWindow(event);"/> - <command id="cmd_closeWindow" oncommand="BrowserTryToCloseWindow(event)"/> + <command id="cmd_close" oncommand="BrowserCommands.closeTabOrWindow(event);"/> + <command id="cmd_closeWindow" oncommand="BrowserCommands.tryToCloseWindow(event)"/> <command id="cmd_toggleMute" oncommand="gBrowser.toggleMuteAudioOnMultiSelectedTabs(gBrowser.selectedTab)"/> <command id="cmd_CustomizeToolbars" oncommand="gCustomizeMode.enter()"/> <command id="cmd_toggleOfflineStatus" oncommand="BrowserOffline.toggleOfflineStatus();"/> <command id="cmd_quitApplication" oncommand="goQuitApplication(event)"/> <command id="View:AboutProcesses" oncommand="switchToTabHavingURI('about:processes', true)"/> - <command id="View:PageSource" oncommand="BrowserViewSource(window.gBrowser.selectedBrowser);"/> - <command id="View:PageInfo" oncommand="BrowserPageInfo();"/> - <command id="View:FullScreen" oncommand="BrowserFullScreen();"/> + <command id="View:PageSource" oncommand="BrowserCommands.viewSource(window.gBrowser.selectedBrowser);"/> + <command id="View:PageInfo" oncommand="BrowserCommands.pageInfo();"/> + <command id="View:FullScreen" oncommand="BrowserCommands.fullScreen();"/> <command id="View:ReaderView" oncommand="AboutReaderParent.toggleReaderMode(event);"/> <command id="View:PictureInPicture" oncommand="PictureInPicture.onCommand(event);"/> <command id="cmd_find" oncommand="gLazyFindCommand('onFindCommand')"/> @@ -60,20 +60,20 @@ oncommand="PlacesCommandHook.searchBookmarks();"/> <command id="Browser:BookmarkAllTabs" oncommand="PlacesCommandHook.bookmarkTabs();"/> - <command id="Browser:Back" oncommand="BrowserBack();" disabled="true"/> - <command id="Browser:BackOrBackDuplicate" oncommand="BrowserBack(event);" disabled="true"> + <command id="Browser:Back" oncommand="BrowserCommands.back();" disabled="true"/> + <command id="Browser:BackOrBackDuplicate" oncommand="BrowserCommands.back(event);" disabled="true"> <observes element="Browser:Back" attribute="disabled"/> </command> - <command id="Browser:Forward" oncommand="BrowserForward();" disabled="true"/> - <command id="Browser:ForwardOrForwardDuplicate" oncommand="BrowserForward(event);" disabled="true"> + <command id="Browser:Forward" oncommand="BrowserCommands.forward();" disabled="true"/> + <command id="Browser:ForwardOrForwardDuplicate" oncommand="BrowserCommands.forward(event);" disabled="true"> <observes element="Browser:Forward" attribute="disabled"/> </command> - <command id="Browser:Stop" oncommand="BrowserStop();" disabled="true"/> - <command id="Browser:Reload" oncommand="if (event.shiftKey) BrowserReloadSkipCache(); else BrowserReload()" disabled="true"/> - <command id="Browser:ReloadOrDuplicate" oncommand="BrowserReloadOrDuplicate(event)" disabled="true"> + <command id="Browser:Stop" oncommand="BrowserCommands.stop();" disabled="true"/> + <command id="Browser:Reload" oncommand="if (event.shiftKey) BrowserCommands.reloadSkipCache(); else BrowserCommands.reload()" disabled="true"/> + <command id="Browser:ReloadOrDuplicate" oncommand="BrowserCommands.reloadOrDuplicate(event)" disabled="true"> <observes element="Browser:Reload" attribute="disabled"/> </command> - <command id="Browser:ReloadSkipCache" oncommand="BrowserReloadSkipCache()" disabled="true"> + <command id="Browser:ReloadSkipCache" oncommand="BrowserCommands.reloadSkipCache()" disabled="true"> <observes element="Browser:Reload" attribute="disabled"/> </command> <command id="Browser:NextTab" oncommand="gBrowser.tabContainer.advanceSelectedTab(1, true);"/> @@ -91,8 +91,8 @@ <command id="Browser:NewUserContextTab" oncommand="openNewUserContextTab(event.sourceEvent);"/> <command id="Browser:OpenAboutContainers" oncommand="openPreferences('paneContainers');"/> <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/> - <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/> - <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/> + <command id="Tools:Downloads" oncommand="BrowserCommands.downloadsUI();"/> + <command id="Tools:Addons" oncommand="BrowserAddonUI.openAddonsMgr();"/> <command id="Tools:Sanitize" oncommand="Sanitizer.showUI(window);"/> <command id="Tools:PrivateBrowsing" oncommand="OpenBrowserWindow({private: true});"/> @@ -216,7 +216,7 @@ <key id="goBackKb2" data-l10n-id="nav-back-shortcut-alt" command="Browser:Back" modifiers="accel"/> <key id="goForwardKb2" data-l10n-id="nav-fwd-shortcut-alt" command="Browser:Forward" modifiers="accel"/> #endif - <key id="goHome" keycode="VK_HOME" oncommand="BrowserHome();" modifiers="alt"/> + <key id="goHome" keycode="VK_HOME" oncommand="BrowserCommands.home();" modifiers="alt"/> <key keycode="VK_F5" command="Browser:Reload"/> #ifndef XP_MACOSX <key id="showAllHistoryKb" data-l10n-id="history-show-all-shortcut" command="Browser:ShowAllHistory" modifiers="accel,shift"/> @@ -276,7 +276,7 @@ <key id="viewBookmarksSidebarKb" data-l10n-id="bookmark-show-sidebar-shortcut" modifiers="accel" - oncommand="SidebarUI.toggle('viewBookmarksSidebar');"/> + oncommand="SidebarController.toggle('viewBookmarksSidebar');"/> <key id="viewBookmarksToolbarKb" data-l10n-id="bookmark-show-toolbar-shortcut" oncommand="BookmarkingUI.toggleBookmarksToolbar('shortcut');" @@ -295,7 +295,7 @@ #else modifiers="accel" #endif - oncommand="SidebarUI.toggle('viewHistorySidebar');"/> + oncommand="SidebarController.toggle('viewHistorySidebar');"/> <key id="key_fullZoomReduce" data-l10n-id="full-zoom-reduce-shortcut" command="cmd_fullZoomReduce" modifiers="accel"/> <key data-l10n-id="full-zoom-reduce-shortcut-alt-a" command="cmd_fullZoomReduce" modifiers="accel"/> diff --git a/browser/base/content/browser-sidebar.js b/browser/base/content/browser-sidebar.js deleted file mode 100644 index 2d730700a6..0000000000 --- a/browser/base/content/browser-sidebar.js +++ /dev/null @@ -1,674 +0,0 @@ -/* 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/. */ - -/** - * SidebarUI controls showing and hiding the browser sidebar. - */ -var SidebarUI = { - get sidebars() { - if (this._sidebars) { - return this._sidebars; - } - - function makeSidebar({ elementId, ...rest }) { - return { - get sourceL10nEl() { - return document.getElementById(elementId); - }, - get title() { - return document.getElementById(elementId).getAttribute("label"); - }, - ...rest, - }; - } - - return (this._sidebars = new Map([ - [ - "viewBookmarksSidebar", - makeSidebar({ - elementId: "sidebar-switcher-bookmarks", - url: "chrome://browser/content/places/bookmarksSidebar.xhtml", - menuId: "menu_bookmarksSidebar", - }), - ], - [ - "viewHistorySidebar", - makeSidebar({ - elementId: "sidebar-switcher-history", - url: "chrome://browser/content/places/historySidebar.xhtml", - menuId: "menu_historySidebar", - triggerButtonId: "appMenuViewHistorySidebar", - }), - ], - [ - "viewTabsSidebar", - makeSidebar({ - elementId: "sidebar-switcher-tabs", - url: "chrome://browser/content/syncedtabs/sidebar.xhtml", - menuId: "menu_tabsSidebar", - }), - ], - ])); - }, - - // Avoid getting the browser element from init() to avoid triggering the - // <browser> constructor during startup if the sidebar is hidden. - get browser() { - if (this._browser) { - return this._browser; - } - return (this._browser = document.getElementById("sidebar")); - }, - POSITION_START_PREF: "sidebar.position_start", - DEFAULT_SIDEBAR_ID: "viewBookmarksSidebar", - - // lastOpenedId is set in show() but unlike currentID it's not cleared out on hide - // and isn't persisted across windows - lastOpenedId: null, - - _box: null, - // The constructor of this label accesses the browser element due to the - // control="sidebar" attribute, so avoid getting this label during startup. - get _title() { - if (this.__title) { - return this.__title; - } - return (this.__title = document.getElementById("sidebar-title")); - }, - _splitter: null, - _reversePositionButton: null, - _switcherPanel: null, - _switcherTarget: null, - _switcherArrow: null, - _inited: false, - - /** - * @type {MutationObserver | null} - */ - _observer: null, - - _initDeferred: Promise.withResolvers(), - - get promiseInitialized() { - return this._initDeferred.promise; - }, - - get initialized() { - return this._inited; - }, - - init() { - this._box = document.getElementById("sidebar-box"); - this._splitter = document.getElementById("sidebar-splitter"); - this._reversePositionButton = document.getElementById( - "sidebar-reverse-position" - ); - this._switcherPanel = document.getElementById("sidebarMenu-popup"); - this._switcherTarget = document.getElementById("sidebar-switcher-target"); - this._switcherArrow = document.getElementById("sidebar-switcher-arrow"); - - this._switcherTarget.addEventListener("command", () => { - this.toggleSwitcherPanel(); - }); - this._switcherTarget.addEventListener("keydown", event => { - this.handleKeydown(event); - }); - - this._inited = true; - - Services.obs.addObserver(this, "intl:app-locales-changed"); - - this._initDeferred.resolve(); - }, - - uninit() { - // If this is the last browser window, persist various values that should be - // remembered for after a restart / reopening a browser window. - let enumerator = Services.wm.getEnumerator("navigator:browser"); - if (!enumerator.hasMoreElements()) { - let xulStore = Services.xulStore; - xulStore.persist(this._box, "sidebarcommand"); - - if (this._box.hasAttribute("positionend")) { - xulStore.persist(this._box, "positionend"); - } else { - xulStore.removeValue( - document.documentURI, - "sidebar-box", - "positionend" - ); - } - if (this._box.hasAttribute("checked")) { - xulStore.persist(this._box, "checked"); - } else { - xulStore.removeValue(document.documentURI, "sidebar-box", "checked"); - } - - xulStore.persist(this._box, "style"); - xulStore.persist(this._title, "value"); - } - - Services.obs.removeObserver(this, "intl:app-locales-changed"); - - if (this._observer) { - this._observer.disconnect(); - this._observer = null; - } - }, - - /** - * The handler for Services.obs.addObserver. - **/ - observe(_subject, topic, _data) { - switch (topic) { - case "intl:app-locales-changed": { - if (this.isOpen) { - // The <tree> component used in history and bookmarks, but it does not - // support live switching the app locale. Reload the entire sidebar to - // invalidate any old text. - this.hide(); - this.showInitially(this.lastOpenedId); - break; - } - } - } - }, - - /** - * Ensure the title stays in sync with the source element, which updates for - * l10n changes. - * - * @param {HTMLElement} [element] - */ - observeTitleChanges(element) { - if (!element) { - return; - } - let observer = this._observer; - if (!observer) { - observer = new MutationObserver(() => { - this.title = this.sidebars.get(this.lastOpenedId).title; - }); - // Re-use the observer. - this._observer = observer; - } - observer.disconnect(); - observer.observe(element, { - attributes: true, - attributeFilter: ["label"], - }); - }, - - /** - * Opens the switcher panel if it's closed, or closes it if it's open. - */ - toggleSwitcherPanel() { - if ( - this._switcherPanel.state == "open" || - this._switcherPanel.state == "showing" - ) { - this.hideSwitcherPanel(); - } else if (this._switcherPanel.state == "closed") { - this.showSwitcherPanel(); - } - }, - - /** - * Handles keydown on the the switcherTarget button - * @param {Event} event - */ - handleKeydown(event) { - switch (event.key) { - case "Enter": - case " ": { - this.toggleSwitcherPanel(); - event.stopPropagation(); - event.preventDefault(); - break; - } - case "Escape": { - this.hideSwitcherPanel(); - event.stopPropagation(); - event.preventDefault(); - break; - } - } - }, - - hideSwitcherPanel() { - this._switcherPanel.hidePopup(); - }, - - showSwitcherPanel() { - this._switcherPanel.addEventListener( - "popuphiding", - () => { - this._switcherTarget.classList.remove("active"); - this._switcherTarget.setAttribute("aria-expanded", false); - }, - { once: true } - ); - - // Combine start/end position with ltr/rtl to set the label in the popup appropriately. - let label = - this._positionStart == RTL_UI - ? gNavigatorBundle.getString("sidebar.moveToLeft") - : gNavigatorBundle.getString("sidebar.moveToRight"); - this._reversePositionButton.setAttribute("label", label); - - // Open the sidebar switcher popup, anchored off the switcher toggle - this._switcherPanel.hidden = false; - this._switcherPanel.openPopup(this._switcherTarget); - - this._switcherTarget.classList.add("active"); - this._switcherTarget.setAttribute("aria-expanded", true); - }, - - updateShortcut({ keyId }) { - let menuitem = this._switcherPanel?.querySelector(`[key="${keyId}"]`); - if (!menuitem) { - // If the menu item doesn't exist yet then the accel text will be set correctly - // upon creation so there's nothing to do now. - return; - } - menuitem.removeAttribute("acceltext"); - }, - - /** - * Change the pref that will trigger a call to setPosition - */ - reversePosition() { - Services.prefs.setBoolPref(this.POSITION_START_PREF, !this._positionStart); - }, - - /** - * Read the positioning pref and position the sidebar and the splitter - * appropriately within the browser container. - */ - setPosition() { - // First reset all ordinals to match DOM ordering. - let browser = document.getElementById("browser"); - [...browser.children].forEach((node, i) => { - node.style.order = i + 1; - }); - - if (!this._positionStart) { - // DOM ordering is: | sidebar-box | splitter | appcontent | - // Want to display as: | appcontent | splitter | sidebar-box | - // So we just swap box and appcontent ordering - let appcontent = document.getElementById("appcontent"); - let boxOrdinal = this._box.style.order; - this._box.style.order = appcontent.style.order; - appcontent.style.order = boxOrdinal; - // Indicate we've switched ordering to the box - this._box.setAttribute("positionend", true); - } else { - this._box.removeAttribute("positionend"); - } - - this.hideSwitcherPanel(); - - let content = SidebarUI.browser.contentWindow; - if (content && content.updatePosition) { - content.updatePosition(); - } - }, - - /** - * Try and adopt the status of the sidebar from another window. - * @param {Window} sourceWindow - Window to use as a source for sidebar status. - * @return true if we adopted the state, or false if the caller should - * initialize the state itself. - */ - adoptFromWindow(sourceWindow) { - // If the opener had a sidebar, open the same sidebar in our window. - // The opener can be the hidden window too, if we're coming from the state - // where no windows are open, and the hidden window has no sidebar box. - let sourceUI = sourceWindow.SidebarUI; - if (!sourceUI || !sourceUI._box) { - // no source UI or no _box means we also can't adopt the state. - return false; - } - - // Set sidebar command even if hidden, so that we keep the same sidebar - // even if it's currently closed. - let commandID = sourceUI._box.getAttribute("sidebarcommand"); - if (commandID) { - this._box.setAttribute("sidebarcommand", commandID); - } - - if (sourceUI._box.hidden) { - // just hidden means we have adopted the hidden state. - return true; - } - - // dynamically generated sidebars will fail this check, but we still - // consider it adopted. - if (!this.sidebars.has(commandID)) { - return true; - } - - this._box.style.width = sourceUI._box.getBoundingClientRect().width + "px"; - this.showInitially(commandID); - - return true; - }, - - windowPrivacyMatches(w1, w2) { - return ( - PrivateBrowsingUtils.isWindowPrivate(w1) === - PrivateBrowsingUtils.isWindowPrivate(w2) - ); - }, - - /** - * If loading a sidebar was delayed on startup, start the load now. - */ - startDelayedLoad() { - let sourceWindow = window.opener; - // No source window means this is the initial window. If we're being - // opened from another window, check that it is one we might open a sidebar - // for. - if (sourceWindow) { - if ( - sourceWindow.closed || - sourceWindow.location.protocol != "chrome:" || - !this.windowPrivacyMatches(sourceWindow, window) - ) { - return; - } - // Try to adopt the sidebar state from the source window - if (this.adoptFromWindow(sourceWindow)) { - return; - } - } - - // If we're not adopting settings from a parent window, set them now. - let wasOpen = this._box.getAttribute("checked"); - if (!wasOpen) { - return; - } - - let commandID = this._box.getAttribute("sidebarcommand"); - if (commandID && this.sidebars.has(commandID)) { - this.showInitially(commandID); - } else { - this._box.removeAttribute("checked"); - // Remove the |sidebarcommand| attribute, because the element it - // refers to no longer exists, so we should assume this sidebar - // panel has been uninstalled. (249883) - // We use setAttribute rather than removeAttribute so it persists - // correctly. - this._box.setAttribute("sidebarcommand", ""); - // On a startup in which the startup cache was invalidated (e.g. app update) - // extensions will not be started prior to delayedLoad, thus the - // sidebarcommand element will not exist yet. Store the commandID so - // extensions may reopen if necessary. A startup cache invalidation - // can be forced (for testing) by deleting compatibility.ini from the - // profile. - this.lastOpenedId = commandID; - } - }, - - /** - * Fire a "SidebarShown" event on the sidebar to give any interested parties - * a chance to update the button or whatever. - */ - _fireShowEvent() { - let event = new CustomEvent("SidebarShown", { bubbles: true }); - this._switcherTarget.dispatchEvent(event); - }, - - /** - * Fire a "SidebarFocused" event on the sidebar's |window| to give the sidebar - * a chance to adjust focus as needed. An additional event is needed, because - * we don't want to focus the sidebar when it's opened on startup or in a new - * window, only when the user opens the sidebar. - */ - _fireFocusedEvent() { - let event = new CustomEvent("SidebarFocused", { bubbles: true }); - this.browser.contentWindow.dispatchEvent(event); - }, - - /** - * True if the sidebar is currently open. - */ - get isOpen() { - return !this._box.hidden; - }, - - /** - * The ID of the current sidebar. - */ - get currentID() { - return this.isOpen ? this._box.getAttribute("sidebarcommand") : ""; - }, - - get title() { - return this._title.value; - }, - - set title(value) { - this._title.value = value; - }, - - /** - * Toggle the visibility of the sidebar. If the sidebar is hidden or is open - * with a different commandID, then the sidebar will be opened using the - * specified commandID. Otherwise the sidebar will be hidden. - * - * @param {string} commandID ID of the sidebar. - * @param {DOMNode} [triggerNode] Node, usually a button, that triggered the - * visibility toggling of the sidebar. - * @return {Promise} - */ - toggle(commandID = this.lastOpenedId, triggerNode) { - if ( - CustomizationHandler.isCustomizing() || - CustomizationHandler.isExitingCustomizeMode - ) { - return Promise.resolve(); - } - // First priority for a default value is this.lastOpenedId which is set during show() - // and not reset in hide(), unlike currentID. If show() hasn't been called and we don't - // have a persisted command either, or the command doesn't exist anymore, then - // fallback to a default sidebar. - if (!commandID) { - commandID = this._box.getAttribute("sidebarcommand"); - } - if (!commandID || !this.sidebars.has(commandID)) { - commandID = this.DEFAULT_SIDEBAR_ID; - } - - if (this.isOpen && commandID == this.currentID) { - this.hide(triggerNode); - return Promise.resolve(); - } - return this.show(commandID, triggerNode); - }, - - _loadSidebarExtension(commandID) { - let sidebar = this.sidebars.get(commandID); - let { extensionId } = sidebar; - if (extensionId) { - SidebarUI.browser.contentWindow.loadPanel( - extensionId, - sidebar.panel, - sidebar.browserStyle - ); - } - }, - - /** - * Show the sidebar. - * - * This wraps the internal method, including a ping to telemetry. - * - * @param {string} commandID ID of the sidebar to use. - * @param {DOMNode} [triggerNode] Node, usually a button, that triggered the - * showing of the sidebar. - * @return {Promise<boolean>} - */ - async show(commandID, triggerNode) { - let panelType = commandID.substring(4, commandID.length - 7); - Services.telemetry.keyedScalarAdd("sidebar.opened", panelType, 1); - - // Extensions without private window access wont be in the - // sidebars map. - if (!this.sidebars.has(commandID)) { - return false; - } - return this._show(commandID).then(() => { - this._loadSidebarExtension(commandID); - - if (triggerNode) { - updateToggleControlLabel(triggerNode); - } - - this._fireFocusedEvent(); - return true; - }); - }, - - /** - * Show the sidebar, without firing the focused event or logging telemetry. - * This is intended to be used when the sidebar is opened automatically - * when a window opens (not triggered by user interaction). - * - * @param {string} commandID ID of the sidebar. - * @return {Promise<boolean>} - */ - async showInitially(commandID) { - let panelType = commandID.substring(4, commandID.length - 7); - Services.telemetry.keyedScalarAdd("sidebar.opened", panelType, 1); - - // Extensions without private window access wont be in the - // sidebars map. - if (!this.sidebars.has(commandID)) { - return false; - } - return this._show(commandID).then(() => { - this._loadSidebarExtension(commandID); - return true; - }); - }, - - /** - * Implementation for show. Also used internally for sidebars that are shown - * when a window is opened and we don't want to ping telemetry. - * - * @param {string} commandID ID of the sidebar. - * @return {Promise<void>} - */ - _show(commandID) { - return new Promise(resolve => { - this.selectMenuItem(commandID); - - this._box.hidden = this._splitter.hidden = false; - this.setPosition(); - - this.hideSwitcherPanel(); - - this._box.setAttribute("checked", "true"); - this._box.setAttribute("sidebarcommand", commandID); - this.lastOpenedId = commandID; - - let { url, title, sourceL10nEl } = this.sidebars.get(commandID); - this.title = title; - // Keep the title element in sync with any l10n changes. - this.observeTitleChanges(sourceL10nEl); - this.browser.setAttribute("src", url); // kick off async load - - if (this.browser.contentDocument.location.href != url) { - this.browser.addEventListener( - "load", - event => { - // We're handling the 'load' event before it bubbles up to the usual - // (non-capturing) event handlers. Let it bubble up before resolving. - setTimeout(() => { - resolve(); - - // Now that the currentId is updated, fire a show event. - this._fireShowEvent(); - }, 0); - }, - { capture: true, once: true } - ); - } else { - resolve(); - - // Now that the currentId is updated, fire a show event. - this._fireShowEvent(); - } - }); - }, - - /** - * Hide the sidebar. - * - * @param {DOMNode} [triggerNode] Node, usually a button, that triggered the - * hiding of the sidebar. - */ - hide(triggerNode) { - if (!this.isOpen) { - return; - } - - this.hideSwitcherPanel(); - - this.selectMenuItem(""); - - // Replace the document currently displayed in the sidebar with about:blank - // so that we can free memory by unloading the page. We need to explicitly - // create a new content viewer because the old one doesn't get destroyed - // until about:blank has loaded (which does not happen as long as the - // element is hidden). - this.browser.setAttribute("src", "about:blank"); - this.browser.docShell.createAboutBlankDocumentViewer(null, null); - - this._box.removeAttribute("checked"); - this._box.hidden = this._splitter.hidden = true; - - let selBrowser = gBrowser.selectedBrowser; - selBrowser.focus(); - if (triggerNode) { - updateToggleControlLabel(triggerNode); - } - }, - - /** - * Sets the checked state only on the menu items of the specified sidebar, or - * none if the argument is an empty string. - */ - selectMenuItem(commandID) { - for (let [id, { menuId, triggerButtonId }] of this.sidebars) { - let menu = document.getElementById(menuId); - let triggerbutton = - triggerButtonId && document.getElementById(triggerButtonId); - if (id == commandID) { - menu.setAttribute("checked", "true"); - if (triggerbutton) { - triggerbutton.setAttribute("checked", "true"); - updateToggleControlLabel(triggerbutton); - } - } else { - menu.removeAttribute("checked"); - if (triggerbutton) { - triggerbutton.removeAttribute("checked"); - updateToggleControlLabel(triggerbutton); - } - } - } - }, -}; - -// Add getters related to the position here, since we will want them -// available for both startDelayedLoad and init. -XPCOMUtils.defineLazyPreferenceGetter( - SidebarUI, - "_positionStart", - SidebarUI.POSITION_START_PREF, - true, - SidebarUI.setPosition.bind(SidebarUI) -); diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js index a2a5f6ff71..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); @@ -456,7 +455,9 @@ var gIdentityHandler = { ); // Reload the page with the content unblocked - BrowserReloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE); + BrowserCommands.reloadWithFlags( + Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE + ); if (this._popupInitialized) { PanelMultiView.hidePopup(this._identityPopup); } @@ -475,7 +476,7 @@ var gIdentityHandler = { "mixed-content" ); if (reload) { - BrowserReload(); + BrowserCommands.reload(); } if (this._popupInitialized) { PanelMultiView.hidePopup(this._identityPopup); @@ -496,7 +497,7 @@ var gIdentityHandler = { port, gBrowser.contentPrincipal.originAttributes ); - BrowserReloadSkipCache(); + BrowserCommands.reloadSkipCache(); if (this._popupInitialized) { PanelMultiView.hidePopup(this._identityPopup); } @@ -611,7 +612,7 @@ var gIdentityHandler = { // Because "off" is 1 and "off temporarily" is 2, we can just check if the // sum of newValue and oldValue is 3. if (newValue + oldValue !== 3) { - BrowserReloadSkipCache(); + BrowserCommands.reloadSkipCache(); if (this._popupInitialized) { PanelMultiView.hidePopup(this._identityPopup); } @@ -1260,7 +1261,7 @@ var gIdentityHandler = { } }, - handleEvent(event) { + handleEvent() { let elem = document.activeElement; let position = elem.compareDocumentPosition(this._identityPopup); @@ -1278,7 +1279,7 @@ var gIdentityHandler = { } }, - observe(subject, topic, data) { + observe(subject, topic) { switch (topic) { case "perm-changed": { // Exclude permissions which do not appear in the UI in order to avoid diff --git a/browser/base/content/browser-sitePermissionPanel.js b/browser/base/content/browser-sitePermissionPanel.js index d81b636668..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; } }, @@ -353,7 +350,7 @@ var gPermissionPanel = { } }, - handleEvent(event) { + handleEvent() { let elem = document.activeElement; let position = elem.compareDocumentPosition(this._permissionPopup); @@ -371,7 +368,7 @@ var gPermissionPanel = { } }, - observe(subject, topic, data) { + observe(subject, topic) { switch (topic) { case "fullscreen-painted": { if (subject != window || !this._exitedEventReceived) { diff --git a/browser/base/content/browser-siteProtections.js b/browser/base/content/browser-siteProtections.js index c44b4d3e8e..31b87ac7e0 100644 --- a/browser/base/content/browser-siteProtections.js +++ b/browser/base/content/browser-siteProtections.js @@ -31,8 +31,6 @@ class ProtectionCategory { * @param {Object} options - Category options. * @param {string} options.prefEnabled - ID of pref which controls the * category enabled state. - * @param {string} [options.l10nId] - Identifier l10n strings are keyed under - * for this category. Defaults to protection ID. * @param {Object} flags - Flags for this category to look for in the content * blocking event and content blocking log. * @param {Number} [flags.load] - Load flag for this protection category. If @@ -49,7 +47,7 @@ class ProtectionCategory { */ constructor( id, - { prefEnabled, l10nId }, + { prefEnabled }, { load, block, @@ -416,7 +414,6 @@ let TrackingProtection = super( "trackers", { - l10nId: "trackingContent", prefEnabled: "privacy.trackingprotection.enabled", }, { @@ -1065,7 +1062,6 @@ let SocialTracking = super( "socialblock", { - l10nId: "socialMediaTrackers", prefEnabled: "privacy.socialtracking.block_cookies.enabled", }, { @@ -1381,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(); @@ -1595,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() { @@ -1641,42 +1634,42 @@ var gProtectionsHandler = { ); }, - async showTrackersSubview(event) { + async showTrackersSubview() { await TrackingProtection.updateSubView(); this._protectionsPopupMultiView.showSubView( "protections-popup-trackersView" ); }, - async showSocialblockerSubview(event) { + async showSocialblockerSubview() { await SocialTracking.updateSubView(); this._protectionsPopupMultiView.showSubView( "protections-popup-socialblockView" ); }, - async showCookiesSubview(event) { + async showCookiesSubview() { await ThirdPartyCookies.updateSubView(); this._protectionsPopupMultiView.showSubView( "protections-popup-cookiesView" ); }, - async showFingerprintersSubview(event) { + async showFingerprintersSubview() { await Fingerprinting.updateSubView(); this._protectionsPopupMultiView.showSubView( "protections-popup-fingerprintersView" ); }, - async showCryptominersSubview(event) { + async showCryptominersSubview() { await Cryptomining.updateSubView(); this._protectionsPopupMultiView.showSubView( "protections-popup-cryptominersView" ); }, - async onCookieBannerClick(event) { + async onCookieBannerClick() { if (!cookieBannerHandling.isSiteSupported) { return; } @@ -2055,7 +2048,7 @@ var gProtectionsHandler = { } }, - observe(subject, topic, data) { + observe(subject, topic) { switch (topic) { case "browser:purge-session-history": // We need to update the earliest recorded date if history has been @@ -2194,7 +2187,7 @@ var gProtectionsHandler = { ContentBlockingAllowList.add(gBrowser.selectedBrowser); if (shouldReload) { this._hidePopup(); - BrowserReload(); + BrowserCommands.reload(); } }, @@ -2202,11 +2195,11 @@ var gProtectionsHandler = { ContentBlockingAllowList.remove(gBrowser.selectedBrowser); if (shouldReload) { this._hidePopup(); - BrowserReload(); + BrowserCommands.reload(); } }, - async onTPSwitchCommand(event) { + async onTPSwitchCommand() { // When the switch is clicked, we wait 500ms and then disable/enable // protections, causing the page to refresh, and close the popup. // We need to ensure we don't handle more clicks during the 500ms delay, @@ -2533,12 +2526,12 @@ var gProtectionsHandler = { }; const doc = event.target.ownerDocument; - const container = doc.getElementById("messaging-system-message-container"); + const container = doc.getElementById("info-message-container"); const infoButton = doc.getElementById("protections-popup-info-button"); const panelContainer = doc.getElementById("protections-popup"); const toggleMessage = () => { const learnMoreLink = doc.querySelector( - "#messaging-system-message-container .text-link" + "#info-message-container .text-link" ); if (learnMoreLink) { container.toggleAttribute("disabled"); @@ -2605,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 a94bf2b896..9aa6cc5cd4 100644 --- a/browser/base/content/browser-sync.js +++ b/browser/base/content/browser-sync.js @@ -55,7 +55,7 @@ this.SyncedTabsPanelList = class SyncedTabsPanelList { this.createSyncedTabs(); } - observe(subject, topic, data) { + observe(subject, topic) { if (topic == SyncedTabs.TOPIC_TABS_CHANGED) { this._showSyncedTabs(); } @@ -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(); }, @@ -648,7 +756,7 @@ var gSync = { // shows the device list will start with `recentDeviceList`, but should also // force a refresh, both of which should mean in the worst-case, the UI is up // to date after a very short delay. - async ensureFxaDevices(options) { + async ensureFxaDevices() { if (UIState.get().status != UIState.STATUS_SIGNED_IN) { console.info("Skipping device list refresh; not signed in"); return; @@ -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"); @@ -768,7 +866,7 @@ var gSync = { } } - item.addEventListener("command", event => { + item.addEventListener("command", () => { if (panelNode) { PanelMultiView.hidePopup(panelNode); } @@ -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); @@ -1364,7 +1461,7 @@ var gSync = { return; } if (!createDeviceNodeFn) { - createDeviceNodeFn = (targetId, name, targetType, lastModified) => { + createDeviceNodeFn = (targetId, name) => { let eltName = name ? "menuitem" : "menuseparator"; return document.createXULElement(eltName); }; @@ -1462,7 +1559,7 @@ var gSync = { fxAccounts.flushLogFile(); }); }; - const onSendAllCommand = event => { + const onSendAllCommand = () => { send(targets); }; const onTargetDeviceCommand = event => { @@ -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-tabsintitlebar.js b/browser/base/content/browser-tabsintitlebar.js index caf9986b2f..d7f71ed450 100644 --- a/browser/base/content/browser-tabsintitlebar.js +++ b/browser/base/content/browser-tabsintitlebar.js @@ -43,7 +43,7 @@ var TabsInTitlebar = { return document.documentElement.getAttribute("tabsintitlebar") == "true"; }, - observe(subject, topic, data) { + observe(subject, topic) { if (topic == "nsPref:changed") { this._readPref(); } diff --git a/browser/base/content/browser-thumbnails.js b/browser/base/content/browser-thumbnails.js index 1162914ddf..2ca6148b67 100644 --- a/browser/base/content/browser-thumbnails.js +++ b/browser/base/content/browser-thumbnails.js @@ -103,7 +103,7 @@ var gBrowserThumbnails = { ChromeUtils.defineLazyGetter(this, "_topSiteURLs", getTopSiteURLs); }, - notify: function Thumbnails_notify(timer) { + notify: function Thumbnails_notify() { gBrowserThumbnails._topSiteURLsRefreshTimer = null; gBrowserThumbnails.clearTopSiteURLCache(); }, @@ -116,7 +116,7 @@ var gBrowserThumbnails = { aWebProgress, aRequest, aStateFlags, - aStatus + _aStatus ) { if ( aStateFlags & Ci.nsIWebProgressListener.STATE_STOP && diff --git a/browser/base/content/browser-toolbarKeyNav.js b/browser/base/content/browser-toolbarKeyNav.js index caa01100c5..c65d99f6f0 100644 --- a/browser/base/content/browser-toolbarKeyNav.js +++ b/browser/base/content/browser-toolbarKeyNav.js @@ -137,7 +137,7 @@ ToolbarKeyboardNavigator = { }, // CustomizableUI event handler - onWidgetAdded(aWidgetId, aArea, aPosition) { + onWidgetAdded(aWidgetId, aArea) { if (!this.kToolbars.includes(aArea)) { return; } diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index c9ebddb7f5..6e776a9ce7 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -250,8 +250,7 @@ toolbar[customizing] > .overflow-button { display: none; } -toolbar[customizing] #ion-button, -toolbar[customizing] #whats-new-menu-button { +toolbar[customizing] #ion-button { display: none; } @@ -382,7 +381,7 @@ toolbarpaletteitem { toolbar[brighttext] & { list-style-image: var(--webextension-toolbar-image-light, inherit); } - toolbar:not([brighttext]) &:-moz-lwtheme { + :root[lwtheme] toolbar:not([brighttext]) & { list-style-image: var(--webextension-toolbar-image-dark, inherit); } toolbaritem:is([overflowedItem="true"], [cui-areatype="panel"]) > & { @@ -480,12 +479,6 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks { flex: 1; } -@media (-moz-platform: macos) { - :root[inFullscreen="true"] { - padding-top: 0; /* override drawintitlebar="true" */ - } -} - /* Hide menu elements intended for keyboard access support */ #main-menubar[openedwithkey=false] .show-only-for-keyboard { display: none; @@ -916,7 +909,7 @@ menupopup[emptyplacesresult="true"] > .hide-if-empty-places-result { position: absolute; } -browser[tabmodalPromptShowing], browser[tabDialogShowing] { +browser[tabDialogShowing] { -moz-user-focus: none !important; } diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index c91a5d4db2..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: @@ -79,7 +80,6 @@ ChromeUtils.defineESModuleGetters(this, { SubDialog: "resource://gre/modules/SubDialog.sys.mjs", SubDialogManager: "resource://gre/modules/SubDialog.sys.mjs", TabCrashHandler: "resource:///modules/ContentCrashHandlers.sys.mjs", - TabModalPrompt: "chrome://global/content/tabprompts.sys.mjs", TabsSetupFlowManager: "resource:///modules/firefox-view-tabs-setup-manager.sys.mjs", TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.sys.mjs", @@ -109,6 +109,12 @@ ChromeUtils.defineLazyGetter(this, "fxAccounts", () => { XPCOMUtils.defineLazyScriptGetter( this, + ["BrowserCommands", "kSkipCacheFlags"], + "chrome://browser/content/browser-commands.js" +); + +XPCOMUtils.defineLazyScriptGetter( + this, "PlacesTreeView", "chrome://browser/content/places/treeView.js" ); @@ -546,7 +552,7 @@ XPCOMUtils.defineLazyPreferenceGetter( "gFxaToolbarAccessed", "identity.fxaccounts.toolbar.accessed", false, - (aPref, aOldVal, aNewVal) => { + () => { updateFxaToolbarMenu(gFxaToolbarEnabled); } ); @@ -691,7 +697,6 @@ function shouldSuppressPopupNotifications() { // don't cover up the prompt. return ( window.windowState == window.STATE_MINIMIZED || - gBrowser?.selectedBrowser.hasAttribute("tabmodalChromePromptShowing") || gBrowser?.selectedBrowser.hasAttribute("tabDialogShowing") || gDialogBox?.isOpen ); @@ -1019,7 +1024,7 @@ const gClickAndHoldListenersOnElement = { }; const gSessionHistoryObserver = { - observe(subject, topic, data) { + observe(subject, topic) { if (topic != "browser:purge-session-history") { return; } @@ -1037,7 +1042,7 @@ const gSessionHistoryObserver = { const gStoragePressureObserver = { _lastNotificationTime: -1, - async observe(subject, topic, data) { + async observe(subject, topic) { if (topic != "QuotaManager::StoragePressure") { return; } @@ -1088,7 +1093,7 @@ const gStoragePressureObserver = { document.l10n.setAttributes(message, "space-alert-over-5gb-message2"); buttons.push({ "l10n-id": "space-alert-over-5gb-settings-button", - callback(notificationBar, button) { + callback() { // The advanced subpanes are only supported in the old organization, which will // be removed by bug 1349689. openPreferences("privacy-sitedata"); @@ -1475,7 +1480,7 @@ var gKeywordURIFixup = { ); }, - observe(fixupInfo, topic, data) { + observe(fixupInfo) { fixupInfo.QueryInterface(Ci.nsIURIFixupInfo); let browser = fixupInfo.consumer?.top?.embedderElement; @@ -1499,1154 +1504,36 @@ 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(() => { - // load the tab preview component - import("chrome://browser/content/tabpreview/tabpreview.mjs").catch( - console.error - ); - }); - - 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": - BrowserBack(); + BrowserCommands.back(); break; case "Forward": - BrowserForward(); + BrowserCommands.forward(); break; case "Reload": - BrowserReloadSkipCache(); + BrowserCommands.reloadSkipCache(); break; case "Stop": if (XULBrowserWindow.stopCommand.getAttribute("disabled") != "true") { - BrowserStop(); + BrowserCommands.stop(); } break; case "Search": BrowserSearch.webSearch(); break; case "Bookmarks": - SidebarUI.toggle("viewBookmarksSidebar"); + SidebarController.toggle("viewBookmarksSidebar"); break; case "Home": - BrowserHome(); + BrowserCommands.home(); break; case "New": - BrowserOpenTab(); + BrowserCommands.openTab(); break; case "Close": - BrowserCloseTabOrWindow(); + BrowserCommands.closeTabOrWindow(); break; case "Find": gLazyFindCommand("onFindCommand"); @@ -2655,7 +1542,7 @@ function HandleAppCommandEvent(evt) { openHelpLink("firefox-help"); break; case "Open": - BrowserOpenFileWindow(); + BrowserCommands.openFileWindow(); break; case "Print": PrintUtils.startPrintWindow(gBrowser.selectedBrowser.browsingContext); @@ -2673,203 +1560,6 @@ function HandleAppCommandEvent(evt) { evt.preventDefault(); } -function gotoHistoryIndex(aEvent) { - aEvent = getRootEvent(aEvent); - - let index = aEvent.target.getAttribute("index"); - if (!index) { - return false; - } - - let where = whereToOpenLink(aEvent); - - if (where == "current") { - // Normal click. Go there in the current tab and update session history. - - try { - gBrowser.gotoIndex(index); - } catch (ex) { - return false; - } - return true; - } - // Modified click. Go there in a new tab/window. - - let historyindex = aEvent.target.getAttribute("historyindex"); - duplicateTabIn(gBrowser.selectedTab, where, Number(historyindex)); - return true; -} - -function BrowserForward(aEvent) { - let where = whereToOpenLink(aEvent, false, true); - - if (where == "current") { - try { - gBrowser.goForward(); - } catch (ex) {} - } else { - duplicateTabIn(gBrowser.selectedTab, where, 1); - } -} - -function BrowserBack(aEvent) { - let where = whereToOpenLink(aEvent, false, true); - - if (where == "current") { - try { - gBrowser.goBack(); - } catch (ex) {} - } else { - duplicateTabIn(gBrowser.selectedTab, where, -1); - } -} - -function BrowserHandleBackspace() { - switch (Services.prefs.getIntPref("browser.backspace_action")) { - case 0: - BrowserBack(); - break; - case 1: - goDoCommand("cmd_scrollPageUp"); - break; - } -} - -function BrowserHandleShiftBackspace() { - switch (Services.prefs.getIntPref("browser.backspace_action")) { - case 0: - BrowserForward(); - break; - case 1: - goDoCommand("cmd_scrollPageDown"); - break; - } -} - -function BrowserStop() { - gBrowser.webNavigation.stop(Ci.nsIWebNavigation.STOP_ALL); -} - -function BrowserReloadOrDuplicate(aEvent) { - aEvent = getRootEvent(aEvent); - let accelKeyPressed = - AppConstants.platform == "macosx" ? aEvent.metaKey : aEvent.ctrlKey; - var backgroundTabModifier = aEvent.button == 1 || accelKeyPressed; - - if (aEvent.shiftKey && !backgroundTabModifier) { - BrowserReloadSkipCache(); - return; - } - - let where = whereToOpenLink(aEvent, false, true); - if (where == "current") { - BrowserReload(); - } else { - duplicateTabIn(gBrowser.selectedTab, where); - } -} - -function BrowserReload() { - if (gBrowser.currentURI.schemeIs("view-source")) { - // Bug 1167797: For view source, we always skip the cache - return BrowserReloadSkipCache(); - } - const reloadFlags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE; - BrowserReloadWithFlags(reloadFlags); -} - -const kSkipCacheFlags = - Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | - Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE; -function BrowserReloadSkipCache() { - // Bypass proxy and cache. - BrowserReloadWithFlags(kSkipCacheFlags); -} - -function BrowserHome(aEvent) { - if (aEvent && "button" in aEvent && aEvent.button == 2) { - // right-click: do nothing - return; - } - - var homePage = HomePage.get(window); - var where = whereToOpenLink(aEvent, false, true); - var urls; - var notifyObservers; - - // Don't load the home page in pinned or hidden tabs (e.g. Firefox View). - if ( - where == "current" && - (gBrowser?.selectedTab.pinned || gBrowser?.selectedTab.hidden) - ) { - where = "tab"; - } - - // openTrustedLinkIn in utilityOverlay.js doesn't handle loading multiple pages - switch (where) { - case "current": - // If we're going to load an initial page in the current tab as the - // home page, we set initialPageLoadedFromURLBar so that the URL - // bar is cleared properly (even during a remoteness flip). - if (isInitialPage(homePage)) { - gBrowser.selectedBrowser.initialPageLoadedFromUserAction = homePage; - } - loadOneOrMoreURIs( - homePage, - Services.scriptSecurityManager.getSystemPrincipal(), - null - ); - if (isBlankPageURL(homePage)) { - gURLBar.select(); - } else { - gBrowser.selectedBrowser.focus(); - } - notifyObservers = true; - aEvent?.preventDefault(); - break; - case "tabshifted": - case "tab": - urls = homePage.split("|"); - var loadInBackground = Services.prefs.getBoolPref( - "browser.tabs.loadBookmarksInBackground", - false - ); - // The homepage observer event should only be triggered when the homepage opens - // in the foreground. This is mostly to support the homepage changed by extension - // doorhanger which doesn't currently support background pages. This may change in - // bug 1438396. - notifyObservers = !loadInBackground; - gBrowser.loadTabs(urls, { - inBackground: loadInBackground, - triggeringPrincipal: - Services.scriptSecurityManager.getSystemPrincipal(), - csp: null, - }); - if (!loadInBackground) { - if (isBlankPageURL(homePage)) { - gURLBar.select(); - } else { - gBrowser.selectedBrowser.focus(); - } - } - aEvent?.preventDefault(); - break; - case "window": - // OpenBrowserWindow will trigger the observer event, so no need to do so here. - notifyObservers = false; - OpenBrowserWindow(); - aEvent?.preventDefault(); - break; - } - if (notifyObservers) { - // A notification for when a user has triggered their homepage. This is used - // to display a doorhanger explaining that an extension has modified the - // homepage, if necessary. Observers are only notified if the homepage - // becomes the active page. - Services.obs.notifyObservers(null, "browser-open-homepage-start"); - } -} - function loadOneOrMoreURIs(aURIString, aTriggeringPrincipal, aCsp) { // we're not a browser window, pass the URI string to a new browser window if (window.location.href != AppConstants.BROWSER_CHROME_URL) { @@ -2918,62 +1608,6 @@ function openLocation(event) { ); } -function BrowserOpenTab({ event, url } = {}) { - let werePassedURL = !!url; - url ??= BROWSER_NEW_TAB_URL; - let searchClipboard = gMiddleClickNewTabUsesPasteboard && event?.button == 1; - - let relatedToCurrent = false; - let where = "tab"; - - if (event) { - where = whereToOpenLink(event, false, true); - - switch (where) { - case "tab": - case "tabshifted": - // When accel-click or middle-click are used, open the new tab as - // related to the current tab. - relatedToCurrent = true; - break; - case "current": - where = "tab"; - break; - } - } - - // A notification intended to be useful for modular peformance tracking - // starting as close as is reasonably possible to the time when the user - // expressed the intent to open a new tab. Since there are a lot of - // entry points, this won't catch every single tab created, but most - // initiated by the user should go through here. - // - // Note 1: This notification gets notified with a promise that resolves - // with the linked browser when the tab gets created - // Note 2: This is also used to notify a user that an extension has changed - // the New Tab page. - Services.obs.notifyObservers( - { - wrappedJSObject: new Promise(resolve => { - let options = { - relatedToCurrent, - resolveOnNewTabCreated: resolve, - }; - if (!werePassedURL && searchClipboard) { - let clipboard = readFromClipboard(); - clipboard = UrlbarUtils.stripUnsafeProtocolOnPaste(clipboard).trim(); - if (clipboard) { - url = clipboard; - options.allowThirdPartyFixup = true; - } - } - openTrustedLinkIn(url, where, options); - }), - }, - "browser-open-newtab-start" - ); -} - var gLastOpenDirectory = { _lastDir: null, get path() { @@ -3014,76 +1648,6 @@ var gLastOpenDirectory = { }, }; -function BrowserOpenFileWindow() { - // Get filepicker component. - try { - const nsIFilePicker = Ci.nsIFilePicker; - let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); - let fpCallback = function fpCallback_done(aResult) { - if (aResult == nsIFilePicker.returnOK) { - try { - if (fp.file) { - gLastOpenDirectory.path = fp.file.parent.QueryInterface(Ci.nsIFile); - } - } catch (ex) {} - openTrustedLinkIn(fp.fileURL.spec, "current"); - } - }; - - fp.init( - window.browsingContext, - gNavigatorBundle.getString("openFile"), - nsIFilePicker.modeOpen - ); - fp.appendFilters( - nsIFilePicker.filterAll | - nsIFilePicker.filterText | - nsIFilePicker.filterImages | - nsIFilePicker.filterXML | - nsIFilePicker.filterHTML | - nsIFilePicker.filterPDF - ); - fp.displayDirectory = gLastOpenDirectory.path; - fp.open(fpCallback); - } catch (ex) {} -} - -function BrowserCloseTabOrWindow(event) { - // If we're not a browser window, just close the window. - if (window.location.href != AppConstants.BROWSER_CHROME_URL) { - closeWindow(true); - return; - } - - // In a multi-select context, close all selected tabs - if (gBrowser.multiSelectedTabsCount) { - gBrowser.removeMultiSelectedTabs(); - return; - } - - // Keyboard shortcuts that would close a tab that is pinned select the first - // unpinned tab instead. - if ( - event && - (event.ctrlKey || event.metaKey || event.altKey) && - gBrowser.selectedTab.pinned - ) { - if (gBrowser.visibleTabs.length > gBrowser._numPinnedTabs) { - gBrowser.tabContainer.selectedIndex = gBrowser._numPinnedTabs; - } - return; - } - - // If the current tab is the last one, this will close the window. - gBrowser.removeCurrentTab({ animate: true }); -} - -function BrowserTryToCloseWindow(event) { - if (WindowIsClosing(event)) { - window.close(); - } // WindowIsClosing does all the necessary checks -} - function getLoadContext() { return window.docShell.QueryInterface(Ci.nsILoadContext); } @@ -3120,162 +1684,6 @@ function readFromClipboard() { return url; } -/** - * Open the View Source dialog. - * - * @param args - * An object with the following properties: - * - * URL (required): - * A string URL for the page we'd like to view the source of. - * browser (optional): - * The browser containing the document that we would like to view the - * source of. This is required if outerWindowID is passed. - * outerWindowID (optional): - * The outerWindowID of the content window containing the document that - * we want to view the source of. You only need to provide this if you - * want to attempt to retrieve the document source from the network - * cache. - * lineNumber (optional): - * The line number to focus on once the source is loaded. - */ -async function BrowserViewSourceOfDocument(args) { - // Check if external view source is enabled. If so, try it. If it fails, - // fallback to internal view source. - if (Services.prefs.getBoolPref("view_source.editor.external")) { - try { - await top.gViewSourceUtils.openInExternalEditor(args); - return; - } catch (data) {} - } - - let tabBrowser = gBrowser; - let preferredRemoteType; - let initialBrowsingContextGroupId; - if (args.browser) { - preferredRemoteType = args.browser.remoteType; - initialBrowsingContextGroupId = args.browser.browsingContext.group.id; - } else { - if (!tabBrowser) { - throw new Error( - "BrowserViewSourceOfDocument should be passed the " + - "subject browser if called from a window without " + - "gBrowser defined." - ); - } - // Some internal URLs (such as specific chrome: and about: URLs that are - // not yet remote ready) cannot be loaded in a remote browser. View - // source in tab expects the new view source browser's remoteness to match - // that of the original URL, so disable remoteness if necessary for this - // URL. - var oa = E10SUtils.predictOriginAttributes({ window }); - preferredRemoteType = E10SUtils.getRemoteTypeForURI( - args.URL, - gMultiProcessBrowser, - gFissionBrowser, - E10SUtils.DEFAULT_REMOTE_TYPE, - null, - oa - ); - } - - // In the case of popups, we need to find a non-popup browser window. - if (!tabBrowser || !window.toolbar.visible) { - // This returns only non-popup browser windows by default. - let browserWindow = BrowserWindowTracker.getTopWindow(); - tabBrowser = browserWindow.gBrowser; - } - - const inNewWindow = !Services.prefs.getBoolPref("view_source.tab"); - - // `viewSourceInBrowser` will load the source content from the page - // descriptor for the tab (when possible) or fallback to the network if - // that fails. Either way, the view source module will manage the tab's - // location, so use "about:blank" here to avoid unnecessary redundant - // requests. - let tab = tabBrowser.addTab("about:blank", { - relatedToCurrent: true, - inBackground: inNewWindow, - skipAnimation: inNewWindow, - preferredRemoteType, - initialBrowsingContextGroupId, - triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), - skipLoad: true, - }); - args.viewSourceBrowser = tabBrowser.getBrowserForTab(tab); - top.gViewSourceUtils.viewSourceInBrowser(args); - - if (inNewWindow) { - tabBrowser.hideTab(tab); - tabBrowser.replaceTabWithWindow(tab); - } -} - -/** - * Opens the View Source dialog for the source loaded in the root - * top-level document of the browser. This is really just a - * convenience wrapper around BrowserViewSourceOfDocument. - * - * @param browser - * The browser that we want to load the source of. - */ -function BrowserViewSource(browser) { - BrowserViewSourceOfDocument({ - browser, - outerWindowID: browser.outerWindowID, - URL: browser.currentURI.spec, - }); -} - -// documentURL - URL of the document to view, or null for this window's document -// initialTab - name of the initial tab to display, or null for the first tab -// imageElement - image to load in the Media Tab of the Page Info window; can be null/omitted -// browsingContext - the browsingContext of the frame that we want to view information about; can be null/omitted -// browser - the browser containing the document we're interested in inspecting; can be null/omitted -function BrowserPageInfo( - documentURL, - initialTab, - imageElement, - browsingContext, - browser -) { - let args = { initialTab, imageElement, browsingContext, browser }; - - documentURL = documentURL || window.gBrowser.selectedBrowser.currentURI.spec; - - let isPrivate = PrivateBrowsingUtils.isWindowPrivate(window); - - // Check for windows matching the url - for (let currentWindow of Services.wm.getEnumerator("Browser:page-info")) { - if (currentWindow.closed) { - continue; - } - if ( - currentWindow.document.documentElement.getAttribute("relatedUrl") == - documentURL && - PrivateBrowsingUtils.isWindowPrivate(currentWindow) == isPrivate - ) { - currentWindow.focus(); - currentWindow.resetPageInfo(args); - return currentWindow; - } - } - - // We didn't find a matching window, so open a new one. - let options = "chrome,toolbar,dialog=no,resizable"; - - // Ensure the window groups correctly in the Windows taskbar - if (isPrivate) { - options += ",private"; - } - return openDialog( - "chrome://browser/content/pageinfo/pageInfo.xhtml", - "", - options, - args - ); -} - function UpdateUrlbarSearchSplitterState() { var splitter = document.getElementById("urlbar-search-splitter"); var urlbar = document.getElementById("urlbar-container"); @@ -3480,88 +1888,6 @@ function getDefaultHomePage() { return url; } -function BrowserFullScreen() { - window.fullScreen = !window.fullScreen || BrowserHandler.kiosk; -} - -function BrowserReloadWithFlags(reloadFlags) { - let unchangedRemoteness = []; - - for (let tab of gBrowser.selectedTabs) { - let browser = tab.linkedBrowser; - let url = browser.currentURI; - let urlSpec = url.spec; - // We need to cache the content principal here because the browser will be - // reconstructed when the remoteness changes and the content prinicpal will - // be cleared after reconstruction. - let principal = tab.linkedBrowser.contentPrincipal; - if (gBrowser.updateBrowserRemotenessByURL(browser, urlSpec)) { - // If the remoteness has changed, the new browser doesn't have any - // information of what was loaded before, so we need to load the previous - // URL again. - if (tab.linkedPanel) { - loadBrowserURI(browser, url, principal); - } else { - // Shift to fully loaded browser and make - // sure load handler is instantiated. - tab.addEventListener( - "SSTabRestoring", - () => loadBrowserURI(browser, url, principal), - { once: true } - ); - gBrowser._insertBrowser(tab); - } - } else { - unchangedRemoteness.push(tab); - } - } - - if (!unchangedRemoteness.length) { - return; - } - - // Reset temporary permissions on the remaining tabs to reload. - // This is done here because we only want to reset - // permissions on user reload. - for (let tab of unchangedRemoteness) { - SitePermissions.clearTemporaryBlockPermissions(tab.linkedBrowser); - // Also reset DOS mitigations for the basic auth prompt on reload. - delete tab.linkedBrowser.authPromptAbuseCounter; - } - gIdentityHandler.hidePopup(); - gPermissionPanel.hidePopup(); - - let handlingUserInput = document.hasValidTransientUserGestureActivation; - - for (let tab of unchangedRemoteness) { - if (tab.linkedPanel) { - sendReloadMessage(tab); - } else { - // Shift to fully loaded browser and make - // sure load handler is instantiated. - tab.addEventListener("SSTabRestoring", () => sendReloadMessage(tab), { - once: true, - }); - gBrowser._insertBrowser(tab); - } - } - - function loadBrowserURI(browser, url, principal) { - browser.loadURI(url, { - flags: reloadFlags, - triggeringPrincipal: principal, - }); - } - - function sendReloadMessage(tab) { - tab.linkedBrowser.sendMessageToActor( - "Browser:Reload", - { flags: reloadFlags, handlingUserInput }, - "BrowserTab" - ); - } -} - // TODO: can we pull getPEMString in from pippki.js instead of // duplicating them here? function getPEMString(cert) { @@ -4053,7 +2379,7 @@ const BrowserSearch = { win.BrowserSearch.webSearch(); } else { // If there are no open browser windows, open a new one - var observer = function (subject, topic, data) { + var observer = function (subject) { if (subject == win) { BrowserSearch.webSearch(); Services.obs.removeObserver( @@ -4200,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"; @@ -4444,7 +2770,8 @@ function FillHistoryMenu(aParent) { item.setAttribute("label", entry.title || uri); item.setAttribute("index", j); - // Cache this so that gotoHistoryIndex doesn't need the original index + // Cache this so that BrowserCommands.gotoHistoryIndex doesn't need the + // original index item.setAttribute("historyindex", j - index); if (j != index) { @@ -4505,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); @@ -5037,7 +3356,7 @@ var XULBrowserWindow = { this.setOverLink("", { hideStatusPanelImmediately: true }); }, - showTooltip(xDevPix, yDevPix, tooltip, direction, browser) { + showTooltip(xDevPix, yDevPix, tooltip, direction, _browser) { if ( Cc["@mozilla.org/widget/dragservice;1"] .getService(Ci.nsIDragService) @@ -5070,14 +3389,7 @@ var XULBrowserWindow = { return gBrowser.tabs.length; }, - onProgressChange( - aWebProgress, - aRequest, - aCurSelfProgress, - aMaxSelfProgress, - aCurTotalProgress, - aMaxTotalProgress - ) { + onProgressChange() { // Do nothing. }, @@ -5420,7 +3732,7 @@ var XULBrowserWindow = { } } - if (TranslationsParent.isRestrictedPage(gBrowser)) { + if (TranslationsParent.isFullPageTranslationsRestrictedForPage(gBrowser)) { this._menuItemForTranslations.setAttribute("disabled", "true"); } else { this._menuItemForTranslations.removeAttribute("disabled"); @@ -5576,7 +3888,7 @@ var XULBrowserWindow = { // 2. Called by tabbrowser.xml when updating the current browser. // 3. Called directly during this object's initializations. // aRequest will be null always in case 2 and 3, and sometimes in case 1. - onSecurityChange(aWebProgress, aRequest, aState, aIsSimulated) { + onSecurityChange(aWebProgress, aRequest, aState, _aIsSimulated) { // Don't need to do anything if the data we use to update the UI hasn't // changed let uri = gBrowser.currentURI; @@ -5619,7 +3931,7 @@ var XULBrowserWindow = { aStateFlags, aStatus, aMessage, - aTotalProgress + _aTotalProgress ) { if (FullZoom.updateBackgroundTabs) { FullZoom.onLocationChange(gBrowser.currentURI, true); @@ -6087,7 +4399,7 @@ nsBrowserAccess.prototype = { } if (aIsExternal && (!aURI || aURI.spec == "about:blank")) { - win.BrowserOpenTab(); // this also focuses the location bar + win.BrowserCommands.openTab(); // this also focuses the location bar win.focus(); return win.gBrowser.selectedBrowser; } @@ -6228,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; @@ -6272,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 @@ -6682,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; @@ -6699,6 +5012,7 @@ function setToolbarVisibility( isVisible = BookmarkingUI.isOnNewTabPage(currentURI); document.documentElement.toggleAttribute(overlapAttr, isVisible); break; + } } } @@ -6801,7 +5115,7 @@ var gTabletModePageCounter = { }; function displaySecurityInfo() { - BrowserPageInfo(null, "securityTab"); + BrowserCommands.pageInfo(null, "securityTab"); } // Updates the UI density (for touch and compact mode) based on the uidensity pref. @@ -6855,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) { @@ -6873,7 +5188,7 @@ var gUIDensity = { } } if (shouldUpdateSidebar) { - let tree = SidebarUI.browser.contentDocument.querySelector( + let tree = SidebarController.browser.contentDocument.querySelector( ".sidebar-placesTree" ); if (tree) { @@ -7110,7 +5425,7 @@ function handleLinkClick(event, href, linkNode) { return false; } - var where = whereToOpenLink(event); + var where = BrowserUtils.whereToOpenLink(event); if (where == "current") { return false; } @@ -7183,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; @@ -7297,11 +5612,6 @@ function handleDroppedLink( } } -function BrowserForceEncodingDetection() { - gBrowser.selectedBrowser.forceEncodingDetection(); - BrowserReloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE); -} - var ToolbarContextMenu = { updateDownloadsAutoHide(popup) { let checkbox = document.getElementById( @@ -7467,7 +5777,7 @@ var BrowserOffline = { }, // nsIObserver - observe(aSubject, aTopic, aState) { + observe(aSubject, aTopic) { if (aTopic != "network:offline-status-changed") { return; } @@ -7695,8 +6005,8 @@ var WebAuthnPromptHelper = { if (data.prompt.type == "presence") { this.presence_required(mgr, data); - } else if (data.prompt.type == "register-direct") { - this.registerDirect(mgr, data); + } else if (data.prompt.type == "attestation-consent") { + this.attestation_consent(mgr, data); } else if (data.prompt.type == "pin-required") { this.pin_required(mgr, false, data); } else if (data.prompt.type == "pin-invalid") { @@ -7815,7 +6125,7 @@ var WebAuthnPromptHelper = { secondaryActions.push({ label, accessKey: i.toString(), - callback(aState) { + callback() { mgr.selectionCallback(tid, i); }, }); @@ -7859,9 +6169,23 @@ var WebAuthnPromptHelper = { ); }, - registerDirect(mgr, { origin, tid }) { - let mainAction = this.buildProceedAction(mgr, tid); - let secondaryActions = [this.buildCancelAction(mgr, tid)]; + attestation_consent(mgr, { origin, tid }) { + let mainAction = { + label: gNavigatorBundle.getString("webauthn.allow"), + accessKey: gNavigatorBundle.getString("webauthn.allow.accesskey"), + callback(_state) { + mgr.setHasAttestationConsent(tid, true); + }, + }; + let secondaryActions = [ + { + label: gNavigatorBundle.getString("webauthn.block"), + accessKey: gNavigatorBundle.getString("webauthn.block.accesskey"), + callback(_state) { + mgr.setHasAttestationConsent(tid, false); + }, + }, + ]; let learnMoreURL = Services.urlFormatter.formatURLPref("app.support.baseURL") + @@ -7869,9 +6193,6 @@ var WebAuthnPromptHelper = { let options = { learnMoreURL, - checkbox: { - label: gNavigatorBundle.getString("webauthn.anonymize"), - }, hintText: "webauthn.registerDirectPromptHint", }; this.show( @@ -7994,16 +6315,6 @@ var WebAuthnPromptHelper = { } }, - buildProceedAction(mgr, tid) { - return { - label: gNavigatorBundle.getString("webauthn.proceed"), - accessKey: gNavigatorBundle.getString("webauthn.proceed.accesskey"), - callback(state) { - mgr.resumeMakeCredential(tid, state.checkboxChecked); - }, - }; - }, - buildCancelAction(mgr, tid) { return { label: gNavigatorBundle.getString("webauthn.cancel"), @@ -8195,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, aTopic, aData) { - 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, aData) { - 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."); @@ -8449,7 +6682,7 @@ function ReportSiteIssue() { * and when the "remote-listening" system notification fires. */ const gRemoteControl = { - observe(subject, topic, data) { + observe() { gRemoteControl.updateVisualCue(); }, @@ -8658,7 +6891,7 @@ function switchToTabHavingURI( ignoreQueryString || replaceQueryString, ignoreFragmentWhenComparing ); - let browserUserContextId = browser.getAttribute("usercontextid"); + let browserUserContextId = browser.getAttribute("usercontextid") || ""; if (aUserContextId != null && aUserContextId != browserUserContextId) { continue; } @@ -8823,7 +7056,7 @@ function safeModeRestart() { */ function duplicateTabIn(aTab, where, delta) { switch (where) { - case "window": + case "window": { let otherWin = OpenBrowserWindow({ private: PrivateBrowsingUtils.isBrowserPrivate(aTab.linkedBrowser), }); @@ -8845,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. @@ -9447,221 +7681,6 @@ TabDialogBox.prototype.QueryInterface = ChromeUtils.generateQI([ "nsISupportsWeakReference", ]); -function TabModalPromptBox(browser) { - this._weakBrowserRef = Cu.getWeakReference(browser); - /* - * These WeakMaps holds the TabModalPrompt instances, key to the <tabmodalprompt> prompt - * in the DOM. We don't want to hold the instances directly to avoid leaking. - * - * WeakMap also prevents us from reading back its insertion order. - * Order of the elements in the DOM should be the only order to consider. - */ - this._contentPrompts = new WeakMap(); - this._tabPrompts = new WeakMap(); -} - -TabModalPromptBox.prototype = { - _promptCloseCallback( - onCloseCallback, - principalToAllowFocusFor, - allowFocusCheckbox, - ...args - ) { - if ( - principalToAllowFocusFor && - allowFocusCheckbox && - allowFocusCheckbox.checked - ) { - Services.perms.addFromPrincipal( - principalToAllowFocusFor, - "focus-tab-by-prompt", - Services.perms.ALLOW_ACTION - ); - } - onCloseCallback.apply(this, args); - }, - - getPrompt(promptEl) { - if (promptEl.classList.contains("tab-prompt")) { - return this._tabPrompts.get(promptEl); - } - return this._contentPrompts.get(promptEl); - }, - - appendPrompt(args, onCloseCallback) { - let browser = this.browser; - let newPrompt = new TabModalPrompt(browser.ownerGlobal); - - if (args.modalType === Ci.nsIPrompt.MODAL_TYPE_TAB) { - newPrompt.element.classList.add("tab-prompt"); - this._tabPrompts.set(newPrompt.element, newPrompt); - } else { - newPrompt.element.classList.add("content-prompt"); - this._contentPrompts.set(newPrompt.element, newPrompt); - } - - browser.parentNode.insertBefore( - newPrompt.element, - browser.nextElementSibling - ); - browser.setAttribute("tabmodalPromptShowing", true); - - // Indicate if a tab modal chrome prompt is being shown so that - // PopupNotifications are suppressed. - if ( - args.modalType === Ci.nsIPrompt.MODAL_TYPE_TAB && - !browser.hasAttribute("tabmodalChromePromptShowing") - ) { - browser.setAttribute("tabmodalChromePromptShowing", true); - // Notify popup notifications of the UI change so they hide their - // notification panels. - UpdatePopupNotificationsVisibility(); - } - - let prompts = this.listPrompts(args.modalType); - if (prompts.length > 1) { - // Let's hide ourself behind the current prompt. - newPrompt.element.hidden = true; - } - - let principalToAllowFocusFor = this._allowTabFocusByPromptPrincipal; - delete this._allowTabFocusByPromptPrincipal; - - let allowFocusCheckbox; // Define outside the if block so we can bind it into the callback. - let hostForAllowFocusCheckbox = ""; - try { - hostForAllowFocusCheckbox = principalToAllowFocusFor.URI.host; - } catch (ex) { - /* Ignore exceptions for host-less URIs */ - } - if (hostForAllowFocusCheckbox) { - let allowFocusRow = document.createElement("div"); - - let spacer = document.createElement("div"); - allowFocusRow.appendChild(spacer); - - allowFocusCheckbox = document.createXULElement("checkbox"); - document.l10n.setAttributes( - allowFocusCheckbox, - "tabbrowser-allow-dialogs-to-get-focus", - { domain: hostForAllowFocusCheckbox } - ); - allowFocusRow.appendChild(allowFocusCheckbox); - - newPrompt.ui.rows.append(allowFocusRow); - } - - let tab = gBrowser.getTabForBrowser(browser); - let closeCB = this._promptCloseCallback.bind( - null, - onCloseCallback, - principalToAllowFocusFor, - allowFocusCheckbox - ); - newPrompt.init(args, tab, closeCB); - return newPrompt; - }, - - removePrompt(aPrompt) { - let { modalType } = aPrompt.args; - if (modalType === Ci.nsIPrompt.MODAL_TYPE_TAB) { - this._tabPrompts.delete(aPrompt.element); - } else { - this._contentPrompts.delete(aPrompt.element); - } - - let browser = this.browser; - aPrompt.element.remove(); - - let prompts = this.listPrompts(modalType); - if (prompts.length) { - let prompt = prompts[prompts.length - 1]; - prompt.element.hidden = false; - // Because we were hidden before, this won't have been possible, so do it now: - prompt.Dialog.setDefaultFocus(); - } else if (modalType === Ci.nsIPrompt.MODAL_TYPE_TAB) { - // If we remove the last tab chrome prompt, also remove the browser - // attribute. - browser.removeAttribute("tabmodalChromePromptShowing"); - // Notify popup notifications of the UI change so they show notification - // panels again. - UpdatePopupNotificationsVisibility(); - } - // Check if all prompts are closed - if (!this._hasPrompts()) { - browser.removeAttribute("tabmodalPromptShowing"); - browser.focus(); - } - }, - - /** - * Checks if the prompt box has prompt elements. - * @returns {Boolean} - true if there are prompt elements. - */ - _hasPrompts() { - return !!this._getPromptElements().length; - }, - - /** - * Get list of current prompt elements. - * @param {Number} [aModalType] - Optionally filter by - * Ci.nsIPrompt.MODAL_TYPE_. - * @returns {NodeList} - A list of tabmodalprompt elements. - */ - _getPromptElements(aModalType = null) { - let selector = "tabmodalprompt"; - - if (aModalType != null) { - if (aModalType === Ci.nsIPrompt.MODAL_TYPE_TAB) { - selector += ".tab-prompt"; - } else { - selector += ".content-prompt"; - } - } - return this.browser.parentNode.querySelectorAll(selector); - }, - - /** - * Get a list of all TabModalPrompt objects associated with the prompt box. - * @param {Number} [aModalType] - Optionally filter by - * Ci.nsIPrompt.MODAL_TYPE_. - * @returns {TabModalPrompt[]} - An array of TabModalPrompt objects. - */ - listPrompts(aModalType = null) { - // Get the nodelist, then return the TabModalPrompt instances as an array - let promptMap; - - if (aModalType) { - if (aModalType === Ci.nsIPrompt.MODAL_TYPE_TAB) { - promptMap = this._tabPrompts; - } else { - promptMap = this._contentPrompts; - } - } - - let elements = this._getPromptElements(aModalType); - - if (promptMap) { - return [...elements].map(el => promptMap.get(el)); - } - return [...elements].map( - el => this._contentPrompts.get(el) || this._tabPrompts.get(el) - ); - }, - - onNextPromptShowAllowFocusCheckboxFor(principal) { - this._allowTabFocusByPromptPrincipal = principal; - }, - - get browser() { - let browser = this._weakBrowserRef.get(); - if (!browser) { - throw new Error("Stale promptbox! The associated browser is gone."); - } - return browser; - }, -}; - // Handle window-modal prompts that we want to display with the same style as // tab-modal prompts. var gDialogBox = { @@ -9907,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; @@ -10018,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) { @@ -10075,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); @@ -10086,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); @@ -10096,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; @@ -10134,11 +8143,6 @@ var FirefoxViewHandler = { _onTabForegrounded() { if (this.tab?.selected) { this.SyncedTabs.syncTabs(); - Services.obs.notifyObservers( - null, - "firefoxview-notification-dot-update", - "false" - ); } }, _recordViewIfTabSelected() { @@ -10162,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 c767bb5beb..910e0b5ca9 100644 --- a/browser/base/content/browser.js.globals +++ b/browser/base/content/browser.js.globals @@ -28,41 +28,20 @@ "gPopupBlockerObserver", "gKeywordURIFixup", "_createNullPrincipalFromTabUserContextId", - "_resolveDelayedStartup", - "delayedStartupPromise", - "gBrowserInit", "HandleAppCommandEvent", - "gotoHistoryIndex", - "BrowserForward", - "BrowserBack", - "BrowserHandleBackspace", - "BrowserHandleShiftBackspace", - "BrowserStop", - "BrowserReloadOrDuplicate", - "BrowserReload", + "BrowserCommands", "kSkipCacheFlags", - "BrowserReloadSkipCache", - "BrowserHome", "loadOneOrMoreURIs", "openLocation", - "BrowserOpenTab", "gLastOpenDirectory", - "BrowserOpenFileWindow", - "BrowserCloseTabOrWindow", - "BrowserTryToCloseWindow", "getLoadContext", "readFromClipboard", - "BrowserViewSourceOfDocument", - "BrowserViewSource", - "BrowserPageInfo", "UpdateUrlbarSearchSplitterState", "UpdatePopupNotificationsVisibility", "PageProxyClickHandler", "BrowserOnClick", "getMeOutOfHere", "getDefaultHomePage", - "BrowserFullScreen", - "BrowserReloadWithFlags", "getPEMString", "browserDragAndDrop", "homeButtonObserver", @@ -72,7 +51,6 @@ "BrowserSearch", "CreateContainerTabMenu", "FillHistoryMenu", - "BrowserDownloadsUI", "toOpenWindowByType", "OpenBrowserWindow", "updateEditUIVisibility", @@ -103,7 +81,6 @@ "handleLinkClick", "middleMousePaste", "handleDroppedLink", - "BrowserForceEncodingDetection", "ToolbarContextMenu", "BrowserOffline", "CanvasPermissionPromptHelper", @@ -112,7 +89,6 @@ "WindowIsClosing", "warnAboutClosingWindow", "MailIntegration", - "BrowserOpenAddonsMgr", "AddKeywordForSearchField", "restoreLastClosedTabOrWindowOrSession", "undoCloseTab", @@ -131,7 +107,6 @@ "PanicButtonNotifier", "SafeBrowsingNotificationBox", "TabDialogBox", - "TabModalPromptBox", "gDialogBox", "ConfirmationHint", "FirefoxViewHandler", @@ -154,7 +129,6 @@ "DownloadsCommon", "E10SUtils", "ExtensionsUI", - "FirefoxViewNotificationManager", "HomePage", "isProductURL", "LightweightThemeConsumer", @@ -196,7 +170,6 @@ "SubDialog", "SubDialogManager", "TabCrashHandler", - "TabModalPrompt", "TabsSetupFlowManager", "TelemetryEnvironment", "TranslationsParent", diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index 1dcdd02cd1..aec0983a67 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -38,11 +38,7 @@ both "content" and "skin" packages, which bug 1385444 will unify later. --> <link rel="stylesheet" href="chrome://global/skin/global.css" /> - <link rel="stylesheet" href="chrome://global/content/tabprompts.css" /> - <link rel="stylesheet" href="chrome://global/skin/tabprompts.css" /> - <link rel="stylesheet" href="chrome://browser/content/browser.css" /> - <link rel="stylesheet" href="chrome://browser/content/tabbrowser.css" /> <link rel="stylesheet" href="chrome://browser/content/downloads/downloads.css" @@ -87,7 +83,6 @@ <link rel="localization" href="browser/translations.ftl" /> <link rel="localization" href="browser/unifiedExtensions.ftl"/> <link rel="localization" href="browser/webrtcIndicator.ftl"/> - <link rel="localization" href="toolkit/branding/accounts.ftl"/> <link rel="localization" href="toolkit/branding/brandings.ftl"/> <link rel="localization" href="toolkit/global/contextual-identity.ftl"/> <link rel="localization" href="toolkit/global/textActions.ftl"/> @@ -95,9 +90,9 @@ <!-- Untranslated FTL files --> <link rel="localization" href="preview/enUS-searchFeatures.ftl" /> <link rel="localization" href="preview/interventions.ftl" /> - <link rel="localization" href="preview/select-translations.ftl"/> <link rel="localization" href="browser/shopping.ftl"/> <link rel="localization" href="preview/shopping.ftl"/> + <link rel="localization" href="preview/sidebar.ftl"/> <link rel="localization" href="preview/profiles.ftl"/> <link rel="localization" href="preview/onboarding.ftl"/> @@ -110,6 +105,7 @@ <script> /* eslint-env mozilla/browser-window */ + Services.scriptloader.loadSubScript("chrome://browser/content/browser-init.js", this); Services.scriptloader.loadSubScript("chrome://global/content/contentAreaUtils.js", this); Services.scriptloader.loadSubScript("chrome://browser/content/browser-captivePortal.js", this); if (AppConstants.MOZ_DATA_REPORTING) { @@ -119,7 +115,7 @@ Services.scriptloader.loadSubScript("chrome://browser/content/browser-development-helpers.js", this); } Services.scriptloader.loadSubScript("chrome://browser/content/browser-pageActions.js", this); - Services.scriptloader.loadSubScript("chrome://browser/content/browser-sidebar.js", this); + Services.scriptloader.loadSubScript("chrome://browser/content/sidebar/browser-sidebar.js", this); Services.scriptloader.loadSubScript("chrome://browser/content/browser-tabsintitlebar.js", this); Services.scriptloader.loadSubScript("chrome://browser/content/browser-unified-extensions.js", this); Services.scriptloader.loadSubScript("chrome://browser/content/tabbrowser.js", this); diff --git a/browser/base/content/contentTheme.js b/browser/base/content/contentTheme.js index 3c46b80bec..2eb339d69b 100644 --- a/browser/base/content/contentTheme.js +++ b/browser/base/content/contentTheme.js @@ -43,8 +43,8 @@ let browserStyle = element.ownerGlobal?.docShell?.chromeEventHandler.style; + element.toggleAttribute("lwt-newtab", !!rgbaChannels); if (!rgbaChannels) { - element.removeAttribute("lwt-newtab"); element.toggleAttribute( "lwt-newtab-brighttext", prefersDarkQuery.matches @@ -55,7 +55,6 @@ return null; } - element.setAttribute("lwt-newtab", "true"); const { r, g, b, a } = rgbaChannels; let darkMode = !_isTextColorDark(r, g, b); element.toggleAttribute("lwt-newtab-brighttext", darkMode); @@ -159,15 +158,10 @@ * @param {Object} event object containing the theme or query update. */ handleEvent(event) { - const root = document.documentElement; - if (event.type == "LightweightTheme:Set") { - let { data } = event.detail; - if (!data) { - data = {}; - } - this._setProperties(root, data); + this._setProperties(event.detail.data || {}); } else if (event.type == "change") { + const root = document.documentElement; // If a lightweight theme doesn't apply, update lwt-newtab-brighttext to // reflect prefers-color-scheme. if (!root.hasAttribute("lwt-newtab")) { @@ -192,22 +186,23 @@ /** * Apply theme data to an element - * @param {Element} root The element where the properties should be applied. * @param {Object} themeData The theme data. */ - _setProperties(elem, themeData) { + _setProperties(themeData) { + const root = document.documentElement; + root.toggleAttribute("lwtheme", themeData.hasTheme); for (let [cssVarName, definition] of inContentVariableMap) { const { lwtProperty, processColor } = definition; let value = themeData[lwtProperty]; if (processColor) { - value = processColor(value, elem); + value = processColor(value, root); } else if (value) { const { r, g, b, a } = value; value = `rgba(${r}, ${g}, ${b}, ${a})`; } - this._setProperty(elem, cssVarName, value); + this._setProperty(root, cssVarName, value); } }, }; diff --git a/browser/base/content/macWindow.inc.xhtml b/browser/base/content/macWindow.inc.xhtml index b9ca44c7eb..b5afa5f644 100644 --- a/browser/base/content/macWindow.inc.xhtml +++ b/browser/base/content/macWindow.inc.xhtml @@ -16,7 +16,6 @@ <html:link rel="localization" href="browser/menubar.ftl"/> <html:link rel="localization" href="browser/reportBrokenSite.ftl"/> <html:link rel="localization" href="browser/screenshots.ftl"/> - <html:link rel="localization" href="toolkit/branding/accounts.ftl"/> <html:link rel="localization" href="toolkit/branding/brandings.ftl"/> <html:link rel="localization" href="toolkit/global/textActions.ftl"/> </linkset> diff --git a/browser/base/content/main-popupset.inc.xhtml b/browser/base/content/main-popupset.inc.xhtml index bff8d98b27..ef8245938e 100644 --- a/browser/base/content/main-popupset.inc.xhtml +++ b/browser/base/content/main-popupset.inc.xhtml @@ -77,13 +77,16 @@ data-lazy-l10n-id="tab-context-close-n-tabs" data-l10n-args='{"tabCount": 1}' oncommand="TabContextMenu.closeContextTabs();"/> + <menuitem id="context_closeDuplicateTabs" + data-lazy-l10n-id="tab-context-close-duplicate-tabs" + oncommand="gBrowser.removeDuplicateTabs(TabContextMenu.contextTab);"/> <menu id="context_closeTabOptions" data-lazy-l10n-id="tab-context-close-multiple-tabs"> <menupopup id="closeTabOptions"> <menuitem id="context_closeTabsToTheStart" data-lazy-l10n-id="close-tabs-to-the-start" - oncommand="gBrowser.removeTabsToTheStartFrom(TabContextMenu.contextTab, {animate: true});"/> + oncommand="gBrowser.removeTabsToTheStartFrom(TabContextMenu.contextTab);"/> <menuitem id="context_closeTabsToTheEnd" data-lazy-l10n-id="close-tabs-to-the-end" - oncommand="gBrowser.removeTabsToTheEndFrom(TabContextMenu.contextTab, {animate: true});"/> + oncommand="gBrowser.removeTabsToTheEndFrom(TabContextMenu.contextTab);"/> <menuitem id="context_closeOtherTabs" data-lazy-l10n-id="close-other-tabs" oncommand="gBrowser.removeAllTabsBut(TabContextMenu.contextTab);"/> </menupopup> @@ -100,7 +103,7 @@ oncommand="FullScreen.setAutohide();"/> <menuitem contexttype="fullscreen" data-lazy-l10n-id="full-screen-exit" - oncommand="BrowserFullScreen();"/> + oncommand="BrowserCommands.fullScreen();"/> </menupopup> <!-- bug 415444/582485: event.stopPropagation is here for the cloned version @@ -109,7 +112,7 @@ --> <menupopup id="backForwardMenu" onpopupshowing="return FillHistoryMenu(event.target);" - oncommand="gotoHistoryIndex(event); event.stopPropagation();"/> + oncommand="BrowserCommands.gotoHistoryIndex(event); event.stopPropagation();"/> <tooltip id="aHTMLTooltip" page="true"/> <tooltip id="remoteBrowserTooltip"/> @@ -253,23 +256,26 @@ <menuitem id="sidebar-switcher-bookmarks" data-l10n-id="sidebar-menu-bookmarks" key="viewBookmarksSidebarKb" - oncommand="SidebarUI.show('viewBookmarksSidebar');"/> + oncommand="SidebarController.show('viewBookmarksSidebar');"/> <menuitem id="sidebar-switcher-history" data-l10n-id="sidebar-menu-history" key="key_gotoHistory" - oncommand="SidebarUI.show('viewHistorySidebar');"/> + oncommand="SidebarController.show('viewHistorySidebar');"/> <menuitem id="sidebar-switcher-tabs" data-l10n-id="sidebar-menu-synced-tabs" class="sync-ui-item" - oncommand="SidebarUI.show('viewTabsSidebar');"/> + oncommand="SidebarController.show('viewTabsSidebar');"/> + <menuitem id="sidebar-switcher-megalist" + data-l10n-id="sidebar-menu-megalist" + oncommand="SidebarController.show('viewMegalistSidebar');"/> <menuseparator/> <!-- Extension toolbarbuttons go here. --> <menuseparator id="sidebar-extensions-separator"/> <menuitem id="sidebar-reverse-position" - oncommand="SidebarUI.reversePosition()"/> + oncommand="SidebarController.reversePosition()"/> <menuseparator/> <menuitem data-l10n-id="sidebar-menu-close" - oncommand="SidebarUI.hide()"/> + oncommand="SidebarController.hide()"/> </menupopup> <menupopup id="toolbar-context-menu" @@ -360,7 +366,7 @@ oncommand="FullScreen.setAutohide();"/> <menuitem contexttype="fullscreen" data-lazy-l10n-id="full-screen-exit" - oncommand="BrowserFullScreen();"/> + oncommand="BrowserCommands.fullScreen();"/> </menupopup> <menupopup id="blockedPopupOptions" @@ -412,7 +418,24 @@ <hbox id="ctrlTab-showAll-container" pack="center"/> </panel> - <html:tab-preview id="tabbrowser-tab-preview" hidden="true" /> + <!-- TODO: create lazily? --> + <panel id="tab-preview-panel" + type="arrow" + orient="vertical" + noautofocus="true" + norolluponanchor="true" + rolluponmousewheel="true" + consumeoutsideclicks="false"> + <html:div class="tab-preview-text-container"> + <html:div class="tab-preview-title"></html:div> + <html:div class="tab-preview-uri"></html:div> + <html:div class="tab-preview-pid-activeness"> + <html:div class="tab-preview-pid"></html:div> + <html:div class="tab-preview-activeness"></html:div> + </html:div> + </html:div> + <html:div class="tab-preview-thumbnail-container"></html:div> + </panel> <html:template id="pageActionPanelTemplate"> <panel id="pageActionPanel" @@ -624,7 +647,7 @@ oncommand="gUnifiedExtensions.reportExtension(this.parentElement)" /> </menupopup> - <menupopup id="translations-panel-settings-menupopup" + <menupopup id="full-page-translations-panel-settings-menupopup" onpopupshown="FullPageTranslationsPanel.handleSettingsPopupShownEvent()" onpopuphidden="FullPageTranslationsPanel.handleSettingsPopupHiddenEvent()"> <menuitem class="always-offer-translations-menuitem" @@ -659,4 +682,14 @@ <menuitem data-l10n-id="translations-panel-settings-about2" oncommand="FullPageTranslationsPanel.onAboutTranslations()"/> </menupopup> + + <menupopup id="select-translations-panel-settings-menupopup"> + <menuitem id="select-translations-panel-open-settings-page-menuitem" + class="manage-languages-menuitem" + data-l10n-id="select-translations-panel-open-translations-settings-menuitem" + oncommand="SelectTranslationsPanel.openTranslationsSettingsPage()"/> + <menuitem id="select-translations-panel-about-translations-menuitem" + data-l10n-id="translations-panel-settings-about2" + oncommand="SelectTranslationsPanel.onAboutTranslations()"/> + </menupopup> </popupset> diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml index fc19910726..0a67afa81f 100644 --- a/browser/base/content/navigator-toolbox.inc.xhtml +++ b/browser/base/content/navigator-toolbox.inc.xhtml @@ -100,6 +100,9 @@ <image class="private-browsing-indicator-icon"/> <label data-l10n-id="private-browsing-indicator-label"></label> </hbox> + <toolbarbutton id="content-analysis-indicator" + oncommand="ContentAnalysis.showPanel(this, PanelUI);" + class="toolbarbutton-1 content-analysis-indicator-icon"/> #include titlebar-items.inc.xhtml @@ -491,13 +494,6 @@ tooltiptext="Ion" onmousedown="switchToTabHavingURI('about:ion', true);" onkeypress="switchToTabHavingURI('about:ion', true);"/> - <toolbarbutton id="whats-new-menu-button" - class="toolbarbutton-1" - delegatesanchor="true" - hidden="true" - badged="true" - onmousedown="PanelUI.showSubView('PanelUI-whatsNew', this, event);" - onkeypress="PanelUI.showSubView('PanelUI-whatsNew', this, event);"/> <toolbarbutton id="PanelUI-menu-button" class="toolbarbutton-1" delegatesanchor="true" @@ -516,12 +512,12 @@ customizable="true"> <toolbartabstop skipintoolbarset="true"/> - <hbox id="personal-toolbar-empty" skipintoolbarset="true" removable="false" hidden="true"> + <hbox id="personal-toolbar-empty" skipintoolbarset="true" removable="false" hidden="true" role="alert"> <description id="personal-toolbar-empty-description" data-l10n-id="bookmarks-toolbar-empty-message" onclick="BookmarkingUI.openLibraryIfLinkClicked(event);" onkeydown="BookmarkingUI.openLibraryIfLinkClicked(event);"> - <html:a data-l10n-name="manage-bookmarks" class="text-link" tabindex="0"/> + <html:a data-l10n-name="manage-bookmarks" class="text-link" tabindex="0" role="link"/> </description> </hbox> @@ -625,7 +621,7 @@ <menuitem id="BMB_viewBookmarksSidebar" data-l10n-id="bookmarks-tools-sidebar-visibility" data-l10n-args='{ "isVisible": false }' - oncommand="SidebarUI.toggle('viewBookmarksSidebar');" + oncommand="SidebarController.toggle('viewBookmarksSidebar');" key="viewBookmarksSidebarKb"/> <menuitem id="BMB_searchBookmarks" data-l10n-id="bookmarks-search" @@ -708,7 +704,7 @@ ondragenter="homeButtonObserver.onDragOver(event)" ondrop="homeButtonObserver.onDrop(event)" key="goHome" - onclick="BrowserHome(event);" + onclick="BrowserCommands.home(event);" cui-areatype="toolbar"/> <toolbarbutton id="library-button" class="toolbarbutton-1 chromeclass-toolbar-additional subviewbutton-nav" diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 031a32dddf..1811dfcaca 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -1347,8 +1347,6 @@ class nsContextMenu { !this.onTextInput && !this.onLink && !this.onPlainTextLink && - !this.onImage && - !this.onVideo && !this.onAudio && !this.onEditable && !this.onPassword; @@ -1619,7 +1617,7 @@ class nsContextMenu { // Open new "view source" window with the frame's URL. viewFrameSource() { - BrowserViewSourceOfDocument({ + BrowserCommands.viewSourceOfDocument({ browser: this.browser, URL: this.contentData.docLocation, outerWindowID: this.frameOuterWindowID, @@ -1627,7 +1625,7 @@ class nsContextMenu { } viewInfo() { - BrowserPageInfo( + BrowserCommands.pageInfo( this.contentData.docLocation, null, null, @@ -1637,7 +1635,7 @@ class nsContextMenu { } viewImageInfo() { - BrowserPageInfo( + BrowserCommands.pageInfo( this.contentData.docLocation, "mediaTab", this.imageInfo, @@ -1661,7 +1659,7 @@ class nsContextMenu { } viewFrameInfo() { - BrowserPageInfo( + BrowserCommands.pageInfo( this.contentData.docLocation, null, null, @@ -1685,7 +1683,7 @@ class nsContextMenu { // Change current window to the URL of the image, video, or audio. viewMedia(e) { - let where = whereToOpenLink(e, false, false); + let where = BrowserUtils.whereToOpenLink(e, false, false); if (where == "current") { where = "tab"; } @@ -1982,7 +1980,7 @@ class nsContextMenu { // we give up waiting for the filename. function timerCallback() {} timerCallback.prototype = { - notify: function sLA_timer_notify(aTimer) { + notify: function sLA_timer_notify() { channel.cancel(NS_ERROR_SAVE_LINK_AS_TIMEOUT); }, }; @@ -2175,7 +2173,10 @@ class nsContextMenu { var clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService( Ci.nsIClipboardHelper ); - clipboard.copyString(addresses); + clipboard.copyString( + addresses, + this.actor.manager.browsingContext.currentWindowGlobal + ); } // Extract phone and put it on clipboard @@ -2195,7 +2196,10 @@ class nsContextMenu { var clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService( Ci.nsIClipboardHelper ); - clipboard.copyString(phone); + clipboard.copyString( + phone, + this.actor.manager.browsingContext.currentWindowGlobal + ); } copyLink() { @@ -2204,7 +2208,10 @@ class nsContextMenu { var clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService( Ci.nsIClipboardHelper ); - clipboard.copyString(linkURL); + clipboard.copyString( + linkURL, + this.actor.manager.browsingContext.currentWindowGlobal + ); } /** @@ -2220,7 +2227,10 @@ class nsContextMenu { let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService( Ci.nsIClipboardHelper ); - clipboard.copyString(strippedLinkURL); + clipboard.copyString( + strippedLinkURL, + this.actor.manager.browsingContext.currentWindowGlobal + ); } } @@ -2324,8 +2334,8 @@ class nsContextMenu { try { strippedLinkURI = QueryStringStripper.stripForCopyOrShare(this.linkURI); } catch (e) { - console.warn(`isLinkURIStrippable: ${e.message}`); - return null; + console.warn(`stripForCopyOrShare: ${e.message}`); + return this.linkURI; } // If nothing can be stripped, we return the original URI @@ -2458,7 +2468,10 @@ class nsContextMenu { var clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService( Ci.nsIClipboardHelper ); - clipboard.copyString(this.originalMediaURL); + clipboard.copyString( + this.originalMediaURL, + this.actor.manager.browsingContext.currentWindowGlobal + ); } getImageText() { @@ -2484,7 +2497,7 @@ class nsContextMenu { let drmInfoURL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "drm-content"; - let dest = whereToOpenLink(aEvent); + let dest = BrowserUtils.whereToOpenLink(aEvent); // Don't ever want this to open in the same tab as it'll unload the // DRM'd video, which is going to be a bad idea in most cases. if (dest == "current") { @@ -2494,23 +2507,6 @@ class nsContextMenu { } /** - * Retrieves an instance of the TranslationsParent actor. - * @returns {TranslationsParent} - The TranslationsParent actor. - * @throws Throws if an instance of the actor cannot be retrieved. - */ - static #getTranslationsActor() { - const actor = - gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.getActor( - "Translations" - ); - - if (!actor) { - throw new Error("Unable to get the TranslationsParent"); - } - return actor; - } - - /** * Determines if Full Page Translations is currently active on this page. * * @returns {boolean} @@ -2518,7 +2514,9 @@ class nsContextMenu { static #isFullPageTranslationsActive() { try { const { requestedTranslationPair } = - this.#getTranslationsActor().languageState; + TranslationsParent.getTranslationsActor( + gBrowser.selectedBrowser + ).languageState; return requestedTranslationPair !== null; } catch { // Failed to retrieve the Full Page Translations actor, do nothing. @@ -2532,7 +2530,16 @@ class nsContextMenu { * @param {Event} event - The triggering event for opening the panel. */ openSelectTranslationsPanel(event) { - SelectTranslationsPanel.open(event, this.#translationsLangPairPromise); + const context = this.contentData.context; + let screenX = context.screenXDevPx / window.devicePixelRatio; + let screenY = context.screenYDevPx / window.devicePixelRatio; + SelectTranslationsPanel.open( + event, + screenX, + screenY, + this.#getTextToTranslate(), + this.#translationsLangPairPromise + ).catch(console.error); } /** @@ -2583,6 +2590,17 @@ class nsContextMenu { } /** + * Fetches text for translation, prioritizing selected text over link text. + * + * @returns {string} The text to translate. + */ + #getTextToTranslate() { + return this.isTextSelected + ? this.selectionInfo.fullText.trim() + : this.linkTextStr.trim(); + } + + /** * Displays or hides the translate-selection item in the context menu. */ showTranslateSelectionItem() { @@ -2596,14 +2614,13 @@ class nsContextMenu { "browser.translations.select.enable" ); - // Selected text takes precedence over link text. - const textToTranslate = this.isTextSelected - ? this.selectedText.trim() - : this.linkTextStr.trim(); + const textToTranslate = this.#getTextToTranslate(); translateSelectionItem.hidden = // Only show the item if the feature is enabled. !(translationsEnabled && selectTranslationsEnabled) || + // Only show the item if Translations is supported on this hardware. + !TranslationsParent.getIsTranslationsEngineSupported() || // If there is no text to translate, we have nothing to do. textToTranslate.length === 0 || // We do not allow translating selections on top of Full Page Translations. diff --git a/browser/base/content/pageinfo/pageInfo.js b/browser/base/content/pageinfo/pageInfo.js index f3999a7cc5..c186e9572d 100644 --- a/browser/base/content/pageinfo/pageInfo.js +++ b/browser/base/content/pageinfo/pageInfo.js @@ -47,7 +47,7 @@ pageInfoTreeView.prototype = { return this.data[row][column.index] || ""; }, - setCellValue(row, column, value) {}, + setCellValue() {}, setCellText(row, column, value) { this.data[row][column.index] = value; @@ -112,52 +112,52 @@ pageInfoTreeView.prototype = { this.sortcol = treecol.index; }, - getRowProperties(row) { + getRowProperties() { return ""; }, - getCellProperties(row, column) { + getCellProperties() { return ""; }, - getColumnProperties(column) { + getColumnProperties() { return ""; }, - isContainer(index) { + isContainer() { return false; }, - isContainerOpen(index) { + isContainerOpen() { return false; }, - isSeparator(index) { + isSeparator() { return false; }, isSorted() { return this.sortcol > -1; }, - canDrop(index, orientation) { + canDrop() { return false; }, - drop(row, orientation) { + drop() { return false; }, - getParentIndex(index) { + getParentIndex() { return 0; }, - hasNextSibling(index, after) { + hasNextSibling() { return false; }, - getLevel(index) { + getLevel() { return 0; }, - getImageSrc(row, column) {}, + getImageSrc() {}, getCellValue(row, column) { let col = column != null ? column : this.copycol; return row < 0 || col < 0 ? "" : this.data[row][col] || ""; }, - toggleOpenState(index) {}, - cycleHeader(col) {}, + toggleOpenState() {}, + cycleHeader() {}, selectionChanged() {}, - cycleCell(row, column) {}, - isEditable(row, column) { + cycleCell() {}, + isEditable() { return false; }, }; @@ -475,10 +475,10 @@ async function loadTab(args) { function openCacheEntry(key, cb) { var checkCacheListener = { - onCacheEntryCheck(entry) { + onCacheEntryCheck() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; }, - onCacheEntryAvailable(entry, isNew, status) { + onCacheEntryAvailable(entry) { cb(entry); }, }; @@ -1085,7 +1085,7 @@ let treeController = { return command == "cmd_copy" || command == "cmd_selectAll"; }, - isCommandEnabled(command) { + isCommandEnabled() { return true; // not worth checking for this }, diff --git a/browser/base/content/pageinfo/pageInfo.xhtml b/browser/base/content/pageinfo/pageInfo.xhtml index baa017702f..cca293c534 100644 --- a/browser/base/content/pageinfo/pageInfo.xhtml +++ b/browser/base/content/pageinfo/pageInfo.xhtml @@ -10,6 +10,10 @@ data-l10n-id="page-info-window" data-l10n-attrs="style" windowtype="Browser:page-info" +#ifdef XP_MACOSX + drawtitle="true" + chromemargin="0,0,0,0" +#endif onload="onLoadPageInfo()" align="stretch" screenX="10" screenY="10" diff --git a/browser/base/content/pageinfo/permissions.js b/browser/base/content/pageinfo/permissions.js index 7834e27c98..7803cbafe5 100644 --- a/browser/base/content/pageinfo/permissions.js +++ b/browser/base/content/pageinfo/permissions.js @@ -28,7 +28,7 @@ let gPermissions = SitePermissions.listPermissions() }); var permissionObserver = { - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { if (aTopic == "perm-changed") { var permission = aSubject.QueryInterface(Ci.nsIPermission); if ( diff --git a/browser/base/content/pageinfo/security.js b/browser/base/content/pageinfo/security.js index 3acd3cc452..9f9fb17bea 100644 --- a/browser/base/content/pageinfo/security.js +++ b/browser/base/content/pageinfo/security.js @@ -399,7 +399,7 @@ function realmHasPasswords(uri) { * * @param host - the domain name to look for in history */ -function previousVisitCount(host, endTimeReference) { +function previousVisitCount(host) { if (!host) { return 0; } diff --git a/browser/base/content/popup-notifications.inc b/browser/base/content/popup-notifications.inc index daee34e6fe..3d57f4808c 100644 --- a/browser/base/content/popup-notifications.inc +++ b/browser/base/content/popup-notifications.inc @@ -35,7 +35,7 @@ <description id="webRTC-all-windows-shared" hidden="true" data-l10n-id="popup-all-windows-shared"></description> </popupnotificationcontent> - <popupnotificationcontent id="webRTC-preview" hidden="true"> + <popupnotificationcontent id="webRTC-preview" orient="vertical" hidden="true"> <html:video id="webRTC-previewVideo" tabindex="-1"/> <vbox id="webRTC-previewWarningBox"> <description id="webRTC-previewWarning"/> diff --git a/browser/base/content/sanitizeDialog.js b/browser/base/content/sanitizeDialog.js index 09a7d927df..1d9ea978b9 100644 --- a/browser/base/content/sanitizeDialog.js +++ b/browser/base/content/sanitizeDialog.js @@ -218,7 +218,7 @@ var gSanitizePromptDialog = { acceptButton.disabled = noneChecked; }, - selectByTimespan() { + async selectByTimespan() { // This method is the onselect handler for the duration dropdown. As a // result it's called a couple of times before onload calls init(). if (!this._inited) { @@ -247,7 +247,7 @@ var gSanitizePromptDialog = { } // make sure the sizes are updated in the new dialog else { - this.updateDataSizesInUI(); + await this.updateDataSizesInUI(); } return; } @@ -267,7 +267,7 @@ var gSanitizePromptDialog = { if (!lazy.USE_OLD_DIALOG) { // We only update data sizes to display on the new dialog - this.updateDataSizesInUI(); + await this.updateDataSizesInUI(); } }, @@ -399,7 +399,7 @@ var gSanitizePromptDialog = { this.cacheSize = lazy.DownloadUtils.convertByteUnits(cacheSize); this._dataSizesUpdated = true; - this.updateDataSizesInUI(); + await this.updateDataSizesInUI(); }, /** @@ -473,7 +473,7 @@ var gSanitizePromptDialog = { /** * Updates data sizes displayed based on new selected timespan */ - updateDataSizesInUI() { + async updateDataSizesInUI() { if (!this._dataSizesUpdated) { return; } @@ -491,6 +491,7 @@ var gSanitizePromptDialog = { let timeSpanSelected = TIMESPAN_SELECTION_MAP[index]; let [amount, unit] = this.siteDataSizes[timeSpanSelected]; + document.l10n.pauseObserving(); document.l10n.setAttributes( this._cookiesAndSiteDataCheckbox, "item-cookies-site-data-with-size", @@ -503,6 +504,18 @@ var gSanitizePromptDialog = { "item-cached-content-with-size", { amount, unit } ); + + // make sure l10n updates are completed + await document.l10n.translateElements([ + this._cookiesAndSiteDataCheckbox, + this._cacheCheckbox, + ]); + + document.l10n.resumeObserving(); + + // the data sizes may have led to wrapping, resize dialog to make sure the buttons + // don't move out of view + await window.resizeDialog(); }, /** diff --git a/browser/base/content/spotlight.html b/browser/base/content/spotlight.html index a948f8dbf4..216f290efd 100644 --- a/browser/base/content/spotlight.html +++ b/browser/base/content/spotlight.html @@ -19,6 +19,7 @@ <link rel="localization" href="branding/brand.ftl" /> <link rel="localization" href="toolkit/branding/brandings.ftl" /> <link rel="localization" href="browser/newtab/asrouter.ftl" /> + <link rel="localization" href="preview/onboarding.ftl" /> <link rel="localization" href="browser/newtab/onboarding.ftl" /> <link rel="localization" href="browser/spotlight.ftl" /> <link rel="localization" href="browser/migrationWizard.ftl" /> diff --git a/browser/base/content/tabbrowser-tab.js b/browser/base/content/tabbrowser-tab.js index ed3d4bb727..807a7d93fd 100644 --- a/browser/base/content/tabbrowser-tab.js +++ b/browser/base/content/tabbrowser-tab.js @@ -259,6 +259,14 @@ return this._lastAccessed == Infinity ? Date.now() : this._lastAccessed; } + /** + * Returns a timestamp which attempts to represent the last time the user saw this tab. + * If the tab has not been active in this session, any lastAccessed is used. We + * differentiate between selected and explicitly visible; a selected tab in a hidden + * window is last seen when that window and tab were last visible. + * We use the application start time as a fallback value when no other suitable value + * is available. + */ get lastSeenActive() { const isForegroundWindow = this.ownerGlobal == @@ -270,8 +278,16 @@ if (this._lastSeenActive) { return this._lastSeenActive; } - // Use the application start time as the fallback value - return Services.startup.getStartupInfo().start.getTime(); + + const appStartTime = Services.startup.getStartupInfo().start.getTime(); + if (!this._lastAccessed || this._lastAccessed >= appStartTime) { + // When the tab was created this session but hasn't been seen by the user, + // default to the application start time. + return appStartTime; + } + // The tab was restored from a previous session but never seen. + // Use the lastAccessed as the best proxy for when the user might have seen it. + return this._lastAccessed; } get _overPlayingIcon() { @@ -457,7 +473,7 @@ } } - on_mouseup(event) { + on_mouseup() { // Make sure that clear-selection is released. // Otherwise selection using Shift key may be broken. gBrowser.unlockClearMultiSelection(); @@ -706,11 +722,11 @@ this.setAttribute("aria-describedby", "tabbrowser-tab-a11y-desc"); } - on_focus(event) { + on_focus() { this.updateA11yDescription(); } - on_AriaFocus(event) { + on_AriaFocus() { this.updateA11yDescription(); } } diff --git a/browser/base/content/tabbrowser-tabs.js b/browser/base/content/tabbrowser-tabs.js index 36b6aeb390..9b30584077 100644 --- a/browser/base/content/tabbrowser-tabs.js +++ b/browser/base/content/tabbrowser-tabs.js @@ -34,6 +34,7 @@ this.addEventListener("drop", this); this.addEventListener("dragend", this); this.addEventListener("dragleave", this); + this.addEventListener("mouseleave", this); } init() { @@ -61,6 +62,7 @@ this._hiddenSoundPlayingTabs = new Set(); this._allTabs = null; this._visibleTabs = null; + this._previewPanel = null; var tab = this.allTabs[0]; tab.label = this.emptyTabTitle; @@ -123,26 +125,17 @@ this.tabbox.tabpanels.setAttribute("async", "true"); } - this.configureTooltip = () => { - // fall back to original tooltip behavior if pref is not set - this.tooltip = this._showCardPreviews ? null : "tabbrowser-tab-tooltip"; - - // activate new tooltip behavior if pref is set - document - .getElementById("tabbrowser-tab-preview") - .toggleAttribute("hidden", !this._showCardPreviews); - }; XPCOMUtils.defineLazyPreferenceGetter( this, "_showCardPreviews", TAB_PREVIEW_PREF, - false, - () => this.configureTooltip() + false ); - this.configureTooltip(); + this.tooltip = "tabbrowser-tab-tooltip"; + this._previewPanel = null; } - on_TabSelect(event) { + on_TabSelect() { this._handleTabSelect(); } @@ -188,23 +181,23 @@ } on_TabHoverStart(event) { - if (this._showCardPreviews) { - const previewContainer = document.getElementById( - "tabbrowser-tab-preview" + if (!this._showCardPreviews) { + return; + } + if (!this._previewPanel) { + // load the tab preview component + const TabPreviewPanel = ChromeUtils.importESModule( + "chrome://browser/content/tabpreview/tab-preview-panel.mjs" + ).default; + this._previewPanel = new TabPreviewPanel( + document.getElementById("tab-preview-panel") ); - previewContainer.tab = event.target; } + this._previewPanel.activate(event.target); } on_TabHoverEnd(event) { - if (this._showCardPreviews) { - const previewContainer = document.getElementById( - "tabbrowser-tab-preview" - ); - if (previewContainer.tab === event.target) { - previewContainer.tab = null; - } - } + this._previewPanel?.deactivate(event.target); } on_transitionend(event) { @@ -241,7 +234,7 @@ } if (!this._blockDblClick) { - BrowserOpenTab(); + BrowserCommands.openTab(); } event.preventDefault(); @@ -333,7 +326,7 @@ (!RTL_UI && event.clientX > endOfTab) || (RTL_UI && event.clientX < endOfTab) ) { - BrowserOpenTab(); + BrowserCommands.openTab(); } } else { return; @@ -450,6 +443,7 @@ return; } + this._previewPanel?.deactivate(); this.startTabDrag(event, tab); } @@ -1092,6 +1086,10 @@ return children; } + get previewPanel() { + return this._previewPanel; + } + _getVisibleTabs() { if (!this._visibleTabs) { this._visibleTabs = Array.prototype.filter.call( @@ -1205,7 +1203,7 @@ }; } - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { switch (aTopic) { case "nsPref:changed": // This is has to deal with changes in @@ -1851,6 +1849,9 @@ this._unlockTabSizing(); } break; + case "mouseleave": + this._previewPanel?.deactivate(); + break; default: let methodName = `on_${aEvent.type}`; if (methodName in this) { diff --git a/browser/base/content/tabbrowser.css b/browser/base/content/tabbrowser.css deleted file mode 100644 index 120203141c..0000000000 --- a/browser/base/content/tabbrowser.css +++ /dev/null @@ -1,101 +0,0 @@ -/* 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/. */ - -.tab-close-button[pinned], -#tabbrowser-tabs[closebuttons="activetab"] > #tabbrowser-arrowscrollbox > .tabbrowser-tab > .tab-stack > .tab-content > .tab-close-button:not([selected]), -.tab-icon-pending:not([pendingicon]), -.tab-icon-pending[busy], -.tab-icon-pending[pinned], -.tab-icon-image:not([src], [pinned], [crashed], [pictureinpicture])[selected], -.tab-icon-image:not([src], [pinned], [crashed], [sharing], [pictureinpicture]), -.tab-icon-image[busy], -.tab-throbber:not([busy]), -.tab-sharing-icon-overlay, -.tab-icon-overlay { - display: none; -} - -:root[uidensity=compact] .tab-secondary-label, -.tab-secondary-label:not([soundplaying], [muted], [activemedia-blocked], [pictureinpicture]), -.tab-secondary-label:not([activemedia-blocked]) > .tab-icon-sound-blocked-label, -.tab-secondary-label[muted][activemedia-blocked] > .tab-icon-sound-blocked-label, -.tab-secondary-label[activemedia-blocked] > .tab-icon-sound-playing-label, -.tab-secondary-label[muted] > .tab-icon-sound-playing-label, -.tab-secondary-label[pictureinpicture] > .tab-icon-sound-playing-label, -.tab-secondary-label[pictureinpicture] > .tab-icon-sound-muted-label, -.tab-secondary-label:not([pictureinpicture]) > .tab-icon-sound-pip-label, -.tab-secondary-label:not([muted]) > .tab-icon-sound-muted-label, -.tab-secondary-label:not([showtooltip]) > .tab-icon-sound-tooltip-label, -.tab-secondary-label[showtooltip] > .tab-icon-sound-label:not(.tab-icon-sound-tooltip-label) { - display: none; -} - -.tab-sharing-icon-overlay[sharing]:not([selected]), -.tab-icon-overlay:is([soundplaying], [muted], [activemedia-blocked], [crashed]) { - display: revert; -} - -.tabbrowser-tab { - --tab-label-mask-size: 2em; -} - -.tab-label { - white-space: nowrap; - line-height: 1.7; /* override 'normal' in case of fallback math fonts with huge metrics */ -} - -.tab-secondary-label { - margin: -.3em 0 .3em; /* adjust margins to compensate for line-height of .tab-label */ -} - -.tab-label-container { - overflow: hidden; -} - -.tab-label-container[pinned] { - width: 0; -} - -.tab-label-container[textoverflow][labeldirection=ltr]:not([pinned]), -.tab-label-container[textoverflow]:not([labeldirection], [pinned]):-moz-locale-dir(ltr) { - direction: ltr; - mask-image: linear-gradient(to left, transparent, black var(--tab-label-mask-size)); -} - -.tab-label-container[textoverflow][labeldirection=rtl]:not([pinned]), -.tab-label-container[textoverflow]:not([labeldirection], [pinned]):-moz-locale-dir(rtl) { - direction: rtl; - mask-image: linear-gradient(to right, transparent, black var(--tab-label-mask-size)); -} - -tabpanels { - background-color: transparent; -} - -/* Apply crisp rendering for favicons at exactly 2dppx resolution */ -@media (resolution: 2dppx) { - .tab-icon-image { - image-rendering: -moz-crisp-edges; - } -} - -.closing-tabs-spacer { - pointer-events: none; -} - -#tabbrowser-arrowscrollbox:not(:hover) > #tabbrowser-arrowscrollbox-periphery > .closing-tabs-spacer { - transition: width .15s ease-out; -} - -browser[blank], -browser[pendingpaint] { - opacity: 0; -} - -#tabbrowser-tabpanels[pendingpaint] { - background-image: url(chrome://browser/skin/tabbrowser/pendingpaint.png); - background-repeat: no-repeat; - background-position: center center; - background-size: 30px; -} diff --git a/browser/base/content/tabbrowser.js b/browser/base/content/tabbrowser.js index 54a801939a..f319fd5d46 100644 --- a/browser/base/content/tabbrowser.js +++ b/browser/base/content/tabbrowser.js @@ -67,7 +67,7 @@ replaceContainerClass("color", hbox, identity.color); let label = ContextualIdentityService.getUserContextLabel(userContextId); - document.getElementById("userContext-label").setAttribute("value", label); + document.getElementById("userContext-label").textContent = label; // Also set the container label as the tooltip so we can only show the icon // in small windows. hbox.setAttribute("tooltiptext", label); @@ -110,6 +110,12 @@ "privacy.exposeContentTitleInWindow.pbm", true ); + XPCOMUtils.defineLazyPreferenceGetter( + this, + "_showTabCardPreview", + "browser.tabs.cardPreview.enabled", + true + ); if (AppConstants.MOZ_CRASHREPORTER) { ChromeUtils.defineESModuleGetters(this, { @@ -161,6 +167,8 @@ TO_START: 2, TO_END: 3, MULTI_SELECTED: 4, + DUPLICATES: 6, + ALL_DUPLICATES: 7, }, _lastRelatedTabMap: new WeakMap(), @@ -348,6 +356,90 @@ return this.tabContainer._getVisibleTabs(); }, + getDuplicateTabsToClose(aTab) { + // One would think that a set is better, but it would need to copy all + // the strings instead of just keeping references to the nsIURI objects, + // and the array is presumed to be small anyways. + let keys = []; + let keyForTab = tab => { + let uri = tab.linkedBrowser?.currentURI; + if (!uri) { + return null; + } + return { + uri, + userContextId: tab.userContextId, + }; + }; + let keyEquals = (a, b) => { + return a.userContextId == b.userContextId && a.uri.equals(b.uri); + }; + if (aTab.multiselected) { + for (let tab of this.selectedTabs) { + let key = keyForTab(tab); + if (key) { + keys.push(key); + } + } + } else { + let key = keyForTab(aTab); + if (key) { + keys.push(key); + } + } + + if (!keys.length) { + return []; + } + + let duplicateTabs = []; + for (let tab of this.tabs) { + if (tab == aTab || tab.pinned) { + continue; + } + if (aTab.multiselected && tab.multiselected) { + continue; + } + let key = keyForTab(tab); + if (key && keys.some(k => keyEquals(k, key))) { + duplicateTabs.push(tab); + } + } + + return duplicateTabs; + }, + + getAllDuplicateTabsToClose() { + let lastSeenTabs = this.tabs.toSorted( + (a, b) => b.lastSeenActive - a.lastSeenActive + ); + let duplicateTabs = []; + let keys = []; + for (let tab of lastSeenTabs) { + const uri = tab.linkedBrowser?.currentURI; + if (!uri) { + // Can't tell if it's a duplicate without a URI. + // Safest to leave it be. + continue; + } + + const key = { + uri, + userContextId: tab.userContextId, + }; + if ( + !tab.pinned && + keys.some( + k => k.userContextId == key.userContextId && k.uri.equals(key.uri) + ) + ) { + duplicateTabs.push(tab); + } + keys.push(key); + } + return duplicateTabs; + }, + get _numPinnedTabs() { for (var i = 0; i < this.tabs.length; i++) { if (!this.tabs[i].pinned) { @@ -893,14 +985,6 @@ : ""; }, - getTabModalPromptBox(aBrowser) { - let browser = aBrowser || this.selectedBrowser; - if (!browser.tabModalPromptBox) { - browser.tabModalPromptBox = new TabModalPromptBox(browser); - } - return browser.tabModalPromptBox; - }, - getTabDialogBox(aBrowser) { if (!aBrowser) { throw new Error("aBrowser is required"); @@ -1116,6 +1200,11 @@ return; } + let oldBrowser = this.selectedBrowser; + // Once the async switcher starts, it's unpredictable when it will touch + // the address bar, thus we store its state immediately. + gURLBar?.saveSelectionStateForBrowser(oldBrowser); + let newTab = this.getTabForBrowser(newBrowser); if (!aForceUpdate) { @@ -1145,8 +1234,6 @@ } this._lastRelatedTabMap = new WeakMap(); - let oldBrowser = this.selectedBrowser; - if (!gMultiProcessBrowser) { oldBrowser.removeAttribute("primary"); oldBrowser.docShellIsActive = false; @@ -1154,11 +1241,6 @@ newBrowser.docShellIsActive = !document.hidden; } - if (gURLBar) { - oldBrowser._urlbarSelectionStart = gURLBar.selectionStart; - oldBrowser._urlbarSelectionEnd = gURLBar.selectionEnd; - } - this._selectedBrowser = newBrowser; this._selectedTab = newTab; this.showTab(newTab); @@ -1320,31 +1402,6 @@ this.addToMultiSelectedTabs(oldTab); } - if (oldBrowser != newBrowser && oldBrowser.getInPermitUnload) { - oldBrowser.getInPermitUnload(inPermitUnload => { - if (!inPermitUnload) { - return; - } - // Since the user is switching away from a tab that has - // a beforeunload prompt active, we remove the prompt. - // This prevents confusing user flows like the following: - // 1. User attempts to close Firefox - // 2. User switches tabs (ingoring a beforeunload prompt) - // 3. User returns to tab, presses "Leave page" - let promptBox = this.getTabModalPromptBox(oldBrowser); - let prompts = promptBox.listPrompts(); - // There might not be any prompts here if the tab was closed - // while in an onbeforeunload prompt, which will have - // destroyed aforementioned prompt already, so check there's - // something to remove, first: - if (prompts.length) { - // NB: This code assumes that the beforeunload prompt - // is the top-most prompt on the tab. - prompts[prompts.length - 1].abortPrompt(); - } - }); - } - if (!gMultiProcessBrowser) { this._adjustFocusBeforeTabSwitch(oldTab, newTab); this._adjustFocusAfterTabSwitch(newTab); @@ -1439,19 +1496,6 @@ newBrowser.tabDialogBox.focus(); return; } - if (newBrowser.hasAttribute("tabmodalPromptShowing")) { - // If there's a tabmodal prompt showing, focus it. - let prompts = newBrowser.tabModalPromptBox.listPrompts(); - let prompt = prompts[prompts.length - 1]; - // @tabmodalPromptShowing is also set for other tab modal prompts - // (e.g. the Payment Request dialog) so there may not be a <tabmodalprompt>. - // Bug 1492814 will implement this for the Payment Request dialog. - if (prompt) { - prompt.Dialog.setDefaultFocus(); - return; - } - } - // Focus the location bar if it was previously focused for that tab. // In full screen mode, only bother making the location bar visible // if the tab is a blank one. @@ -1491,19 +1535,12 @@ if (currentActiveElement != document.activeElement) { return; } - - gURLBar.setSelectionRange( - newBrowser._urlbarSelectionStart, - newBrowser._urlbarSelectionEnd - ); + gURLBar.restoreSelectionStateForBrowser(newBrowser); }, { once: true } ); } else { - gURLBar.setSelectionRange( - newBrowser._urlbarSelectionStart, - newBrowser._urlbarSelectionEnd - ); + gURLBar.restoreSelectionStateForBrowser(newBrowser); } }; @@ -1656,6 +1693,22 @@ _dataURLRegEx: /^data:[^,]+;base64,/i, + // Regex to test if a string (potential tab label) consists of only non- + // printable characters. We consider Unicode categories Separator + // (spaces & line-breaks) and Other (control chars, private use, non- + // character codepoints) to be unprintable, along with a few specific + // characters whose expected rendering is blank: + // U+2800 BRAILLE PATTERN BLANK (category So) + // U+115F HANGUL CHOSEONG FILLER (category Lo) + // U+1160 HANGUL JUNGSEONG FILLER (category Lo) + // U+3164 HANGUL FILLER (category Lo) + // U+FFA0 HALFWIDTH HANGUL FILLER (category Lo) + // We also ignore combining marks, as in the absence of a printable base + // character they are unlikely to be usefully rendered, and may well be + // clipped away entirely. + _nonPrintingRegEx: + /^[\p{Z}\p{C}\p{M}\u{115f}\u{1160}\u{2800}\u{3164}\u{ffa0}]*$/u, + setTabTitle(aTab) { var browser = this.getBrowserForTab(aTab); var title = browser.contentTitle; @@ -1676,6 +1729,16 @@ } let isURL = false; + + // Trim leading and trailing whitespace from the title. + title = title.trim(); + + // If the title contains only non-printing characters (or only combining + // marks, but no base character for them), we won't use it. + if (this._nonPrintingRegEx.test(title)) { + title = ""; + } + let isContentTitle = !!title; if (!title) { // See if we can use the URI as the title. @@ -2097,18 +2160,6 @@ // doesn't keep the window alive. b.permanentKey = new (Cu.getGlobalForObject(Services).Object)(); - // Ensure that SessionStore has flushed any session history state from the - // content process before we this browser's remoteness. - if (!Services.appinfo.sessionHistoryInParent) { - b.prepareToChangeRemoteness = () => - SessionStore.prepareToChangeRemoteness(b); - b.afterChangeRemoteness = switchId => { - let tab = this.getTabForBrowser(b); - SessionStore.finishTabRemotenessChange(tab, switchId); - return true; - }; - } - const defaultBrowserAttributes = { contextmenu: "contentAreaContextMenu", message: "true", @@ -2176,16 +2227,12 @@ b.setAttribute("name", name); } - let notificationbox = document.createXULElement("notificationbox"); - notificationbox.setAttribute("notificationside", "top"); - let stack = document.createXULElement("stack"); stack.className = "browserStack"; stack.appendChild(b); let browserContainer = document.createXULElement("vbox"); browserContainer.className = "browserContainer"; - browserContainer.appendChild(notificationbox); browserContainer.appendChild(stack); let browserSidebarContainer = document.createXULElement("hbox"); @@ -2682,8 +2729,6 @@ animate, userContextId, openerTab, - createLazyBrowser, - skipAnimation, pinned, noInitialLabel, skipBackgroundNotify, @@ -2849,8 +2894,6 @@ uriString, userContextId, openerTab, - createLazyBrowser, - skipAnimation, pinned, noInitialLabel, skipBackgroundNotify, @@ -3306,6 +3349,24 @@ return true; } + const shownDupeDialogPref = + "browser.tabs.haveShownCloseAllDuplicateTabsWarning"; + if ( + aCloseTabs == this.closingTabsEnum.ALL_DUPLICATES && + !Services.prefs.getBoolPref(shownDupeDialogPref, false) + ) { + // The first time a user closes all duplicate tabs, tell them what will + // happen and give them a chance to back away. + Services.prefs.setBoolPref(shownDupeDialogPref, true); + + window.focus(); + const [title, text] = this.tabLocalization.formatValuesSync([ + { id: "tabbrowser-confirm-close-duplicate-tabs-title" }, + { id: "tabbrowser-confirm-close-duplicate-tabs-text" }, + ]); + return Services.prompt.confirm(window, title, text); + } + const pref = aCloseTabs == this.closingTabsEnum.ALL ? "browser.tabs.warnOnClose" @@ -3367,7 +3428,7 @@ Services.telemetry.setEventRecordingEnabled("close_tab_warning", true); let closeTabEnumKey = Object.entries(this.closingTabsEnum) - .find(([k, v]) => v == aCloseTabs)?.[0] + .find(([, v]) => v == aCloseTabs)?.[0] ?.toLowerCase() || "some"; let warnCheckbox = warnOnClose.value ? "checked" : "unchecked"; @@ -3545,6 +3606,42 @@ return tabsToEnd; }, + removeDuplicateTabs(aTab) { + this._removeDuplicateTabs( + aTab, + this.getDuplicateTabsToClose(aTab), + this.closingTabsEnum.DUPLICATES + ); + }, + + _removeDuplicateTabs(aConfirmationAnchor, tabs, aCloseTabs) { + if (!tabs.length) { + return; + } + + if (!this.warnAboutClosingTabs(tabs.length, aCloseTabs)) { + return; + } + + this.removeTabs(tabs); + ConfirmationHint.show( + aConfirmationAnchor, + "confirmation-hint-duplicate-tabs-closed", + { l10nArgs: { tabCount: tabs.length } } + ); + }, + + removeAllDuplicateTabs() { + // I would like to have the caller provide this target, + // but the caller lives in a different document. + let alltabsButton = document.getElementById("alltabs-button"); + this._removeDuplicateTabs( + alltabsButton, + this.getAllDuplicateTabsToClose(), + this.closingTabsEnum.ALL_DUPLICATES + ); + }, + /** * In a multi-select context, the tabs (except pinned tabs) that are located to the * left of the leftmost selected tab will be removed. @@ -3674,6 +3771,8 @@ tabs, { animate, + // See bug 1883051 + // eslint-disable-next-line no-unused-vars suppressWarnAboutClosingWindow, skipPermitUnload, skipRemoves, @@ -4390,6 +4489,56 @@ ); } }, + /** + * Closes tabs within the browser that match a given list of nsURIs. Returns + * any nsURIs that could not be closed successfully. This does not close any + * tabs that have a beforeUnload prompt + * + * @param {nsURI[]} urisToClose + * The set of uris to remove. + * @returns {nsURI[]} + * the nsURIs that weren't found in this browser + */ + async closeTabsByURI(urisToClose) { + let remainingURIsToClose = [...urisToClose]; + let tabsToRemove = []; + for (let tab of this.tabs) { + let currentURI = tab.linkedBrowser.currentURI; + // Find any URI that matches the current tab's URI + const matchedIndex = remainingURIsToClose.findIndex(uriToClose => + uriToClose.equals(currentURI) + ); + + if (matchedIndex > -1) { + tabsToRemove.push(tab); + remainingURIsToClose.splice(matchedIndex, 1); // Remove the matched URI + } + } + + if (tabsToRemove.length) { + const { beforeUnloadComplete, lastToClose } = this._startRemoveTabs( + tabsToRemove, + { + animate: false, + suppressWarnAboutClosingWindow: true, + skipPermitUnload: false, + skipRemoves: false, + skipSessionStore: false, + } + ); + + // Wait for the beforeUnload handlers to complete. + await beforeUnloadComplete; + + // _startRemoveTabs doesn't close the last tab in the window + // for this use case, we simply close it + if (lastToClose) { + this.removeTab(lastToClose); + } + } + // If we still have uris, that means we couldn't find them in this window instance + return remainingURIsToClose; + }, /** * Handles opening a new tab with mouse middleclick. @@ -4406,7 +4555,7 @@ } // Do nothing if (event.button == 1) { - BrowserOpenTab({ event }); + BrowserCommands.openTab({ event }); // Stop the propagation of the click event, to prevent the event from being // handled more than once. // E.g. see https://bugzilla.mozilla.org/show_bug.cgi?id=1657992#c4 @@ -5719,6 +5868,20 @@ } }, + getTabPids(tab) { + if (!tab.linkedBrowser) { + return []; + } + + // Get the PIDs of the content process and remote subframe processes + let [contentPid, ...framePids] = E10SUtils.getBrowserPids( + tab.linkedBrowser, + gFissionBrowser + ); + let pids = contentPid ? [contentPid] : []; + return pids.concat(framePids.sort()); + }, + getTabTooltip(tab, includeLabel = true) { let labelArray = []; if (includeLabel) { @@ -5730,24 +5893,14 @@ false ) ) { - if (tab.linkedBrowser) { - // Show the PIDs of the content process and remote subframe processes. - let [contentPid, ...framePids] = E10SUtils.getBrowserPids( - tab.linkedBrowser, - gFissionBrowser - ); - if (contentPid) { - if (framePids && framePids.length) { - labelArray.push( - `(pids ${contentPid}, ${framePids.sort().join(", ")})` - ); - } else { - labelArray.push(`(pid ${contentPid})`); - } - } - if (tab.linkedBrowser.docShellIsActive) { - labelArray.push("[A]"); - } + const pids = this.getTabPids(tab); + if (pids.length) { + let pidLabel = pids.length > 1 ? "pids" : "pid"; + labelArray.push(`(${pidLabel} ${pids.join(", ")})`); + } + + if (tab.linkedBrowser.docShellIsActive) { + labelArray.push("[A]"); } } @@ -5810,6 +5963,13 @@ tooltip.label = ""; document.l10n.setAttributes(tooltip, l10nId, l10nArgs); } else { + // Prevent the tooltip from appearing if card preview is enabled, but + // only if the user is not hovering over the media play icon or the + // close button + if (this._showTabCardPreview) { + event.preventDefault(); + return; + } tooltip.label = this.getTabTooltip(tab, true); } }, @@ -5849,7 +6009,7 @@ } }, - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { switch (aTopic) { case "contextual-identity-updated": { let identity = aSubject.wrappedJSObject; @@ -6105,12 +6265,7 @@ ); if (permission != Services.perms.ALLOW_ACTION) { // Tell the prompt box we want to show the user a checkbox: - let tabPrompt = Services.prefs.getBoolPref( - "prompts.contentPromptSubDialog" - ) - ? this.getTabDialogBox(tabForEvent.linkedBrowser) - : this.getTabModalPromptBox(tabForEvent.linkedBrowser); - + let tabPrompt = this.getTabDialogBox(tabForEvent.linkedBrowser); tabPrompt.onNextPromptShowAllowFocusCheckboxFor( promptPrincipal ); @@ -6352,7 +6507,7 @@ let oldUserTypedValue = browser.userTypedValue; let hadStartedLoad = browser.didStartLoadSinceLastUserTyping(); - let didChange = didChangeEvent => { + let didChange = () => { browser.userTypedValue = oldUserTypedValue; if (hadStartedLoad) { browser.urlbarChangeTracker.startedLoad(); @@ -7461,7 +7616,7 @@ var TabBarVisibility = { toolbar.collapsed = collapse; let navbar = document.getElementById("nav-bar"); - navbar.setAttribute("tabs-hidden", collapse); + navbar.toggleAttribute("tabs-hidden", collapse); document.getElementById("menu_closeWindow").hidden = collapse; document.l10n.setAttributes( @@ -7593,9 +7748,8 @@ var TabContextMenu = { tabsToMove[0] == visibleTabs[gBrowser._numPinnedTabs]; contextMoveTabToStart.disabled = isFirstTab && allSelectedTabsAdjacent; - if (this.contextTab.hasAttribute("customizemode")) { - document.getElementById("context_openTabInWindow").disabled = true; - } + document.getElementById("context_openTabInWindow").disabled = + this.contextTab.hasAttribute("customizemode"); // Only one of "Duplicate Tab"/"Duplicate Tabs" should be visible. document.getElementById("context_duplicateTab").hidden = @@ -7629,6 +7783,17 @@ var TabContextMenu = { .getElementById("context_closeTab") .setAttribute("data-l10n-args", tabCountInfo); + let closeDuplicateEnabled = Services.prefs.getBoolPref( + "browser.tabs.context.close-duplicate.enabled" + ); + let closeDuplicateTabsItem = document.getElementById( + "context_closeDuplicateTabs" + ); + closeDuplicateTabsItem.hidden = !closeDuplicateEnabled; + closeDuplicateTabsItem.disabled = + !closeDuplicateEnabled || + !gBrowser.getDuplicateTabsToClose(this.contextTab).length; + // Disable "Close Multiple Tabs" if all sub menuitems are disabled document.getElementById("context_closeTabOptions").disabled = closeTabsToTheStartItem.disabled && @@ -7785,7 +7950,7 @@ var TabContextMenu = { } }, - closeContextTabs(event) { + closeContextTabs() { if (this.contextTab.multiselected) { gBrowser.removeMultiSelectedTabs(); } else { diff --git a/browser/base/content/test/about/browser.toml b/browser/base/content/test/about/browser.toml index 98961200a0..2c6dafb4dd 100644 --- a/browser/base/content/test/about/browser.toml +++ b/browser/base/content/test/about/browser.toml @@ -66,7 +66,6 @@ support-files = [ ["browser_aboutNewTab_bookmarksToolbar.js"] ["browser_aboutNewTab_bookmarksToolbarEmpty.js"] -fail-if = ["a11y_checks"] # Bug 1854233 text-link may not be focusable skip-if = ["tsan"] # Bug 1676326, highly frequent on TSan ["browser_aboutNewTab_bookmarksToolbarNewWindow.js"] diff --git a/browser/base/content/test/about/browser_aboutCertError.js b/browser/base/content/test/about/browser_aboutCertError.js index 9af82b807f..5939b026bd 100644 --- a/browser/base/content/test/about/browser_aboutCertError.js +++ b/browser/base/content/test/about/browser_aboutCertError.js @@ -121,7 +121,7 @@ add_task(async function checkReturnToPreviousPage() { "pageshow", true ); - await SpecialPowers.spawn(bc, [useFrame], async function (subFrame) { + await SpecialPowers.spawn(bc, [useFrame], async function () { let returnButton = content.document.getElementById("returnButton"); returnButton.click(); }); @@ -544,7 +544,7 @@ add_task(async function checkViewSource() { certOverrideService.clearValidityOverride("expired.example.com", -1, {}); loaded = BrowserTestUtils.waitForErrorPage(browser); - BrowserReloadSkipCache(); + BrowserCommands.reloadSkipCache(); await loaded; BrowserTestUtils.removeTab(gBrowser.selectedTab); diff --git a/browser/base/content/test/about/browser_aboutNetError_csp_iframe.js b/browser/base/content/test/about/browser_aboutNetError_csp_iframe.js index c8028a4cf4..d245d0cd3c 100644 --- a/browser/base/content/test/about/browser_aboutNetError_csp_iframe.js +++ b/browser/base/content/test/about/browser_aboutNetError_csp_iframe.js @@ -8,6 +8,10 @@ const BLOCKED_PAGE = "http://example.org:8000/browser/browser/base/content/test/about/csp_iframe.sjs"; add_task(async function test_csp() { + await SpecialPowers.pushPrefEnv({ + set: [["security.xfocsp.hideOpenInNewWindow", false]], + }); + let { iframePageTab, blockedPageTab } = await setupPage( "iframe_page_csp.html", BLOCKED_PAGE diff --git a/browser/base/content/test/about/browser_aboutNetError_xfo_iframe.js b/browser/base/content/test/about/browser_aboutNetError_xfo_iframe.js index f5fd240643..2373bd8b50 100644 --- a/browser/base/content/test/about/browser_aboutNetError_xfo_iframe.js +++ b/browser/base/content/test/about/browser_aboutNetError_xfo_iframe.js @@ -8,6 +8,10 @@ const BLOCKED_PAGE = "http://example.org:8000/browser/browser/base/content/test/about/xfo_iframe.sjs"; add_task(async function test_xfo_iframe() { + await SpecialPowers.pushPrefEnv({ + set: [["security.xfocsp.hideOpenInNewWindow", false]], + }); + let { iframePageTab, blockedPageTab } = await setupPage( "iframe_page_xfo.html", BLOCKED_PAGE diff --git a/browser/base/content/test/alerts/browser.toml b/browser/base/content/test/alerts/browser.toml index d0d56f7392..aaca2ba7dc 100644 --- a/browser/base/content/test/alerts/browser.toml +++ b/browser/base/content/test/alerts/browser.toml @@ -19,10 +19,6 @@ skip-if = ["os == 'win'"] # Bug 1411118 https_first_disabled = true skip-if = ["os == 'win'"] # Bug 1411118 -["browser_notification_replace.js"] -https_first_disabled = true -skip-if = ["os == 'win'"] # Bug 1422928 - ["browser_notification_tab_switching.js"] https_first_disabled = true skip-if = ["os == 'win'"] # Bug 1243263 diff --git a/browser/base/content/test/alerts/browser_notification_close.js b/browser/base/content/test/alerts/browser_notification_close.js index 7568f1cc2d..3fd50bed5b 100644 --- a/browser/base/content/test/alerts/browser_notification_close.js +++ b/browser/base/content/test/alerts/browser_notification_close.js @@ -21,17 +21,16 @@ add_task(async function test_notificationClose() { Services.prefs.setBoolPref("alerts.showFavicons", true); await PlacesTestUtils.addVisits(notificationURI); - let faviconURI = await new Promise(resolve => { - let uri = makeURI( - "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC" - ); - PlacesUtils.favicons.setAndFetchFaviconForPage( + let dataURL = makeURI( + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC" + ); + await new Promise(resolve => { + PlacesUtils.favicons.setFaviconForPage( notificationURI, - uri, - true, - PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, - uriResult => resolve(uriResult), - Services.scriptSecurityManager.getSystemPrincipal() + dataURL, + dataURL, + null, + resolve ); }); @@ -67,11 +66,7 @@ add_task(async function test_notificationClose() { "Body text of notification should be present" ); let alertIcon = alertWindow.document.getElementById("alertIcon"); - is( - alertIcon.src, - faviconURI.spec, - "Icon of notification should be present" - ); + is(alertIcon.src, dataURL.spec, "Icon of notification should be present"); let alertCloseButton = alertWindow.document.querySelector(".close-icon"); is(alertCloseButton.localName, "toolbarbutton", "close button found"); diff --git a/browser/base/content/test/alerts/browser_notification_open_settings.js b/browser/base/content/test/alerts/browser_notification_open_settings.js index ed51cd782b..e7f1c28251 100644 --- a/browser/base/content/test/alerts/browser_notification_open_settings.js +++ b/browser/base/content/test/alerts/browser_notification_open_settings.js @@ -14,7 +14,7 @@ add_task(async function test_settingsOpen_observer() { gBrowser, url: "about:robots", }, - async function dummyTabTask(aBrowser) { + async function dummyTabTask() { // Ensure preferences is loaded before removing the tab. let syncPaneLoadedPromise = TestUtils.topicObserved( "sync-pane-loaded", diff --git a/browser/base/content/test/alerts/browser_notification_replace.js b/browser/base/content/test/alerts/browser_notification_replace.js deleted file mode 100644 index 9c72e90ab1..0000000000 --- a/browser/base/content/test/alerts/browser_notification_replace.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; - -let notificationURL = - // eslint-disable-next-line @microsoft/sdl/no-insecure-url - "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html"; - -add_task(async function test_notificationReplace() { - await addNotificationPermission(notificationURL); - - await BrowserTestUtils.withNewTab( - { - gBrowser, - url: notificationURL, - }, - async function dummyTabTask(aBrowser) { - await SpecialPowers.spawn(aBrowser, [], async function () { - let win = content.window.wrappedJSObject; - let notification = win.showNotification1(); - let promiseCloseEvent = ContentTaskUtils.waitForEvent( - notification, - "close" - ); - - let showEvent = await ContentTaskUtils.waitForEvent( - notification, - "show" - ); - Assert.equal( - showEvent.target.body, - "Test body 1", - "Showed tagged notification" - ); - - let newNotification = win.showNotification2(); - let newShowEvent = await ContentTaskUtils.waitForEvent( - newNotification, - "show" - ); - Assert.equal( - newShowEvent.target.body, - "Test body 2", - "Showed new notification with same tag" - ); - - let closeEvent = await promiseCloseEvent; - Assert.equal( - closeEvent.target.body, - "Test body 1", - "Closed previous tagged notification" - ); - - let promiseNewCloseEvent = ContentTaskUtils.waitForEvent( - newNotification, - "close" - ); - newNotification.close(); - let newCloseEvent = await promiseNewCloseEvent; - Assert.equal( - newCloseEvent.target.body, - "Test body 2", - "Closed new notification" - ); - }); - } - ); -}); diff --git a/browser/base/content/test/alerts/head.js b/browser/base/content/test/alerts/head.js index 4be18f6c41..eaf3a2bb74 100644 --- a/browser/base/content/test/alerts/head.js +++ b/browser/base/content/test/alerts/head.js @@ -20,7 +20,7 @@ async function addNotificationPermission(originString) { */ function promiseWindowClosed(window) { return new Promise(function (resolve) { - Services.ww.registerNotification(function observer(subject, topic, data) { + Services.ww.registerNotification(function observer(subject, topic) { if (topic == "domwindowclosed" && subject == window) { Services.ww.unregisterNotification(observer); resolve(); diff --git a/browser/base/content/test/captivePortal/browser_captivePortal_certErrorUI.js b/browser/base/content/test/captivePortal/browser_captivePortal_certErrorUI.js index 6389338a6f..b65a419884 100644 --- a/browser/base/content/test/captivePortal/browser_captivePortal_certErrorUI.js +++ b/browser/base/content/test/captivePortal/browser_captivePortal_certErrorUI.js @@ -117,7 +117,7 @@ add_task(async function testCaptivePortalAdvancedPanel() { await BrowserTestUtils.waitForLocationChange(gBrowser, BAD_CERT_PAGE); info("(waitForLocationChange resolved)"); })(); - await SpecialPowers.spawn(browser, [BAD_CERT_PAGE], async expectedURL => { + await SpecialPowers.spawn(browser, [BAD_CERT_PAGE], async () => { const doc = content.document; let advancedButton = doc.getElementById("advancedButton"); await ContentTaskUtils.waitForCondition( diff --git a/browser/base/content/test/contextMenu/browser.toml b/browser/base/content/test/contextMenu/browser.toml index 3eb6a1d606..c7af1bc437 100644 --- a/browser/base/content/test/contextMenu/browser.toml +++ b/browser/base/content/test/contextMenu/browser.toml @@ -8,7 +8,6 @@ support-files = [ "subtst_contextmenu_xul.xhtml", "ctxmenu-image.png", "../general/head.js", - "../general/video.ogg", "../general/audio.ogg", "../../../../../toolkit/components/pdfjs/test/file_pdfjs_test.pdf", "contextmenu_common.js", @@ -19,6 +18,7 @@ support-files = [ ["browser_bug1798178.js"] ["browser_contextmenu.js"] +support-files = [ "../general/video.webm" ] tags = "fullscreen" skip-if = [ "os == 'linux'", @@ -86,6 +86,8 @@ skip-if = ["os == 'linux' && socketprocess_networking"] ["browser_strip_on_share_link.js"] +["browser_strip_on_share_nested_link.js"] + ["browser_utilityOverlay.js"] https_first_disabled = true skip-if = ["os == 'linux' && socketprocess_networking"] @@ -99,3 +101,5 @@ support-files = [ "test_view_image_inline_svg.html", ] skip-if = ["os == 'linux' && socketprocess_networking"] + +["browser_contextmenu_cross_boundary_selection.js"] diff --git a/browser/base/content/test/contextMenu/browser_contextmenu.js b/browser/base/content/test/contextMenu/browser_contextmenu.js index ebeb4bdb04..d8dc0ab5e0 100644 --- a/browser/base/content/test/contextMenu/browser_contextmenu.js +++ b/browser/base/content/test/contextMenu/browser_contextmenu.js @@ -41,6 +41,10 @@ let hasContainers = Services.prefs.getBoolPref("privacy.userContext.enabled") && ContextualIdentityService.getPublicIdentities().length; +const hasSelectTranslations = + Services.prefs.getBoolPref("browser.translations.enable") && + Services.prefs.getBoolPref("browser.translations.select.enable"); + const example_base = // eslint-disable-next-line @microsoft/sdl/no-insecure-url "http://example.com/browser/browser/base/content/test/contextMenu/"; @@ -112,6 +116,7 @@ add_task(async function test_xul_text_link_label() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]); // Clean up so won't affect HTML element test cases. @@ -137,7 +142,7 @@ add_task(async function test_setup_html() { audio.loop = true; audio.src = "audio.ogg"; video.loop = true; - video.src = "video.ogg"; + video.src = "video.webm"; let awaitPause = ContentTaskUtils.waitForEvent(audio, "pause"); await ContentTaskUtils.waitForCondition( @@ -204,6 +209,7 @@ const kLinkItems = [ true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]; add_task(async function test_link() { @@ -234,6 +240,7 @@ add_task(async function test_mailto() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]); }); @@ -247,6 +254,7 @@ add_task(async function test_tel() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]); }); @@ -273,6 +281,10 @@ add_task(async function test_image() { null, "context-setDesktopBackground", true, + "---", + null, + "context-take-screenshot", + true, ], { onContextMenuShown() { @@ -356,6 +368,10 @@ add_task(async function test_video_ok() { true, "context-sendvideo", true, + "---", + null, + "context-take-screenshot", + true, ]); await SpecialPowers.popPrefEnv(); @@ -404,6 +420,10 @@ add_task(async function test_video_ok() { true, "context-sendvideo", true, + "---", + null, + "context-take-screenshot", + true, ]); await SpecialPowers.popPrefEnv(); @@ -490,6 +510,10 @@ add_task(async function test_video_bad() { true, "context-sendvideo", true, + "---", + null, + "context-take-screenshot", + true, ]); await SpecialPowers.popPrefEnv(); @@ -538,6 +562,10 @@ add_task(async function test_video_bad() { true, "context-sendvideo", true, + "---", + null, + "context-take-screenshot", + true, ]); await SpecialPowers.popPrefEnv(); @@ -588,6 +616,10 @@ add_task(async function test_video_bad2() { false, "context-sendvideo", false, + "---", + null, + "context-take-screenshot", + true, ]); await SpecialPowers.popPrefEnv(); @@ -636,6 +668,10 @@ add_task(async function test_video_bad2() { false, "context-sendvideo", false, + "---", + null, + "context-take-screenshot", + true, ]); await SpecialPowers.popPrefEnv(); @@ -767,6 +803,10 @@ add_task(async function test_video_in_iframe() { true, "---", null, + "context-take-frame-screenshot", + true, + "---", + null, "context-viewframeinfo", true, ]), @@ -846,6 +886,10 @@ add_task(async function test_video_in_iframe() { true, "---", null, + "context-take-frame-screenshot", + true, + "---", + null, "context-viewframeinfo", true, ]), @@ -967,6 +1011,10 @@ add_task(async function test_image_in_iframe() { true, "---", null, + "context-take-frame-screenshot", + true, + "---", + null, "context-viewframeinfo", true, ]), @@ -1336,6 +1384,7 @@ add_task(async function test_select_text() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), "---", null, "context-viewpartialsource-selection", @@ -1369,6 +1418,9 @@ add_task(async function test_select_text_search_service_not_initialized() { null, "context-take-screenshot", true, + ...(hasSelectTranslations + ? ["---", null, "context-translate-selection", true] + : []), "---", null, "context-viewpartialsource-selection", @@ -1423,6 +1475,7 @@ add_task(async function test_select_text_link() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), "---", null, "context-viewpartialsource-selection", @@ -1490,6 +1543,9 @@ add_task(async function test_imagelink() { null, "context-setDesktopBackground", true, + ...(hasSelectTranslations + ? ["---", null, "context-translate-selection", true] + : []), ]); }); @@ -1591,6 +1647,10 @@ add_task(async function test_longdesc() { null, "context-setDesktopBackground", true, + "---", + null, + "context-take-screenshot", + true, ]); }); @@ -1682,6 +1742,7 @@ add_task(async function test_svg_link() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]); await test_contextmenu("#svg-with-link2 > a", [ @@ -1711,6 +1772,7 @@ add_task(async function test_svg_link() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]); await test_contextmenu("#svg-with-link3 > a", [ @@ -1740,6 +1802,7 @@ add_task(async function test_svg_link() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]); }); @@ -1771,6 +1834,7 @@ add_task(async function test_svg_relative_link() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]); await test_contextmenu("#svg-with-relative-link2 > a", [ @@ -1800,6 +1864,7 @@ add_task(async function test_svg_relative_link() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]); await test_contextmenu("#svg-with-relative-link3 > a", [ @@ -1829,6 +1894,7 @@ add_task(async function test_svg_relative_link() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]); }); @@ -1898,6 +1964,7 @@ add_task(async function test_background_image() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]); // Don't show image related context menu commands when there is a selection @@ -1921,6 +1988,7 @@ add_task(async function test_background_image() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), "---", null, "context-viewpartialsource-selection", @@ -1989,6 +2057,7 @@ add_task(async function test_strip_on_share_on_secure_about_page() { true, "context-searchselect-private", true, + ...(hasSelectTranslations ? ["context-translate-selection", true] : []), ]); // Clean up diff --git a/browser/base/content/test/contextMenu/browser_contextmenu_badiframe.js b/browser/base/content/test/contextMenu/browser_contextmenu_badiframe.js index 991a55af70..57d9808f5d 100644 --- a/browser/base/content/test/contextMenu/browser_contextmenu_badiframe.js +++ b/browser/base/content/test/contextMenu/browser_contextmenu_badiframe.js @@ -30,7 +30,7 @@ async function openTestPage() { let pageAndIframesLoaded = BrowserTestUtils.browserLoaded( browser, true /* includeSubFrames */, - url => { + () => { expectedLoads--; return !expectedLoads; }, diff --git a/browser/base/content/test/contextMenu/browser_contextmenu_cross_boundary_selection.js b/browser/base/content/test/contextMenu/browser_contextmenu_cross_boundary_selection.js new file mode 100644 index 0000000000..3137a1e136 --- /dev/null +++ b/browser/base/content/test/contextMenu/browser_contextmenu_cross_boundary_selection.js @@ -0,0 +1,73 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const PAGE = ` + data:text/html, + <div>OuterText<div> + <div id="host"> + <template shadowrootmode="open"> + <span id="innerText">InnerText</span> + </template> + </div> + `; +/** + * Tests that right click on a cross boundary selection shows the context menu + */ +add_task(async function () { + await SpecialPowers.pushPrefEnv({ + set: [["dom.shadowdom.selection_across_boundary.enabled", true]], + }); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: PAGE, + }, + async function (browser) { + let contextMenu = document.getElementById("contentAreaContextMenu"); + let awaitPopupShown = BrowserTestUtils.waitForEvent( + contextMenu, + "popupshown" + ); + + let awaitPopupHidden = BrowserTestUtils.waitForEvent( + contextMenu, + "popuphidden" + ); + + await SpecialPowers.spawn(browser, [], () => { + let host = content.document.getElementById("host"); + content.getSelection().setBaseAndExtent( + content.document.body, + 0, + host.shadowRoot.getElementById("innerText").firstChild, + 3 // Only select the first three characters of the inner text + ); + }); + + await BrowserTestUtils.synthesizeMouseAtCenter( + "div", // Click on the div for OuterText + { + type: "contextmenu", + button: 2, + }, + browser + ); + + await awaitPopupShown; + + const allVisibleMenuItems = Array.from(contextMenu.children) + .filter(elem => { + return !elem.hidden; + }) + .map(elem => elem.id); + + ok( + allVisibleMenuItems.includes("context-copy"), + "copy button should exist" + ); + + contextMenu.hidePopup(); + await awaitPopupHidden; + } + ); +}); diff --git a/browser/base/content/test/contextMenu/browser_contextmenu_save_blocked.js b/browser/base/content/test/contextMenu/browser_contextmenu_save_blocked.js index 062fbeac08..7e6b71e8e4 100644 --- a/browser/base/content/test/contextMenu/browser_contextmenu_save_blocked.js +++ b/browser/base/content/test/contextMenu/browser_contextmenu_save_blocked.js @@ -64,7 +64,7 @@ add_task(async function test_save_link_blocked_by_extension() { setTimeout(resolve, 0); }; - MockFilePicker.showCallback = function (fp) { + MockFilePicker.showCallback = function () { ok(false, "filepicker should never been shown"); setTimeout(resolve, 0); return Ci.nsIFilePicker.returnCancel; diff --git a/browser/base/content/test/contextMenu/browser_strip_on_share_link.js b/browser/base/content/test/contextMenu/browser_strip_on_share_link.js index 435b1aa0ff..144076cfb2 100644 --- a/browser/base/content/test/contextMenu/browser_strip_on_share_link.js +++ b/browser/base/content/test/contextMenu/browser_strip_on_share_link.js @@ -97,6 +97,18 @@ add_task(async function testQueryParamIsNotStrippedForWrongSiteSpecific() { }); }); +// Ensuring clean copy works with magnet links. We don't strip anything but copying the original URI should still work. +add_task(async function testMagneticLinks() { + let originalUrl = "magnet:?xt=urn:btih:somesha1hash"; + let shortenedUrl = "magnet:?xt=urn:btih:somesha1hash"; + await testStripOnShare({ + selectWholeUrl: true, + validUrl: originalUrl, + strippedUrl: shortenedUrl, + useTestList: true, + }); +}); + /** * Opens a new tab, opens the context menu and checks that the strip-on-share menu item is visible. * Checks that the stripped version of the url is copied to the clipboard. diff --git a/browser/base/content/test/contextMenu/browser_strip_on_share_nested_link.js b/browser/base/content/test/contextMenu/browser_strip_on_share_nested_link.js new file mode 100644 index 0000000000..d11649e648 --- /dev/null +++ b/browser/base/content/test/contextMenu/browser_strip_on_share_nested_link.js @@ -0,0 +1,162 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +let listService; + +const TEST_URL = + "https://example.com/browser/browser/base/content/test/general/dummy_page.html"; + +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [["privacy.query_stripping.strip_list", "stripParam"]], + }); + + // Get the list service so we can wait for it to be fully initialized before running tests. + listService = Cc["@mozilla.org/query-stripping-list-service;1"].getService( + Ci.nsIURLQueryStrippingListService + ); + + await listService.testWaitForInit(); +}); + +/* +Tests the strip-on-share feature for in-content links with nested urls +*/ + +// Testing nested stripping with global params +add_task(async function testNestedStrippingGlobalParam() { + let validUrl = + "https://www.example.com/?test=https%3A%2F%2Fwww.example.net%2F%3Futm_ad%3D1234"; + let shortenedUrl = + "https://www.example.com/?test=https%3A%2F%2Fwww.example.net%2F"; + await testStripOnShare({ + originalURI: validUrl, + strippedURI: shortenedUrl, + }); +}); + +// Testing nested stripping with site specific params +add_task(async function testNestedStrippingSiteSpecific() { + let validUrl = + "https://www.example.com/?test=https%3A%2F%2Fwww.example.net%2F%3Ftest_3%3D1234"; + let shortenedUrl = + "https://www.example.com/?test=https%3A%2F%2Fwww.example.net%2F"; + await testStripOnShare({ + originalURI: validUrl, + strippedURI: shortenedUrl, + }); +}); + +// Testing nested stripping with incorrect site specific params +add_task(async function testNoStrippedNestedParam() { + let validUrl = + "https://www.example.com/?test=https%3A%2F%2Fwww.example.com%2F%3Ftest_3%3D1234"; + let shortenedUrl = + "https://www.example.com/?test=https%3A%2F%2Fwww.example.com%2F%3Ftest_3%3D1234"; + await testStripOnShare({ + originalURI: validUrl, + strippedURI: shortenedUrl, + }); +}); + +// Testing order of stripping for nested stripping +add_task(async function testOrderOfStripping() { + let validUrl = + "https://www.example.com/?test_1=https%3A%2F%2Fwww.example.net%2F%3Ftest_3%3D1234"; + let shortenedUrl = "https://www.example.com/"; + await testStripOnShare({ + originalURI: validUrl, + strippedURI: shortenedUrl, + }); +}); + +// Testing correct scoping of site specific params for nested stripping +add_task(async function testMultipleQueryParamsWithNestedStripping() { + let validUrl = + "https://www.example.com/?test_3=1234&test=https%3A%2F%2Fwww.example.net%2F%3Ftest_3%3D1234"; + let shortenedUrl = + "https://www.example.com/?test_3=1234&test=https%3A%2F%2Fwww.example.net%2F"; + await testStripOnShare({ + originalURI: validUrl, + strippedURI: shortenedUrl, + }); +}); + +// Testing functionality with no https pages +add_task(async function testNonHTTPsPages() { + let validUrl = "https://www.example.com/?test_2=1234&test=about%3A%3Aconfig"; + let shortenedUrl = "https://www.example.com/?test=about%3A%3Aconfig"; + await testStripOnShare({ + originalURI: validUrl, + strippedURI: shortenedUrl, + }); +}); + +/** + * Opens a new tab, opens the context menu and checks that the strip-on-share menu item is visible. + * Checks that the stripped version of the url is copied to the clipboard. + * + * @param {string} originalURI - The orginal url before the stripping occurs + * @param {string} strippedURI - The expected url after stripping occurs + */ +async function testStripOnShare({ originalURI, strippedURI }) { + await SpecialPowers.pushPrefEnv({ + set: [ + ["privacy.query_stripping.strip_on_share.enabled", true], + ["privacy.query_stripping.strip_on_share.enableTestMode", true], + ], + }); + + let testJson = { + global: { + queryParams: ["utm_ad"], + topLevelSites: ["*"], + }, + example: { + queryParams: ["test_2", "test_1"], + topLevelSites: ["www.example.com"], + }, + exampleNet: { + queryParams: ["test_3", "test_4"], + topLevelSites: ["www.example.net"], + }, + }; + + await listService.testSetList(testJson); + + await BrowserTestUtils.withNewTab(TEST_URL, async function (browser) { + // Prepare a link + await SpecialPowers.spawn(browser, [originalURI], function (startingURI) { + let link = content.document.createElement("a"); + link.href = startingURI; + link.textContent = "link with query param"; + link.id = "link"; + content.document.body.appendChild(link); + }); + let contextMenu = document.getElementById("contentAreaContextMenu"); + // Open the context menu + let awaitPopupShown = BrowserTestUtils.waitForEvent( + contextMenu, + "popupshown" + ); + await BrowserTestUtils.synthesizeMouseAtCenter( + "#link", + { type: "contextmenu", button: 2 }, + browser + ); + await awaitPopupShown; + let awaitPopupHidden = BrowserTestUtils.waitForEvent( + contextMenu, + "popuphidden" + ); + let stripOnShare = contextMenu.querySelector("#context-stripOnShareLink"); + Assert.ok(BrowserTestUtils.isVisible(stripOnShare), "Menu item is visible"); + // Make sure the stripped link will be copied to the clipboard + await SimpleTest.promiseClipboardChange(strippedURI, () => { + contextMenu.activateItem(stripOnShare); + }); + await awaitPopupHidden; + }); +} diff --git a/browser/base/content/test/contextMenu/contextmenu_common.js b/browser/base/content/test/contextMenu/contextmenu_common.js index ac61aa2a3a..2c9a1967f6 100644 --- a/browser/base/content/test/contextMenu/contextmenu_common.js +++ b/browser/base/content/test/contextMenu/contextmenu_common.js @@ -39,7 +39,7 @@ function closeContextMenu() { contextMenu.hidePopup(); } -function getVisibleMenuItems(aMenu, aData) { +function getVisibleMenuItems(aMenu) { var items = []; var accessKeys = {}; for (var i = 0; i < aMenu.children.length; i++) { @@ -65,7 +65,7 @@ function getVisibleMenuItems(aMenu, aData) { var label = item.getAttribute("label"); ok(label.length, "menuitem " + item.id + " has a label"); if (isGenerated) { - is(key, "", "Generated items shouldn't have an access key"); + is(key, null, "Generated items shouldn't have an access key"); items.push("*" + label); } else if ( item.id.indexOf("spell-check-dictionary-") != 0 && diff --git a/browser/base/content/test/contextMenu/subtst_contextmenu.html b/browser/base/content/test/contextMenu/subtst_contextmenu.html index 2c263fbce4..2facd9fecc 100644 --- a/browser/base/content/test/contextMenu/subtst_contextmenu.html +++ b/browser/base/content/test/contextMenu/subtst_contextmenu.html @@ -26,14 +26,14 @@ document.getElementById("shadow-host-in-link").attachShadow({ mode: "closed" }). <image id="test-svg-image" href="ctxmenu-image.png"/> </svg> <canvas id="test-canvas" width="100" height="100" style="background-color: blue"></canvas> -<video controls id="test-video-ok" src="video.ogg" width="100" height="100" style="background-color: green"></video> +<video controls id="test-video-ok" src="video.webm" width="100" height="100" style="background-color: green"></video> <video id="test-audio-in-video" src="audio.ogg" width="100" height="100" style="background-color: red"></video> <video controls id="test-video-bad" src="bogus.duh" width="100" height="100" style="background-color: orange"></video> <video controls id="test-video-bad2" width="100" height="100" style="background-color: yellow"> <source src="bogus.duh" type="video/durrrr;"> </video> <iframe id="test-iframe" width="98" height="98" style="border: 1px solid black"></iframe> -<iframe id="test-video-in-iframe" src="video.ogg" width="98" height="98" style="border: 1px solid black"></iframe> +<iframe id="test-video-in-iframe" src="video.webm" width="98" height="98" style="border: 1px solid black"></iframe> <iframe id="test-audio-in-iframe" src="audio.ogg" width="98" height="98" style="border: 1px solid black"></iframe> <iframe id="test-image-in-iframe" src="ctxmenu-image.png" width="98" height="98" style="border: 1px solid black"></iframe> <iframe id="test-pdf-viewer-in-frame" src="file_pdfjs_test.pdf" width="100" height="100" style="border: 1px solid black"></iframe> diff --git a/browser/base/content/test/contextMenu/subtst_contextmenu_webext.html b/browser/base/content/test/contextMenu/subtst_contextmenu_webext.html index ac3b5415dd..be45c2ddd0 100644 --- a/browser/base/content/test/contextMenu/subtst_contextmenu_webext.html +++ b/browser/base/content/test/contextMenu/subtst_contextmenu_webext.html @@ -7,6 +7,6 @@ <body> Browser context menu subtest. <a href="moz-extension://foo-bar/tab.html" id="link">Link to an extension resource</a> - <video src="moz-extension://foo-bar/video.ogg" id="video"></video> + <video src="moz-extension://foo-bar/video.webm" id="video"></video> </body> </html> diff --git a/browser/base/content/test/favicons/browser_favicon_change_not_in_document.js b/browser/base/content/test/favicons/browser_favicon_change_not_in_document.js index b8215dcc3e..85240aaa95 100644 --- a/browser/base/content/test/favicons/browser_favicon_change_not_in_document.js +++ b/browser/base/content/test/favicons/browser_favicon_change_not_in_document.js @@ -36,8 +36,8 @@ add_task(async function () { )); let domLinkAddedFired = 0; let domLinkChangedFired = 0; - const linkAddedHandler = event => domLinkAddedFired++; - const linkChangedhandler = event => domLinkChangedFired++; + const linkAddedHandler = () => domLinkAddedFired++; + const linkChangedhandler = () => domLinkChangedFired++; BrowserTestUtils.addContentEventListener( gBrowser.selectedBrowser, "DOMLinkAdded", @@ -80,8 +80,8 @@ add_task(async function () { let domLinkAddedFired = 0; let domLinkChangedFired = 0; - const linkAddedHandler = event => domLinkAddedFired++; - const linkChangedhandler = event => domLinkChangedFired++; + const linkAddedHandler = () => domLinkAddedFired++; + const linkChangedhandler = () => domLinkChangedFired++; BrowserTestUtils.addContentEventListener( browser, "DOMLinkAdded", diff --git a/browser/base/content/test/favicons/browser_favicon_load.js b/browser/base/content/test/favicons/browser_favicon_load.js index 10c2b8f24e..7b78ae494f 100644 --- a/browser/base/content/test/favicons/browser_favicon_load.js +++ b/browser/base/content/test/favicons/browser_favicon_load.js @@ -50,7 +50,7 @@ function FaviconObserver(aPageURI, aFaviconURL, aTailingEnabled) { } FaviconObserver.prototype = { - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { // Make sure that the topic is 'http-on-modify-request'. if (aTopic === "http-on-modify-request") { let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel); diff --git a/browser/base/content/test/favicons/browser_favicon_nostore.js b/browser/base/content/test/favicons/browser_favicon_nostore.js index 3fec666bbe..c12c7a87cd 100644 --- a/browser/base/content/test/favicons/browser_favicon_nostore.js +++ b/browser/base/content/test/favicons/browser_favicon_nostore.js @@ -140,20 +140,17 @@ add_task(async function root_icon_stored() { response.write("<html>A page without icon</html>"); }); - let noStorePromise = TestUtils.topicObserved( - "http-on-stop-request", - (s, t, d) => { - let chan = s.QueryInterface(Ci.nsIHttpChannel); - return chan?.URI.spec == "http://www.nostore.com/favicon.ico"; - } - ).then(([chan]) => chan.isNoStoreResponse()); + let noStorePromise = TestUtils.topicObserved("http-on-stop-request", s => { + let chan = s.QueryInterface(Ci.nsIHttpChannel); + return chan?.URI.spec == "http://www.nostore.com/favicon.ico"; + }).then(([chan]) => chan.isNoStoreResponse()); await BrowserTestUtils.withNewTab( { gBrowser, url: "http://www.nostore.com/page", }, - async function (browser) { + async function () { await TestUtils.waitForCondition(async () => { let uri = await new Promise(resolve => PlacesUtils.favicons.getFaviconURLForPage( diff --git a/browser/base/content/test/favicons/browser_favicon_referer.js b/browser/base/content/test/favicons/browser_favicon_referer.js index ed332e7413..9fee9771b0 100644 --- a/browser/base/content/test/favicons/browser_favicon_referer.js +++ b/browser/base/content/test/favicons/browser_favicon_referer.js @@ -14,7 +14,7 @@ add_task(async function test_check_referrer_for_discovered_favicon() { async browser => { let referrerPromise = TestUtils.topicObserved( "http-on-modify-request", - (s, t, d) => { + s => { let chan = s.QueryInterface(Ci.nsIHttpChannel); return chan.URI.spec == "http://mochi.test:8888/favicon.ico"; } @@ -42,7 +42,7 @@ add_task( async browser => { let referrerPromise = TestUtils.topicObserved( "http-on-modify-request", - (s, t, d) => { + s => { let chan = s.QueryInterface(Ci.nsIHttpChannel); return chan.URI.spec == `${FOLDER}file_favicon.png`; } diff --git a/browser/base/content/test/favicons/browser_missing_favicon.js b/browser/base/content/test/favicons/browser_missing_favicon.js index f619425909..fd60d362b4 100644 --- a/browser/base/content/test/favicons/browser_missing_favicon.js +++ b/browser/base/content/test/favicons/browser_missing_favicon.js @@ -28,7 +28,7 @@ add_task(async () => { is(browser.mIconURL, null, "Should have blanked the icon."); is( gBrowser.getTabForBrowser(browser).getAttribute("image"), - "", + null, "Should have blanked the tab icon." ); } diff --git a/browser/base/content/test/forms/browser.toml b/browser/base/content/test/forms/browser.toml index 95b666369e..c7cabfa1b0 100644 --- a/browser/base/content/test/forms/browser.toml +++ b/browser/base/content/test/forms/browser.toml @@ -14,6 +14,8 @@ skip-if = ["os == 'linux'"] # Bug 1329991 - test fails intermittently on Linux b ["browser_selectpopup_dir.js"] +["browser_selectpopup_focus.js"] + ["browser_selectpopup_hr.js"] ["browser_selectpopup_large.js"] diff --git a/browser/base/content/test/forms/browser_selectpopup.js b/browser/base/content/test/forms/browser_selectpopup.js index abcdee486f..72112974c2 100644 --- a/browser/base/content/test/forms/browser_selectpopup.js +++ b/browser/base/content/test/forms/browser_selectpopup.js @@ -186,7 +186,7 @@ async function doSelectTests(contentType, content) { ); // Backspace should not go back - let handleKeyPress = function (event) { + let handleKeyPress = function () { ok(false, "Should not get keypress event"); }; window.addEventListener("keypress", handleKeyPress); @@ -708,7 +708,7 @@ add_task(async function test_mousemove_correcttarget() { window, "sizemodechange" ); - BrowserFullScreen(); + BrowserCommands.fullScreen(); await sizeModeChanged; await popupHiddenPromise; } diff --git a/browser/base/content/test/forms/browser_selectpopup_colors.js b/browser/base/content/test/forms/browser_selectpopup_colors.js index 63cece0ce5..f4b3e8a516 100644 --- a/browser/base/content/test/forms/browser_selectpopup_colors.js +++ b/browser/base/content/test/forms/browser_selectpopup_colors.js @@ -255,7 +255,7 @@ function rgbaToString(parsedColor) { return `rgba(${r}, ${g}, ${b}, ${a})`; } -function testOptionColors(test, index, item, menulist) { +function testOptionColors(test, index, item) { // The label contains a JSON string of the expected colors for // `color` and `background-color`. let expected = JSON.parse(item.label); diff --git a/browser/base/content/test/forms/browser_selectpopup_dir.js b/browser/base/content/test/forms/browser_selectpopup_dir.js index aaf4a61fc2..a0ad90d909 100644 --- a/browser/base/content/test/forms/browser_selectpopup_dir.js +++ b/browser/base/content/test/forms/browser_selectpopup_dir.js @@ -13,7 +13,7 @@ add_task(async function () { gBrowser, url, }, - async function (browser) { + async function () { let popup = await openSelectPopup("click"); is(popup.style.direction, "rtl", "Should be the right dir"); } diff --git a/browser/base/content/test/forms/browser_selectpopup_focus.js b/browser/base/content/test/forms/browser_selectpopup_focus.js new file mode 100644 index 0000000000..24ff947c50 --- /dev/null +++ b/browser/base/content/test/forms/browser_selectpopup_focus.js @@ -0,0 +1,38 @@ +// Empty select to make sure that we click on the menulist button. +const PAGE = ` +<!doctype html> +<select style="padding: 0"> + <option></option> +</select> +`; + +function tick() { + return new Promise(r => + requestAnimationFrame(() => requestAnimationFrame(r)) + ); +} + +add_task(async function () { + const url = "data:text/html," + encodeURI(PAGE); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + }, + async function (browser) { + await openSelectPopup("click"); + await SpecialPowers.spawn(browser, [], () => { + is( + content.document.activeElement, + content.document.querySelector("select"), + "Select is the active element" + ); + ok( + content.document.querySelector("select").matches(":focus"), + "Select matches :focus" + ); + }); + await hideSelectPopup(); + } + ); +}); diff --git a/browser/base/content/test/forms/browser_selectpopup_large.js b/browser/base/content/test/forms/browser_selectpopup_large.js index 722e0d9588..40f6d1b160 100644 --- a/browser/base/content/test/forms/browser_selectpopup_large.js +++ b/browser/base/content/test/forms/browser_selectpopup_large.js @@ -297,7 +297,7 @@ add_task(async function test_large_popup_in_small_window() { newWin, "resize", false, - e => { + () => { info(`Got resize event (innerHeight: ${newWin.innerHeight})`); return newWin.innerHeight <= 450; } diff --git a/browser/base/content/test/forms/browser_selectpopup_minFontSize.js b/browser/base/content/test/forms/browser_selectpopup_minFontSize.js index d240c2d2d0..522ed1ffcf 100644 --- a/browser/base/content/test/forms/browser_selectpopup_minFontSize.js +++ b/browser/base/content/test/forms/browser_selectpopup_minFontSize.js @@ -20,7 +20,7 @@ add_task(async function () { gBrowser, url, }, - async function (browser) { + async function () { let popup = await openSelectPopup("click"); let menuitems = popup.querySelectorAll("menuitem"); is( diff --git a/browser/base/content/test/forms/browser_selectpopup_text_transform.js b/browser/base/content/test/forms/browser_selectpopup_text_transform.js index 671f39e2a6..04da532ddc 100644 --- a/browser/base/content/test/forms/browser_selectpopup_text_transform.js +++ b/browser/base/content/test/forms/browser_selectpopup_text_transform.js @@ -16,7 +16,7 @@ add_task(async function () { gBrowser, url, }, - async function (browser) { + async function () { let popup = await openSelectPopup("click"); let menuitems = popup.querySelectorAll("menuitem"); is(menuitems[0].textContent, "abc", "Option text should be lowercase"); diff --git a/browser/base/content/test/forms/browser_selectpopup_user_input.js b/browser/base/content/test/forms/browser_selectpopup_user_input.js index b3cdeaf7e6..028ceadf9a 100644 --- a/browser/base/content/test/forms/browser_selectpopup_user_input.js +++ b/browser/base/content/test/forms/browser_selectpopup_user_input.js @@ -71,7 +71,7 @@ async function testHandlingUserInputOnChange(aTriggerFn) { // This test checks if the change/click event is considered as user input event. add_task(async function test_handling_user_input_key() { - return testHandlingUserInputOnChange(async function (popup) { + return testHandlingUserInputOnChange(async function () { EventUtils.synthesizeKey("KEY_ArrowDown"); await hideSelectPopup(); }); diff --git a/browser/base/content/test/forms/browser_selectpopup_width.js b/browser/base/content/test/forms/browser_selectpopup_width.js index d8f748fb18..0df0fd24ee 100644 --- a/browser/base/content/test/forms/browser_selectpopup_width.js +++ b/browser/base/content/test/forms/browser_selectpopup_width.js @@ -19,7 +19,7 @@ add_task(async function () { gBrowser, url, }, - async function (browser) { + async function () { let popup = await openSelectPopup("click"); let arrowSB = popup.shadowRoot.querySelector(".menupopup-arrowscrollbox"); is( diff --git a/browser/base/content/test/forms/browser_selectpopup_xhtml.js b/browser/base/content/test/forms/browser_selectpopup_xhtml.js index 091649be89..27597eb5ac 100644 --- a/browser/base/content/test/forms/browser_selectpopup_xhtml.js +++ b/browser/base/content/test/forms/browser_selectpopup_xhtml.js @@ -21,7 +21,7 @@ add_task(async function () { gBrowser, url, }, - async function (browser) { + async function () { let popup = await openSelectPopup("click"); let menuitems = popup.querySelectorAll("menuitem"); is(menuitems.length, 2, "Should've properly detected two menu items"); diff --git a/browser/base/content/test/fullscreen/browser_fullscreen_context_menu.js b/browser/base/content/test/fullscreen/browser_fullscreen_context_menu.js index 9d9891acd2..3bca1a205d 100644 --- a/browser/base/content/test/fullscreen/browser_fullscreen_context_menu.js +++ b/browser/base/content/test/fullscreen/browser_fullscreen_context_menu.js @@ -51,7 +51,7 @@ async function testContextMenu() { window, "sizemodechange", false, - e => window.fullScreen + () => window.fullScreen ), BrowserTestUtils.waitForPopupEvent(contextMenu, "hidden"), ]); @@ -96,7 +96,7 @@ async function testContextMenu() { window, "sizemodechange", false, - e => !window.fullScreen + () => !window.fullScreen ), BrowserTestUtils.waitForPopupEvent(contextMenu2, "hidden"), ]); diff --git a/browser/base/content/test/fullscreen/browser_fullscreen_window_focus.js b/browser/base/content/test/fullscreen/browser_fullscreen_window_focus.js index 5dd71e1a92..6e471e8124 100644 --- a/browser/base/content/test/fullscreen/browser_fullscreen_window_focus.js +++ b/browser/base/content/test/fullscreen/browser_fullscreen_window_focus.js @@ -74,7 +74,7 @@ async function testWindowElementFocus(isPopup) { false, async () => { info("Calling element.focus() on popup"); - await ContentTask.spawn(tab.linkedBrowser, {}, async args => { + await ContentTask.spawn(tab.linkedBrowser, {}, async () => { await content.wrappedJSObject.sendMessage( content.wrappedJSObject.openedWindow, "elementfocus" diff --git a/browser/base/content/test/fullscreen/head.js b/browser/base/content/test/fullscreen/head.js index 4d5543461e..0d56c5a7c9 100644 --- a/browser/base/content/test/fullscreen/head.js +++ b/browser/base/content/test/fullscreen/head.js @@ -5,7 +5,7 @@ function waitForFullScreenState(browser, state, actionAfterFSEvent) { return new Promise(resolve => { let eventReceived = false; - let observe = (subject, topic, data) => { + let observe = () => { if (!eventReceived) { return; } diff --git a/browser/base/content/test/general/browser.toml b/browser/base/content/test/general/browser.toml index 6928ba2d4b..31d519d550 100644 --- a/browser/base/content/test/general/browser.toml +++ b/browser/base/content/test/general/browser.toml @@ -37,10 +37,6 @@ support-files = [ "title_test.svg", "unknownContentType_file.pif", "unknownContentType_file.pif^headers^", - "video.ogg", - "web_video.html", - "web_video1.ogv", - "web_video1.ogv^headers^", "!/image/test/mochitest/blue.png", "!/toolkit/content/tests/browser/common/mockTransfer.js", ] @@ -211,6 +207,7 @@ support-files = [ "dummy.ics", "dummy.ics^headers^", "redirect_download.sjs", + "video.webm", ] # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD. @@ -435,9 +432,19 @@ skip-if = [ "os == 'win' && debug", "os =='linux'", #Bug 1212419 ] +support-files = [ + "web_video.html", + "web_video1.webm", + "web_video1.webm^headers^", +] # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD. ["browser_save_video_frame.js"] +support-files = [ + "web_video.html", + "web_video1.webm", + "web_video1.webm^headers^", +] # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD. ["browser_selectTabAtIndex.js"] diff --git a/browser/base/content/test/general/browser_accesskeys.js b/browser/base/content/test/general/browser_accesskeys.js index 0809553404..965da8d9df 100644 --- a/browser/base/content/test/general/browser_accesskeys.js +++ b/browser/base/content/test/general/browser_accesskeys.js @@ -122,7 +122,7 @@ add_task(async function () { function performAccessKey(browser, key) { return new Promise(resolve => { let removeFocus, removeKeyDown, removeKeyUp; - function callback(eventName, result) { + function callback() { removeFocus(); removeKeyUp(); removeKeyDown(); @@ -190,7 +190,7 @@ function performAccessKey(browser, key) { } // This version is used when a chrome element is expected to be found for an accesskey. -async function performAccessKeyForChrome(key, inChild) { +async function performAccessKeyForChrome(key) { let waitFocusChangePromise = BrowserTestUtils.waitForEvent( document, "focus", diff --git a/browser/base/content/test/general/browser_alltabslistener.js b/browser/base/content/test/general/browser_alltabslistener.js index c7829d16fe..fc950d6ce5 100644 --- a/browser/base/content/test/general/browser_alltabslistener.js +++ b/browser/base/content/test/general/browser_alltabslistener.js @@ -7,16 +7,9 @@ function getOriginalURL(request) { } var gFrontProgressListener = { - onProgressChange( - aWebProgress, - aRequest, - aCurSelfProgress, - aMaxSelfProgress, - aCurTotalProgress, - aMaxTotalProgress - ) {}, + onProgressChange() {}, - onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) { + onStateChange(aWebProgress, aRequest, aStateFlags) { var url = getOriginalURL(aRequest); if (url == "about:blank") { return; @@ -28,7 +21,7 @@ var gFrontProgressListener = { assertCorrectBrowserAndEventOrderForFront(state); }, - onLocationChange(aWebProgress, aRequest, aLocationURI, aFlags) { + onLocationChange(aWebProgress, aRequest, aLocationURI) { var url = getOriginalURL(aRequest); if (url == "about:blank") { return; @@ -64,7 +57,7 @@ function assertCorrectBrowserAndEventOrderForFront(aEventName) { } var gAllProgressListener = { - onStateChange(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) { + onStateChange(aBrowser, aWebProgress, aRequest, aStateFlags) { var url = getOriginalURL(aRequest); if (url == "about:blank") { // ignore initial about blank diff --git a/browser/base/content/test/general/browser_beforeunload_duplicate_dialogs.js b/browser/base/content/test/general/browser_beforeunload_duplicate_dialogs.js index 8eb07a863a..81ed5a1040 100644 --- a/browser/base/content/test/general/browser_beforeunload_duplicate_dialogs.js +++ b/browser/base/content/test/general/browser_beforeunload_duplicate_dialogs.js @@ -57,7 +57,7 @@ add_task(async function closeWindowWithMultipleTabsIncludingOneBeforeUnload() { ); let windowClosedPromise = BrowserTestUtils.domWindowClosed(newWin); expectingDialog = true; - newWin.BrowserTryToCloseWindow(); + newWin.BrowserCommands.tryToCloseWindow(); await windowClosedPromise; ok(!expectingDialog, "There should have been a dialog."); ok(newWin.closed, "Window should be closed."); @@ -71,7 +71,7 @@ add_task(async function closeWindoWithSingleTabTwice() { let windowClosedPromise = BrowserTestUtils.domWindowClosed(newWin); expectingDialog = true; wantToClose = false; - let firstDialogShownPromise = new Promise((resolve, reject) => { + let firstDialogShownPromise = new Promise(resolve => { resolveDialogPromise = resolve; }); firstTab.closeButton.click(); diff --git a/browser/base/content/test/general/browser_bug356571.js b/browser/base/content/test/general/browser_bug356571.js index aa3569c93d..69b45e040d 100644 --- a/browser/base/content/test/general/browser_bug356571.js +++ b/browser/base/content/test/general/browser_bug356571.js @@ -45,7 +45,7 @@ const kURIs = ["bad://www.mozilla.org/", kDummyPage, kDummyPage]; var gProgressListener = { _runCount: 0, - onStateChange(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) { + onStateChange(aBrowser, aWebProgress, aRequest, aStateFlags) { if ((aStateFlags & kCompleteState) == kCompleteState) { if (++this._runCount != kURIs.length) { return; diff --git a/browser/base/content/test/general/browser_bug417483.js b/browser/base/content/test/general/browser_bug417483.js index 68e2e99511..28da91eea1 100644 --- a/browser/base/content/test/general/browser_bug417483.js +++ b/browser/base/content/test/general/browser_bug417483.js @@ -8,7 +8,7 @@ add_task(async function () { BrowserTestUtils.startLoadingURIString(gBrowser, htmlContent); await loadedPromise; - await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function (arg) { + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { let frame = content.frames[0]; let sel = frame.getSelection(); let range = frame.document.createRange(); diff --git a/browser/base/content/test/general/browser_bug537013.js b/browser/base/content/test/general/browser_bug537013.js index 5c871a759c..58bcec9754 100644 --- a/browser/base/content/test/general/browser_bug537013.js +++ b/browser/base/content/test/general/browser_bug537013.js @@ -15,7 +15,7 @@ var HasFindClipboard = Services.clipboard.isClipboardTypeSupported( Services.clipboard.kFindClipboard ); -function addTabWithText(aText, aCallback) { +function addTabWithText(aText) { let newTab = BrowserTestUtils.addTab( gBrowser, "data:text/html;charset=utf-8,<h1 id='h1'>" + aText + "</h1>" diff --git a/browser/base/content/test/general/browser_bug565575.js b/browser/base/content/test/general/browser_bug565575.js index 6176c537e3..b974b17205 100644 --- a/browser/base/content/test/general/browser_bug565575.js +++ b/browser/base/content/test/general/browser_bug565575.js @@ -3,7 +3,7 @@ add_task(async function () { await BrowserTestUtils.openNewForegroundTab( gBrowser, - () => BrowserOpenTab(), + () => BrowserCommands.openTab(), false ); ok(gURLBar.focused, "location bar is focused for a new tab"); diff --git a/browser/base/content/test/general/browser_bug567306.js b/browser/base/content/test/general/browser_bug567306.js index 3d3e47e17d..24280371d8 100644 --- a/browser/base/content/test/general/browser_bug567306.js +++ b/browser/base/content/test/general/browser_bug567306.js @@ -10,7 +10,7 @@ add_task(async function () { let newwindow = await BrowserTestUtils.openNewBrowserWindow(); let selectedBrowser = newwindow.gBrowser.selectedBrowser; - await new Promise((resolve, reject) => { + await new Promise(resolve => { BrowserTestUtils.waitForContentEvent( selectedBrowser, "pageshow", diff --git a/browser/base/content/test/general/browser_bug609700.js b/browser/base/content/test/general/browser_bug609700.js index 8195eba4ec..615b63c3d8 100644 --- a/browser/base/content/test/general/browser_bug609700.js +++ b/browser/base/content/test/general/browser_bug609700.js @@ -1,11 +1,7 @@ function test() { waitForExplicitFinish(); - Services.ww.registerNotification(function notification( - aSubject, - aTopic, - aData - ) { + Services.ww.registerNotification(function notification(aSubject, aTopic) { if (aTopic == "domwindowopened") { Services.ww.unregisterNotification(notification); diff --git a/browser/base/content/test/general/browser_bug623893.js b/browser/base/content/test/general/browser_bug623893.js index 79cd10c591..0f742a8e8e 100644 --- a/browser/base/content/test/general/browser_bug623893.js +++ b/browser/base/content/test/general/browser_bug623893.js @@ -38,7 +38,7 @@ async function promiseGetIndex(browser) { return shistory.index; } -let duplicate = async function (delta, msg, cb) { +let duplicate = async function (delta, msg) { var startIndex = await promiseGetIndex(gBrowser.selectedBrowser); duplicateTabIn(gBrowser.selectedTab, "tab", delta); diff --git a/browser/base/content/test/general/browser_bug676619.js b/browser/base/content/test/general/browser_bug676619.js index 80bbce8cb0..90dd8f4f7c 100644 --- a/browser/base/content/test/general/browser_bug676619.js +++ b/browser/base/content/test/general/browser_bug676619.js @@ -22,7 +22,7 @@ function waitForNewWindow() { var domwindow = aXULWindow.docShell.domWindow; domwindow.addEventListener("load", downloadOnLoad, true); }, - onCloseWindow: aXULWindow => {}, + onCloseWindow: () => {}, }; Services.wm.addListener(listener); @@ -97,7 +97,7 @@ async function testLink(link, name) { } // Cross-origin URL does not trigger a download -async function testLocation(link, url) { +async function testLocation(link) { let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser); SpecialPowers.spawn(gBrowser.selectedBrowser, [link], contentLink => { @@ -116,8 +116,8 @@ async function runTest(url) { await BrowserTestUtils.browserLoaded(browser); await testLink("link1", "test.txt"); - await testLink("link2", "video.ogg"); - await testLink("link3", "just some video.ogg"); + await testLink("link2", "video.webm"); + await testLink("link3", "just some video.webm"); await testLink("link4", "with-target.txt"); await testLink("link5", "javascript.html"); await testLink("link6", "test.blob"); @@ -132,8 +132,8 @@ async function runTest(url) { // Check that we enforce the correct extension if the website's // is bogus or missing. These extensions can differ slightly (ogx vs ogg, // htm vs html) on different OSes. - let oggExtension = getMIMEInfoForType("application/ogg").primaryExtension; - await testLink("link13", "no file extension." + oggExtension); + let webmExtension = getMIMEInfoForType("video/webm").primaryExtension; + await testLink("link13", "no file extension." + webmExtension); // See https://bugzilla.mozilla.org/show_bug.cgi?id=1690051#c8 if (AppConstants.platform != "win") { diff --git a/browser/base/content/test/general/browser_bug734076.js b/browser/base/content/test/general/browser_bug734076.js index bd86f8e2b3..e9bec6834e 100644 --- a/browser/base/content/test/general/browser_bug734076.js +++ b/browser/base/content/test/general/browser_bug734076.js @@ -36,7 +36,7 @@ add_task(async function () { ); }, verify(browser) { - return SpecialPowers.spawn(browser, [], async function (arg) { + return SpecialPowers.spawn(browser, [], async function () { Assert.equal( content.document.body.textContent, "", @@ -67,7 +67,7 @@ add_task(async function () { ); }, verify(browser) { - return SpecialPowers.spawn(browser, [], async function (arg) { + return SpecialPowers.spawn(browser, [], async function () { Assert.equal( content.document.body.textContent, "", @@ -105,7 +105,7 @@ add_task(async function () { ); }, verify(browser) { - return SpecialPowers.spawn(browser, [], async function (arg) { + return SpecialPowers.spawn(browser, [], async function () { Assert.equal( content.document.body.textContent, "", diff --git a/browser/base/content/test/general/browser_bug763468_perwindowpb.js b/browser/base/content/test/general/browser_bug763468_perwindowpb.js index bed03561ca..05a7f90550 100644 --- a/browser/base/content/test/general/browser_bug763468_perwindowpb.js +++ b/browser/base/content/test/general/browser_bug763468_perwindowpb.js @@ -44,7 +44,7 @@ add_task(async function testPBNewTab() { async function openNewTab(aWindow, aExpectedURL) { // Open a new tab - aWindow.BrowserOpenTab(); + aWindow.BrowserCommands.openTab(); let browser = aWindow.gBrowser.selectedBrowser; // We're already loaded. diff --git a/browser/base/content/test/general/browser_bug767836_perwindowpb.js b/browser/base/content/test/general/browser_bug767836_perwindowpb.js index 7fcc6ad565..e237f1216d 100644 --- a/browser/base/content/test/general/browser_bug767836_perwindowpb.js +++ b/browser/base/content/test/general/browser_bug767836_perwindowpb.js @@ -59,7 +59,7 @@ add_task(async function test_newTabService() { async function openNewTab(aWindow, aExpectedURL) { // Open a new tab - aWindow.BrowserOpenTab(); + aWindow.BrowserCommands.openTab(); let browser = aWindow.gBrowser.selectedBrowser; // We're already loaded. diff --git a/browser/base/content/test/general/browser_bug817947.js b/browser/base/content/test/general/browser_bug817947.js index ea3c39222e..f83e07a9af 100644 --- a/browser/base/content/test/general/browser_bug817947.js +++ b/browser/base/content/test/general/browser_bug817947.js @@ -32,7 +32,7 @@ add_task(async () => { win.close(); }); -async function preparePendingTab(aCallback) { +async function preparePendingTab() { let tab = BrowserTestUtils.addTab(gBrowser, URL); await BrowserTestUtils.browserLoaded(tab.linkedBrowser); diff --git a/browser/base/content/test/general/browser_clipboard.js b/browser/base/content/test/general/browser_clipboard.js index a4c823969f..7820c4ec89 100644 --- a/browser/base/content/test/general/browser_clipboard.js +++ b/browser/base/content/test/general/browser_clipboard.js @@ -68,7 +68,7 @@ add_task(async function () { let selection = content.document.getSelection(); selection.modify("move", "right", "line"); - return new Promise((resolve, reject) => { + return new Promise(resolve => { content.addEventListener( "paste", event => { @@ -130,7 +130,7 @@ add_task(async function () { selection.modify("extend", "left", "word"); selection.modify("extend", "left", "character"); - return new Promise((resolve, reject) => { + return new Promise(resolve => { content.addEventListener( "cut", event => { @@ -157,7 +157,7 @@ add_task(async function () { let selection = content.document.getSelection(); selection.modify("move", "left", "line"); - return new Promise((resolve, reject) => { + return new Promise(resolve => { content.addEventListener( "paste", event => { diff --git a/browser/base/content/test/general/browser_clipboard_pastefile.js b/browser/base/content/test/general/browser_clipboard_pastefile.js index f034883ef2..6ef3edf30e 100644 --- a/browser/base/content/test/general/browser_clipboard_pastefile.js +++ b/browser/base/content/test/general/browser_clipboard_pastefile.js @@ -50,7 +50,7 @@ add_task(async function () { ); let browser = tab.linkedBrowser; - let resultPromise = SpecialPowers.spawn(browser, [], function (arg) { + let resultPromise = SpecialPowers.spawn(browser, [], function () { return new Promise(resolve => { content.document.addEventListener("testresult", event => { resolve(event.detail.result); @@ -73,7 +73,7 @@ add_task(async function () { document.documentElement.appendChild(input); input.focus(); - await new Promise((resolve, reject) => { + await new Promise(resolve => { input.addEventListener( "paste", function (event) { diff --git a/browser/base/content/test/general/browser_documentnavigation.js b/browser/base/content/test/general/browser_documentnavigation.js index 880db6110f..b68e6ec3f0 100644 --- a/browser/base/content/test/general/browser_documentnavigation.js +++ b/browser/base/content/test/general/browser_documentnavigation.js @@ -229,7 +229,7 @@ add_task(async function () { let sidebar = document.getElementById("sidebar"); let loadPromise = BrowserTestUtils.waitForEvent(sidebar, "load", true); - SidebarUI.toggle("viewBookmarksSidebar"); + SidebarController.toggle("viewBookmarksSidebar"); await loadPromise; gURLBar.focus(); @@ -278,7 +278,7 @@ add_task(async function () { "back focus with sidebar urlbar" ); - SidebarUI.toggle("viewBookmarksSidebar"); + SidebarController.toggle("viewBookmarksSidebar"); }); // Navigate when the downloads panel is open diff --git a/browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js b/browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js index c96fa6cf7b..f44620c29e 100644 --- a/browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js +++ b/browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js @@ -149,7 +149,7 @@ add_task(async function () { gBrowser.selectedBrowser, FS_CHANGE_SIZE ); - executeSoon(() => BrowserFullScreen()); + executeSoon(() => BrowserCommands.fullScreen()); await fullscreenPromise; } }); @@ -195,7 +195,7 @@ add_task(async function () { // dispatched synchronously, which would cause the event listener // miss that event and wait infinitely. fullscreenPromise = waitForFullscreenChanges(browser, FS_CHANGE_SIZE); - executeSoon(() => BrowserFullScreen()); + executeSoon(() => BrowserCommands.fullScreen()); contentStates = await fullscreenPromise; checkState({ inDOMFullscreen: false, inFullscreen: true }, contentStates); @@ -228,7 +228,7 @@ add_task(async function () { if (window.fullScreen) { info("> Cleanup"); fullscreenPromise = waitForFullscreenChanges(browser, FS_CHANGE_SIZE); - executeSoon(() => BrowserFullScreen()); + executeSoon(() => BrowserCommands.fullScreen()); await fullscreenPromise; } } diff --git a/browser/base/content/test/general/browser_double_close_tab.js b/browser/base/content/test/general/browser_double_close_tab.js index f5f2f1b6c7..6beea0f42b 100644 --- a/browser/base/content/test/general/browser_double_close_tab.js +++ b/browser/base/content/test/general/browser_double_close_tab.js @@ -18,7 +18,7 @@ function waitForDialog(callback) { function waitForDialogDestroyed(node, callback) { // Now listen for the dialog going away again... - let observer = new MutationObserver(function (muts) { + let observer = new MutationObserver(function () { if (!node.parentNode) { ok(true, "Dialog is gone"); done(); diff --git a/browser/base/content/test/general/browser_focusonkeydown.js b/browser/base/content/test/general/browser_focusonkeydown.js index 9cf1f113f5..53919bc1b3 100644 --- a/browser/base/content/test/general/browser_focusonkeydown.js +++ b/browser/base/content/test/general/browser_focusonkeydown.js @@ -20,7 +20,7 @@ add_task(async function () { gURLBar.addEventListener( "keydown", - function (event) { + function () { gBrowser.selectedBrowser.focus(); }, { capture: true, once: true } diff --git a/browser/base/content/test/general/browser_fullscreen-window-open.js b/browser/base/content/test/general/browser_fullscreen-window-open.js index 2b21e34e92..be1d2ca3a3 100644 --- a/browser/base/content/test/general/browser_fullscreen-window-open.js +++ b/browser/base/content/test/general/browser_fullscreen-window-open.js @@ -26,14 +26,14 @@ async function test() { await promiseTabLoadEvent(newBrowser.selectedTab, gHttpTestRoot + TEST_FILE); // Enter browser fullscreen mode. - newWin.BrowserFullScreen(); + newWin.BrowserCommands.fullScreen(); runNextTest(); } registerCleanupFunction(async function () { // Exit browser fullscreen mode. - newWin.BrowserFullScreen(); + newWin.BrowserCommands.fullScreen(); await BrowserTestUtils.closeWindow(newWin); @@ -336,7 +336,7 @@ WindowListener.prototype = { Services.wm.removeListener(this); let domwindow = aXULWindow.docShell.domWindow; - let onLoad = aEvent => { + let onLoad = () => { is( domwindow.document.location.href, this.test_url, @@ -361,6 +361,6 @@ WindowListener.prototype = { }; domwindow.addEventListener("load", onLoad, true); }, - onCloseWindow(aXULWindow) {}, + onCloseWindow() {}, QueryInterface: ChromeUtils.generateQI(["nsIWindowMediatorListener"]), }; diff --git a/browser/base/content/test/general/browser_invalid_uri_back_forward_manipulation.js b/browser/base/content/test/general/browser_invalid_uri_back_forward_manipulation.js index 1624a1514d..fae1130685 100644 --- a/browser/base/content/test/general/browser_invalid_uri_back_forward_manipulation.js +++ b/browser/base/content/test/general/browser_invalid_uri_back_forward_manipulation.js @@ -33,7 +33,7 @@ add_task(async function checkBackFromInvalidURI() { false, // Be paranoid we *are* actually seeing this other page load, not some kind of race // for if/when we do start firing pageshow for the error page... - function (e) { + function () { return gBrowser.currentURI.spec == "about:robots"; } ); diff --git a/browser/base/content/test/general/browser_newWindowDrop.js b/browser/base/content/test/general/browser_newWindowDrop.js index 3e41b0d6ac..445999befd 100644 --- a/browser/base/content/test/general/browser_newWindowDrop.js +++ b/browser/base/content/test/general/browser_newWindowDrop.js @@ -184,7 +184,7 @@ function dropText(text, expectedURLs, ignoreFirstWindow = false) { ); } -async function drop(dragData, expectedURLs, ignoreFirstWindow = false) { +async function drop(dragData, expectedURLs) { let dragDataString = JSON.stringify(dragData); info( `Starting test for dragData:${dragDataString}; expectedURLs.length:${expectedURLs.length}` diff --git a/browser/base/content/test/general/browser_plainTextLinks.js b/browser/base/content/test/general/browser_plainTextLinks.js index 706f21387c..44c9b8422b 100644 --- a/browser/base/content/test/general/browser_plainTextLinks.js +++ b/browser/base/content/test/general/browser_plainTextLinks.js @@ -19,7 +19,7 @@ add_task(async function () { await SimpleTest.promiseFocus(gBrowser.selectedBrowser); // Initial setup of the content area. - await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function (arg) { + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { let doc = content.document; let range = doc.createRange(); let selection = content.getSelection(); diff --git a/browser/base/content/test/general/browser_private_no_prompt.js b/browser/base/content/test/general/browser_private_no_prompt.js index d8c9f8e7b5..80ba0ca746 100644 --- a/browser/base/content/test/general/browser_private_no_prompt.js +++ b/browser/base/content/test/general/browser_private_no_prompt.js @@ -3,8 +3,8 @@ function test() { var privateWin = OpenBrowserWindow({ private: true }); whenDelayedStartupFinished(privateWin, function () { - privateWin.BrowserOpenTab(); - privateWin.BrowserTryToCloseWindow(); + privateWin.BrowserCommands.openTab(); + privateWin.BrowserCommands.tryToCloseWindow(); ok(true, "didn't prompt"); executeSoon(finish); diff --git a/browser/base/content/test/general/browser_remoteTroubleshoot.js b/browser/base/content/test/general/browser_remoteTroubleshoot.js index 84722b2603..55627f0b28 100644 --- a/browser/base/content/test/general/browser_remoteTroubleshoot.js +++ b/browser/base/content/test/general/browser_remoteTroubleshoot.js @@ -19,9 +19,9 @@ const TEST_URI_GOOD_OBJECT = Services.io.newURI( // Creates a one-shot web-channel for the test data to be sent back from the test page. function promiseChannelResponse(channelID, originOrPermission) { - return new Promise((resolve, reject) => { + return new Promise(resolve => { let channel = new WebChannel(channelID, originOrPermission); - channel.listen((id, data, target) => { + channel.listen((id, data) => { channel.stopListening(); resolve(data); }); diff --git a/browser/base/content/test/general/browser_save_link-perwindowpb.js b/browser/base/content/test/general/browser_save_link-perwindowpb.js index 234813ca2c..29fd54d2d9 100644 --- a/browser/base/content/test/general/browser_save_link-perwindowpb.js +++ b/browser/base/content/test/general/browser_save_link-perwindowpb.js @@ -14,7 +14,7 @@ function triggerSave(aWindow, aCallback) { let testBrowser = aWindow.gBrowser.selectedBrowser; // This page sets a cookie if and only if a cookie does not exist yet let testURI = - "https://example.com/browser/browser/base/content/test/general/bug792517-2.html"; + "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517-2.html"; BrowserTestUtils.startLoadingURIString(testBrowser, testURI); BrowserTestUtils.browserLoaded(testBrowser, false, testURI).then(() => { waitForFocus(function () { @@ -68,7 +68,7 @@ function triggerSave(aWindow, aCallback) { info("popup hidden"); } - function onTransferComplete(aWindow2, downloadSuccess, destDir) { + function onTransferComplete(aWindow2, downloadSuccess) { ok(downloadSuccess, "Link should have been downloaded successfully"); aWindow2.close(); @@ -118,7 +118,7 @@ function test() { info("Finished running the cleanup code"); }); - function observer(subject, topic, state) { + function observer(subject, topic) { info("observer called with " + topic); if (topic == "http-on-modify-request") { onModifyRequest(subject); @@ -132,7 +132,7 @@ function test() { info("onExamineResponse with " + channel.URI.spec); if ( channel.URI.spec != - "https://example.com/browser/browser/base/content/test/general/bug792517.sjs" + "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517.sjs" ) { info("returning"); return; @@ -158,7 +158,7 @@ function test() { info("onModifyRequest with " + channel.URI.spec); if ( channel.URI.spec != - "https://example.com/browser/browser/base/content/test/general/bug792517.sjs" + "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517.sjs" ) { return; } diff --git a/browser/base/content/test/general/browser_save_link_when_window_navigates.js b/browser/base/content/test/general/browser_save_link_when_window_navigates.js index 65daef5f1b..e5c7fa76b2 100644 --- a/browser/base/content/test/general/browser_save_link_when_window_navigates.js +++ b/browser/base/content/test/general/browser_save_link_when_window_navigates.js @@ -36,7 +36,7 @@ function triggerSave(aWindow, aCallback) { var fileName; let testBrowser = aWindow.gBrowser.selectedBrowser; let testURI = - "https://example.com/browser/browser/base/content/test/general/navigating_window_with_download.html"; + "http://mochi.test:8888/browser/browser/base/content/test/general/navigating_window_with_download.html"; // Only observe the UTC dialog if it's enabled by pref if (Services.prefs.getBoolPref(ALWAYS_ASK_PREF)) { @@ -70,7 +70,7 @@ function triggerSave(aWindow, aCallback) { info("done mockTransferCallback"); }; - function onUCTDialog(dialog) { + function onUCTDialog() { SpecialPowers.spawn(testBrowser, [], async () => { content.document.querySelector("iframe").remove(); }).then(() => executeSoon(continueDownloading)); @@ -104,7 +104,7 @@ var windowObserver = { } this._callback = aCallback; }, - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { if (aTopic != "domwindowopened") { return; } @@ -113,7 +113,7 @@ var windowObserver = { win.addEventListener( "load", - function (event) { + function () { if (win.location == UCT_URI) { SimpleTest.executeSoon(function () { if (windowObserver._callback) { diff --git a/browser/base/content/test/general/browser_save_private_link_perwindowpb.js b/browser/base/content/test/general/browser_save_private_link_perwindowpb.js index 42632bdc5a..1312c7b954 100644 --- a/browser/base/content/test/general/browser_save_private_link_perwindowpb.js +++ b/browser/base/content/test/general/browser_save_private_link_perwindowpb.js @@ -12,9 +12,9 @@ function createTemporarySaveDirectory() { } function promiseNoCacheEntry(filename) { - return new Promise((resolve, reject) => { + return new Promise(resolve => { Visitor.prototype = { - onCacheStorageInfo(num, consumption) { + onCacheStorageInfo(num) { info("disk storage contains " + num + " entries"); }, onCacheEntryInfo(uri) { @@ -40,7 +40,7 @@ function promiseNoCacheEntry(filename) { } function promiseImageDownloaded() { - return new Promise((resolve, reject) => { + return new Promise(resolve => { let fileName; let MockFilePicker = SpecialPowers.MockFilePicker; MockFilePicker.init(window.browsingContext); diff --git a/browser/base/content/test/general/browser_save_video.js b/browser/base/content/test/general/browser_save_video.js index e9701d7023..f0450ac1fa 100644 --- a/browser/base/content/test/general/browser_save_video.js +++ b/browser/base/content/test/general/browser_save_video.js @@ -14,7 +14,7 @@ add_task(async function () { let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); BrowserTestUtils.startLoadingURIString( gBrowser, - "https://example.com/browser/browser/base/content/test/general/web_video.html" + "http://mochi.test:8888/browser/browser/base/content/test/general/web_video.html" ); await loadPromise; @@ -52,7 +52,7 @@ add_task(async function () { is( fileName, - "web-video1-expectedName.ogv", + "web-video1-expectedName.webm", "Video file name is correctly retrieved from Content-Disposition http header" ); resolve(); diff --git a/browser/base/content/test/general/browser_tabfocus.js b/browser/base/content/test/general/browser_tabfocus.js index b057a504e5..7cc9158084 100644 --- a/browser/base/content/test/general/browser_tabfocus.js +++ b/browser/base/content/test/general/browser_tabfocus.js @@ -322,7 +322,7 @@ add_task(async function () { "tab change when selected tab element was focused" ); - let switchWaiter = new Promise((resolve, reject) => { + let switchWaiter = new Promise(resolve => { gBrowser.addEventListener( "TabSwitchDone", function () { @@ -516,7 +516,7 @@ add_task(async function () { // now go back again gURLBar.focus(); - await new Promise((resolve, reject) => { + await new Promise(resolve => { BrowserTestUtils.waitForContentEvent( window.gBrowser.selectedBrowser, "pageshow", diff --git a/browser/base/content/test/general/browser_tabs_owner.js b/browser/base/content/test/general/browser_tabs_owner.js index 4a32da12f1..e214b861e8 100644 --- a/browser/base/content/test/general/browser_tabs_owner.js +++ b/browser/base/content/test/general/browser_tabs_owner.js @@ -8,13 +8,13 @@ function test() { is(gBrowser.tabs.length, 4, "4 tabs are open"); owner = gBrowser.selectedTab = gBrowser.tabs[2]; - BrowserOpenTab(); + BrowserCommands.openTab(); is(gBrowser.selectedTab, gBrowser.tabs[4], "newly opened tab is selected"); gBrowser.removeCurrentTab(); is(gBrowser.selectedTab, owner, "owner is selected"); owner = gBrowser.selectedTab; - BrowserOpenTab(); + BrowserCommands.openTab(); gBrowser.selectedTab = gBrowser.tabs[1]; gBrowser.selectedTab = gBrowser.tabs[4]; gBrowser.removeCurrentTab(); @@ -25,7 +25,7 @@ function test() { ); owner = gBrowser.selectedTab; - BrowserOpenTab(); + BrowserCommands.openTab(); gBrowser.moveTabTo(gBrowser.selectedTab, 0); gBrowser.removeCurrentTab(); is( diff --git a/browser/base/content/test/general/browser_viewSourceInTabOnViewSource.js b/browser/base/content/test/general/browser_viewSourceInTabOnViewSource.js index 6c62670e6f..26c040324a 100644 --- a/browser/base/content/test/general/browser_viewSourceInTabOnViewSource.js +++ b/browser/base/content/test/general/browser_viewSourceInTabOnViewSource.js @@ -1,7 +1,7 @@ function wait_while_tab_is_busy() { return new Promise(resolve => { let progressListener = { - onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) { + onStateChange(aWebProgress, aRequest, aStateFlags) { if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) { gBrowser.removeProgressListener(this); setTimeout(resolve, 0); @@ -27,7 +27,7 @@ var with_new_tab_opened = async function (options, taskFn) { }; add_task(async function test_regular_page() { - function test_expect_view_source_enabled(browser) { + function test_expect_view_source_enabled() { for (let element of [...XULBrowserWindow._elementsForViewSource]) { ok(!element.hasAttribute("disabled"), "View Source should be enabled"); } @@ -44,7 +44,7 @@ add_task(async function test_regular_page() { }); add_task(async function test_view_source_page() { - function test_expect_view_source_disabled(browser) { + function test_expect_view_source_disabled() { for (let element of [...XULBrowserWindow._elementsForViewSource]) { ok(element.hasAttribute("disabled"), "View Source should be disabled"); } diff --git a/browser/base/content/test/general/browser_zbug569342.js b/browser/base/content/test/general/browser_zbug569342.js index 4aa6bfbb9c..0c30ff3d1d 100644 --- a/browser/base/content/test/general/browser_zbug569342.js +++ b/browser/base/content/test/general/browser_zbug569342.js @@ -57,7 +57,7 @@ function testFindDisabled(url) { } async function testFindEnabled(url) { - return BrowserTestUtils.withNewTab(url, async function (browser) { + return BrowserTestUtils.withNewTab(url, async function () { ok( !document.getElementById("cmd_find").getAttribute("disabled"), "Find command should not be disabled" diff --git a/browser/base/content/test/general/download_page.html b/browser/base/content/test/general/download_page.html index 300bacdb72..625ff46aab 100644 --- a/browser/base/content/test/general/download_page.html +++ b/browser/base/content/test/general/download_page.html @@ -13,10 +13,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=676619 <ul> <li><a href="download_page_1.txt" download="test.txt" id="link1">Download "test.txt"</a></li> - <li><a href="video.ogg" - download id="link2">Download "video.ogg"</a></li> - <li><a href="video.ogg" - download="just some video.ogg" id="link3">Download "just some video.ogg"</a></li> + <li><a href="video.webm" + download id="link2">Download "video.webm"</a></li> + <li><a href="video.webm" + download="just some video.webm" id="link3">Download "just some video.webm"</a></li> <li><a href="download_page_2.txt" download="with-target.txt" id="link4">Download "with-target.txt"</a></li> <li><a href="javascript:(1+2)+''" @@ -33,7 +33,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=676619 download="download_page_4.txt" id="link11">Download "download_page_4.txt"</a></li> <li><a href="http://example.com/" download="example.com" id="link12" target="_blank">Download "example.com"</a></li> - <li><a href="video.ogg" + <li><a href="video.webm" download="no file extension" id="link13">Download "force extension"</a></li> <li><a href="dummy.ics" download="dummy.not-ics" id="link14">Download "dummy.not-ics"</a></li> @@ -64,7 +64,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=676619 "wrong-file-name", {type: "application/x-some-file"})); document.getElementById("link7").href = fileURL; - window.addEventListener("beforeunload", function(evt) { + window.addEventListener("beforeunload", function() { document.getElementById("unload-flag").textContent = "Fail"; }); </script> diff --git a/browser/base/content/test/general/head.js b/browser/base/content/test/general/head.js index f7b4a0d93b..94f60f2936 100644 --- a/browser/base/content/test/general/head.js +++ b/browser/base/content/test/general/head.js @@ -165,7 +165,7 @@ function promiseOpenAndLoadWindow(aOptions, aWaitForDelayedStartup = false) { return new Promise(resolve => { let win = OpenBrowserWindow(aOptions); if (aWaitForDelayedStartup) { - Services.obs.addObserver(function onDS(aSubject, aTopic, aData) { + Services.obs.addObserver(function onDS(aSubject) { if (aSubject != win) { return; } @@ -185,7 +185,7 @@ function promiseOpenAndLoadWindow(aOptions, aWaitForDelayedStartup = false) { } async function whenNewTabLoaded(aWindow, aCallback) { - aWindow.BrowserOpenTab(); + aWindow.BrowserCommands.openTab(); let expectedURL = AboutNewTab.newTabURL; let browser = aWindow.gBrowser.selectedBrowser; diff --git a/browser/base/content/test/general/navigating_window_with_download.html b/browser/base/content/test/general/navigating_window_with_download.html index 8649168cf5..6b0918941f 100644 --- a/browser/base/content/test/general/navigating_window_with_download.html +++ b/browser/base/content/test/general/navigating_window_with_download.html @@ -2,6 +2,6 @@ <html> <head><title>This window will navigate while you're downloading something</title></head> <body> - <iframe src="https://example.com/browser/browser/base/content/test/general/unknownContentType_file.pif"></iframe> + <iframe src="http://mochi.test:8888/browser/browser/base/content/test/general/unknownContentType_file.pif"></iframe> </body> </html> diff --git a/browser/base/content/test/general/video.ogg b/browser/base/content/test/general/video.ogg Binary files differdeleted file mode 100644 index ac7ece3519..0000000000 --- a/browser/base/content/test/general/video.ogg +++ /dev/null diff --git a/browser/base/content/test/general/video.webm b/browser/base/content/test/general/video.webm Binary files differnew file mode 100644 index 0000000000..0ca38d3cf0 --- /dev/null +++ b/browser/base/content/test/general/video.webm diff --git a/browser/base/content/test/general/web_video.html b/browser/base/content/test/general/web_video.html index 467fb0ce1c..e03c85d1dc 100644 --- a/browser/base/content/test/general/web_video.html +++ b/browser/base/content/test/general/web_video.html @@ -5,6 +5,6 @@ <body> This document has some web video in it. <br> - <video src="web_video1.ogv" id="video1"> </video> + <video src="web_video1.webm" id="video1"> </video> </body> </html> diff --git a/browser/base/content/test/general/web_video1.ogv b/browser/base/content/test/general/web_video1.ogv Binary files differdeleted file mode 100644 index 093158432a..0000000000 --- a/browser/base/content/test/general/web_video1.ogv +++ /dev/null diff --git a/browser/base/content/test/general/web_video1.ogv^headers^ b/browser/base/content/test/general/web_video1.ogv^headers^ deleted file mode 100644 index 4511e92552..0000000000 --- a/browser/base/content/test/general/web_video1.ogv^headers^ +++ /dev/null @@ -1,3 +0,0 @@ -Content-Disposition: filename="web-video1-expectedName.ogv" -Content-Type: video/ogg - diff --git a/browser/base/content/test/general/web_video1.webm b/browser/base/content/test/general/web_video1.webm Binary files differnew file mode 100644 index 0000000000..2c9d7dad8d --- /dev/null +++ b/browser/base/content/test/general/web_video1.webm diff --git a/browser/base/content/test/general/web_video1.webm^headers^ b/browser/base/content/test/general/web_video1.webm^headers^ new file mode 100644 index 0000000000..d027132ea2 --- /dev/null +++ b/browser/base/content/test/general/web_video1.webm^headers^ @@ -0,0 +1,3 @@ +Content-Disposition: filename="web-video1-expectedName.webm" +Content-Type: video/webm + diff --git a/browser/base/content/test/historySwipeAnimation/browser_historySwipeAnimation.js b/browser/base/content/test/historySwipeAnimation/browser_historySwipeAnimation.js index a5910964e7..eeeb7e8b9e 100644 --- a/browser/base/content/test/historySwipeAnimation/browser_historySwipeAnimation.js +++ b/browser/base/content/test/historySwipeAnimation/browser_historySwipeAnimation.js @@ -5,7 +5,7 @@ function test() { waitForExplicitFinish(); - BrowserOpenTab(); + BrowserCommands.openTab(); let tab = gBrowser.selectedTab; registerCleanupFunction(function () { gBrowser.removeTab(tab); diff --git a/browser/base/content/test/keyboard/browser_toolbarButtonKeyPress.js b/browser/base/content/test/keyboard/browser_toolbarButtonKeyPress.js index 8640716bab..ef92d4c528 100644 --- a/browser/base/content/test/keyboard/browser_toolbarButtonKeyPress.js +++ b/browser/base/content/test/keyboard/browser_toolbarButtonKeyPress.js @@ -12,7 +12,7 @@ const kDevPanelID = "PanelUI-developer-tools"; function waitForLocationChange() { let promise = new Promise(resolve => { let wpl = { - onLocationChange(aWebProgress, aRequest, aLocation) { + onLocationChange() { gBrowser.removeProgressListener(wpl); resolve(); }, @@ -213,31 +213,23 @@ add_task(async function testSidebarsButtonPress() { // This is an image with a click handler on its parent and no command handler, // but the toolbar keyboard navigation code should handle keyboard activation. add_task(async function testBookmarkButtonPress() { - await BrowserTestUtils.withNewTab( - "https://example.com", - async function (aBrowser) { - let button = document.getElementById("star-button-box"); - StarUI._createPanelIfNeeded(); - let panel = document.getElementById("editBookmarkPanel"); - let focused = BrowserTestUtils.waitForEvent(panel, "focus", true); - // The button ignores activation while the bookmarked status is being - // updated. So, wait for it to finish updating. - await TestUtils.waitForCondition( - () => BookmarkingUI.status != BookmarkingUI.STATUS_UPDATING - ); - await focusAndActivateElement(button, () => - EventUtils.synthesizeKey(" ") - ); - await focused; - ok( - true, - "Focus inside edit bookmark panel after Bookmark button pressed" - ); - let hidden = BrowserTestUtils.waitForEvent(panel, "popuphidden"); - EventUtils.synthesizeKey("KEY_Escape"); - await hidden; - } - ); + await BrowserTestUtils.withNewTab("https://example.com", async function () { + let button = document.getElementById("star-button-box"); + StarUI._createPanelIfNeeded(); + let panel = document.getElementById("editBookmarkPanel"); + let focused = BrowserTestUtils.waitForEvent(panel, "focus", true); + // The button ignores activation while the bookmarked status is being + // updated. So, wait for it to finish updating. + await TestUtils.waitForCondition( + () => BookmarkingUI.status != BookmarkingUI.STATUS_UPDATING + ); + await focusAndActivateElement(button, () => EventUtils.synthesizeKey(" ")); + await focused; + ok(true, "Focus inside edit bookmark panel after Bookmark button pressed"); + let hidden = BrowserTestUtils.waitForEvent(panel, "popuphidden"); + EventUtils.synthesizeKey("KEY_Escape"); + await hidden; + }); }); // Test activation of the Bookmarks Menu button from the keyboard. @@ -302,33 +294,24 @@ add_task(async function testDownloadsButtonPress() { // with a browser element to embed the pocket UI into it. // The Pocket panel should appear and focus should move inside it. add_task(async function testPocketButtonPress() { - await BrowserTestUtils.withNewTab( - "https://example.com", - async function (aBrowser) { - let button = document.getElementById("save-to-pocket-button"); - // The panel is created on the fly, so we can't simply wait for focus - // inside it. - let showing = BrowserTestUtils.waitForEvent( - document, - "popupshowing", - true - ); - await focusAndActivateElement(button, () => - EventUtils.synthesizeKey(" ") - ); - let event = await showing; - let panel = event.target; - is(panel.id, "customizationui-widget-panel"); - let focused = BrowserTestUtils.waitForEvent(panel, "focus", true); - await focused; - is( - document.activeElement.tagName, - "browser", - "Focus inside Pocket panel after Bookmark button pressed" - ); - let hidden = BrowserTestUtils.waitForEvent(panel, "popuphidden"); - EventUtils.synthesizeKey("KEY_Escape"); - await hidden; - } - ); + await BrowserTestUtils.withNewTab("https://example.com", async function () { + let button = document.getElementById("save-to-pocket-button"); + // The panel is created on the fly, so we can't simply wait for focus + // inside it. + let showing = BrowserTestUtils.waitForEvent(document, "popupshowing", true); + await focusAndActivateElement(button, () => EventUtils.synthesizeKey(" ")); + let event = await showing; + let panel = event.target; + is(panel.id, "customizationui-widget-panel"); + let focused = BrowserTestUtils.waitForEvent(panel, "focus", true); + await focused; + is( + document.activeElement.tagName, + "browser", + "Focus inside Pocket panel after Bookmark button pressed" + ); + let hidden = BrowserTestUtils.waitForEvent(panel, "popuphidden"); + EventUtils.synthesizeKey("KEY_Escape"); + await hidden; + }); }); diff --git a/browser/base/content/test/metaTags/browser_bad_meta_tags.js b/browser/base/content/test/metaTags/browser_bad_meta_tags.js index 00cc128ec0..aa025725dc 100644 --- a/browser/base/content/test/metaTags/browser_bad_meta_tags.js +++ b/browser/base/content/test/metaTags/browser_bad_meta_tags.js @@ -9,11 +9,12 @@ const TEST_PATH = ) + "bad_meta_tags.html"; /** - * This tests that with the page bad_meta_tags.html, ContentMetaHandler.jsm parses - * out the meta tags available and does not store content provided by a malformed - * meta tag. In this case the best defined meta tags are malformed, so here we - * test that we store the next best ones - "description" and "twitter:image". The - * list of meta tags and order of preference is found in ContentMetaHandler.jsm. + * This tests that with the page bad_meta_tags.html, ContentMetaHandler.sys.mjs + * parses out the meta tags available and does not store content provided by a + * malformed meta tag. In this case the best defined meta tags are malformed, so + * here we test that we store the next best ones - "description" and "twitter:image". + * The list of meta tags and order of preference is found in + * ContentMetaHandler.sys.mjs. */ add_task(async function test_bad_meta_tags() { const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PATH); diff --git a/browser/base/content/test/metaTags/browser_meta_tags.js b/browser/base/content/test/metaTags/browser_meta_tags.js index 380a71214c..870860dc18 100644 --- a/browser/base/content/test/metaTags/browser_meta_tags.js +++ b/browser/base/content/test/metaTags/browser_meta_tags.js @@ -8,11 +8,11 @@ const TEST_PATH = "https://example.com" ) + "meta_tags.html"; /** - * This tests that with the page meta_tags.html, ContentMetaHandler.jsm parses - * out the meta tags avilable and only stores the best one for description and - * one for preview image url. In the case of this test, the best defined meta + * This tests that with the page meta_tags.html, ContentMetaHandler.sys.mjs + * parses out the meta tags avilable and only stores the best one for description + * and one for preview image url. In the case of this test, the best defined meta * tags are "og:description" and "og:image:secure_url". The list of meta tags - * and order of preference is found in ContentMetaHandler.jsm. + * and order of preference is found in ContentMetaHandler.sys.mjs. */ add_task(async function test_metadata() { const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PATH); diff --git a/browser/base/content/test/outOfProcess/browser_basic_outofprocess.js b/browser/base/content/test/outOfProcess/browser_basic_outofprocess.js index 50914a286c..41fc96986e 100644 --- a/browser/base/content/test/outOfProcess/browser_basic_outofprocess.js +++ b/browser/base/content/test/outOfProcess/browser_basic_outofprocess.js @@ -121,12 +121,9 @@ add_task(async function test_subframes_function() { let browser = tab.linkedBrowser; let counter = 0; - let browsingContexts = await initChildFrames( - browser, - function (browsingContext) { - return "<p>Text " + ++counter + "</p>"; - } - ); + let browsingContexts = await initChildFrames(browser, function () { + return "<p>Text " + ++counter + "</p>"; + }); is( counter, diff --git a/browser/base/content/test/pageActions/head.js b/browser/base/content/test/pageActions/head.js index cd269bf9b5..370f01734c 100644 --- a/browser/base/content/test/pageActions/head.js +++ b/browser/base/content/test/pageActions/head.js @@ -124,7 +124,7 @@ async function promiseAnimationFrame(win = window) { async function promisePopupNotShown(id, win = window) { let deferred = Promise.withResolvers(); - function listener(e) { + function listener() { deferred.reject("Unexpected popupshown"); } let panel = win.document.getElementById(id); diff --git a/browser/base/content/test/pageinfo/browser.toml b/browser/base/content/test/pageinfo/browser.toml index ae70eb68ff..9e14392450 100644 --- a/browser/base/content/test/pageinfo/browser.toml +++ b/browser/base/content/test/pageinfo/browser.toml @@ -5,7 +5,7 @@ support-files = [ "image.html", "../general/audio.ogg", "../general/moz.png", - "../general/video.ogg", + "../general/video.webm", ] ["browser_pageinfo_iframe_media.js"] diff --git a/browser/base/content/test/pageinfo/browser_pageinfo_firstPartyIsolation.js b/browser/base/content/test/pageinfo/browser_pageinfo_firstPartyIsolation.js index 354e85a241..dbd5d8fe25 100644 --- a/browser/base/content/test/pageinfo/browser_pageinfo_firstPartyIsolation.js +++ b/browser/base/content/test/pageinfo/browser_pageinfo_firstPartyIsolation.js @@ -76,7 +76,7 @@ async function test() { // Pass a dummy imageElement, if there isn't an imageElement, pageInfo.js // will do a preview, however this sometimes will cause intermittent failures, // see bug 1403365. - let pageInfo = BrowserPageInfo(url, "mediaTab", {}); + let pageInfo = BrowserCommands.pageInfo(url, "mediaTab", {}); info("waitForEvent pageInfo"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); diff --git a/browser/base/content/test/pageinfo/browser_pageinfo_iframe_media.js b/browser/base/content/test/pageinfo/browser_pageinfo_iframe_media.js index 7550379ad1..3dad0a50f3 100644 --- a/browser/base/content/test/pageinfo/browser_pageinfo_iframe_media.js +++ b/browser/base/content/test/pageinfo/browser_pageinfo_iframe_media.js @@ -10,7 +10,7 @@ add_task(async function test_all_images_mentioned() { await BrowserTestUtils.withNewTab( TEST_PATH + "iframes.html", async function () { - let pageInfo = BrowserPageInfo( + let pageInfo = BrowserCommands.pageInfo( gBrowser.selectedBrowser.currentURI.spec, "mediaTab" ); diff --git a/browser/base/content/test/pageinfo/browser_pageinfo_image_info.js b/browser/base/content/test/pageinfo/browser_pageinfo_image_info.js index 374cd5f032..0fea68d640 100644 --- a/browser/base/content/test/pageinfo/browser_pageinfo_image_info.js +++ b/browser/base/content/test/pageinfo/browser_pageinfo_image_info.js @@ -28,7 +28,7 @@ add_task(async function () { }; }); - let pageInfo = BrowserPageInfo( + let pageInfo = BrowserCommands.pageInfo( browser.currentURI.spec, "mediaTab", imageInfo diff --git a/browser/base/content/test/pageinfo/browser_pageinfo_images.js b/browser/base/content/test/pageinfo/browser_pageinfo_images.js index e1f71204d0..c356c1c690 100644 --- a/browser/base/content/test/pageinfo/browser_pageinfo_images.js +++ b/browser/base/content/test/pageinfo/browser_pageinfo_images.js @@ -10,7 +10,7 @@ add_task(async function test_all_images_mentioned() { await BrowserTestUtils.withNewTab( TEST_PATH + "all_images.html", async function () { - let pageInfo = BrowserPageInfo( + let pageInfo = BrowserCommands.pageInfo( gBrowser.selectedBrowser.currentURI.spec, "mediaTab" ); @@ -97,7 +97,7 @@ add_task(async function test_image_size() { await BrowserTestUtils.withNewTab( TEST_PATH + "all_images.html", async function () { - let pageInfo = BrowserPageInfo( + let pageInfo = BrowserCommands.pageInfo( gBrowser.selectedBrowser.currentURI.spec, "mediaTab" ); diff --git a/browser/base/content/test/pageinfo/browser_pageinfo_permissions.js b/browser/base/content/test/pageinfo/browser_pageinfo_permissions.js index ebf027811d..6b11ac19b9 100644 --- a/browser/base/content/test/pageinfo/browser_pageinfo_permissions.js +++ b/browser/base/content/test/pageinfo/browser_pageinfo_permissions.js @@ -7,8 +7,8 @@ const TEST_ORIGIN_CERT_ERROR = "https://expired.example.com"; const LOW_TLS_VERSION = "https://tls1.example.com/"; async function testPermissions(defaultPermission) { - await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function (browser) { - let pageInfo = BrowserPageInfo(TEST_ORIGIN, "permTab"); + await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function () { + let pageInfo = BrowserCommands.pageInfo(TEST_ORIGIN, "permTab"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let defaultCheckbox = await TestUtils.waitForCondition(() => @@ -94,7 +94,7 @@ add_task(async function test_CertificateError() { await pageLoaded; - let pageInfo = BrowserPageInfo(TEST_ORIGIN_CERT_ERROR, "permTab"); + let pageInfo = BrowserCommands.pageInfo(TEST_ORIGIN_CERT_ERROR, "permTab"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let permissionTab = pageInfo.document.getElementById("permTab"); await TestUtils.waitForCondition( @@ -145,7 +145,7 @@ add_task(async function test_NetworkError() { await pageLoaded; - let pageInfo = BrowserPageInfo(LOW_TLS_VERSION, "permTab"); + let pageInfo = BrowserCommands.pageInfo(LOW_TLS_VERSION, "permTab"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let permissionTab = pageInfo.document.getElementById("permTab"); await TestUtils.waitForCondition( @@ -192,8 +192,8 @@ add_task(async function test_default_geo_permission() { // Test special behavior for cookie permissions. add_task(async function test_cookie_permission() { - await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function (browser) { - let pageInfo = BrowserPageInfo(TEST_ORIGIN, "permTab"); + await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function () { + let pageInfo = BrowserCommands.pageInfo(TEST_ORIGIN, "permTab"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let defaultCheckbox = await TestUtils.waitForCondition(() => diff --git a/browser/base/content/test/pageinfo/browser_pageinfo_rtl.js b/browser/base/content/test/pageinfo/browser_pageinfo_rtl.js index d0c06a03ff..677a58516e 100644 --- a/browser/base/content/test/pageinfo/browser_pageinfo_rtl.js +++ b/browser/base/content/test/pageinfo/browser_pageinfo_rtl.js @@ -1,18 +1,15 @@ async function testPageInfo() { - await BrowserTestUtils.withNewTab( - "https://example.com", - async function (browser) { - let pageInfo = BrowserPageInfo(); - await BrowserTestUtils.waitForEvent(pageInfo, "page-info-init"); - is( - getComputedStyle(pageInfo.document.documentElement).direction, - "rtl", - "Should be RTL" - ); - ok(true, "Didn't assert or crash"); - pageInfo.close(); - } - ); + await BrowserTestUtils.withNewTab("https://example.com", async function () { + let pageInfo = BrowserCommands.pageInfo(); + await BrowserTestUtils.waitForEvent(pageInfo, "page-info-init"); + is( + getComputedStyle(pageInfo.document.documentElement).direction, + "rtl", + "Should be RTL" + ); + ok(true, "Didn't assert or crash"); + pageInfo.close(); + }); } add_task(async function test_page_info_rtl() { diff --git a/browser/base/content/test/pageinfo/browser_pageinfo_security.js b/browser/base/content/test/pageinfo/browser_pageinfo_security.js index 47df97db06..17ff0b9b75 100644 --- a/browser/base/content/test/pageinfo/browser_pageinfo_security.js +++ b/browser/base/content/test/pageinfo/browser_pageinfo_security.js @@ -24,7 +24,7 @@ add_task(async function test_ShowCertificate() { TEST_SUB_ORIGIN ); - let pageInfo = BrowserPageInfo(TEST_SUB_ORIGIN, "securityTab"); + let pageInfo = BrowserCommands.pageInfo(TEST_SUB_ORIGIN, "securityTab"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let pageInfoDoc = pageInfo.document; let securityTab = pageInfoDoc.getElementById("securityTab"); @@ -74,7 +74,7 @@ add_task(async function test_image() { let url = TEST_PATH + "moz.png"; await BrowserTestUtils.openNewForegroundTab(gBrowser, url); - let pageInfo = BrowserPageInfo(url, "securityTab"); + let pageInfo = BrowserCommands.pageInfo(url, "securityTab"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let pageInfoDoc = pageInfo.document; let securityTab = pageInfoDoc.getElementById("securityTab"); @@ -128,7 +128,10 @@ add_task(async function test_CertificateError() { await pageLoaded; - let pageInfo = BrowserPageInfo(TEST_ORIGIN_CERT_ERROR, "securityTab"); + let pageInfo = BrowserCommands.pageInfo( + TEST_ORIGIN_CERT_ERROR, + "securityTab" + ); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let pageInfoDoc = pageInfo.document; let securityTab = pageInfoDoc.getElementById("securityTab"); @@ -165,7 +168,7 @@ add_task(async function test_CertificateError() { add_task(async function test_SecurityHTTP() { await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_HTTP_ORIGIN); - let pageInfo = BrowserPageInfo(TEST_HTTP_ORIGIN, "securityTab"); + let pageInfo = BrowserCommands.pageInfo(TEST_HTTP_ORIGIN, "securityTab"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let pageInfoDoc = pageInfo.document; let securityTab = pageInfoDoc.getElementById("securityTab"); @@ -201,7 +204,7 @@ add_task(async function test_SecurityHTTP() { add_task(async function test_ValidCert() { await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_ORIGIN); - let pageInfo = BrowserPageInfo(TEST_ORIGIN, "securityTab"); + let pageInfo = BrowserCommands.pageInfo(TEST_ORIGIN, "securityTab"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let pageInfoDoc = pageInfo.document; let securityTab = pageInfoDoc.getElementById("securityTab"); @@ -237,11 +240,11 @@ add_task(async function test_ValidCert() { add_task(async function test_SiteData() { await SiteDataTestUtils.addToIndexedDB(TEST_ORIGIN); - await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function (browser) { + await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function () { let totalUsage = await SiteDataTestUtils.getQuotaUsage(TEST_ORIGIN); Assert.greater(totalUsage, 0, "The total usage should not be 0"); - let pageInfo = BrowserPageInfo(TEST_ORIGIN, "securityTab"); + let pageInfo = BrowserCommands.pageInfo(TEST_ORIGIN, "securityTab"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let pageInfoDoc = pageInfo.document; @@ -302,8 +305,8 @@ add_task(async function test_Cookies() { value: "1", }); - await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function (browser) { - let pageInfo = BrowserPageInfo(TEST_ORIGIN, "securityTab"); + await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function () { + let pageInfo = BrowserCommands.pageInfo(TEST_ORIGIN, "securityTab"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let pageInfoDoc = pageInfo.document; diff --git a/browser/base/content/test/pageinfo/browser_pageinfo_separate_private.js b/browser/base/content/test/pageinfo/browser_pageinfo_separate_private.js index ac93b7ddb2..74289107a8 100644 --- a/browser/base/content/test/pageinfo/browser_pageinfo_separate_private.js +++ b/browser/base/content/test/pageinfo/browser_pageinfo_separate_private.js @@ -9,7 +9,7 @@ add_task(async function () { "https://example.com" ); let browser = tab.linkedBrowser; - let pageInfo = BrowserPageInfo(browser.currentURI.spec); + let pageInfo = BrowserCommands.pageInfo(browser.currentURI.spec); await BrowserTestUtils.waitForEvent(pageInfo, "page-info-init"); Assert.strictEqual( pageInfo.docShell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing, @@ -25,7 +25,7 @@ add_task(async function () { "https://example.com" ); let privateBrowser = privateTab.linkedBrowser; - let privatePageInfo = privateWindow.BrowserPageInfo( + let privatePageInfo = privateWindow.BrowserCommands.pageInfo( privateBrowser.currentURI.spec ); await BrowserTestUtils.waitForEvent(privatePageInfo, "page-info-init"); diff --git a/browser/base/content/test/pageinfo/browser_pageinfo_svg_image.js b/browser/base/content/test/pageinfo/browser_pageinfo_svg_image.js index 3934cd2aea..b00df72851 100644 --- a/browser/base/content/test/pageinfo/browser_pageinfo_svg_image.js +++ b/browser/base/content/test/pageinfo/browser_pageinfo_svg_image.js @@ -7,7 +7,7 @@ add_task(async function () { BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, URI); await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, URI); - const pageInfo = BrowserPageInfo( + const pageInfo = BrowserCommands.pageInfo( gBrowser.selectedBrowser.currentURI.spec, "mediaTab" ); diff --git a/browser/base/content/test/pageinfo/image.html b/browser/base/content/test/pageinfo/image.html index 1261be8e7b..35e2d78e1e 100644 --- a/browser/base/content/test/pageinfo/image.html +++ b/browser/base/content/test/pageinfo/image.html @@ -1,5 +1,5 @@ <html> <img src='moz.png' height=100 width=150 id='test-image'> - <video src='video.ogg' id='test-video'></video> + <video src='video.webm' id='test-video'></video> <audio src='audio.ogg' id='test-audio'></audio> </html> diff --git a/browser/base/content/test/performance/StartupContentSubframe.sys.mjs b/browser/base/content/test/performance/StartupContentSubframe.sys.mjs index a78e456afb..7d2d711765 100644 --- a/browser/base/content/test/performance/StartupContentSubframe.sys.mjs +++ b/browser/base/content/test/performance/StartupContentSubframe.sys.mjs @@ -16,7 +16,7 @@ export class StartupContentSubframeParent extends JSWindowActorParent { } export class StartupContentSubframeChild extends JSWindowActorChild { - async handleEvent(event) { + async handleEvent() { // When the remote subframe is loaded, an event will be fired to this actor, // which will cause us to send the `LoadedScripts` message to the parent // process. diff --git a/browser/base/content/test/performance/browser_preferences_usage.js b/browser/base/content/test/performance/browser_preferences_usage.js index 6bc623a360..9ad9a8dde8 100644 --- a/browser/base/content/test/performance/browser_preferences_usage.js +++ b/browser/base/content/test/performance/browser_preferences_usage.js @@ -70,13 +70,6 @@ function checkPrefGetters(stats, max, knownProblematicPrefs = {}) { } } - // This pref will be accessed by mozJSComponentLoader when loading modules, - // which fails TV runs since they run the test multiple times without restarting. - // We just ignore this pref, since it's for testing only anyway. - if (knownProblematicPrefs["browser.startup.record"]) { - delete knownProblematicPrefs["browser.startup.record"]; - } - let unusedPrefs = Object.keys(knownProblematicPrefs); is( unusedPrefs.length, @@ -104,18 +97,9 @@ add_task(async function startup() { let max = 40; let knownProblematicPrefs = { - "browser.startup.record": { - // This pref is accessed in Nighly and debug builds only. - min: 200, - max: 400, - }, "network.loadinfo.skip_type_assertion": { // This is accessed in debug only. }, - "chrome.override_package.global": { - min: 0, - max: 50, - }, }; let startupRecorder = @@ -135,9 +119,6 @@ add_task(async function open_10_tabs() { const max = 4 * DEFAULT_PROCESS_COUNT; let knownProblematicPrefs = { - "browser.startup.record": { - max: 20, - }, "browser.tabs.remote.logSwitchTiming": { max: 35, }, diff --git a/browser/base/content/test/performance/browser_startup_content.js b/browser/base/content/test/performance/browser_startup_content.js index b0f861e47f..fac82ad990 100644 --- a/browser/base/content/test/performance/browser_startup_content.js +++ b/browser/base/content/test/performance/browser_startup_content.js @@ -57,18 +57,11 @@ const known_scripts = { ]), }; -if (!Services.appinfo.sessionHistoryInParent) { - known_scripts.modules.add( - "resource:///modules/sessionstore/ContentSessionStore.sys.mjs" - ); -} - // Items on this list *might* load when creating the process, as opposed to // items in the main list, which we expect will always load. const intermittently_loaded_scripts = { modules: new Set([ "resource://gre/modules/nsAsyncShutdown.sys.mjs", - "resource://gre/modules/sessionstore/Utils.sys.mjs", // Translations code which may be preffed on. "resource://gre/actors/TranslationsChild.sys.mjs", @@ -119,7 +112,8 @@ add_task(async function () { let mm = gBrowser.selectedBrowser.messageManager; let promise = BrowserTestUtils.waitForMessage(mm, "Test:LoadedScripts"); - // Load a custom frame script to avoid using ContentTask which loads Task.jsm + // Load a custom frame script to avoid using SpecialPowers.spawn which may + // load other modules. mm.loadFrameScript( "data:text/javascript,(" + function () { diff --git a/browser/base/content/test/performance/browser_startup_mainthreadio.js b/browser/base/content/test/performance/browser_startup_mainthreadio.js index b65ede26d5..a89a068f13 100644 --- a/browser/base/content/test/performance/browser_startup_mainthreadio.js +++ b/browser/base/content/test/performance/browser_startup_mainthreadio.js @@ -189,6 +189,7 @@ const startupPhases = { { // bug 1541601 path: "PrfDef:channel-prefs.js", + condition: !MAC, stat: 1, read: 1, close: 1, diff --git a/browser/base/content/test/performance/browser_tabdetach.js b/browser/base/content/test/performance/browser_tabdetach.js index a860362f1f..3cbdde50fc 100644 --- a/browser/base/content/test/performance/browser_tabdetach.js +++ b/browser/base/content/test/performance/browser_tabdetach.js @@ -59,7 +59,7 @@ add_task(async function test_detach_not_overflowed() { expectedReflows: EXPECTED_REFLOWS, // we are opening a whole new window, so there's no point in tracking // rects being painted - frames: { filter: rects => [] }, + frames: { filter: () => [] }, } ); @@ -87,7 +87,7 @@ add_task(async function test_detach_overflowed() { expectedReflows: EXPECTED_REFLOWS, // we are opening a whole new window, so there's no point in tracking // rects being painted - frames: { filter: rects => [] }, + frames: { filter: () => [] }, } ); diff --git a/browser/base/content/test/performance/browser_tabopen.js b/browser/base/content/test/performance/browser_tabopen.js index 2457812cb7..b7eabf4844 100644 --- a/browser/base/content/test/performance/browser_tabopen.js +++ b/browser/base/content/test/performance/browser_tabopen.js @@ -144,7 +144,7 @@ add_task(async function () { await withPerfObserver( async function () { let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); - BrowserOpenTab(); + BrowserCommands.openTab(); await BrowserTestUtils.waitForEvent( gBrowser.selectedTab, "TabAnimationEnd" diff --git a/browser/base/content/test/performance/browser_tabopen_squeeze.js b/browser/base/content/test/performance/browser_tabopen_squeeze.js index f92bdc2ea4..dd73f66030 100644 --- a/browser/base/content/test/performance/browser_tabopen_squeeze.js +++ b/browser/base/content/test/performance/browser_tabopen_squeeze.js @@ -52,7 +52,7 @@ add_task(async function () { await withPerfObserver( async function () { let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); - BrowserOpenTab(); + BrowserCommands.openTab(); await BrowserTestUtils.waitForEvent( gBrowser.selectedTab, "TabAnimationEnd" diff --git a/browser/base/content/test/performance/browser_tabstrip_overflow_underflow.js b/browser/base/content/test/performance/browser_tabstrip_overflow_underflow.js index 1fd33ed836..50d108c062 100644 --- a/browser/base/content/test/performance/browser_tabstrip_overflow_underflow.js +++ b/browser/base/content/test/performance/browser_tabstrip_overflow_underflow.js @@ -90,7 +90,7 @@ add_task(async function () { await withPerfObserver( async function () { let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); - BrowserOpenTab(); + BrowserCommands.openTab(); await BrowserTestUtils.waitForEvent( gBrowser.selectedTab, "TabAnimationEnd" @@ -115,7 +115,7 @@ add_task(async function () { await withPerfObserver( async function () { let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone"); - BrowserOpenTab(); + BrowserCommands.openTab(); await switchDone; await TestUtils.waitForCondition(() => { return gBrowser.tabContainer.arrowScrollbox.hasAttribute( diff --git a/browser/base/content/test/performance/browser_tabswitch.js b/browser/base/content/test/performance/browser_tabswitch.js index bbbbac3a21..ba29efa662 100644 --- a/browser/base/content/test/performance/browser_tabswitch.js +++ b/browser/base/content/test/performance/browser_tabswitch.js @@ -59,6 +59,14 @@ add_task(async function () { getComputedStyle(gBrowser.selectedTab).paddingInlineStart ); let minTabWidth = firstTabRect.width - 2 * tabPaddingStart; + if (AppConstants.platform == "macosx") { + // On macOS, after bug 1886729, gecko screenshots like the ones for this + // test can't screenshot the native titlebar. That, plus the fact that + // there's no border or shadow (see bug 1702653) means that we only end up + // with the tab text color changing, which is smaller than the tab + // background size. + minTabWidth = 0; + } let maxTabWidth = firstTabRect.width; let inRange = (val, min, max) => min <= val && val <= max; @@ -84,11 +92,7 @@ add_task(async function () { // The tab selection changes between 2 adjacent tabs, so we expect // both to change color at once: this should be a single rect of the // width of 2 tabs. - inRange( - r.w, - minTabWidth - 1, // -1 for the border on Win7 - maxTabWidth * 2 - ) + inRange(r.w, minTabWidth, maxTabWidth * 2) ) ) ), diff --git a/browser/base/content/test/performance/browser_windowclose.js b/browser/base/content/test/performance/browser_windowclose.js index 7d11779acc..11fa669be0 100644 --- a/browser/base/content/test/performance/browser_windowclose.js +++ b/browser/base/content/test/performance/browser_windowclose.js @@ -53,7 +53,7 @@ add_task(async function () { { expectedReflows: EXPECTED_REFLOWS, frames: { - filter(rects, frame, previousFrame) { + filter(rects, frame) { // Ignore the focus-out animation. if (isLikelyFocusChange(rects, frame)) { return []; diff --git a/browser/base/content/test/performance/browser_windowopen.js b/browser/base/content/test/performance/browser_windowopen.js index 02c6172948..b258cb67f5 100644 --- a/browser/base/content/test/performance/browser_windowopen.js +++ b/browser/base/content/test/performance/browser_windowopen.js @@ -44,7 +44,7 @@ add_task(async function () { let expectations = { expectedReflows: EXPECTED_REFLOWS, frames: { - filter(rects, frame, previousFrame) { + filter(rects, frame) { // The first screenshot we get in OSX / Windows shows an unfocused browser // window for some reason. See bug 1445161. if (!alreadyFocused && isLikelyFocusChange(rects, frame)) { diff --git a/browser/base/content/test/performance/head.js b/browser/base/content/test/performance/head.js index 29722e6bbe..42f7ae95fc 100644 --- a/browser/base/content/test/performance/head.js +++ b/browser/base/content/test/performance/head.js @@ -42,7 +42,7 @@ async function recordReflows(testPromise, win = window) { let reflows = []; let observer = { - reflow(start, end) { + reflow() { // Gather information about the current code path. reflows.push(new Error().stack); @@ -50,7 +50,7 @@ async function recordReflows(testPromise, win = window) { dirtyFrame(win); }, - reflowInterruptible(start, end) { + reflowInterruptible() { // Interruptible reflows are the reflows caused by the refresh // driver ticking. These are fine. }, @@ -99,11 +99,9 @@ async function recordReflows(testPromise, win = window) { * // Sometimes, due to unpredictable timings, the reflow may be hit * // less times. * stack: [ - * "select@chrome://global/content/bindings/textbox.xml", - * "focusAndSelectUrlBar@chrome://browser/content/browser.js", - * "openLinkIn@chrome://browser/content/utilityOverlay.js", - * "openUILinkIn@chrome://browser/content/utilityOverlay.js", - * "BrowserOpenTab@chrome://browser/content/browser.js", + * "somefunction@chrome://somepackage/content/somefile.mjs", + * "otherfunction@chrome://otherpackage/content/otherfile.js", + * "morecode@resource://somewhereelse/SomeModule.sys.mjs", * ], * // We expect this particular reflow to happen up to 2 times. * maxCount: 2, @@ -113,10 +111,9 @@ async function recordReflows(testPromise, win = window) { * // This reflow is caused by lorem ipsum. We expect this reflow * // to only happen once, so we can omit the "maxCount" property. * stack: [ - * "get_scrollPosition@chrome://global/content/bindings/scrollbox.xml", - * "_fillTrailingGap@chrome://browser/content/tabbrowser.xml", - * "_handleNewTab@chrome://browser/content/tabbrowser.xml", - * "onxbltransitionend@chrome://browser/content/tabbrowser.xml", + * "somefunction@chrome://somepackage/content/somefile.mjs", + * "otherfunction@chrome://otherpackage/content/otherfile.js", + * "morecode@resource://somewhereelse/SomeModule.sys.mjs", * ], * } * ] @@ -430,7 +427,7 @@ async function recordFrames(testPromise, win = window) { let frames = []; - let afterPaintListener = event => { + let afterPaintListener = () => { let width, height; canvas.width = width = win.innerWidth; canvas.height = height = win.innerHeight; diff --git a/browser/base/content/test/permissions/browser_autoplay_blocked.js b/browser/base/content/test/permissions/browser_autoplay_blocked.js index d81481d6a5..7fd45a4340 100644 --- a/browser/base/content/test/permissions/browser_autoplay_blocked.js +++ b/browser/base/content/test/permissions/browser_autoplay_blocked.js @@ -102,7 +102,7 @@ add_task(async function testMainViewVisible() { Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED); - await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function (browser) { + await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function () { let permissionsList = document.getElementById( "permission-popup-permission-list" ); diff --git a/browser/base/content/test/permissions/browser_canvas_fingerprinting_resistance.js b/browser/base/content/test/permissions/browser_canvas_fingerprinting_resistance.js index dbb2d1ea32..62a49e359c 100644 --- a/browser/base/content/test/permissions/browser_canvas_fingerprinting_resistance.js +++ b/browser/base/content/test/permissions/browser_canvas_fingerprinting_resistance.js @@ -336,7 +336,7 @@ async function withNewTabInput( await SpecialPowers.spawn(browser, [], initTab); await enableResistFingerprinting(randomDataOnCanvasExtract, true); let popupShown = promisePopupShown(); - await SpecialPowers.spawn(browser, [], function (host) { + await SpecialPowers.spawn(browser, [], function () { E10SUtils.wrapHandlingUserInput(content, true, function () { var button = content.document.getElementById("clickme"); button.click(); @@ -361,11 +361,7 @@ async function withNewTabInput( await SpecialPowers.popPrefEnv(); } -async function doTestInput( - randomDataOnCanvasExtract, - grantPermission, - autoDeclineNoInput -) { +async function doTestInput(randomDataOnCanvasExtract, grantPermission) { await BrowserTestUtils.withNewTab( kUrl, withNewTabInput.bind(null, randomDataOnCanvasExtract, grantPermission) diff --git a/browser/base/content/test/permissions/browser_site_scoped_permissions.js b/browser/base/content/test/permissions/browser_site_scoped_permissions.js index 7a8953de47..949d7a0596 100644 --- a/browser/base/content/test/permissions/browser_site_scoped_permissions.js +++ b/browser/base/content/test/permissions/browser_site_scoped_permissions.js @@ -21,7 +21,7 @@ add_task(async function testSiteScopedPermissionSubdomainAffectsBaseDomain() { ); let id = "3rdPartyStorage^https://example.org"; - await BrowserTestUtils.withNewTab(EMPTY_PAGE, async function (browser) { + await BrowserTestUtils.withNewTab(EMPTY_PAGE, async function () { Services.perms.addFromPrincipal( subdomainPrincipal, id, @@ -76,49 +76,46 @@ add_task(async function testSiteScopedPermissionBaseDomainAffectsSubdomain() { Services.scriptSecurityManager.createContentPrincipalFromOrigin(origin); let id = "3rdPartyStorage^https://example.org"; - await BrowserTestUtils.withNewTab( - SUBDOMAIN_EMPTY_PAGE, - async function (browser) { - Services.perms.addFromPrincipal(principal, id, SitePermissions.ALLOW); - await openPermissionPopup(); - - let permissionsList = document.getElementById( - "permission-popup-permission-list" - ); - let listEntryCount = permissionsList.querySelectorAll( - ".permission-popup-permission-item" - ).length; - is( - listEntryCount, - 1, - "Permission exists on base domain when set on subdomain" - ); - - closePermissionPopup(); - - Services.perms.removeFromPrincipal(principal, id); - - // We intentionally turn off a11y_checks, because the following function - // is expected to click a toolbar button that may be already hidden - // with "display:none;". The permissions panel anchor is hidden because - // the last permission was removed, however we force opening the panel - // anyways in order to test that the list has been properly emptied: - AccessibilityUtils.setEnv({ - mustHaveAccessibleRule: false, - }); - await openPermissionPopup(); - AccessibilityUtils.resetEnv(); - - listEntryCount = permissionsList.querySelectorAll( - ".permission-popup-permission-item-3rdPartyStorage" - ).length; - is( - listEntryCount, - 0, - "Permission removed on base domain when removed on subdomain" - ); - - await closePermissionPopup(); - } - ); + await BrowserTestUtils.withNewTab(SUBDOMAIN_EMPTY_PAGE, async function () { + Services.perms.addFromPrincipal(principal, id, SitePermissions.ALLOW); + await openPermissionPopup(); + + let permissionsList = document.getElementById( + "permission-popup-permission-list" + ); + let listEntryCount = permissionsList.querySelectorAll( + ".permission-popup-permission-item" + ).length; + is( + listEntryCount, + 1, + "Permission exists on base domain when set on subdomain" + ); + + closePermissionPopup(); + + Services.perms.removeFromPrincipal(principal, id); + + // We intentionally turn off a11y_checks, because the following function + // is expected to click a toolbar button that may be already hidden + // with "display:none;". The permissions panel anchor is hidden because + // the last permission was removed, however we force opening the panel + // anyways in order to test that the list has been properly emptied: + AccessibilityUtils.setEnv({ + mustHaveAccessibleRule: false, + }); + await openPermissionPopup(); + AccessibilityUtils.resetEnv(); + + listEntryCount = permissionsList.querySelectorAll( + ".permission-popup-permission-item-3rdPartyStorage" + ).length; + is( + listEntryCount, + 0, + "Permission removed on base domain when removed on subdomain" + ); + + await closePermissionPopup(); + }); }); diff --git a/browser/base/content/test/permissions/browser_temporary_permissions_navigation.js b/browser/base/content/test/permissions/browser_temporary_permissions_navigation.js index 7da79b1810..490da04374 100644 --- a/browser/base/content/test/permissions/browser_temporary_permissions_navigation.js +++ b/browser/base/content/test/permissions/browser_temporary_permissions_navigation.js @@ -41,7 +41,7 @@ add_task(async function testTempPermissionOnReload() { reloaded = BrowserTestUtils.browserLoaded(browser, false, origin); // Reload as a user (should remove the temp permission). - BrowserReload(); + BrowserCommands.reload(); await reloaded; diff --git a/browser/base/content/test/plugins/head.js b/browser/base/content/test/plugins/head.js index 4f6c25b92a..76f87dfc43 100644 --- a/browser/base/content/test/plugins/head.js +++ b/browser/base/content/test/plugins/head.js @@ -147,7 +147,7 @@ function promiseWaitForFocus(aWindow) { * @return Promise */ function waitForNotificationBar(notificationID, browser, callback) { - return new Promise((resolve, reject) => { + return new Promise(resolve => { let notification; let notificationBox = gBrowser.getNotificationBox(browser); waitForCondition( @@ -189,7 +189,7 @@ function waitForNotificationShown(notification, callback) { } PopupNotifications.panel.addEventListener( "popupshown", - function (e) { + function () { callback(); }, { once: true } diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification.js b/browser/base/content/test/popupNotifications/browser_popupNotification.js index 235aa90b5f..4479cb1ee7 100644 --- a/browser/base/content/test/popupNotifications/browser_popupNotification.js +++ b/browser/base/content/test/popupNotifications/browser_popupNotification.js @@ -26,7 +26,7 @@ var tests = [ checkPopup(popup, this.notifyObj); triggerMainCommand(popup); }, - onHidden(popup) { + onHidden() { ok(this.notifyObj.mainActionClicked, "mainAction was clicked"); ok( !this.notifyObj.dismissalCallbackTriggered, @@ -55,7 +55,7 @@ var tests = [ checkPopup(popup, this.notifyObj); triggerSecondaryCommand(popup, 0); }, - onHidden(popup) { + onHidden() { ok(this.notifyObj.secondaryActionClicked, "secondaryAction was clicked"); ok( !this.notifyObj.dismissalCallbackTriggered, @@ -89,7 +89,7 @@ var tests = [ checkPopup(popup, this.notifyObj); triggerSecondaryCommand(popup, 1); }, - onHidden(popup) { + onHidden() { ok( this.extraSecondaryActionClicked, "extra secondary action was clicked" @@ -123,7 +123,7 @@ var tests = [ checkPopup(popup, this.notifyObj); triggerSecondaryCommand(popup, 2); }, - onHidden(popup) { + onHidden() { ok( this.extraSecondaryActionClicked, "extra secondary action was clicked" @@ -145,7 +145,7 @@ var tests = [ checkPopup(popup, this.notifyObj); dismissNotification(popup); }, - onHidden(popup) { + onHidden() { ok( this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered" @@ -205,7 +205,7 @@ var tests = [ // switch back to the old browser gBrowser.selectedTab = this.oldSelectedTab; }, - onHidden(popup) { + onHidden() { // actually remove the notification to prevent it from reappearing ok( wrongBrowserNotificationObject.dismissalCallbackTriggered, @@ -247,7 +247,7 @@ var tests = [ checkPopup(popup, this.notifyObj); this.notification2.remove(); }, - onHidden(popup) { + onHidden() { ok( !this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered" @@ -276,7 +276,7 @@ var tests = [ is(popup.children.length, 1, "only one notification left"); triggerSecondaryCommand(popup, 0); }, - onHidden(popup) { + onHidden() { ok(this.testNotif1.mainActionClicked, "main action #1 was clicked"); ok( !this.testNotif1.secondaryActionClicked, @@ -316,7 +316,7 @@ var tests = [ ); triggerMainCommand(popup); }, - onHidden(popup) { + onHidden() { ok(!this.notifyObj.mainActionClicked, "mainAction was not clicked"); ok( !this.notifyObj.dismissalCallbackTriggered, @@ -348,7 +348,7 @@ var tests = [ ); triggerMainCommand(popup); }, - onHidden(popup) { + onHidden() { ok(!this.notifyObj.mainActionClicked, "mainAction was not clicked"); ok( !this.notifyObj.dismissalCallbackTriggered, @@ -380,7 +380,7 @@ var tests = [ ); dismissNotification(popup); }, - onHidden(popup) { + onHidden() { // Remove the notifications this.firstNotification.remove(); this.secondNotification.remove(); diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification_2.js b/browser/base/content/test/popupNotifications/browser_popupNotification_2.js index 8738a3b605..1b0dea66f6 100644 --- a/browser/base/content/test/popupNotifications/browser_popupNotification_2.js +++ b/browser/base/content/test/popupNotifications/browser_popupNotification_2.js @@ -24,7 +24,7 @@ var tests = [ checkPopup(popup, this.notifyObj); dismissNotification(popup); }, - onHidden(popup) { + onHidden() { ok( this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered" @@ -52,7 +52,7 @@ var tests = [ ); dismissNotification(popup); }, - onHidden(popup) { + onHidden() { let icon = document.getElementById("geo-notification-icon"); isnot( icon.getBoundingClientRect().width, @@ -84,7 +84,7 @@ var tests = [ }); this.notification = showNotification(this.notifyObj); }, - async onShown(popup) { + async onShown() { this.complete = false; // eslint-disable-next-line @microsoft/sdl/no-insecure-url await promiseTabLoadEvent(gBrowser.selectedTab, "http://example.org/"); @@ -95,7 +95,7 @@ var tests = [ // eslint-disable-next-line @microsoft/sdl/no-insecure-url await promiseTabLoadEvent(gBrowser.selectedTab, "http://example.org/"); }, - onHidden(popup) { + onHidden() { ok( this.complete, "Should only have hidden the notification after 3 page loads" @@ -122,7 +122,7 @@ var tests = [ }); this.notification = showNotification(this.notifyObj); }, - async onShown(popup) { + async onShown() { this.complete = false; // eslint-disable-next-line @microsoft/sdl/no-insecure-url await promiseTabLoadEvent(gBrowser.selectedTab, "http://example.org/"); @@ -134,7 +134,7 @@ var tests = [ // eslint-disable-next-line @microsoft/sdl/no-insecure-url await promiseTabLoadEvent(gBrowser.selectedTab, "http://example.org/"); }, - onHidden(popup) { + onHidden() { ok( this.complete, "Should only have hidden the notification after the timeout was passed" @@ -172,7 +172,7 @@ var tests = [ this.complete = true; dismissNotification(popup); }, - onHidden(popup) { + onHidden() { ok( this.complete, "Should only have hidden the notification after it was dismissed" @@ -212,7 +212,7 @@ var tests = [ checkPopup(popup, this.notifyObj); dismissNotification(popup); }, - onHidden(popup) { + onHidden() { this.notification.remove(); this.box.remove(); }, @@ -272,7 +272,7 @@ var tests = [ let notification = popup.children[0]; EventUtils.synthesizeMouseAtCenter(notification.closebutton, {}); }, - onHidden(popup) { + onHidden() { ok( this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered" @@ -302,7 +302,7 @@ var tests = [ ); dismissNotification(popup); }, - onHidden(popup) { + onHidden() { ok( this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered" diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification_3.js b/browser/base/content/test/popupNotifications/browser_popupNotification_3.js index 1b7626c660..1d8b6b473b 100644 --- a/browser/base/content/test/popupNotifications/browser_popupNotification_3.js +++ b/browser/base/content/test/popupNotifications/browser_popupNotification_3.js @@ -27,7 +27,7 @@ var tests = [ checkPopup(popup, this.notifyObj); dismissNotification(popup); }, - onHidden(popup) { + onHidden() { ok( !this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered" @@ -70,7 +70,7 @@ var tests = [ dismissNotification(popup); }, - onHidden(popup) { + onHidden() { this.notification1.remove(); ok( this.notifyObj1.removedCallbackTriggered, @@ -127,7 +127,7 @@ var tests = [ dismissNotification(popup); }, - onHidden(popup) { + onHidden() { this.notificationNew.remove(); gBrowser.removeTab(gBrowser.selectedTab); @@ -156,7 +156,7 @@ var tests = [ dismissNotification(popup); }); }, - onHidden(popup) { + onHidden() { ok( !this.notifyObj.mainActionClicked, "mainAction was not clicked because it was too soon" @@ -188,7 +188,7 @@ var tests = [ triggerMainCommand(popup); }, 500); }, - onHidden(popup) { + onHidden() { ok( this.notifyObj.mainActionClicked, "mainAction was clicked after the delay" @@ -308,7 +308,7 @@ var tests = [ }; showNotification(this.notifyObj); }, - async onShown(popup) { + async onShown() { info("Adding observer and performing navigation"); await Promise.all([ diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification_4.js b/browser/base/content/test/popupNotifications/browser_popupNotification_4.js index b0e8f016ef..3ea0e943a3 100644 --- a/browser/base/content/test/popupNotifications/browser_popupNotification_4.js +++ b/browser/base/content/test/popupNotifications/browser_popupNotification_4.js @@ -23,7 +23,7 @@ var tests = [ checkPopup(popup, this.testNotif); triggerMainCommand(popup); }, - onHidden(popup) { + onHidden() { ok(this.testNotif.mainActionClicked, "main action has been triggered"); }, }, @@ -38,7 +38,7 @@ var tests = [ checkPopup(popup, this.testNotif); triggerSecondaryCommand(popup, 0); }, - onHidden(popup) { + onHidden() { ok( this.testNotif.secondaryActionClicked, "secondary action has been triggered" @@ -83,7 +83,7 @@ var tests = [ dismissNotification(popup); }, - onHidden(popup) { + onHidden() { this.notification1.remove(); this.notification2.remove(); }, @@ -213,7 +213,7 @@ var tests = [ checkPopup(popup, this.notifyObj); triggerMainCommand(popup); }, - onHidden(popup) { + onHidden() { ok( this.notifyObj.dismissalCallbackTriggered, "dismissal callback was triggered" @@ -237,7 +237,7 @@ var tests = [ checkPopup(popup, this.notifyObj); triggerSecondaryCommand(popup, 0); }, - onHidden(popup) { + onHidden() { ok( this.notifyObj.dismissalCallbackTriggered, "dismissal callback was triggered" diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification_5.js b/browser/base/content/test/popupNotifications/browser_popupNotification_5.js index 0ec5de0c3a..48640b9b00 100644 --- a/browser/base/content/test/popupNotifications/browser_popupNotification_5.js +++ b/browser/base/content/test/popupNotifications/browser_popupNotification_5.js @@ -62,7 +62,7 @@ var tests = [ this.notification1.remove(); this.notification2.remove(); }, - onHidden(popup) {}, + onHidden() {}, }, // The anchor icon should be shown for notifications in background windows. { @@ -116,7 +116,7 @@ var tests = [ this.complete = true; triggerSecondaryCommand(popup, 0); }, - onHidden(popup) { + onHidden() { ok( !this.complete, "Should have hidden the notification after navigation" @@ -155,7 +155,7 @@ var tests = [ this.complete = true; triggerSecondaryCommand(popup, 0); }, - onHidden(popup) { + onHidden() { ok( this.complete, "Should have hidden the notification after clicking Not Now" @@ -174,7 +174,7 @@ var tests = [ this.notifyObj.options.persistent = true; gNotification = showNotification(this.notifyObj); }, - async onShown(popup) { + async onShown() { this.oldSelectedTab = gBrowser.selectedTab; await BrowserTestUtils.openNewForegroundTab( gBrowser, @@ -182,7 +182,7 @@ var tests = [ "http://example.com/" ); }, - onHidden(popup) { + onHidden() { ok(true, "Should have hidden the notification after tab switch"); gBrowser.removeTab(gBrowser.selectedTab); gBrowser.selectedTab = this.oldSelectedTab; @@ -318,7 +318,7 @@ var tests = [ this.notification1.remove(); this.notification2.remove(); }, - onHidden(popup) {}, + onHidden() {}, }, // Test that persistent notifications are shown stacked by anchor on update { @@ -363,7 +363,7 @@ var tests = [ this.notification2.remove(); this.notification3.remove(); }, - onHidden(popup) {}, + onHidden() {}, }, // Test that on closebutton click, only the persistent notification // that contained the closebutton loses its persistent status. diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification_accesskey.js b/browser/base/content/test/popupNotifications/browser_popupNotification_accesskey.js index 4a68105e27..7e8e3f0269 100644 --- a/browser/base/content/test/popupNotifications/browser_popupNotification_accesskey.js +++ b/browser/base/content/test/popupNotifications/browser_popupNotification_accesskey.js @@ -36,7 +36,7 @@ var tests = [ // process of being hidden right now. isnot(popup.state, "hiding", "popup is not hiding"); }, - onHidden(popup) { + onHidden() { window.removeEventListener("command", commandTriggered, true); ok(buttonPressed, "button pressed"); }, diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification_keyboard.js b/browser/base/content/test/popupNotifications/browser_popupNotification_keyboard.js index 5c20751c3f..bd6fd38d3f 100644 --- a/browser/base/content/test/popupNotifications/browser_popupNotification_keyboard.js +++ b/browser/base/content/test/popupNotifications/browser_popupNotification_keyboard.js @@ -46,7 +46,7 @@ var tests = [ checkPopup(popup, this.notifyObj); EventUtils.synthesizeKey("KEY_Escape"); }, - onHidden(popup) { + onHidden() { ok(!this.notifyObj.mainActionClicked, "mainAction was not clicked"); ok(this.notifyObj.secondaryActionClicked, "secondaryAction was clicked"); ok( @@ -77,7 +77,7 @@ var tests = [ checkPopup(popup, this.notifyObj); EventUtils.synthesizeKey("KEY_Escape"); }, - onHidden(popup) { + onHidden() { ok(!this.notifyObj.mainActionClicked, "mainAction was not clicked"); ok( !this.notifyObj.secondaryActionClicked, @@ -123,7 +123,7 @@ var tests = [ is(document.activeElement, popup.children[0].closebutton); this.notification.remove(); }, - onHidden(popup) {}, + onHidden() {}, }, // Test that you can switch between active notifications with the space key // and that the notification is focused on selection. diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification_no_anchors.js b/browser/base/content/test/popupNotifications/browser_popupNotification_no_anchors.js index a73e1f5948..68e782cea6 100644 --- a/browser/base/content/test/popupNotifications/browser_popupNotification_no_anchors.js +++ b/browser/base/content/test/popupNotifications/browser_popupNotification_no_anchors.js @@ -43,7 +43,7 @@ var tests = [ ); dismissNotification(popup); }, - onHidden(popup) { + onHidden() { this.notification.remove(); gBrowser.removeTab(gBrowser.selectedTab); gBrowser.selectedTab = this.oldSelectedTab; @@ -85,7 +85,7 @@ var tests = [ ); dismissNotification(popup); }, - onHidden(popup) { + onHidden() { this.notification.remove(); gBrowser.removeTab(gBrowser.selectedTab); gBrowser.selectedTab = this.oldSelectedTab; @@ -135,7 +135,7 @@ var tests = [ checkPopup(popup, this.notifyObj); dismissNotification(popup); }, - onHidden(popup) { + onHidden() { this.notification.remove(); gBrowser.removeTab(gBrowser.selectedTab); gBrowser.selectedTab = this.oldSelectedTab; diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification_security_delay.js b/browser/base/content/test/popupNotifications/browser_popupNotification_security_delay.js index 3b027bc1ef..3c652b26a2 100644 --- a/browser/base/content/test/popupNotifications/browser_popupNotification_security_delay.js +++ b/browser/base/content/test/popupNotifications/browser_popupNotification_security_delay.js @@ -44,22 +44,22 @@ add_setup(async function () { }); }); +/** + * The security delay calculation in PopupNotification.sys.mjs is dependent on + * the monotonically increasing value of performance.now. This timestamp is + * not relative to a fixed date, but to runtime. + * We need to wait for the value performance.now() to be larger than the + * security delay in order to observe the bug. Only then does the + * timeSinceShown check in PopupNotifications.sys.mjs lead to a timeSinceShown + * value that is unconditionally greater than lazy.buttonDelay for + * notification.timeShown = null = 0. + * See: https://searchfox.org/mozilla-central/rev/f32d5f3949a3f4f185122142b29f2e3ab776836e/toolkit/modules/PopupNotifications.sys.mjs#1870-1872 + * + * When running in automation as part of a larger test suite performance.now() + * should usually be already sufficiently high in which case this check should + * directly resolve. + */ async function ensureSecurityDelayReady() { - /** - * The security delay calculation in PopupNotification.sys.mjs is dependent on - * the monotonically increasing value of performance.now. This timestamp is - * not relative to a fixed date, but to runtime. - * We need to wait for the value performance.now() to be larger than the - * security delay in order to observe the bug. Only then does the - * timeSinceShown check in PopupNotifications.sys.mjs lead to a timeSinceShown - * value that is unconditionally greater than lazy.buttonDelay for - * notification.timeShown = null = 0. - * See: https://searchfox.org/mozilla-central/rev/f32d5f3949a3f4f185122142b29f2e3ab776836e/toolkit/modules/PopupNotifications.sys.mjs#1870-1872 - * - * When running in automation as part of a larger test suite performance.now() - * should usually be already sufficiently high in which case this check should - * directly resolve. - */ await TestUtils.waitForCondition( () => performance.now() > TEST_SECURITY_DELAY, "Wait for performance.now() > SECURITY_DELAY", @@ -69,73 +69,73 @@ async function ensureSecurityDelayReady() { } /** - * Tests that when we show a second notification while the panel is open the - * timeShown attribute is correctly set and the security delay is enforced - * properly. + * Test helper for security delay tests which performs the following steps: + * 1. Shows a test notification. + * 2. Waits for the notification panel to be shown and checks that the initial + * security delay blocks clicks. + * 3. Waits for the security delay to expire. Clicks should now be allowed. + * 4. Executes the provided onSecurityDelayExpired function. This function + * should renew the security delay. + * 5. Tests that the security delay was renewed. + * 6. Ensures that after the security delay the notification can be closed. + * + * @param {*} options + * @param {function} options.onSecurityDelayExpired - Function to run after the + * security delay has expired. This function should trigger a renew of the + * security delay. + * @param {function} options.cleanupFn - Optional cleanup function to run after + * the test has completed. + * @returns {Promise<void>} - Resolves when the test has completed. */ -add_task(async function test_timeShownMultipleNotifications() { +async function runPopupNotificationSecurityDelayTest({ + onSecurityDelayExpired, + cleanupFn = () => {}, +}) { await ensureSecurityDelayReady(); - ok( - !PopupNotifications.isPanelOpen, - "PopupNotification panel should not be open initially." - ); - - info("Open the first notification."); + info("Open a notification."); let popupShownPromise = waitForNotificationPanel(); showNotification(); await popupShownPromise; ok( PopupNotifications.isPanelOpen, - "PopupNotification should be open after first show call." + "PopupNotification should be open after show call." ); - is( - PopupNotifications._currentNotifications.length, - 1, - "There should only be one notification" + // Test that the initial security delay works. + info( + "Trigger main action via button click during the initial security delay." ); + triggerMainCommand(PopupNotifications.panel); + await new Promise(resolve => setTimeout(resolve, 0)); + + ok(PopupNotifications.isPanelOpen, "PopupNotification should still be open."); let notification = PopupNotifications.getNotification( "foo", gBrowser.selectedBrowser ); - is(notification?.id, "foo", "There should be a notification with id foo"); - ok(notification.timeShown, "The notification should have timeShown set"); - - info( - "Call show again with the same notification id while the PopupNotification panel is still open." - ); - showNotification(); ok( - PopupNotifications.isPanelOpen, - "PopupNotification should still open after second show call." - ); - notification = PopupNotifications.getNotification( - "foo", - gBrowser.selectedBrowser - ); - is( - PopupNotifications._currentNotifications.length, - 1, - "There should still only be one notification" + notification, + "Notification should still be open because we clicked during the security delay." ); + // If the notification is no longer shown (test failure) skip the remaining + // checks. + if (!notification) { + await cleanupFn(); + return; + } - is( - notification?.id, - "foo", - "There should still be a notification with id foo" + info("Wait for security delay to expire."); + await new Promise(resolve => + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + setTimeout(resolve, TEST_SECURITY_DELAY + 500) ); - ok(notification.timeShown, "The notification should have timeShown set"); - let notificationHiddenPromise = waitForNotificationPanelHidden(); - - info("Trigger main action via button click during security delay"); - - // Wait for a tick of the event loop to ensure the button we're clicking - // has been slotted into moz-button-group - await new Promise(resolve => setTimeout(resolve, 0)); + info("Run test specific actions which restarts the security delay."); + await onSecurityDelayExpired(); + info("Trigger main action via button click during the new security delay."); triggerMainCommand(PopupNotifications.panel); await new Promise(resolve => setTimeout(resolve, 0)); @@ -149,10 +149,10 @@ add_task(async function test_timeShownMultipleNotifications() { notification, "Notification should still be open because we clicked during the security delay." ); - // If the notification is no longer shown (test failure) skip the remaining // checks. if (!notification) { + await cleanupFn(); return; } @@ -163,6 +163,7 @@ add_task(async function test_timeShownMultipleNotifications() { notification.timeShown = performance.now() - fakeTimeShown; info("Trigger main action via button click outside security delay"); + let notificationHiddenPromise = waitForNotificationPanelHidden(); triggerMainCommand(PopupNotifications.panel); info("Wait for panel to be hidden."); @@ -170,15 +171,19 @@ add_task(async function test_timeShownMultipleNotifications() { ok( !PopupNotifications.getNotification("foo", gBrowser.selectedBrowser), - "Should not longer see the notification." + "Should no longer see the notification." ); -}); + + info("Cleanup."); + await cleanupFn(); +} /** - * Tests that when we reshow a notification after a tab switch the timeShown - * attribute is correctly reset and the security delay is enforced. + * Tests that when we show a second notification while the panel is open the + * timeShown attribute is correctly set and the security delay is enforced + * properly. */ -add_task(async function test_notificationReshowTabSwitch() { +add_task(async function test_timeShownMultipleNotifications() { await ensureSecurityDelayReady(); ok( @@ -195,6 +200,12 @@ add_task(async function test_notificationReshowTabSwitch() { "PopupNotification should be open after first show call." ); + is( + PopupNotifications._currentNotifications.length, + 1, + "There should only be one notification" + ); + let notification = PopupNotifications.getNotification( "foo", gBrowser.selectedBrowser @@ -202,69 +213,39 @@ add_task(async function test_notificationReshowTabSwitch() { is(notification?.id, "foo", "There should be a notification with id foo"); ok(notification.timeShown, "The notification should have timeShown set"); - info("Trigger main action via button click during security delay"); - triggerMainCommand(PopupNotifications.panel); - - await new Promise(resolve => setTimeout(resolve, 0)); - - ok(PopupNotifications.isPanelOpen, "PopupNotification should still be open."); - notification = PopupNotifications.getNotification( - "foo", - gBrowser.selectedBrowser - ); - ok( - notification, - "Notification should still be open because we clicked during the security delay." - ); - - // If the notification is no longer shown (test failure) skip the remaining - // checks. - if (!notification) { - return; - } - - let panelHiddenPromise = waitForNotificationPanelHidden(); - let panelShownPromise; - - info("Open a new tab which hides the notification panel."); - await BrowserTestUtils.withNewTab("https://example.com", async browser => { - info("Wait for panel to be hidden by tab switch."); - await panelHiddenPromise; - info( - "Keep the tab open until the security delay for the original notification show has expired." - ); - await new Promise(resolve => - // eslint-disable-next-line mozilla/no-arbitrary-setTimeout - setTimeout(resolve, TEST_SECURITY_DELAY + 500) - ); - - panelShownPromise = waitForNotificationPanel(); - }); info( - "Wait for the panel to show again after the tab close. We're showing the original tab again." + "Call show again with the same notification id while the PopupNotification panel is still open." ); - await panelShownPromise; - + showNotification(); ok( PopupNotifications.isPanelOpen, - "PopupNotification should be shown after tab close." + "PopupNotification should still open after second show call." ); notification = PopupNotifications.getNotification( "foo", gBrowser.selectedBrowser ); is( + PopupNotifications._currentNotifications.length, + 1, + "There should still only be one notification" + ); + + is( notification?.id, "foo", "There should still be a notification with id foo" ); + ok(notification.timeShown, "The notification should have timeShown set"); let notificationHiddenPromise = waitForNotificationPanelHidden(); - info( - "Because we re-show the panel after tab close / switch the security delay should have reset." - ); - info("Trigger main action via button click during the new security delay."); + info("Trigger main action via button click during security delay"); + + // Wait for a tick of the event loop to ensure the button we're clicking + // has been slotted into moz-button-group + await new Promise(resolve => setTimeout(resolve, 0)); + triggerMainCommand(PopupNotifications.panel); await new Promise(resolve => setTimeout(resolve, 0)); @@ -278,6 +259,7 @@ add_task(async function test_notificationReshowTabSwitch() { notification, "Notification should still be open because we clicked during the security delay." ); + // If the notification is no longer shown (test failure) skip the remaining // checks. if (!notification) { @@ -298,109 +280,83 @@ add_task(async function test_notificationReshowTabSwitch() { ok( !PopupNotifications.getNotification("foo", gBrowser.selectedBrowser), - "Should not longer see the notification." + "Should no longer see the notification." ); }); /** + * Tests that when we reshow a notification after a tab switch the timeShown + * attribute is correctly reset and the security delay is enforced. + */ +add_task(async function test_notificationReshowTabSwitch() { + await runPopupNotificationSecurityDelayTest({ + onSecurityDelayExpired: async () => { + let panelHiddenPromise = waitForNotificationPanelHidden(); + let panelShownPromise; + + info("Open a new tab which hides the notification panel."); + await BrowserTestUtils.withNewTab("https://example.com", async () => { + info("Wait for panel to be hidden by tab switch."); + await panelHiddenPromise; + panelShownPromise = waitForNotificationPanel(); + }); + info( + "Wait for the panel to show again after the tab close. We're showing the original tab again." + ); + await panelShownPromise; + + ok( + PopupNotifications.isPanelOpen, + "PopupNotification should be shown after tab close." + ); + let notification = PopupNotifications.getNotification( + "foo", + gBrowser.selectedBrowser + ); + is( + notification?.id, + "foo", + "There should still be a notification with id foo" + ); + + info( + "Because we re-show the panel after tab close / switch the security delay should have reset." + ); + }, + }); +}); + +/** * Tests that the security delay gets reset when a window is repositioned and * the PopupNotifications panel position is updated. */ add_task(async function test_notificationWindowMove() { - await ensureSecurityDelayReady(); - - info("Open a notification."); - let popupShownPromise = waitForNotificationPanel(); - showNotification(); - await popupShownPromise; - ok( - PopupNotifications.isPanelOpen, - "PopupNotification should be open after show call." - ); - - // Test that the initial security delay works. - info("Trigger main action via button click during the new security delay."); - triggerMainCommand(PopupNotifications.panel); - - await new Promise(resolve => setTimeout(resolve, 0)); - - ok(PopupNotifications.isPanelOpen, "PopupNotification should still be open."); - let notification = PopupNotifications.getNotification( - "foo", - gBrowser.selectedBrowser - ); - ok( - notification, - "Notification should still be open because we clicked during the security delay." - ); - // If the notification is no longer shown (test failure) skip the remaining - // checks. - if (!notification) { - return; - } - - info("Wait for security delay to expire."); - await new Promise(resolve => - // eslint-disable-next-line mozilla/no-arbitrary-setTimeout - setTimeout(resolve, TEST_SECURITY_DELAY + 500) - ); - - info("Reposition the window"); - // Remember original window position. - let { screenX, screenY } = window; - - let promisePopupPositioned = BrowserTestUtils.waitForEvent( - PopupNotifications.panel, - "popuppositioned" - ); - - // Move the window. - window.moveTo(200, 200); - - // Wait for the panel to reposition and the PopupNotifications listener to run. - await promisePopupPositioned; - await new Promise(resolve => setTimeout(resolve, 0)); - - info("Trigger main action via button click during the new security delay."); - triggerMainCommand(PopupNotifications.panel); - - await new Promise(resolve => setTimeout(resolve, 0)); - - ok(PopupNotifications.isPanelOpen, "PopupNotification should still be open."); - notification = PopupNotifications.getNotification( - "foo", - gBrowser.selectedBrowser - ); - ok( - notification, - "Notification should still be open because we clicked during the security delay." - ); - // If the notification is no longer shown (test failure) skip the remaining - // checks. - if (!notification) { - return; - } - - // Ensure that once the security delay has passed the notification can be - // closed again. - let fakeTimeShown = TEST_SECURITY_DELAY + 500; - info(`Manually set timeShown to ${fakeTimeShown}ms in the past.`); - notification.timeShown = performance.now() - fakeTimeShown; - - info("Trigger main action via button click outside security delay"); - let notificationHiddenPromise = waitForNotificationPanelHidden(); - triggerMainCommand(PopupNotifications.panel); - - info("Wait for panel to be hidden."); - await notificationHiddenPromise; - - ok( - !PopupNotifications.getNotification("foo", gBrowser.selectedBrowser), - "Should not longer see the notification." - ); - - // Reset window position - window.moveTo(screenX, screenY); + let screenX, screenY; + + await runPopupNotificationSecurityDelayTest({ + onSecurityDelayExpired: async () => { + info("Reposition the window"); + // Remember original window position. + screenX = window.screenX; + screenY = window.screenY; + + let promisePopupPositioned = BrowserTestUtils.waitForEvent( + PopupNotifications.panel, + "popuppositioned" + ); + + // Move the window. + window.moveTo(200, 200); + + // Wait for the panel to reposition and the PopupNotifications listener to run. + await promisePopupPositioned; + await new Promise(resolve => setTimeout(resolve, 0)); + }, + cleanupFn: async () => { + // Reset window position + window.moveTo(screenX, screenY); + }, + }); }); /** @@ -563,5 +519,49 @@ add_task(async function test_notificationDuringFullScreenTransition() { info("Wait for full screen transition end."); await promiseFullScreenTransitionEnd; info("Full screen transition end"); + + await SpecialPowers.popPrefEnv(); + }); +}); + +/** + * Tests that the security delay gets extended when pointer lock is entered. + */ +add_task(async function test_notificationPointerLock() { + // We need a tab to enter pointer lock. + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "https://example.com" + ); + + await runPopupNotificationSecurityDelayTest({ + onSecurityDelayExpired: async () => { + info("Enter pointer lock"); + // Move focus to the browser to ensure pointer lock request succeeds. + gBrowser.selectedBrowser.focus(); + let pointerLockEnterPromise = TestUtils.topicObserved( + "pointer-lock-entered" + ); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { + SpecialPowers.wrap(content.document).notifyUserGestureActivation(); + await content.document.body.requestPointerLock(); + }); + + // Wait for pointer lock to be entered and the PopupNotifications listener to run. + await pointerLockEnterPromise; + await new Promise(resolve => setTimeout(resolve, 0)); + }, + cleanupFn: async () => { + // Cleanup. + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { + SpecialPowers.wrap(content.document).notifyUserGestureActivation(); + await content.document.exitPointerLock(); + }); + await TestUtils.waitForCondition( + () => !window.PointerLock.isActive, + "Wait for pointer lock exit." + ); + BrowserTestUtils.removeTab(tab); + }, }); }); diff --git a/browser/base/content/test/popups/browser_popup_close_main_window.js b/browser/base/content/test/popups/browser_popup_close_main_window.js index 148e937bca..abf6c43c3f 100644 --- a/browser/base/content/test/popups/browser_popup_close_main_window.js +++ b/browser/base/content/test/popups/browser_popup_close_main_window.js @@ -37,7 +37,7 @@ add_task(async function closing_last_window_equals_quitting() { Services.obs.addObserver(obs, "browser-lastwindow-close-requested"); let newWin = await BrowserTestUtils.openNewBrowserWindow(); let closedPromise = BrowserTestUtils.windowClosed(newWin); - newWin.BrowserTryToCloseWindow(); + newWin.BrowserCommands.tryToCloseWindow(); await closedPromise; is(observed, 1, "Got a notification for closing the normal window."); Services.obs.removeObserver(obs, "browser-lastwindow-close-requested"); @@ -68,12 +68,12 @@ add_task(async function closing_last_window_equals_quitting() { }); let popupWin = await popupPromise; let closedPromise = BrowserTestUtils.windowClosed(newWin); - newWin.BrowserTryToCloseWindow(); + newWin.BrowserCommands.tryToCloseWindow(); await closedPromise; is(observed, 0, "Got no notification for closing the normal window."); closedPromise = BrowserTestUtils.windowClosed(popupWin); - popupWin.BrowserTryToCloseWindow(); + popupWin.BrowserCommands.tryToCloseWindow(); await closedPromise; is( observed, diff --git a/browser/base/content/test/protectionsUI/browser_protectionsUI.js b/browser/base/content/test/protectionsUI/browser_protectionsUI.js index 5dc6acebf7..e512f7a415 100644 --- a/browser/base/content/test/protectionsUI/browser_protectionsUI.js +++ b/browser/base/content/test/protectionsUI/browser_protectionsUI.js @@ -500,7 +500,7 @@ add_task(async function testNumberOfBlockedTrackers() { // attribute will only be set if the previous counter is zero. Instead, we // wait for the change of the text content of the counter. let updateCounterPromise = new Promise(resolve => { - let mut = new MutationObserver(mutations => { + let mut = new MutationObserver(() => { resolve(); mut.disconnect(); }); diff --git a/browser/base/content/test/protectionsUI/browser_protectionsUI_cookies_subview.js b/browser/base/content/test/protectionsUI/browser_protectionsUI_cookies_subview.js index 00281ac415..1346fb94c1 100644 --- a/browser/base/content/test/protectionsUI/browser_protectionsUI_cookies_subview.js +++ b/browser/base/content/test/protectionsUI/browser_protectionsUI_cookies_subview.js @@ -397,7 +397,7 @@ add_task(async function testCookiesSubViewAllowedHeuristic() { let popup; let windowCreated = TestUtils.topicObserved( "chrome-document-global-created", - (subject, data) => { + subject => { popup = subject; return true; } diff --git a/browser/base/content/test/protectionsUI/browser_protectionsUI_fetch.js b/browser/base/content/test/protectionsUI/browser_protectionsUI_fetch.js index 26b131d4eb..02aa21474d 100644 --- a/browser/base/content/test/protectionsUI/browser_protectionsUI_fetch.js +++ b/browser/base/content/test/protectionsUI/browser_protectionsUI_fetch.js @@ -15,7 +15,7 @@ add_task(async function test_fetch() { await SpecialPowers.spawn(newTabBrowser, [], async function () { await content.wrappedJSObject .test_fetch() - .then(response => Assert.ok(false, "should have denied the request")) + .then(() => Assert.ok(false, "should have denied the request")) .catch(e => Assert.ok(true, `Caught exception: ${e}`)); }); await contentBlockingEvent; diff --git a/browser/base/content/test/protectionsUI/browser_protectionsUI_info_message.js b/browser/base/content/test/protectionsUI/browser_protectionsUI_info_message.js index fadfaaab98..1e07db2689 100644 --- a/browser/base/content/test/protectionsUI/browser_protectionsUI_info_message.js +++ b/browser/base/content/test/protectionsUI/browser_protectionsUI_info_message.js @@ -51,10 +51,10 @@ add_task(async function testPanelInfoMessage() { }); // Test that the info message is displayed when the panel opens - let container = document.getElementById("messaging-system-message-container"); + let container = document.getElementById("info-message-container"); let message = document.getElementById("protections-popup-message"); let learnMoreLink = document.querySelector( - "#messaging-system-message-container .text-link" + "#info-message-container .text-link" ); // Check the visibility of the info message. diff --git a/browser/base/content/test/referrer/head.js b/browser/base/content/test/referrer/head.js index c812d73e80..34a5f2a58e 100644 --- a/browser/base/content/test/referrer/head.js +++ b/browser/base/content/test/referrer/head.js @@ -165,7 +165,7 @@ function delayedStartupFinished(aWindow) { * @return {Promise} * @resolves With the tab once it's loaded. */ -function someTabLoaded(aWindow) { +function someTabLoaded() { return BrowserTestUtils.waitForNewTab(gTestWindow.gBrowser, null, true); } diff --git a/browser/base/content/test/sanitize/browser_cookiePermission_aboutURL.js b/browser/base/content/test/sanitize/browser_cookiePermission_aboutURL.js index ada8286437..ff6badb535 100644 --- a/browser/base/content/test/sanitize/browser_cookiePermission_aboutURL.js +++ b/browser/base/content/test/sanitize/browser_cookiePermission_aboutURL.js @@ -15,10 +15,10 @@ function checkDataForAboutURL() { {} ); let request = indexedDB.openForPrincipal(principal, "TestDatabase", 1); - request.onupgradeneeded = function (e) { + request.onupgradeneeded = function () { data = false; }; - request.onsuccess = function (e) { + request.onsuccess = function () { resolve(data); }; }); diff --git a/browser/base/content/test/sanitize/browser_sanitize-timespans.js b/browser/base/content/test/sanitize/browser_sanitize-timespans.js index f9be12775b..28b528d71f 100644 --- a/browser/base/content/test/sanitize/browser_sanitize-timespans.js +++ b/browser/base/content/test/sanitize/browser_sanitize-timespans.js @@ -20,7 +20,7 @@ function promiseFormHistoryRemoved() { function promiseDownloadRemoved(list) { return new Promise(resolve => { let view = { - onDownloadRemoved(download) { + onDownloadRemoved() { list.removeView(view); resolve(); }, diff --git a/browser/base/content/test/sanitize/browser_sanitize-timespans_v2.js b/browser/base/content/test/sanitize/browser_sanitize-timespans_v2.js index c732262a1a..067a651890 100644 --- a/browser/base/content/test/sanitize/browser_sanitize-timespans_v2.js +++ b/browser/base/content/test/sanitize/browser_sanitize-timespans_v2.js @@ -23,7 +23,7 @@ function promiseFormHistoryRemoved() { function promiseDownloadRemoved(list) { return new Promise(resolve => { let view = { - onDownloadRemoved(download) { + onDownloadRemoved() { list.removeView(view); resolve(); }, diff --git a/browser/base/content/test/sanitize/browser_sanitizeDialog_v2.js b/browser/base/content/test/sanitize/browser_sanitizeDialog_v2.js index 8ae0263c82..ecdc5490d4 100644 --- a/browser/base/content/test/sanitize/browser_sanitizeDialog_v2.js +++ b/browser/base/content/test/sanitize/browser_sanitizeDialog_v2.js @@ -844,14 +844,14 @@ add_task(async function testLoadtimeTelemetry() { let loadTimeDistribution = Glean.privacySanitize.loadTime.testGetValue(); let expectedNumberOfCounts = Object.entries(EXPECTED_CONTEXT_COUNTS).reduce( - (acc, [key, value]) => acc + value, + (acc, [, value]) => acc + value, 0 ); // No guarantees from timers means no guarantees on buckets. // But we can guarantee it's only two samples. is( Object.entries(loadTimeDistribution.values).reduce( - (acc, [bucket, count]) => acc + count, + (acc, [, count]) => acc + count, 0 ), expectedNumberOfCounts, diff --git a/browser/base/content/test/sanitize/browser_sanitizeDialog_v2_dataSizes.js b/browser/base/content/test/sanitize/browser_sanitizeDialog_v2_dataSizes.js index ccb3c7d519..736df32e81 100644 --- a/browser/base/content/test/sanitize/browser_sanitizeDialog_v2_dataSizes.js +++ b/browser/base/content/test/sanitize/browser_sanitizeDialog_v2_dataSizes.js @@ -10,6 +10,14 @@ ChromeUtils.defineESModuleGetters(this, { Sanitizer: "resource:///modules/Sanitizer.sys.mjs", }); +const LARGE_USAGE_NUM = 100000000000000000000000000000000000000000000000000; + +function isIframeOverflowing(win) { + return ( + win.scrollWidth > win.clientWidth || win.scrollHeight > win.clientHeight + ); +} + add_setup(async function () { await blankSlate(); registerCleanupFunction(async function () { @@ -275,7 +283,7 @@ add_task(async function testClearingBeforeDataSizesLoad() { info("stub called"); info("This promise should never resolve"); - await new Promise(resolve => {}); + await new Promise(() => {}); }); dh.onload = async function () { // we don't need to initiate a event listener to wait for the resolver to be assigned for this @@ -308,3 +316,58 @@ add_task(async function testClearingBeforeDataSizesLoad() { // Restore the sandbox after the test is complete sandbox.restore(); }); + +// tests the dialog resizing upon wrapping of text +// so that the clear buttons do not get cut out of the dialog. +add_task(async function testPossibleWrappingOfDialog() { + await blankSlate(); + + let dh = new ClearHistoryDialogHelper({ + checkingDataSizes: true, + }); + // Create a sandbox for isolated stubbing within the test + let sandbox = sinon.createSandbox(); + sandbox + .stub(SiteDataManager, "getQuotaUsageForTimeRanges") + .callsFake(async () => { + info("stubbed getQuotaUsageForTimeRanges called"); + + return { + TIMESPAN_HOUR: 0, + TIMESPAN_2HOURS: 0, + TIMESPAN_4HOURS: LARGE_USAGE_NUM, + TIMESPAN_TODAY: 0, + TIMESPAN_EVERYTHING: 0, + }; + }); + + dh.onload = async function () { + let windowObj = + window.browsingContext.topChromeWindow.gDialogBox._dialog._frame + .contentWindow; + let promise = new Promise(resolve => { + windowObj.addEventListener("resize", resolve); + }); + this.selectDuration(Sanitizer.TIMESPAN_4HOURS); + + await promise; + ok( + !isIframeOverflowing(windowObj.document.getElementById("SanitizeDialog")), + "There should be no overflow on wrapping in the dialog" + ); + + this.selectDuration(Sanitizer.TIMESPAN_2HOURS); + await promise; + ok( + !isIframeOverflowing(windowObj.document.getElementById("SanitizeDialog")), + "There should be no overflow on wrapping in the dialog" + ); + + this.cancelDialog(); + }; + dh.open(); + await dh.promiseClosed; + + // Restore the sandbox after the test is complete + sandbox.restore(); +}); diff --git a/browser/base/content/test/sanitize/head.js b/browser/base/content/test/sanitize/head.js index 30d96c69f6..1b41226fd1 100644 --- a/browser/base/content/test/sanitize/head.js +++ b/browser/base/content/test/sanitize/head.js @@ -49,10 +49,10 @@ function checkIndexedDB(host, originAttributes) { originAttributes ); let request = indexedDB.openForPrincipal(principal, "TestDatabase", 1); - request.onupgradeneeded = function (e) { + request.onupgradeneeded = function () { data = false; }; - request.onsuccess = function (e) { + request.onsuccess = function () { resolve(data); }; }); diff --git a/browser/base/content/test/sidebar/browser_sidebar_adopt.js b/browser/base/content/test/sidebar/browser_sidebar_adopt.js index 344a71cb9b..988ac1487f 100644 --- a/browser/base/content/test/sidebar/browser_sidebar_adopt.js +++ b/browser/base/content/test/sidebar/browser_sidebar_adopt.js @@ -5,7 +5,7 @@ * during the initial browser startup - but it would be hard to do with a mochitest. */ registerCleanupFunction(() => { - SidebarUI.hide(); + SidebarController.hide(); }); function failIfSidebarFocusedFires() { @@ -26,7 +26,7 @@ add_task(async function testAdoptedTwoWindows() { info("Ensure that sidebar state is adopted only from the opener"); let win1 = await BrowserTestUtils.openNewBrowserWindow(); - await win1.SidebarUI.show("viewBookmarksSidebar"); + await win1.SidebarController.show("viewBookmarksSidebar"); await BrowserTestUtils.closeWindow(win1); let win2 = await BrowserTestUtils.openNewBrowserWindow(); @@ -34,7 +34,7 @@ add_task(async function testAdoptedTwoWindows() { !win2.document.getElementById("sidebar-button").hasAttribute("checked"), "Sidebar button isn't checked" ); - ok(!win2.SidebarUI.isOpen, "Sidebar is closed"); + ok(!win2.SidebarController.isOpen, "Sidebar is closed"); await BrowserTestUtils.closeWindow(win2); }); @@ -46,7 +46,7 @@ add_task(async function testEventsReceivedInMainWindow() { let initialShown = BrowserTestUtils.waitForEvent(window, "SidebarShown"); let initialFocus = BrowserTestUtils.waitForEvent(window, "SidebarFocused"); - await SidebarUI.show("viewBookmarksSidebar"); + await SidebarController.show("viewBookmarksSidebar"); await initialShown; await initialFocus; diff --git a/browser/base/content/test/sidebar/browser_sidebar_app_locale_changed.js b/browser/base/content/test/sidebar/browser_sidebar_app_locale_changed.js index 5b07da9839..1e52895a7d 100644 --- a/browser/base/content/test/sidebar/browser_sidebar_app_locale_changed.js +++ b/browser/base/content/test/sidebar/browser_sidebar_app_locale_changed.js @@ -8,7 +8,7 @@ add_task(function cleanup() { registerCleanupFunction(() => { - SidebarUI.hide(); + SidebarController.hide(); }); }); @@ -17,7 +17,7 @@ add_task(function cleanup() { */ async function testLiveReloading(sidebarName) { info("Showing the sidebar " + sidebarName); - await SidebarUI.show(sidebarName); + await SidebarController.show(sidebarName); function getTreeChildren() { const sidebarDoc = @@ -44,7 +44,7 @@ async function testLiveReloading(sidebarName) { ); info("Hiding the sidebar"); - SidebarUI.hide(); + SidebarController.hide(); } add_task(async function test_bookmarks_sidebar() { diff --git a/browser/base/content/test/sidebar/browser_sidebar_keys.js b/browser/base/content/test/sidebar/browser_sidebar_keys.js index f12d1cf5f7..61e4ce9737 100644 --- a/browser/base/content/test/sidebar/browser_sidebar_keys.js +++ b/browser/base/content/test/sidebar/browser_sidebar_keys.js @@ -11,11 +11,11 @@ async function testSidebarKeyToggle(key, options, expectedSidebarId) { expectedSidebarId ); EventUtils.synthesizeKey(key, options); - Assert.ok(!SidebarUI.isOpen); + Assert.ok(!SidebarController.isOpen); } add_task(async function test_sidebar_keys() { - registerCleanupFunction(() => SidebarUI.hide()); + registerCleanupFunction(() => SidebarController.hide()); await testSidebarKeyToggle("b", { accelKey: true }, "viewBookmarksSidebar"); @@ -30,7 +30,7 @@ add_task(async function test_sidebar_in_customize_mode() { let { CustomizableUI } = ChromeUtils.importESModule( "resource:///modules/CustomizableUI.sys.mjs" ); - registerCleanupFunction(() => SidebarUI.hide()); + registerCleanupFunction(() => SidebarController.hide()); let placement = CustomizableUI.getPlacementOfWidget("sidebar-button"); if (!(placement?.area == CustomizableUI.AREA_NAVBAR)) { @@ -55,7 +55,7 @@ add_task(async function test_sidebar_in_customize_mode() { ).a; let promiseShown = BrowserTestUtils.waitForEvent(window, "SidebarShown"); - SidebarUI.show("viewBookmarksSidebar"); + SidebarController.show("viewBookmarksSidebar"); await promiseShown; Assert.greater( @@ -80,8 +80,8 @@ add_task(async function test_sidebar_in_customize_mode() { ); // Attempt toggle - should fail in customize mode. - await SidebarUI.toggle(); - ok(SidebarUI.isOpen, "Sidebar is still open"); + await SidebarController.toggle(); + ok(SidebarController.isOpen, "Sidebar is still open"); // Exit customize mode. This should re-enable the toggle and make the sidebar // toggle widget appear checked again, since toggle() didn't hide the sidebar. @@ -98,8 +98,8 @@ add_task(async function test_sidebar_in_customize_mode() { "Sidebar widget background should appear checked again" ); - await SidebarUI.toggle(); - ok(!SidebarUI.isOpen, "Sidebar is closed"); + await SidebarController.toggle(); + ok(!SidebarController.isOpen, "Sidebar is closed"); Assert.equal( getBGAlpha(), 0, diff --git a/browser/base/content/test/sidebar/browser_sidebar_move.js b/browser/base/content/test/sidebar/browser_sidebar_move.js index 3de26b7966..05ea9e3322 100644 --- a/browser/base/content/test/sidebar/browser_sidebar_move.js +++ b/browser/base/content/test/sidebar/browser_sidebar_move.js @@ -1,18 +1,20 @@ registerCleanupFunction(() => { Services.prefs.clearUserPref("sidebar.position_start"); - SidebarUI.hide(); + SidebarController.hide(); }); const EXPECTED_START_ORDINALS = [ - ["sidebar-box", 1], - ["sidebar-splitter", 2], - ["appcontent", 3], + ["sidebar-main", 1], + ["sidebar-box", 2], + ["sidebar-splitter", 3], + ["appcontent", 4], ]; const EXPECTED_END_ORDINALS = [ - ["sidebar-box", 3], - ["sidebar-splitter", 2], - ["appcontent", 1], + ["sidebar-main", 5], + ["sidebar-box", 4], + ["sidebar-splitter", 3], + ["appcontent", 2], ]; function getBrowserChildrenWithOrdinals() { @@ -23,8 +25,8 @@ function getBrowserChildrenWithOrdinals() { } add_task(async function () { - await SidebarUI.show("viewBookmarksSidebar"); - SidebarUI.showSwitcherPanel(); + await SidebarController.show("viewBookmarksSidebar"); + SidebarController.showSwitcherPanel(); let reversePositionButton = document.getElementById( "sidebar-reverse-position" @@ -41,8 +43,8 @@ add_task(async function () { ok(!box.hasAttribute("positionend"), "Positioned start"); // Moved to right - SidebarUI.reversePosition(); - SidebarUI.showSwitcherPanel(); + SidebarController.reversePosition(); + SidebarController.showSwitcherPanel(); Assert.deepEqual( getBrowserChildrenWithOrdinals(), EXPECTED_END_ORDINALS, @@ -56,8 +58,8 @@ add_task(async function () { ok(box.hasAttribute("positionend"), "Positioned end"); // Moved to back to left - SidebarUI.reversePosition(); - SidebarUI.showSwitcherPanel(); + SidebarController.reversePosition(); + SidebarController.showSwitcherPanel(); Assert.deepEqual( getBrowserChildrenWithOrdinals(), EXPECTED_START_ORDINALS, diff --git a/browser/base/content/test/sidebar/browser_sidebar_persist.js b/browser/base/content/test/sidebar/browser_sidebar_persist.js index fe67bed9e0..4977c7ef0f 100644 --- a/browser/base/content/test/sidebar/browser_sidebar_persist.js +++ b/browser/base/content/test/sidebar/browser_sidebar_persist.js @@ -18,7 +18,7 @@ add_task(async function persist_sidebar_width() { { info("Showing new window and setting sidebar box"); const win = await BrowserTestUtils.openNewBrowserWindow(); - await win.SidebarUI.show("viewBookmarksSidebar"); + await win.SidebarController.show("viewBookmarksSidebar"); win.document.getElementById("sidebar-box").style.width = "100px"; await BrowserTestUtils.closeWindow(win); } @@ -26,7 +26,7 @@ add_task(async function persist_sidebar_width() { { info("Showing new window and seeing persisted width"); const win = await BrowserTestUtils.openNewBrowserWindow(); - await win.SidebarUI.show("viewBookmarksSidebar"); + await win.SidebarController.show("viewBookmarksSidebar"); is( win.document.getElementById("sidebar-box").style.width, "100px", diff --git a/browser/base/content/test/sidebar/browser_sidebar_switcher.js b/browser/base/content/test/sidebar/browser_sidebar_switcher.js index 032c23b029..0fc9e18e01 100644 --- a/browser/base/content/test/sidebar/browser_sidebar_switcher.js +++ b/browser/base/content/test/sidebar/browser_sidebar_switcher.js @@ -1,5 +1,5 @@ registerCleanupFunction(() => { - SidebarUI.hide(); + SidebarController.hide(); }); /** @@ -9,14 +9,14 @@ registerCleanupFunction(() => { */ function showSwitcherPanelPromise() { return new Promise(resolve => { - SidebarUI._switcherPanel.addEventListener( + SidebarController._switcherPanel.addEventListener( "popupshown", () => { resolve(); }, { once: true } ); - SidebarUI.showSwitcherPanel(); + SidebarController.showSwitcherPanel(); }); } @@ -25,7 +25,10 @@ function showSwitcherPanelPromise() { * @returns Promise which resolves when the popup menu is opened */ async function waitForSwitcherPopupShown() { - return BrowserTestUtils.waitForEvent(SidebarUI._switcherPanel, "popupshown"); + return BrowserTestUtils.waitForEvent( + SidebarController._switcherPanel, + "popupshown" + ); } /** @@ -63,7 +66,7 @@ async function testSidebarMenuKeyToggle(key, sidebarTitle) { info(`Testing "${key}" key handling of sidebar menu popup items to access ${sidebarTitle} sidebar`); - Assert.ok(SidebarUI.isOpen, "Sidebar is open"); + Assert.ok(SidebarController.isOpen, "Sidebar is open"); let sidebarSwitcher = document.querySelector("#sidebar-switcher-target"); let sidebar = document.getElementById("sidebar"); @@ -89,7 +92,7 @@ async function testSidebarMenuKeyToggle(key, sidebarTitle) { "The sidebar switcher target button is focused" ); Assert.equal( - SidebarUI._switcherPanel.state, + SidebarController._switcherPanel.state, "closed", "Sidebar menu popup is closed" ); @@ -102,7 +105,7 @@ async function testSidebarMenuKeyToggle(key, sidebarTitle) { await promisePopupShown; Assert.equal( - SidebarUI._switcherPanel.state, + SidebarController._switcherPanel.state, "open", "Sidebar menu popup is open" ); @@ -111,7 +114,7 @@ async function testSidebarMenuKeyToggle(key, sidebarTitle) { let arrowDown = async (menuitemId, msg) => { let menuItemActive = BrowserTestUtils.waitForEvent( - SidebarUI._switcherPanel, + SidebarController._switcherPanel, "DOMMenuItemActive" ); EventUtils.synthesizeKey("KEY_ArrowDown", {}); @@ -149,18 +152,18 @@ async function testSidebarMenuKeyToggle(key, sidebarTitle) { info("Testing keyboard navigation when a sidebar menu popup is closed"); Assert.equal( - SidebarUI._switcherPanel.state, + SidebarController._switcherPanel.state, "closed", "Sidebar menu popup is closed" ); // Test the sidebar panel is updated Assert.equal( - SidebarUI._box.getAttribute("sidebarcommand"), + SidebarController._box.getAttribute("sidebarcommand"), `view${sidebarTitle}Sidebar` /* e.g. "viewHistorySidebar" */, `${sidebarTitle} sidebar loaded` ); Assert.equal( - SidebarUI.currentID, + SidebarController.currentID, `view${sidebarTitle}Sidebar` /* e.g. "viewHistorySidebar" */, `${sidebarTitle}'s current ID is updated to a target view` ); @@ -173,7 +176,7 @@ add_task(async function markup() { false, "Unexpected sidebar found - a previous test failed to cleanup correctly" ); - SidebarUI.hide(); + SidebarController.hide(); } let sidebarPopup = document.querySelector("#sidebarMenu-popup"); @@ -205,7 +208,7 @@ add_task(async function markup() { info("Test dynamic changes in the markup of the sidebar switcher control"); - await SidebarUI.show("viewBookmarksSidebar"); + await SidebarController.show("viewBookmarksSidebar"); await showSwitcherPanelPromise(); Assert.equal( @@ -229,25 +232,25 @@ add_task(async function markup() { "Sidebar switcher button is collapsed when a sidebar menu is dismissed" ); - SidebarUI.hide(); + SidebarController.hide(); }); add_task(async function keynav() { // If a sidebar is already open, close it. - if (SidebarUI.isOpen) { + if (SidebarController.isOpen) { Assert.ok( false, "Unexpected sidebar found - a previous test failed to cleanup correctly" ); - SidebarUI.hide(); + SidebarController.hide(); } - await SidebarUI.show("viewBookmarksSidebar"); + await SidebarController.show("viewBookmarksSidebar"); await testSidebarMenuKeyToggle("KEY_Enter", "History"); await testSidebarMenuKeyToggle(" ", "Tabs"); - SidebarUI.hide(); + SidebarController.hide(); }); add_task(async function mouse() { @@ -257,11 +260,11 @@ add_task(async function mouse() { false, "Unexpected sidebar found - a previous test failed to cleanup correctly" ); - SidebarUI.hide(); + SidebarController.hide(); } let sidebar = document.querySelector("#sidebar-box"); - await SidebarUI.show("viewBookmarksSidebar"); + await SidebarController.show("viewBookmarksSidebar"); await showSwitcherPanelPromise(); await pickSwitcherMenuitem("#sidebar-switcher-history"); diff --git a/browser/base/content/test/siteIdentity/browser_identityBlock_focus.js b/browser/base/content/test/siteIdentity/browser_identityBlock_focus.js index 858cd3d632..79b6d216c5 100644 --- a/browser/base/content/test/siteIdentity/browser_identityBlock_focus.js +++ b/browser/base/content/test/siteIdentity/browser_identityBlock_focus.js @@ -98,7 +98,7 @@ add_task(async function testWithNotifications() { // Checks that with invalid pageproxystate the identity block is ignored. add_task(async function testInvalidPageProxyState() { await SpecialPowers.pushPrefEnv({ set: [["accessibility.tabfocus", 7]] }); - await BrowserTestUtils.withNewTab("about:blank", async function (browser) { + await BrowserTestUtils.withNewTab("about:blank", async function () { // Loading about:blank will automatically focus the urlbar, which, however, can // race with the test code. So we only send the shortcut if the urlbar isn't focused yet. if (document.activeElement != gURLBar.inputField) { diff --git a/browser/base/content/test/siteIdentity/browser_identityPopup_clearSiteData.js b/browser/base/content/test/siteIdentity/browser_identityPopup_clearSiteData.js index 0107814b98..ff77b42ed8 100644 --- a/browser/base/content/test/siteIdentity/browser_identityPopup_clearSiteData.js +++ b/browser/base/content/test/siteIdentity/browser_identityPopup_clearSiteData.js @@ -67,7 +67,7 @@ async function testClearing( }); } - await BrowserTestUtils.withNewTab(testURI, async function (browser) { + await BrowserTestUtils.withNewTab(testURI, async function () { // Verify we have added quota storage. if (testQuota) { let usage = await SiteDataTestUtils.getQuotaUsage(originA); diff --git a/browser/base/content/test/siteIdentity/browser_navigation_failures.js b/browser/base/content/test/siteIdentity/browser_navigation_failures.js index ac3fcc4067..f71552cdcf 100644 --- a/browser/base/content/test/siteIdentity/browser_navigation_failures.js +++ b/browser/base/content/test/siteIdentity/browser_navigation_failures.js @@ -85,10 +85,10 @@ function startServer(cert) { output = transport.openOutputStream(0, 0, 0); }, - onHandshakeDone(socket, status) { + onHandshakeDone() { input.asyncWait( { - onInputStreamReady(readyInput) { + onInputStreamReady() { try { input.close(); output.close(); diff --git a/browser/base/content/test/siteIdentity/browser_secure_transport_insecure_scheme.js b/browser/base/content/test/siteIdentity/browser_secure_transport_insecure_scheme.js index 9dce76266a..bd004bae1b 100644 --- a/browser/base/content/test/siteIdentity/browser_secure_transport_insecure_scheme.js +++ b/browser/base/content/test/siteIdentity/browser_secure_transport_insecure_scheme.js @@ -19,7 +19,7 @@ const NOT_SECURE_LABEL = Services.prefs.getBoolPref( * @param {string} uri - URI of the page to test with. */ async function testPageInfoNotEncrypted(uri) { - let pageInfo = BrowserPageInfo(uri, "securityTab"); + let pageInfo = BrowserCommands.pageInfo(uri, "securityTab"); await BrowserTestUtils.waitForEvent(pageInfo, "load"); let pageInfoDoc = pageInfo.document; let securityTab = pageInfoDoc.getElementById("securityTab"); @@ -87,7 +87,7 @@ function startServer(cert) { output = transport.openOutputStream(0, 0, 0); }, - onHandshakeDone(socket, status) { + onHandshakeDone() { input.asyncWait( { onInputStreamReady(readyInput) { @@ -152,7 +152,7 @@ add_task(async function () { QueryInterface: ChromeUtils.generateQI(["nsISystemProxySettings"]), mainThreadOnly: true, PACURI: null, - getProxyForURI: (aSpec, aScheme, aHost, aPort) => { + getProxyForURI: () => { return `HTTPS localhost:${server.port}`; }, }; @@ -181,7 +181,7 @@ add_task(async function () { // secure, in a real situation the connection from the proxy to // http://example.com won't be secure, so we treat it as not secure. // eslint-disable-next-line @microsoft/sdl/no-insecure-url - await BrowserTestUtils.withNewTab("http://example.com/", async browser => { + await BrowserTestUtils.withNewTab("http://example.com/", async () => { let identityMode = window.document.getElementById("identity-box").className; is( identityMode, diff --git a/browser/base/content/test/siteIdentity/head.js b/browser/base/content/test/siteIdentity/head.js index 733796ffb7..9936a8bf6f 100644 --- a/browser/base/content/test/siteIdentity/head.js +++ b/browser/base/content/test/siteIdentity/head.js @@ -244,12 +244,12 @@ async function assertMixedContentBlockingState(tabbrowser, states = {}) { ); gIdentityHandler._identityIconBox.click(); await promisePanelOpen; - let popupAttr = doc - .getElementById("identity-popup") - .getAttribute("mixedcontent"); - let bodyAttr = doc - .getElementById("identity-popup-securityView-extended-info") - .getAttribute("mixedcontent"); + let popupAttr = + doc.getElementById("identity-popup").getAttribute("mixedcontent") || ""; + let bodyAttr = + doc + .getElementById("identity-popup-securityView-extended-info") + .getAttribute("mixedcontent") || ""; is( popupAttr.includes("active-loaded"), diff --git a/browser/base/content/test/static/browser_all_files_referenced.js b/browser/base/content/test/static/browser_all_files_referenced.js index 5e83443ec7..9668288181 100644 --- a/browser/base/content/test/static/browser_all_files_referenced.js +++ b/browser/base/content/test/static/browser_all_files_referenced.js @@ -81,6 +81,9 @@ var gExceptionPaths = [ // CSS files are referenced inside JS in an html template "chrome://browser/content/aboutlogins/components/", + + // Strip on Share parameter lists + "chrome://global/content/antitracking/", ]; // These are not part of the omni.ja file, so we find them only when running @@ -99,13 +102,6 @@ if (AppConstants.MOZ_BACKGROUNDTASKS) { gExceptionPaths.push("resource://app/modules/backgroundtasks/"); } -if (AppConstants.NIGHTLY_BUILD) { - // This is nightly-only debug tool. - gExceptionPaths.push( - "chrome://browser/content/places/interactionsViewer.html" - ); -} - // Each allowlist entry should have a comment indicating which file is // referencing the listed file in a way that the test can't detect, or a // bug number to remove or use the file if it is indeed currently unreferenced. @@ -280,9 +276,6 @@ var allowlist = [ // find the references) { file: "chrome://browser/content/screenshots/copied-notification.svg" }, - // Bug 1875361 - { file: "chrome://global/content/ml/SummarizerModel.sys.mjs" }, - // toolkit/xre/MacRunFromDmgUtils.mm { file: "resource://gre/localization/en-US/toolkit/global/run-from-dmg.ftl" }, @@ -291,8 +284,31 @@ var allowlist = [ { file: "chrome://browser/content/screenshots/copy.svg" }, { file: "chrome://browser/content/screenshots/download.svg" }, { file: "chrome://browser/content/screenshots/download-white.svg" }, + + // Referenced programmatically + { file: "chrome://browser/content/backup/BackupManifest.1.schema.json" }, + + // Bug 1892002 + { file: "resource://app/modules/TopSites.sys.mjs" }, ]; +if (AppConstants.NIGHTLY_BUILD) { + allowlist.push( + ...[ + // This is nightly-only debug tool. + { file: "chrome://browser/content/places/interactionsViewer.html" }, + + // A debug tool that is only available in Nightly builds, and is accessed + // directly by developers via the chrome URI (bug 1888491) + { file: "chrome://browser/content/backup/debug.html" }, + + // The Transformers.js prod lib is not used in Nightly builds + { file: "chrome://global/content/ml/transformers.js" }, + { file: "chrome://global/content/ml/ort.js" }, + ] + ); +} + if (AppConstants.platform != "win") { // toolkit/mozapps/defaultagent/Notification.cpp // toolkit/mozapps/defaultagent/ScheduledTask.cpp diff --git a/browser/base/content/test/static/browser_parsable_css.js b/browser/base/content/test/static/browser_parsable_css.js index 602cc5a7e2..6b075fc98f 100644 --- a/browser/base/content/test/static/browser_parsable_css.js +++ b/browser/base/content/test/static/browser_parsable_css.js @@ -14,12 +14,6 @@ let ignoreList = [ { sourceName: /codemirror\.css$/i, isFromDevTools: true }, // UA-only media features. { - sourceName: /\b(autocomplete-item)\.css$/, - errorMessage: /Expected media feature name but found \u2018-moz.*/i, - isFromDevTools: false, - platforms: ["windows"], - }, - { sourceName: /\b(contenteditable|EditorOverride|svg|forms|html|mathml|ua)\.css$/i, errorMessage: /Unknown pseudo-class.*-moz-/i, @@ -27,7 +21,7 @@ let ignoreList = [ }, { sourceName: - /\b(scrollbars|xul|html|mathml|ua|forms|svg|manageDialog|autocomplete-item-shared|formautofill)\.css$/i, + /\b(scrollbars|xul|html|mathml|ua|forms|svg|manageDialog|formautofill)\.css$/i, errorMessage: /Unknown property.*-moz-/i, isFromDevTools: false, }, @@ -42,6 +36,12 @@ let ignoreList = [ errorMessage: /Unknown property.*overflow-clip-box/i, isFromDevTools: false, }, + // content: -moz-alt-content is UA-only. + { + sourceName: /\b(html)\.css$/i, + errorMessage: /Error in parsing value for ‘content’/i, + isFromDevTools: false, + }, // These variables are declared somewhere else, and error when we load the // files directly. They're all marked intermittent because their appearance // in the error console seems to not be consistent. @@ -123,6 +123,8 @@ let propNameAllowlist = [ isFromDevTools: false, }, { propName: "--browser-stack-z-index-rdm-toolbar", isFromDevTools: false }, + // about:profiling is in devtools even though it uses non-devtools styles. + { propName: "--in-content-border-hover", isFromDevTools: false }, // These variables are specified from devtools but read from non-devtools // styles, which confuses the test. @@ -434,13 +436,13 @@ add_task(async function checkAllTheCSS() { let loadCSS = chromeUri => new Promise(resolve => { let linkEl, onLoad, onError; - onLoad = e => { + onLoad = () => { processCSSRules(linkEl.sheet); resolve(); linkEl.removeEventListener("load", onLoad); linkEl.removeEventListener("error", onError); }; - onError = e => { + onError = () => { ok( false, "Loading " + linkEl.getAttribute("href") + " threw an error!" diff --git a/browser/base/content/test/static/browser_parsable_script.js b/browser/base/content/test/static/browser_parsable_script.js index d4dcbd87fe..71a2930ddc 100644 --- a/browser/base/content/test/static/browser_parsable_script.js +++ b/browser/base/content/test/static/browser_parsable_script.js @@ -19,12 +19,13 @@ const kESModuleList = new Set([ /browser\/vpn-card.js$/, /toolkit\/content\/global\/certviewer\/components\/.*\.js$/, /toolkit\/content\/global\/certviewer\/.*\.js$/, + /toolkit\/content\/global\/ml\/transformers.*\.js$/, /chrome\/pdfjs\/content\/web\/.*\.js$/, ]); -// Normally we would use reflect.jsm to get Reflect.parse. However, if -// we do that, then all the AST data is allocated in reflect.jsm's -// zone. That exposes a bug in our GC. The GC collects reflect.jsm's +// Normally we would use reflect.sys.mjs to get Reflect.parse. However, if +// we do that, then all the AST data is allocated in reflect.sys.mjs's +// zone. That exposes a bug in our GC. The GC collects reflect.sys.mjs's // zone but not the zone in which our test code lives (since no new // data is being allocated in it). The cross-compartment wrappers in // our zone that point to the AST data never get collected, and so the @@ -69,7 +70,7 @@ function uriIsESModule(uri) { } function parsePromise(uri, parseTarget) { - let promise = new Promise((resolve, reject) => { + let promise = new Promise(resolve => { let xhr = new XMLHttpRequest(); xhr.open("GET", uri, true); xhr.onreadystatechange = function () { diff --git a/browser/base/content/test/static/browser_sentence_case_strings.js b/browser/base/content/test/static/browser_sentence_case_strings.js index e995f76b1a..12952c9600 100644 --- a/browser/base/content/test/static/browser_sentence_case_strings.js +++ b/browser/base/content/test/static/browser_sentence_case_strings.js @@ -103,7 +103,7 @@ function checkSubheaders(view) { } async function checkUpdateBanner(view) { - let banner = view.querySelector("#appMenu-proton-update-banner"); + let banner = view.querySelector("#appMenu-update-banner"); const notifications = [ "update-downloading", diff --git a/browser/base/content/test/static/head.js b/browser/base/content/test/static/head.js index d9b978e853..317ad430af 100644 --- a/browser/base/content/test/static/head.js +++ b/browser/base/content/test/static/head.js @@ -135,7 +135,7 @@ function* generateEntriesFromJarFile(jarFile, extension) { } function fetchFile(uri) { - return new Promise((resolve, reject) => { + return new Promise(resolve => { let xhr = new XMLHttpRequest(); xhr.responseType = "text"; xhr.open("GET", uri, true); diff --git a/browser/base/content/test/sync/browser_contextmenu_sendpage.js b/browser/base/content/test/sync/browser_contextmenu_sendpage.js index a80cf8a1d0..14b5f72860 100644 --- a/browser/base/content/test/sync/browser_contextmenu_sendpage.js +++ b/browser/base/content/test/sync/browser_contextmenu_sendpage.js @@ -93,47 +93,44 @@ add_task(async function test_link_contextmenu() { "context-sendlinktodevice-popup" ); - let expectedArray = ["context-openlinkintab"]; - - if ( + const expectOpenLinkInUserContextMenu = Services.prefs.getBoolPref("privacy.userContext.enabled") && - ContextualIdentityService.getPublicIdentities().length - ) { - expectedArray.push("context-openlinkinusercontext-menu"); - } + ContextualIdentityService.getPublicIdentities().length; + + const expectStripOnShareLink = Services.prefs.getBoolPref( + "privacy.query_stripping.strip_on_share.enabled" + ); + + const expectTranslateSelection = + Services.prefs.getBoolPref("browser.translations.enable") && + Services.prefs.getBoolPref("browser.translations.select.enable"); - expectedArray.push( + const expectInspectAccessibility = + Services.prefs.getBoolPref("devtools.accessibility.enabled", true) && + (Services.prefs.getBoolPref("devtools.everOpened", false) || + Services.prefs.getIntPref("devtools.selfxss.count", 0) > 0); + + const expectedArray = [ + "context-openlinkintab", + ...(expectOpenLinkInUserContextMenu + ? ["context-openlinkinusercontext-menu"] + : []), "context-openlink", "context-openlinkprivate", "context-sep-open", "context-bookmarklink", "context-savelink", "context-savelinktopocket", - "context-copylink" - ); - - if ( - Services.prefs.getBoolPref("privacy.query_stripping.strip_on_share.enabled") - ) { - expectedArray.push("context-stripOnShareLink"); - } - - expectedArray.push( + "context-copylink", + ...(expectStripOnShareLink ? ["context-stripOnShareLink"] : []), "context-sendlinktodevice", "context-sep-sendlinktodevice", "context-searchselect", - "frame-sep" - ); - - if ( - Services.prefs.getBoolPref("devtools.accessibility.enabled", true) && - (Services.prefs.getBoolPref("devtools.everOpened", false) || - Services.prefs.getIntPref("devtools.selfxss.count", 0) > 0) - ) { - expectedArray.push("context-inspect-a11y"); - } - - expectedArray.push("context-inspect"); + ...(expectTranslateSelection ? ["context-translate-selection"] : []), + "frame-sep", + ...(expectInspectAccessibility ? ["context-inspect-a11y"] : []), + "context-inspect", + ]; let menu = document.getElementById("contentAreaContextMenu"); diff --git a/browser/base/content/test/sync/browser_contextmenu_sendtab.js b/browser/base/content/test/sync/browser_contextmenu_sendtab.js index 4922869c1d..bc49680e37 100644 --- a/browser/base/content/test/sync/browser_contextmenu_sendtab.js +++ b/browser/base/content/test/sync/browser_contextmenu_sendtab.js @@ -323,7 +323,7 @@ async function openTabContextMenu(openSubmenuId = null) { function promiseObserver(topic) { return new Promise(resolve => { - let obs = (aSubject, aTopic, aData) => { + let obs = (aSubject, aTopic) => { Services.obs.removeObserver(obs, aTopic); resolve(aSubject); }; diff --git a/browser/base/content/test/sync/browser_fxa_web_channel.js b/browser/base/content/test/sync/browser_fxa_web_channel.js index c232f26f26..23c5510422 100644 --- a/browser/base/content/test/sync/browser_fxa_web_channel.js +++ b/browser/base/content/test/sync/browser_fxa_web_channel.js @@ -27,7 +27,7 @@ var gTests = [ content_uri: TEST_HTTP_PATH, channel_id: TEST_CHANNEL_ID, }); - let promiseObserver = new Promise((resolve, reject) => { + let promiseObserver = new Promise(resolve => { makeObserver( ON_PROFILE_CHANGE_NOTIFICATION, function (subject, topic, data) { @@ -52,7 +52,7 @@ var gTests = [ { desc: "fxa web channel - login messages should notify the fxAccounts object", async run() { - let promiseLogin = new Promise((resolve, reject) => { + let promiseLogin = new Promise(resolve => { let login = accountData => { Assert.equal(typeof accountData.authAt, "number"); Assert.equal(accountData.email, "testuser@testuser.com"); @@ -91,7 +91,7 @@ var gTests = [ async run() { let properUrl = TEST_BASE_URL + "?can_link_account"; - let promiseEcho = new Promise((resolve, reject) => { + let promiseEcho = new Promise(resolve => { let webChannelOrigin = Services.io.newURI(properUrl); // responses sent to content are echoed back over the // `fxaccounts_webchannel_response_echo` channel. Ensure the @@ -100,7 +100,7 @@ var gTests = [ "fxaccounts_webchannel_response_echo", webChannelOrigin ); - echoWebChannel.listen((webChannelId, message, target) => { + echoWebChannel.listen((webChannelId, message) => { Assert.equal(message.command, "fxaccounts:can_link_account"); Assert.equal(message.messageId, 2); Assert.equal(message.data.ok, true); @@ -136,7 +136,7 @@ var gTests = [ { desc: "fxa web channel - logout messages should notify the fxAccounts object", async run() { - let promiseLogout = new Promise((resolve, reject) => { + let promiseLogout = new Promise(resolve => { let logout = uid => { Assert.equal(uid, "uid"); @@ -167,7 +167,7 @@ var gTests = [ { desc: "fxa web channel - delete messages should notify the fxAccounts object", async run() { - let promiseDelete = new Promise((resolve, reject) => { + let promiseDelete = new Promise(resolve => { let logout = uid => { Assert.equal(uid, "uid"); @@ -199,8 +199,8 @@ var gTests = [ desc: "fxa web channel - firefox_view messages should call the openFirefoxView helper", async run() { let wasCalled = false; - let promiseMessageHandled = new Promise((resolve, reject) => { - let openFirefoxView = (browser, entryPoint) => { + let promiseMessageHandled = new Promise(resolve => { + let openFirefoxView = browser => { wasCalled = true; Assert.ok( !!browser.ownerGlobal, diff --git a/browser/base/content/test/sync/browser_sync.js b/browser/base/content/test/sync/browser_sync.js index 168c6f22b0..03077ea67c 100644 --- a/browser/base/content/test/sync/browser_sync.js +++ b/browser/base/content/test/sync/browser_sync.js @@ -607,17 +607,20 @@ add_task(async function test_experiment_ui_state_unconfigured() { checkFxAAvatar("not_configured"); let expectedLabel = gSync.fluentStrings.formatValueSync( - "appmenuitem-sign-in-account" + "synced-tabs-fxa-sign-in" + ); + + let expectedDescriptionLabel = gSync.fluentStrings.formatValueSync( + "fxa-menu-sync-description" ); await openMainPanel(); checkFxaToolbarButtonPanel({ headerTitle: expectedLabel, - headerDescription: "", + headerDescription: expectedDescriptionLabel, enabledItems: [ "PanelUI-fxa-cta-menu", - "PanelUI-fxa-menu-sync-button", "PanelUI-fxa-menu-monitor-button", "PanelUI-fxa-menu-relay-button", "PanelUI-fxa-menu-vpn-button", @@ -690,7 +693,6 @@ add_task(async function test_experiment_ui_state_signedin() { "PanelUI-fxa-menu-sync-prefs-button", "PanelUI-fxa-menu-account-signout-button", "PanelUI-fxa-cta-menu", - "PanelUI-fxa-menu-sync-button", "PanelUI-fxa-menu-monitor-button", "PanelUI-fxa-menu-relay-button", "PanelUI-fxa-menu-vpn-button", @@ -772,7 +774,7 @@ function checkSyncNowButtons(syncing, tooltip = null) { for (const syncButton of syncButtons) { is( syncButton.getAttribute("syncstatus"), - syncing ? "active" : "", + syncing ? "active" : null, "button active has the right value" ); if (tooltip) { @@ -894,7 +896,7 @@ function checkItemsVisibilities(itemsIds, expectedShownItemId) { function promiseObserver(topic) { return new Promise(resolve => { - let obs = (aSubject, aTopic, aData) => { + let obs = (aSubject, aTopic) => { Services.obs.removeObserver(obs, aTopic); resolve(aSubject); }; diff --git a/browser/base/content/test/tabPrompts/browser.toml b/browser/base/content/test/tabPrompts/browser.toml index 037f1f0d2b..aa7d4c724e 100644 --- a/browser/base/content/test/tabPrompts/browser.toml +++ b/browser/base/content/test/tabPrompts/browser.toml @@ -39,6 +39,8 @@ support-files = ["file_beforeunload_stop.html"] https_first_disabled = true support-files = ["openPromptOffTimeout.html"] +["browser_promptDelays.js"] + ["browser_promptFocus.js"] ["browser_prompt_close_event.js"] diff --git a/browser/base/content/test/tabPrompts/browser_abort_when_in_modal_state.js b/browser/base/content/test/tabPrompts/browser_abort_when_in_modal_state.js index cb3a1f72d6..d6d2434017 100644 --- a/browser/base/content/test/tabPrompts/browser_abort_when_in_modal_state.js +++ b/browser/base/content/test/tabPrompts/browser_abort_when_in_modal_state.js @@ -8,14 +8,10 @@ const { PromiseTestUtils } = ChromeUtils.importESModule( ); /** - * Check that if we're using a window-modal prompt, - * the next synchronous window-internal modal prompt aborts rather than - * leaving us in a deadlock about how to enter modal state. + * Check that the next synchronous window-internal modal prompt aborts rather + * than leaving us in a deadlock about how to enter modal state. */ add_task(async function test_check_multiple_prompts() { - await SpecialPowers.pushPrefEnv({ - set: [["prompts.windowPromptSubDialog", true]], - }); let container = document.getElementById("window-modal-dialog"); let dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(); diff --git a/browser/base/content/test/tabPrompts/browser_auth_spoofing_protection.js b/browser/base/content/test/tabPrompts/browser_auth_spoofing_protection.js index 86d7c992c5..1211694973 100644 --- a/browser/base/content/test/tabPrompts/browser_auth_spoofing_protection.js +++ b/browser/base/content/test/tabPrompts/browser_auth_spoofing_protection.js @@ -119,7 +119,7 @@ async function waitForDialog(doConfirmPrompt, crossDomain, prefEnabled) { } else { Assert.equal( dialog._overlay.getAttribute("hideContent"), - "", + null, "Dialog overlay does not hide the current sites content" ); Assert.equal( @@ -137,7 +137,7 @@ async function waitForDialog(doConfirmPrompt, crossDomain, prefEnabled) { } else { Assert.equal( dialog._overlay.getAttribute("hideContent"), - "", + null, "Dialog overlay does not hide the current sites content" ); Assert.equal( diff --git a/browser/base/content/test/tabPrompts/browser_contentOrigins.js b/browser/base/content/test/tabPrompts/browser_contentOrigins.js index 2bf4ba6039..0c40763a99 100644 --- a/browser/base/content/test/tabPrompts/browser_contentOrigins.js +++ b/browser/base/content/test/tabPrompts/browser_contentOrigins.js @@ -127,12 +127,6 @@ async function checkDialog( }); } -add_setup(async function () { - await SpecialPowers.pushPrefEnv({ - set: [["prompts.modalType.httpAuth", Ci.nsIPrompt.MODAL_TYPE_TAB]], - }); -}); - add_task(async function test_check_prompt_origin_display() { await checkAlert("https://example.com/", { value: "example.com" }); // eslint-disable-next-line @microsoft/sdl/no-insecure-url diff --git a/browser/base/content/test/tabPrompts/browser_promptDelays.js b/browser/base/content/test/tabPrompts/browser_promptDelays.js new file mode 100644 index 0000000000..ecd01cdb69 --- /dev/null +++ b/browser/base/content/test/tabPrompts/browser_promptDelays.js @@ -0,0 +1,113 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const PERMISSION_DIALOG = + "chrome://mozapps/content/handling/permissionDialog.xhtml"; + +add_setup(async function () { + // Set a new handler as default. + const protoSvc = Cc[ + "@mozilla.org/uriloader/external-protocol-service;1" + ].getService(Ci.nsIExternalProtocolService); + let protoInfo = protoSvc.getProtocolHandlerInfo("web+testprotocol"); + protoInfo.preferredAction = protoInfo.useHelperApp; + let handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].createInstance( + Ci.nsIWebHandlerApp + ); + handler.uriTemplate = "https://example.com/foobar?uri=%s"; + handler.name = "Test protocol"; + let handlers = protoInfo.possibleApplicationHandlers; + handlers.appendElement(handler); + + protoInfo.preferredApplicationHandler = handler; + protoInfo.alwaysAskBeforeHandling = false; + + const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService( + Ci.nsIHandlerService + ); + handlerSvc.store(protoInfo); + + registerCleanupFunction(() => { + handlerSvc.remove(protoInfo); + }); +}); + +add_task(async function test_promptWhileNotForeground() { + await BrowserTestUtils.withNewTab("about:blank", async browser => { + let windowOpened = BrowserTestUtils.waitForNewWindow(); + await SpecialPowers.spawn(browser, [], () => { + content.eval(`window.open('about:blank', "_blank", "height=600");`); + }); + let otherWin = await windowOpened; + info("Opened extra window, now start a prompt."); + + // To ensure we test the delay helper correctly, shorten the delay: + await SpecialPowers.pushPrefEnv({ + set: [["security.dialog_enable_delay", 50]], + }); + + let promptPromise = BrowserTestUtils.promiseAlertDialogOpen( + null, + PERMISSION_DIALOG, + { isSubDialog: true } + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.location.href = "web+testprotocol:hello"; + }); + info("Started opening prompt."); + let prompt = await promptPromise; + info("Opened prompt."); + let dialog = prompt.document.querySelector("dialog"); + let button = dialog.getButton("accept"); + is(button.getAttribute("disabled"), "true", "Button should be disabled"); + + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(r => setTimeout(r, 500)); + is( + button.getAttribute("disabled"), + "true", + "Button should still be disabled while the dialog is in the background" + ); + + let buttonGetsEnabled = BrowserTestUtils.waitForMutationCondition( + button, + { attributeFilter: ["disabled"] }, + () => button.getAttribute("disabled") != "true" + ); + await BrowserTestUtils.closeWindow(otherWin); + info("Waiting for button to be enabled."); + await buttonGetsEnabled; + ok(true, "The button was enabled."); + dialog.cancelDialog(); + + await SpecialPowers.popPrefEnv(); + }); +}); + +add_task(async function test_promptWhileForeground() { + await BrowserTestUtils.withNewTab("about:blank", async browser => { + let promptPromise = BrowserTestUtils.promiseAlertDialogOpen( + null, + PERMISSION_DIALOG, + { isSubDialog: true } + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.location.href = "web+testprotocol:hello"; + }); + info("Started opening prompt."); + let prompt = await promptPromise; + info("Opened prompt."); + let dialog = prompt.document.querySelector("dialog"); + let button = dialog.getButton("accept"); + is(button.getAttribute("disabled"), "true", "Button should be disabled"); + await BrowserTestUtils.waitForMutationCondition( + button, + { attributeFilter: ["disabled"] }, + () => button.getAttribute("disabled") != "true" + ); + ok(true, "The button was enabled."); + dialog.cancelDialog(); + }); +}); diff --git a/browser/base/content/test/tabPrompts/browser_promptFocus.js b/browser/base/content/test/tabPrompts/browser_promptFocus.js index 89ca064c10..cab812f57b 100644 --- a/browser/base/content/test/tabPrompts/browser_promptFocus.js +++ b/browser/base/content/test/tabPrompts/browser_promptFocus.js @@ -20,8 +20,7 @@ add_task(async function test_tabdialogbox_tab_switch_focus() { tabPromises.push( BrowserTestUtils.openNewForegroundTab( gBrowser, - // eslint-disable-next-line @microsoft/sdl/no-insecure-url - "http://example.com", + "https://example.com", true ) ); diff --git a/browser/base/content/test/tabPrompts/browser_windowPrompt.js b/browser/base/content/test/tabPrompts/browser_windowPrompt.js index 535142f485..0aca489b50 100644 --- a/browser/base/content/test/tabPrompts/browser_windowPrompt.js +++ b/browser/base/content/test/tabPrompts/browser_windowPrompt.js @@ -7,9 +7,6 @@ * Check that the in-window modal dialogs work correctly. */ add_task(async function test_check_window_modal_prompt_service() { - await SpecialPowers.pushPrefEnv({ - set: [["prompts.windowPromptSubDialog", true]], - }); let dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(); // Avoid blocking the test on the (sync) alert by sticking it in a timeout: setTimeout( @@ -69,9 +66,6 @@ add_task(async function test_check_window_modal_prompt_service() { * Check that the dialog's own closing methods being invoked don't break things. */ add_task(async function test_check_window_modal_prompt_service() { - await SpecialPowers.pushPrefEnv({ - set: [["prompts.windowPromptSubDialog", true]], - }); let dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(); // Avoid blocking the test on the (sync) alert by sticking it in a timeout: setTimeout( @@ -105,9 +99,6 @@ add_task(async function test_check_window_modal_prompt_service() { }); add_task(async function test_check_multiple_prompts() { - await SpecialPowers.pushPrefEnv({ - set: [["prompts.windowPromptSubDialog", true]], - }); let container = document.getElementById("window-modal-dialog"); let dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(); @@ -173,9 +164,6 @@ add_task(async function test_check_minimize_response() { if (AppConstants.platform == "linux") { return; } - await SpecialPowers.pushPrefEnv({ - set: [["prompts.windowPromptSubDialog", true]], - }); let promiseSizeModeChange = BrowserTestUtils.waitForEvent( window, @@ -235,10 +223,6 @@ add_task(async function test_check_minimize_response() { * underlying SubDialog has fully opened. */ add_task(async function test_closed_callback() { - await SpecialPowers.pushPrefEnv({ - set: [["prompts.windowPromptSubDialog", true]], - }); - let promptClosedPromise = Services.prompt.asyncAlert( window.browsingContext, Services.prompt.MODAL_TYPE_INTERNAL_WINDOW, diff --git a/browser/base/content/test/tabcrashed/browser_aboutRestartRequired.toml b/browser/base/content/test/tabcrashed/browser_aboutRestartRequired.toml index 88988434fb..8f8648d810 100644 --- a/browser/base/content/test/tabcrashed/browser_aboutRestartRequired.toml +++ b/browser/base/content/test/tabcrashed/browser_aboutRestartRequired.toml @@ -14,8 +14,10 @@ prefs = [ #["browser_aboutRestartRequired_buildid_false-positive.js"] #skip-if = ["win11_2009 && msix && debug"] # bug 1823581 -["browser_aboutRestartRequired_buildid_mismatch.js"] -skip-if = ["win11_2009 && msix && debug"] # bug 1823581 +# Bug 1888355: re-enable once bug 1877361 is fixed +#["browser_aboutRestartRequired_buildid_mismatch.js"] +#skip-if = ["win11_2009 && msix && debug"] # bug 1823581 -["browser_aboutRestartRequired_buildid_no-platform-ini.js"] -skip-if = ["win11_2009 && msix && debug"] # bug 1823581 +# Bug 1888355: re-enable once bug 1877361 is fixed +#["browser_aboutRestartRequired_buildid_no-platform-ini.js"] +#skip-if = ["win11_2009 && msix && debug"] # bug 1823581 diff --git a/browser/base/content/test/tabcrashed/browser_aboutRestartRequired_noForkServer.toml b/browser/base/content/test/tabcrashed/browser_aboutRestartRequired_noForkServer.toml index ec045ddf79..ddb49a0e26 100644 --- a/browser/base/content/test/tabcrashed/browser_aboutRestartRequired_noForkServer.toml +++ b/browser/base/content/test/tabcrashed/browser_aboutRestartRequired_noForkServer.toml @@ -12,3 +12,11 @@ prefs = [ # Bug 1876056: remove once bug 1877361 is fixed ["browser_aboutRestartRequired_buildid_false-positive.js"] skip-if = ["win11_2009 && msix && debug"] # bug 1823581 + +# Bug 1888355: re-enable once bug 1877361 is fixed +["browser_aboutRestartRequired_buildid_mismatch.js"] +skip-if = ["win11_2009 && msix && debug"] # bug 1823581 + +# Bug 1888355: re-enable once bug 1877361 is fixed +["browser_aboutRestartRequired_buildid_no-platform-ini.js"] +skip-if = ["win11_2009 && msix && debug"] # bug 1823581 diff --git a/browser/base/content/test/tabcrashed/head.js b/browser/base/content/test/tabcrashed/head.js index bb57c85d6d..b4e9137012 100644 --- a/browser/base/content/test/tabcrashed/head.js +++ b/browser/base/content/test/tabcrashed/head.js @@ -117,7 +117,7 @@ async function setupLocalCrashReportServer() { // reports. This test needs them enabled. The test also needs a mock // report server, and fortunately one is already set up by toolkit/ // crashreporter/test/Makefile.in. Assign its URL to MOZ_CRASHREPORTER_URL, - // which CrashSubmit.jsm uses as a server override. + // which CrashSubmit.sys.mjs uses as a server override. let noReport = Services.env.get("MOZ_CRASHREPORTER_NO_REPORT"); let serverUrl = Services.env.get("MOZ_CRASHREPORTER_URL"); Services.env.set("MOZ_CRASHREPORTER_NO_REPORT", ""); @@ -135,7 +135,7 @@ async function setupLocalCrashReportServer() { */ function prepareNoDump() { let originalGetDumpID = TabCrashHandler.getDumpID; - TabCrashHandler.getDumpID = function (browser) { + TabCrashHandler.getDumpID = function () { return null; }; registerCleanupFunction(() => { @@ -156,11 +156,11 @@ function unsetBuildidMatchDontSendEnv() { } function getEventPromise(eventName, eventKind) { - return new Promise(function (resolve, reject) { + return new Promise(function (resolve) { info("Installing event listener (" + eventKind + ")"); window.addEventListener( eventName, - event => { + () => { ok(true, "Received " + eventName + " (" + eventKind + ") event"); info("Call resolve() for " + eventKind + " event"); resolve(); diff --git a/browser/base/content/test/tabs/browser.toml b/browser/base/content/test/tabs/browser.toml index 1b4a6900bf..8a95c87a6e 100644 --- a/browser/base/content/test/tabs/browser.toml +++ b/browser/base/content/test/tabs/browser.toml @@ -30,6 +30,8 @@ skip-if = [ ["browser_bfcache_exemption_about_pages.js"] skip-if = ["!fission"] +["browser_blank_tab_label.js"] + ["browser_bug580956.js"] ["browser_bug_1387976_restore_lazy_tab_browser_muted_state.js"] @@ -76,6 +78,8 @@ support-files = ["tab_that_closes.html"] ["browser_hiddentab_contextmenu.js"] +["browser_lastSeenActive.js"] + ["browser_lazy_tab_browser_events.js"] ["browser_link_in_tab_title_and_url_prefilled_blank_page.js"] @@ -138,6 +142,8 @@ support-files = [ ["browser_multiselect_tabs_close.js"] +["browser_multiselect_tabs_close_duplicate_tabs.js"] + ["browser_multiselect_tabs_close_other_tabs.js"] ["browser_multiselect_tabs_close_tabs_to_the_left.js"] diff --git a/browser/base/content/test/tabs/browser_allow_process_switches_despite_related_browser.js b/browser/base/content/test/tabs/browser_allow_process_switches_despite_related_browser.js index b782c3aada..fea1de8fe0 100644 --- a/browser/base/content/test/tabs/browser_allow_process_switches_despite_related_browser.js +++ b/browser/base/content/test/tabs/browser_allow_process_switches_despite_related_browser.js @@ -13,7 +13,7 @@ add_task(async function () { }); let promiseTab = BrowserTestUtils.waitForNewTab(gBrowser, DATA_URI_SOURCE); - BrowserViewSource(tab.linkedBrowser); + BrowserCommands.viewSource(tab.linkedBrowser); let viewSourceTab = await promiseTab; registerCleanupFunction(async function () { BrowserTestUtils.removeTab(viewSourceTab); diff --git a/browser/base/content/test/tabs/browser_audioTabIcon.js b/browser/base/content/test/tabs/browser_audioTabIcon.js index 53b5140abb..c065e2b173 100644 --- a/browser/base/content/test/tabs/browser_audioTabIcon.js +++ b/browser/base/content/test/tabs/browser_audioTabIcon.js @@ -396,7 +396,7 @@ async function test_swapped_browser_while_not_playing(oldTab, newBrowser) { ); let AudioPlaybackPromise = new Promise(resolve => { - let observer = (subject, topic, data) => { + let observer = () => { ok(false, "Should not see an audio-playback notification"); }; Services.obs.addObserver(observer, "audio-playback"); @@ -443,7 +443,7 @@ async function test_swapped_browser_while_not_playing(oldTab, newBrowser) { await test_tooltip(newTab.overlayIcon, "Unmute tab", true, newTab); } -async function test_browser_swapping(tab, browser) { +async function test_browser_swapping(tab) { // First, test swapping with a playing but muted tab. await play(tab); diff --git a/browser/base/content/test/tabs/browser_blank_tab_label.js b/browser/base/content/test/tabs/browser_blank_tab_label.js new file mode 100644 index 0000000000..9fe5f6b1b0 --- /dev/null +++ b/browser/base/content/test/tabs/browser_blank_tab_label.js @@ -0,0 +1,49 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Ensure that we don't use an entirely-blank (non-printable) document title + * as the tab label. + */ +add_task(async function test_ensure_printable_label() { + const TEST_DOC = ` + <!DOCTYPE html> + <meta charset="utf-8"> + <!-- Title is NO-BREAK SPACE, COMBINING ACUTE ACCENT, ARABIC LETTER MARK --> + <title> &%23x0301;&%23x061C;</title> + Is my title blank?`; + + let newTab; + function tabLabelChecker() { + Assert.stringMatches( + newTab.label, + /\p{L}|\p{N}|\p{P}|\p{S}/u, + "Tab label should contain printable character." + ); + } + let mutationObserver = new MutationObserver(tabLabelChecker); + registerCleanupFunction(() => mutationObserver.disconnect()); + + gBrowser.tabContainer.addEventListener( + "TabOpen", + event => { + newTab = event.target; + tabLabelChecker(); + mutationObserver.observe(newTab, { + attributeFilter: ["label"], + }); + }, + { once: true } + ); + + await BrowserTestUtils.withNewTab("data:text/html," + TEST_DOC, async () => { + // Wait another longer-than-tick to ensure more mutation observer things have + // come in. + await new Promise(executeSoon); + + // Check one last time for good measure, for the final label: + tabLabelChecker(); + }); +}); diff --git a/browser/base/content/test/tabs/browser_e10s_about_page_triggeringprincipal.js b/browser/base/content/test/tabs/browser_e10s_about_page_triggeringprincipal.js index 4610551977..8fbee64db4 100644 --- a/browser/base/content/test/tabs/browser_e10s_about_page_triggeringprincipal.js +++ b/browser/base/content/test/tabs/browser_e10s_about_page_triggeringprincipal.js @@ -86,7 +86,7 @@ add_task(async function test_principal_ctrl_click() { await BrowserTestUtils.withNewTab( "about:test-about-principal-parent", - async function (browser) { + async function () { let loadPromise = BrowserTestUtils.waitForNewTab( gBrowser, "about:test-about-principal-child", @@ -149,7 +149,7 @@ add_task(async function test_principal_right_click_open_link_in_new_tab() { await BrowserTestUtils.withNewTab( "about:test-about-principal-parent", - async function (browser) { + async function () { let loadPromise = BrowserTestUtils.waitForNewTab( gBrowser, "about:test-about-principal-child", diff --git a/browser/base/content/test/tabs/browser_e10s_about_process.js b/browser/base/content/test/tabs/browser_e10s_about_process.js index f73e8e659c..504dfe0265 100644 --- a/browser/base/content/test/tabs/browser_e10s_about_process.js +++ b/browser/base/content/test/tabs/browser_e10s_about_process.js @@ -37,7 +37,7 @@ const TEST_MODULES = [ function AboutModule() {} AboutModule.prototype = { - newChannel(aURI, aLoadInfo) { + newChannel() { throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED); }, @@ -52,7 +52,7 @@ AboutModule.prototype = { return 0; }, - getIndexedDBOriginPostfix(aURI) { + getIndexedDBOriginPostfix() { return null; }, diff --git a/browser/base/content/test/tabs/browser_lastSeenActive.js b/browser/base/content/test/tabs/browser_lastSeenActive.js new file mode 100644 index 0000000000..d6bba57d93 --- /dev/null +++ b/browser/base/content/test/tabs/browser_lastSeenActive.js @@ -0,0 +1,260 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +const { SessionStoreTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/SessionStoreTestUtils.sys.mjs" +); + +const triggeringPrincipal_base64 = E10SUtils.SERIALIZED_SYSTEMPRINCIPAL; + +SessionStoreTestUtils.init(this, window); +// take a state snapshot we can restore to after each test +const ORIG_STATE = SessionStore.getBrowserState(); + +const SECOND_MS = 1000; +const DAY_MS = 24 * 60 * 60 * 1000; +const today = new Date().getTime(); +const yesterday = new Date(Date.now() - DAY_MS).getTime(); + +function tabEntry(url, lastAccessed) { + return { + entries: [{ url, triggeringPrincipal_base64 }], + lastAccessed, + }; +} + +/** + * Make the given window focused and active + */ +async function switchToWindow(win) { + info("switchToWindow, waiting for promiseFocus"); + await SimpleTest.promiseFocus(win); + info("switchToWindow, waiting for correct Services.focus.activeWindow"); + await BrowserTestUtils.waitForCondition( + () => Services.focus.activeWindow == win + ); +} + +async function changeSizeMode(win, mode) { + let promise = BrowserTestUtils.waitForEvent(win, "sizemodechange"); + win[mode](); + await promise; +} + +async function cleanup() { + await switchToWindow(window); + await SessionStoreTestUtils.promiseBrowserState(ORIG_STATE); + is( + BrowserWindowTracker.orderedWindows.length, + 1, + "One window at the end of test cleanup" + ); + info("cleanup, browser state restored"); +} + +function deltaTime(time, expectedTime) { + return Math.abs(expectedTime - time); +} + +function getWindowUrl(win) { + return win.gBrowser.selectedBrowser?.currentURI?.spec; +} + +function getWindowByTabUrl(url) { + return BrowserWindowTracker.orderedWindows.find( + win => getWindowUrl(win) == url + ); +} + +add_task(async function restoredTabs() { + const now = Date.now(); + await SessionStoreTestUtils.promiseBrowserState({ + windows: [ + { + tabs: [ + tabEntry("data:,Window0-Tab0", yesterday), + tabEntry("data:,Window0-Tab1", yesterday), + ], + selected: 2, + }, + ], + }); + is( + gBrowser.visibleTabs[1], + gBrowser.selectedTab, + "The selected tab is the 2nd visible tab" + ); + is( + getWindowUrl(window), + "data:,Window0-Tab1", + "The expected tab is selected" + ); + Assert.greaterOrEqual( + gBrowser.selectedTab.lastSeenActive, + now, + "The selected tab's lastSeenActive is now" + ); + Assert.greaterOrEqual( + gBrowser.selectedTab.lastAccessed, + now, + "The selected tab's lastAccessed is now" + ); + + // tab restored from session but never seen or active + is( + gBrowser.visibleTabs[0].lastSeenActive, + yesterday, + "The restored tab's lastSeenActive is yesterday" + ); + await cleanup(); +}); + +add_task(async function switchingTabs() { + let now = Date.now(); + let initialTab = gBrowser.selectedTab; + let applicationStart = Services.startup.getStartupInfo().start.getTime(); + let openedTab = BrowserTestUtils.addTab(gBrowser, "data:,Tab1"); + await BrowserTestUtils.browserLoaded(openedTab.linkedBrowser); + + ok(!openedTab.selected, "The background tab we opened isn't selected"); + Assert.greaterOrEqual( + initialTab.selected && initialTab.lastSeenActive, + now, + "The initial tab is selected and last seen now" + ); + + is( + openedTab.lastSeenActive, + applicationStart, + `Background tab got default lastSeenActive value, delta: ${deltaTime( + openedTab.lastSeenActive, + applicationStart + )}` + ); + + now = Date.now(); + await BrowserTestUtils.switchTab(gBrowser, openedTab); + Assert.greaterOrEqual( + openedTab.lastSeenActive, + now, + "The tab we switched to is last seen now" + ); + + await cleanup(); +}); + +add_task(async function switchingWindows() { + info("Restoring to the test browser state"); + await SessionStoreTestUtils.promiseBrowserState({ + windows: [ + { + tabs: [tabEntry("data:,Window1-Tab0", yesterday)], + selected: 1, + sizemodeBeforeMinimized: "normal", + sizemode: "maximized", + zIndex: 1, // this will be the selected window + }, + { + tabs: [tabEntry("data:,Window2-Tab0", yesterday)], + selected: 1, + sizemodeBeforeMinimized: "normal", + sizemode: "maximized", + zIndex: 2, + }, + ], + }); + info("promiseBrowserState resolved"); + info( + `BrowserWindowTracker.pendingWindows: ${BrowserWindowTracker.pendingWindows.size}` + ); + await Promise.all( + Array.from(BrowserWindowTracker.pendingWindows.values()).map( + win => win.deferred.promise + ) + ); + info("All the pending windows are resolved"); + info("Waiting for the firstBrowserLoaded in each of the windows"); + await Promise.all( + BrowserWindowTracker.orderedWindows.map(win => { + const selectedUrl = getWindowUrl(win); + if (selectedUrl && selectedUrl !== "about:blank") { + return Promise.resolve(); + } + return BrowserTestUtils.firstBrowserLoaded(win, false); + }) + ); + let expectedTabURLs = ["data:,Window1-Tab0", "data:,Window2-Tab0"]; + let [win1, win2] = expectedTabURLs.map(url => getWindowByTabUrl(url)); + if (BrowserWindowTracker.getTopWindow() !== win1) { + info("Switch to win1 which isn't active/top after restoring session"); + // In theory the zIndex values in the session state should make win1 active + // But in practice that isn't always true. To ensure we're testing from a known state, + // ensure the first window is active before proceeding with the test + await switchToWindow(win1); + [win1, win2] = expectedTabURLs.map(url => getWindowByTabUrl(url)); + } + + let actualTabURLs = Array.from(BrowserWindowTracker.orderedWindows).map(win => + getWindowUrl(win) + ); + Assert.deepEqual( + actualTabURLs, + expectedTabURLs, + "Both windows are open with selected tab URLs in the expected order" + ); + + let lastSeenTimes = [win1, win2].map( + win => win.gBrowser.selectedTab.lastSeenActive + ); + + info("Focusing the other window"); + await switchToWindow(win2); + // wait a little so the timestamps will differ and then check again + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(res => setTimeout(res, 100)); + Assert.greater( + win2.gBrowser.selectedTab.lastSeenActive, + lastSeenTimes[1], + "The foreground window selected tab is last seen more recently than it was before being focused" + ); + Assert.greater( + win2.gBrowser.selectedTab.lastSeenActive, + win1.gBrowser.selectedTab.lastSeenActive, + "The foreground window selected tab is last seen more recently than the backgrounded one" + ); + + lastSeenTimes = [win1, win2].map( + win => win.gBrowser.selectedTab.lastSeenActive + ); + // minimize the foreground window and focus the other + let promiseSizeModeChange = BrowserTestUtils.waitForEvent( + win2, + "sizemodechange" + ); + win2.minimize(); + info("Waiting for the sizemodechange on minimized window"); + await promiseSizeModeChange; + await switchToWindow(win1); + + ok( + !win2.gBrowser.selectedTab.linkedBrowser.docShellIsActive, + "Docshell should be Inactive" + ); + ok(win2.document.hidden, "Minimized windows's document should be hidden"); + + // wait a little so the timestamps will differ and then check again + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(res => setTimeout(res, 100)); + Assert.greater( + win1.gBrowser.selectedTab.lastSeenActive, + win2.gBrowser.selectedTab.lastSeenActive, + "The foreground window selected tab is last seen more recently than the minimized one" + ); + Assert.greater( + win1.gBrowser.selectedTab.lastSeenActive, + lastSeenTimes[0], + "The foreground window selected tab is last seen more recently than it was before being focused" + ); + + await cleanup(); +}); diff --git a/browser/base/content/test/tabs/browser_lazy_tab_browser_events.js b/browser/base/content/test/tabs/browser_lazy_tab_browser_events.js index 665bdb7f69..5e09225cde 100644 --- a/browser/base/content/test/tabs/browser_lazy_tab_browser_events.js +++ b/browser/base/content/test/tabs/browser_lazy_tab_browser_events.js @@ -93,10 +93,10 @@ add_task(async function test_hidden_muted_lazy_tabs_and_swapping() { mutedTab.toggleMuteAudio(); gBrowser.hideTab(hiddenTab); - is(lazyTab.linkedPanel, "", "lazyTab is lazy"); - is(hiddenTab.linkedPanel, "", "hiddenTab is lazy"); - is(mutedTab.linkedPanel, "", "mutedTab is lazy"); - is(normalTab.linkedPanel, "", "normalTab is lazy"); + is(lazyTab.linkedPanel, null, "lazyTab is lazy"); + is(hiddenTab.linkedPanel, null, "hiddenTab is lazy"); + is(mutedTab.linkedPanel, null, "mutedTab is lazy"); + is(normalTab.linkedPanel, null, "normalTab is lazy"); ok(mutedTab.linkedBrowser.audioMuted, "mutedTab is muted"); ok(hiddenTab.hidden, "hiddenTab is hidden"); @@ -117,7 +117,7 @@ add_task(async function test_hidden_muted_lazy_tabs_and_swapping() { }); gBrowser.swapBrowsersAndCloseOther(lazyTab, mutedTab); tabEventTracker.checkExpectations(); - is(lazyTab.linkedPanel, "", "muted lazyTab is still lazy"); + is(lazyTab.linkedPanel, null, "muted lazyTab is still lazy"); ok(lazyTab.linkedBrowser.audioMuted, "muted lazyTab is now muted"); ok(!lazyTab.hidden, "muted lazyTab is not hidden"); @@ -133,7 +133,7 @@ add_task(async function test_hidden_muted_lazy_tabs_and_swapping() { }); gBrowser.swapBrowsersAndCloseOther(lazyTab, hiddenTab); tabEventTracker.checkExpectations(); - is(lazyTab.linkedPanel, "", "hidden lazyTab is still lazy"); + is(lazyTab.linkedPanel, null, "hidden lazyTab is still lazy"); ok(!lazyTab.linkedBrowser.audioMuted, "hidden lazyTab is not muted any more"); ok(lazyTab.hidden, "hidden lazyTab has been hidden"); @@ -149,7 +149,7 @@ add_task(async function test_hidden_muted_lazy_tabs_and_swapping() { }); gBrowser.swapBrowsersAndCloseOther(lazyTab, normalTab); tabEventTracker.checkExpectations(); - is(lazyTab.linkedPanel, "", "normal lazyTab is still lazy"); + is(lazyTab.linkedPanel, null, "normal lazyTab is still lazy"); ok(!lazyTab.linkedBrowser.audioMuted, "normal lazyTab is not muted any more"); ok(!lazyTab.hidden, "normal lazyTab is not hidden any more"); diff --git a/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_blank_target.js b/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_blank_target.js index f8773e3720..9212667a35 100644 --- a/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_blank_target.js +++ b/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_blank_target.js @@ -66,7 +66,7 @@ add_task(async function normal_page__foreground__abort() { tab: WAIT_A_BIT_LOADING_TITLE, urlbar: UrlbarTestUtils.trimURL(WAIT_A_BIT_URL), }, - async actionWhileLoading(onTabLoaded) { + async actionWhileLoading() { info("Abort loading"); document.getElementById("stop-button").click(); }, @@ -160,7 +160,7 @@ add_task(async function normal_page__background__abort() { tab: WAIT_A_BIT_LOADING_TITLE, urlbar: UrlbarTestUtils.trimURL(HOME_URL), }, - async actionWhileLoading(onTabLoaded) { + async actionWhileLoading() { info("Abort loading"); document.getElementById("stop-button").click(); }, diff --git a/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_by_script.js b/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_by_script.js index 07cf7a8ea2..57e28ca834 100644 --- a/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_by_script.js +++ b/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_by_script.js @@ -44,7 +44,7 @@ add_task(async function normal_page__by_script__abort() { tab: BLANK_TITLE, urlbar: UrlbarTestUtils.trimURL(BLANK_URL), }, - async actionWhileLoading(onTabLoaded) { + async actionWhileLoading() { info("Abort loading"); document.getElementById("stop-button").click(); }, diff --git a/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_no_target.js b/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_no_target.js index ab18d7c7e0..464a7c43de 100644 --- a/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_no_target.js +++ b/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_no_target.js @@ -47,7 +47,7 @@ add_task(async function normal_page__no_target__abort() { tab: HOME_TITLE, urlbar: UrlbarTestUtils.trimURL(HOME_URL), }, - async actionWhileLoading(onTabLoaded) { + async actionWhileLoading() { info("Abort loading"); document.getElementById("stop-button").click(); }, diff --git a/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_other_target.js b/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_other_target.js index 7dc0e8fa45..53242ca359 100644 --- a/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_other_target.js +++ b/browser/base/content/test/tabs/browser_link_in_tab_title_and_url_prefilled_normal_page_other_target.js @@ -45,7 +45,7 @@ add_task(async function normal_page__other_target__foreground__abort() { tab: BLANK_TITLE, urlbar: UrlbarTestUtils.trimURL(BLANK_URL), }, - async actionWhileLoading(onTabLoaded) { + async actionWhileLoading() { info("Abort loading"); document.getElementById("stop-button").click(); }, @@ -117,7 +117,7 @@ add_task(async function normal_page__other_target__background__abort() { tab: WAIT_A_BIT_LOADING_TITLE, urlbar: UrlbarTestUtils.trimURL(HOME_URL), }, - async actionWhileLoading(onTabLoaded) { + async actionWhileLoading() { info("Abort loading"); document.getElementById("stop-button").click(); }, diff --git a/browser/base/content/test/tabs/browser_long_data_url_label_truncation.js b/browser/base/content/test/tabs/browser_long_data_url_label_truncation.js index db0571a2c0..89952b6c4d 100644 --- a/browser/base/content/test/tabs/browser_long_data_url_label_truncation.js +++ b/browser/base/content/test/tabs/browser_long_data_url_label_truncation.js @@ -33,7 +33,7 @@ add_task(async function test_ensure_truncation() { let fileReader = new FileReader(); const DATA_URL = await new Promise(resolve => { - fileReader.addEventListener("load", e => resolve(fileReader.result)); + fileReader.addEventListener("load", () => resolve(fileReader.result)); fileReader.readAsDataURL(new Blob([MOBY], { type: "text/html" })); }); // Substring the full URL to avoid log clutter because Assert will print diff --git a/browser/base/content/test/tabs/browser_multiselect_tabs_close_duplicate_tabs.js b/browser/base/content/test/tabs/browser_multiselect_tabs_close_duplicate_tabs.js new file mode 100644 index 0000000000..d18795447f --- /dev/null +++ b/browser/base/content/test/tabs/browser_multiselect_tabs_close_duplicate_tabs.js @@ -0,0 +1,178 @@ +const PREF_WARN_ON_CLOSE = "browser.tabs.warnOnCloseOtherTabs"; +const PREF_SHOWN_DUPE_DIALOG = + "browser.tabs.haveShownCloseAllDuplicateTabsWarning"; + +add_task(async function setPref() { + await SpecialPowers.pushPrefEnv({ + set: [ + [PREF_WARN_ON_CLOSE, false], + [PREF_SHOWN_DUPE_DIALOG, true], + ], + }); +}); + +add_task(async function withAMultiSelectedTab() { + let initialTab = gBrowser.selectedTab; + let tab1 = await addTab(); + let tab2 = await addTab(); + let tab3 = await addTab(); + let tab4 = await addTab(); + + is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs"); + + await triggerClickOn(tab1, { ctrlKey: true }); + + let tab4Pinned = BrowserTestUtils.waitForEvent(tab4, "TabPinned"); + gBrowser.pinTab(tab4); + await tab4Pinned; + + ok(initialTab.multiselected, "InitialTab is multiselected"); + ok(tab1.multiselected, "Tab1 is multiselected"); + ok(!tab2.multiselected, "Tab2 is not multiselected"); + ok(!tab3.multiselected, "Tab3 is not multiselected"); + ok(!tab4.multiselected, "Tab4 is not multiselected"); + ok(tab4.pinned, "Tab4 is pinned"); + is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs"); + is(gBrowser.selectedTab, initialTab, "InitialTab is the active tab"); + + let closingTabs = [tab2, tab3]; + let tabClosingPromises = []; + for (let tab of closingTabs) { + tabClosingPromises.push(BrowserTestUtils.waitForTabClosing(tab)); + } + + gBrowser.removeDuplicateTabs(tab1); + + await Promise.all(tabClosingPromises); + + ok(!initialTab.closing, "InitialTab is not closing"); + ok(!tab1.closing, "Tab1 is not closing"); + ok(tab2.closing, "Tab2 is closing"); + ok(tab3.closing, "Tab3 is closing"); + ok(!tab4.closing, "Tab4 is not closing"); + is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs"); + is(gBrowser.selectedTab, initialTab, "InitialTab is still the active tab"); + + gBrowser.clearMultiSelectedTabs(); + BrowserTestUtils.removeTab(tab1); + BrowserTestUtils.removeTab(tab4); +}); + +add_task(async function withNotAMultiSelectedTab() { + let initialTab = gBrowser.selectedTab; + let tab1 = await addTab("http://mochi.test:8888/"); + let tab2 = await addTab("http://mochi.test:8888/"); + let tab3 = await addTab("http://mochi.test:8888/"); + let tab4 = await addTab("http://mochi.test:8888/"); + let tab5 = await addTab("http://mochi.test:8888/"); + let tab6 = await addTab("http://mochi.test:8888/", { userContextId: 1 }); + + is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs"); + + await BrowserTestUtils.switchTab(gBrowser, tab1); + await triggerClickOn(tab2, { ctrlKey: true }); + await triggerClickOn(tab5, { ctrlKey: true }); + + let tab4Pinned = BrowserTestUtils.waitForEvent(tab4, "TabPinned"); + gBrowser.pinTab(tab4); + await tab4Pinned; + + let tab5Pinned = BrowserTestUtils.waitForEvent(tab5, "TabPinned"); + gBrowser.pinTab(tab5); + await tab5Pinned; + + ok(!initialTab.multiselected, "InitialTab is not multiselected"); + ok(tab1.multiselected, "Tab1 is multiselected"); + ok(tab2.multiselected, "Tab2 is multiselected"); + ok(!tab3.multiselected, "Tab3 is not multiselected"); + ok(!tab4.multiselected, "Tab4 is not multiselected"); + ok(tab4.pinned, "Tab4 is pinned"); + ok(tab5.multiselected, "Tab5 is multiselected"); + ok(tab5.pinned, "Tab5 is pinned"); + ok(!tab6.multiselected, "Tab6 is not multiselected"); + ok(!tab6.pinned, "Tab6 is not pinned"); + is(gBrowser.multiSelectedTabsCount, 3, "Three multiselected tabs"); + is(gBrowser.selectedTab, tab1, "Tab1 is the active tab"); + + let closingTabs = [tab1, tab2]; + let tabClosingPromises = []; + for (let tab of closingTabs) { + tabClosingPromises.push(BrowserTestUtils.waitForTabClosing(tab)); + } + + await BrowserTestUtils.switchTab( + gBrowser, + gBrowser.removeDuplicateTabs(tab3) + ); + + await Promise.all(tabClosingPromises); + + ok(!initialTab.closing, "InitialTab is not closing"); + ok(tab1.closing, "Tab1 is closing"); + ok(tab2.closing, "Tab2 is closing"); + ok(!tab3.closing, "Tab3 is not closing"); + ok(!tab4.closing, "Tab4 is not closing"); + ok(!tab5.closing, "Tab5 is not closing"); + ok(!tab6.closing, "Tab6 is not closing"); + is( + gBrowser.multiSelectedTabsCount, + 0, + "Zero multiselected tabs, selection is cleared" + ); + is(gBrowser.selectedTab, tab3, "tab3 is the active tab now"); + + for (let tab of [tab3, tab4, tab5, tab6]) { + BrowserTestUtils.removeTab(tab); + } +}); + +add_task(async function closeAllDuplicateTabs() { + let initialTab = gBrowser.selectedTab; + let tab1 = await addTab("http://mochi.test:8888/one"); + let tab2 = await addTab("http://mochi.test:8888/two", { userContextId: 1 }); + let tab3 = await addTab("http://mochi.test:8888/one"); + let tab4 = await addTab("http://mochi.test:8888/two"); + let tab5 = await addTab("http://mochi.test:8888/one"); + let tab6 = await addTab("http://mochi.test:8888/two"); + + let tab1Pinned = BrowserTestUtils.waitForEvent(tab1, "TabPinned"); + gBrowser.pinTab(tab1); + await tab1Pinned; + + // So we have 1p,2c,1,2,1,2 + // We expect 1p,2c,X,2,X,X because the pinned 1 will dupe the other two 1, + // but the 2c's userContextId makes it unique against the other two 2, + // but one of the other two 2 will close. + + // Ensure tab4 remains by making it active more recently than tab6. + tab4._lastSeenActive = Date.now(); // as recent as it gets. + + // Assert some preconditions: + ok(tab1.pinned, "Tab1 is pinned"); + Assert.greater(tab4.lastSeenActive, tab6.lastSeenActive); + + let closingTabs = [tab3, tab5, tab6]; + let tabClosingPromises = []; + for (let tab of closingTabs) { + tabClosingPromises.push(BrowserTestUtils.waitForTabClosing(tab)); + } + + await BrowserTestUtils.switchTab( + gBrowser, + gBrowser.removeAllDuplicateTabs(initialTab) + ); + + await Promise.all(tabClosingPromises); + + ok(!initialTab.closing, "InitialTab is not closing"); + ok(!tab1.closing, "Tab1 is not closing"); + ok(!tab2.closing, "Tab2 is not closing"); + ok(tab3.closing, "Tab3 is closing"); + ok(!tab4.closing, "Tab4 is not closing"); + ok(tab5.closing, "Tab5 is closing"); + ok(tab6.closing, "Tab6 is closing"); + + for (let tab of [tab1, tab2, tab4]) { + BrowserTestUtils.removeTab(tab); + } +}); diff --git a/browser/base/content/test/tabs/browser_multiselect_tabs_move_to_new_window_contextmenu.js b/browser/base/content/test/tabs/browser_multiselect_tabs_move_to_new_window_contextmenu.js index d668d21df8..f294769898 100644 --- a/browser/base/content/test/tabs/browser_multiselect_tabs_move_to_new_window_contextmenu.js +++ b/browser/base/content/test/tabs/browser_multiselect_tabs_move_to_new_window_contextmenu.js @@ -61,9 +61,9 @@ add_task(async function testLazyTabs() { await triggerClickOn(oldTabs[i], { ctrlKey: true }); } - isnot(oldTabs[0].linkedPanel, "", `Old tab 0 shouldn't be lazy`); + isnot(oldTabs[0].linkedPanel, null, `Old tab 0 shouldn't be lazy`); for (let i = 1; i < numTabs; ++i) { - is(oldTabs[i].linkedPanel, "", `Old tab ${i} should be lazy`); + is(oldTabs[i].linkedPanel, null, `Old tab ${i} should be lazy`); } is(gBrowser.multiSelectedTabsCount, numTabs, `${numTabs} multiselected tabs`); @@ -79,11 +79,11 @@ add_task(async function testLazyTabs() { if (i == 0) { isnot( oldTab.linkedPanel, - "", + null, `Old tab ${i} should continue not being lazy` ); } else if (i > 0) { - is(oldTab.linkedPanel, "", `Old tab ${i} should continue being lazy`); + is(oldTab.linkedPanel, null, `Old tab ${i} should continue being lazy`); } else { return; } @@ -101,9 +101,13 @@ add_task(async function testLazyTabs() { await tabsMoved; let newTabs = newWindow.gBrowser.tabs; - isnot(newTabs[0].linkedPanel, "", `New tab 0 should continue not being lazy`); + isnot( + newTabs[0].linkedPanel, + null, + `New tab 0 should continue not being lazy` + ); for (let i = 1; i < numTabs; ++i) { - is(newTabs[i].linkedPanel, "", `New tab ${i} should continue being lazy`); + is(newTabs[i].linkedPanel, null, `New tab ${i} should continue being lazy`); } is( diff --git a/browser/base/content/test/tabs/browser_new_tab_bookmarks_toolbar_height.js b/browser/base/content/test/tabs/browser_new_tab_bookmarks_toolbar_height.js index 66258659fd..157254142d 100644 --- a/browser/base/content/test/tabs/browser_new_tab_bookmarks_toolbar_height.js +++ b/browser/base/content/test/tabs/browser_new_tab_bookmarks_toolbar_height.js @@ -12,7 +12,7 @@ async function expectHeightChanges(tab, expectedNewHeightChanges, msg) { let contentObservedHeightChanges = await ContentTask.spawn( tab.linkedBrowser, null, - async args => { + async () => { await new Promise(resolve => content.requestAnimationFrame(resolve)); return content.document.body.innerText; } @@ -109,7 +109,7 @@ add_task(async function () { info("Opening a new tab, making the previous tab non-selected"); await expectBmToolbarVisibilityChange( () => { - BrowserOpenTab(); + BrowserCommands.openTab(); ok( !tab.selected, "non-new tab is in the background (not the selected tab)" diff --git a/browser/base/content/test/tabs/browser_new_tab_in_privilegedabout_process_pref.js b/browser/base/content/test/tabs/browser_new_tab_in_privilegedabout_process_pref.js index ec11951cb0..568510b20a 100644 --- a/browser/base/content/test/tabs/browser_new_tab_in_privilegedabout_process_pref.js +++ b/browser/base/content/test/tabs/browser_new_tab_in_privilegedabout_process_pref.js @@ -159,7 +159,7 @@ add_task(async function process_switching_through_navigation_features() { assertIsPrivilegedProcess(browser, "new tab opened from about:newtab"); // Check that reload does not break the privileged about: content process affinity. - BrowserReload(); + BrowserCommands.reload(); await BrowserTestUtils.browserLoaded(browser, false, ABOUT_NEWTAB); assertIsPrivilegedProcess(browser, "about:newtab after reload"); diff --git a/browser/base/content/test/tabs/browser_new_tab_url.js b/browser/base/content/test/tabs/browser_new_tab_url.js index 233cb4e59e..ab00560929 100644 --- a/browser/base/content/test/tabs/browser_new_tab_url.js +++ b/browser/base/content/test/tabs/browser_new_tab_url.js @@ -3,7 +3,7 @@ "use strict"; add_task(async function test_browser_open_newtab_default_url() { - BrowserOpenTab(); + BrowserCommands.openTab(); const tab = gBrowser.selectedTab; if (tab.linkedBrowser.currentURI.spec !== window.BROWSER_NEW_TAB_URL) { @@ -19,7 +19,7 @@ add_task(async function test_browser_open_newtab_default_url() { add_task(async function test_browser_open_newtab_specific_url() { const url = "https://example.com"; - BrowserOpenTab({ url }); + BrowserCommands.openTab({ url }); const tab = gBrowser.selectedTab; await BrowserTestUtils.browserLoaded(tab.linkedBrowser); diff --git a/browser/base/content/test/tabs/browser_open_newtab_start_observer_notification.js b/browser/base/content/test/tabs/browser_open_newtab_start_observer_notification.js index cb9fc3c6d7..2bc26cf667 100644 --- a/browser/base/content/test/tabs/browser_open_newtab_start_observer_notification.js +++ b/browser/base/content/test/tabs/browser_open_newtab_start_observer_notification.js @@ -9,10 +9,10 @@ add_task(async function test_browser_open_newtab_start_observer_notification() { Services.obs.addObserver(observe, "browser-open-newtab-start"); }); - // We're calling BrowserOpenTab() (rather the using BrowserTestUtils + // We're calling BrowserCommands.openTab() (rather the using BrowserTestUtils // because we want to be sure that it triggers the event to fire, since // it's very close to where various user-actions are triggered. - BrowserOpenTab(); + BrowserCommands.openTab(); const newTabCreatedPromise = await observerFiredPromise; const browser = await newTabCreatedPromise; const tab = gBrowser.selectedTab; diff --git a/browser/base/content/test/tabs/browser_pinnedTabs_closeByKeyboard.js b/browser/base/content/test/tabs/browser_pinnedTabs_closeByKeyboard.js index fbcd0bb492..4631afba42 100644 --- a/browser/base/content/test/tabs/browser_pinnedTabs_closeByKeyboard.js +++ b/browser/base/content/test/tabs/browser_pinnedTabs_closeByKeyboard.js @@ -5,14 +5,14 @@ function test() { waitForExplicitFinish(); - function testState(aPinned) { + function testState() { function elemAttr(id, attr) { return document.getElementById(id).getAttribute(attr); } is( elemAttr("key_close", "disabled"), - "", + null, "key_closed should always be enabled" ); is( diff --git a/browser/base/content/test/tabs/browser_privilegedmozilla_process_pref.js b/browser/base/content/test/tabs/browser_privilegedmozilla_process_pref.js index 9e1c1ff5cd..922f94b07c 100644 --- a/browser/base/content/test/tabs/browser_privilegedmozilla_process_pref.js +++ b/browser/base/content/test/tabs/browser_privilegedmozilla_process_pref.js @@ -140,7 +140,7 @@ add_task(async function process_switching_through_navigation_features() { ); // Check that reload does not break the privileged mozilla content process affinity. - BrowserReload(); + BrowserCommands.reload(); await BrowserTestUtils.browserLoaded(browser, false, TEST_HIGH1); is( browser.frameLoader.remoteTab.osPid, diff --git a/browser/base/content/test/tabs/browser_removeTabs_order.js b/browser/base/content/test/tabs/browser_removeTabs_order.js index 071cc03716..a993415653 100644 --- a/browser/base/content/test/tabs/browser_removeTabs_order.js +++ b/browser/base/content/test/tabs/browser_removeTabs_order.js @@ -16,7 +16,7 @@ add_task(async function () { // Add a beforeunload event listener in one of the tabs; it should be called // before closing any of the tabs. await ContentTask.spawn(tab2.linkedBrowser, null, async function () { - content.window.addEventListener("beforeunload", function (event) {}, true); + content.window.addEventListener("beforeunload", function () {}, true); }); let permitUnloadSpy = sinon.spy(tab2.linkedBrowser, "asyncPermitUnload"); diff --git a/browser/base/content/test/tabs/browser_tab_label_picture_in_picture.js b/browser/base/content/test/tabs/browser_tab_label_picture_in_picture.js index dae4ffc444..59cfd37c0d 100644 --- a/browser/base/content/test/tabs/browser_tab_label_picture_in_picture.js +++ b/browser/base/content/test/tabs/browser_tab_label_picture_in_picture.js @@ -11,7 +11,7 @@ add_task(async function test_pip_label_changes_tab() { let pipLabel = pipTab.querySelector(".tab-icon-sound-pip-label"); - await BrowserTestUtils.withNewTab("about:blank", async browser => { + await BrowserTestUtils.withNewTab("about:blank", async () => { let selectedTab = newWin.document.querySelector( ".tabbrowser-tab[selected]" ); diff --git a/browser/base/content/test/tabs/browser_tab_manager_visibility.js b/browser/base/content/test/tabs/browser_tab_manager_visibility.js index b7de777512..df6e75cd66 100644 --- a/browser/base/content/test/tabs/browser_tab_manager_visibility.js +++ b/browser/base/content/test/tabs/browser_tab_manager_visibility.js @@ -17,7 +17,7 @@ add_task(async function tab_manager_visibility_preference_on() { gBrowser: newWindow.gBrowser, url: TEST_HOSTNAME + DUMMY_PAGE_PATH, }, - async function (browser) { + async function () { await Assert.ok( BrowserTestUtils.isVisible( newWindow.document.getElementById("alltabs-button") @@ -39,7 +39,7 @@ add_task(async function tab_manager_visibility_preference_off() { gBrowser: newWindow.gBrowser, url: TEST_HOSTNAME + DUMMY_PAGE_PATH, }, - async function (browser) { + async function () { await Assert.ok( BrowserTestUtils.isHidden( newWindow.document.getElementById("alltabs-button") diff --git a/browser/base/content/test/tabs/browser_tab_preview.js b/browser/base/content/test/tabs/browser_tab_preview.js index 718afbb940..19ba85b9f8 100644 --- a/browser/base/content/test/tabs/browser_tab_preview.js +++ b/browser/base/content/test/tabs/browser_tab_preview.js @@ -4,14 +4,14 @@ "use strict"; +const { sinon } = ChromeUtils.importESModule( + "resource://testing-common/Sinon.sys.mjs" +); + async function openPreview(tab) { - const previewShown = BrowserTestUtils.waitForEvent( - document.getElementById("tabbrowser-tab-preview"), - "previewshown", - false, - e => { - return e.detail.tab === tab; - } + const previewShown = BrowserTestUtils.waitForPopupEvent( + document.getElementById("tab-preview-panel"), + "shown" ); EventUtils.synthesizeMouseAtCenter(tab, { type: "mouseover" }); return previewShown; @@ -19,9 +19,9 @@ async function openPreview(tab) { async function closePreviews() { const tabs = document.getElementById("tabbrowser-tabs"); - const previewHidden = BrowserTestUtils.waitForEvent( - document.getElementById("tabbrowser-tab-preview"), - "previewhidden" + const previewHidden = BrowserTestUtils.waitForPopupEvent( + document.getElementById("tab-preview-panel"), + "hidden" ); EventUtils.synthesizeMouse(tabs, 0, tabs.outerHeight + 1, { type: "mouseout", @@ -34,6 +34,7 @@ add_setup(async function () { set: [ ["browser.tabs.cardPreview.enabled", true], ["browser.tabs.cardPreview.showThumbnails", false], + ["browser.tabs.tooltipsShowPidAndActiveness", false], ["ui.tooltip.delay_ms", 0], ], }); @@ -53,38 +54,120 @@ add_task(async function hoverTests() { const tabUrl2 = "data:text/html,<html><head><title>Second New Tab</title></head><body>Hello</body></html>"; const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl2); - const previewContainer = document.getElementById("tabbrowser-tab-preview"); + const previewContainer = document.getElementById("tab-preview-panel"); await openPreview(tab1); - Assert.ok( - ["open", "showing"].includes(previewContainer.panel.state), - "tab1 preview shown" - ); Assert.equal( - previewContainer.renderRoot.querySelector(".tab-preview-title").innerText, + previewContainer.querySelector(".tab-preview-title").innerText, "First New Tab", "Preview of tab1 shows correct title" ); + await closePreviews(); await openPreview(tab2); - Assert.ok( - ["open", "showing"].includes(previewContainer.panel.state), - "tab2 preview shown" - ); Assert.equal( - previewContainer.renderRoot.querySelector(".tab-preview-title").innerText, + previewContainer.querySelector(".tab-preview-title").innerText, "Second New Tab", "Preview of tab2 shows correct title" ); await closePreviews(); - Assert.ok( - ["closed", "hiding"].includes(previewContainer.panel.state), - "preview container is now hidden" + + BrowserTestUtils.removeTab(tab1); + BrowserTestUtils.removeTab(tab2); + + // Move the mouse outside of the tab strip. + EventUtils.synthesizeMouseAtCenter(document.documentElement, { + type: "mouseover", + }); +}); + +/** + * Verify that the pid and activeness statuses are not shown + * when the flag is not enabled. + */ +add_task(async function pidAndActivenessHiddenByDefaultTests() { + const tabUrl1 = + "data:text/html,<html><head><title>First New Tab</title></head><body>Hello</body></html>"; + const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl1); + const previewContainer = document.getElementById("tab-preview-panel"); + + await openPreview(tab1); + Assert.equal( + previewContainer.querySelector(".tab-preview-pid").innerText, + "", + "Tab PID is not shown" + ); + Assert.equal( + previewContainer.querySelector(".tab-preview-activeness").innerText, + "", + "Tab activeness is not shown" ); + await closePreviews(); + + BrowserTestUtils.removeTab(tab1); + + // Move the mouse outside of the tab strip. + EventUtils.synthesizeMouseAtCenter(document.documentElement, { + type: "mouseover", + }); +}); + +add_task(async function pidAndActivenessTests() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.tabs.tooltipsShowPidAndActiveness", true]], + }); + + const tabUrl1 = + "data:text/html,<html><head><title>Single process tab</title></head><body>Hello</body></html>"; + const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl1); + const tabUrl2 = `data:text/html,<html> + <head> + <title>Multi-process tab</title> + </head> + <body> + <iframe + id="inlineFrameExample" + title="Inline Frame Example" + width="300" + height="200" + src="https://example.com"> + </iframe> + </body> + </html>`; + const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl2); + const previewContainer = document.getElementById("tab-preview-panel"); + + await openPreview(tab1); + Assert.stringMatches( + previewContainer.querySelector(".tab-preview-pid").innerText, + /^pid: \d+$/, + "Tab PID is shown on single process tab" + ); + Assert.equal( + previewContainer.querySelector(".tab-preview-activeness").innerText, + "", + "Tab activeness is not shown on inactive tab" + ); + await closePreviews(); + + await openPreview(tab2); + Assert.stringMatches( + previewContainer.querySelector(".tab-preview-pid").innerText, + /^pids: \d+, \d+$/, + "Tab PIDs are shown on multi-process tab" + ); + Assert.equal( + previewContainer.querySelector(".tab-preview-activeness").innerText, + "[A]", + "Tab activeness is shown on active tab" + ); + await closePreviews(); + BrowserTestUtils.removeTab(tab1); BrowserTestUtils.removeTab(tab2); + await SpecialPowers.popPrefEnv(); // Move the mouse outside of the tab strip. EventUtils.synthesizeMouseAtCenter(document.documentElement, { @@ -105,29 +188,41 @@ add_task(async function thumbnailTests() { const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl1); const tabUrl2 = "about:blank"; const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl2); - const previewContainer = document.getElementById("tabbrowser-tab-preview"); + const previewPanel = document.getElementById("tab-preview-panel"); - const thumbnailUpdated = BrowserTestUtils.waitForEvent( - previewContainer, - "previewThumbnailUpdated" + let thumbnailUpdated = BrowserTestUtils.waitForEvent( + previewPanel, + "previewThumbnailUpdated", + false, + evt => evt.detail.thumbnail ); await openPreview(tab1); await thumbnailUpdated; Assert.ok( - previewContainer.renderRoot.querySelectorAll("img,canvas").length, + previewPanel.querySelectorAll( + ".tab-preview-thumbnail-container img, .tab-preview-thumbnail-container canvas" + ).length, "Tab1 preview contains thumbnail" ); + await closePreviews(); + thumbnailUpdated = BrowserTestUtils.waitForEvent( + previewPanel, + "previewThumbnailUpdated" + ); await openPreview(tab2); + await thumbnailUpdated; Assert.equal( - previewContainer.renderRoot.querySelectorAll("img,canvas").length, + previewPanel.querySelectorAll( + ".tab-preview-thumbnail-container img, .tab-preview-thumbnail-container canvas" + ).length, 0, "Tab2 (selected) does not contain thumbnail" ); - const previewHidden = BrowserTestUtils.waitForEvent( - document.getElementById("tabbrowser-tab-preview"), - "previewhidden" + const previewHidden = BrowserTestUtils.waitForPopupEvent( + previewPanel, + "hidden" ); BrowserTestUtils.removeTab(tab1); @@ -144,6 +239,102 @@ add_task(async function thumbnailTests() { }); /** + * make sure delay is applied when mouse leaves tabstrip + * but not when moving between tabs on the tabstrip + */ +add_task(async function delayTests() { + const tabUrl1 = + "data:text/html,<html><head><title>First New Tab</title></head><body>Hello</body></html>"; + const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl1); + const tabUrl2 = + "data:text/html,<html><head><title>Second New Tab</title></head><body>Hello</body></html>"; + const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl2); + const previewComponent = gBrowser.tabContainer.previewPanel; + const previewElement = document.getElementById("tab-preview-panel"); + + sinon.spy(previewComponent, "deactivate"); + + await openPreview(tab1); + + // I can't fake this like in hoverTests, need to send an updated-tab signal + //await openPreview(tab2); + + const previewHidden = BrowserTestUtils.waitForPopupEvent( + previewElement, + "hidden" + ); + Assert.ok( + !previewComponent.deactivate.called, + "Delay is not reset when moving between tabs" + ); + + EventUtils.synthesizeMouseAtCenter(document.getElementById("reload-button"), { + type: "mousemove", + }); + + await previewHidden; + + Assert.ok( + previewComponent.deactivate.called, + "Delay is reset when cursor leaves tabstrip" + ); + + BrowserTestUtils.removeTab(tab1); + BrowserTestUtils.removeTab(tab2); + sinon.restore(); +}); + +/** + * Dragging a tab should deactivate the preview + */ +add_task(async function dragTests() { + await SpecialPowers.pushPrefEnv({ + set: [["ui.tooltip.delay_ms", 1000]], + }); + const tabUrl1 = + "data:text/html,<html><head><title>First New Tab</title></head><body>Hello</body></html>"; + const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl1); + const tabUrl2 = + "data:text/html,<html><head><title>Second New Tab</title></head><body>Hello</body></html>"; + const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl2); + const previewComponent = gBrowser.tabContainer.previewPanel; + const previewElement = document.getElementById("tab-preview-panel"); + + sinon.spy(previewComponent, "deactivate"); + + await openPreview(tab1); + const previewHidden = BrowserTestUtils.waitForPopupEvent( + previewElement, + "hidden" + ); + let dragend = BrowserTestUtils.waitForEvent(tab1, "dragend"); + EventUtils.synthesizePlainDragAndDrop({ + srcElement: tab1, + destElement: tab2, + }); + + await previewHidden; + + Assert.ok( + previewComponent.deactivate.called, + "delay is reset after drag started" + ); + + await dragend; + + BrowserTestUtils.removeTab(tab1); + BrowserTestUtils.removeTab(tab2); + sinon.restore(); + + // Move the mouse outside of the tab strip. + EventUtils.synthesizeMouseAtCenter(document.documentElement, { + type: "mouseover", + }); + + await SpecialPowers.popPrefEnv(); +}); + +/** * Wheel events at the document-level of the window should hide the preview. */ add_task(async function wheelTests() { @@ -155,9 +346,9 @@ add_task(async function wheelTests() { await openPreview(tab1); const tabs = document.getElementById("tabbrowser-tabs"); - const previewHidden = BrowserTestUtils.waitForEvent( - document.getElementById("tabbrowser-tab-preview"), - "previewhidden" + const previewHidden = BrowserTestUtils.waitForPopupEvent( + document.getElementById("tab-preview-panel"), + "hidden" ); // Copied from apz_test_native_event_utils.js diff --git a/browser/base/content/test/tabs/browser_tab_tooltips.js b/browser/base/content/test/tabs/browser_tab_tooltips.js index ee82816bce..79be4d0a36 100644 --- a/browser/base/content/test/tabs/browser_tab_tooltips.js +++ b/browser/base/content/test/tabs/browser_tab_tooltips.js @@ -57,7 +57,7 @@ add_task(async function () { ); is( tooltip.getAttribute("position"), - "", + null, "tooltip position attribute for tab" ); diff --git a/browser/base/content/test/tabs/browser_tabswitch_select.js b/browser/base/content/test/tabs/browser_tabswitch_select.js index 3868764bed..b22a75c79c 100644 --- a/browser/base/content/test/tabs/browser_tabswitch_select.js +++ b/browser/base/content/test/tabs/browser_tabswitch_select.js @@ -35,7 +35,7 @@ add_task(async function () { let fullScreenEntered = TestUtils.waitForCondition( () => document.documentElement.getAttribute("sizemode") == "fullscreen" ); - BrowserFullScreen(); + BrowserCommands.fullScreen(); await fullScreenEntered; tab2.linkedBrowser.focus(); @@ -54,7 +54,7 @@ add_task(async function () { let fullScreenExited = TestUtils.waitForCondition( () => document.documentElement.getAttribute("sizemode") != "fullscreen" ); - BrowserFullScreen(); + BrowserCommands.fullScreen(); await fullScreenExited; BrowserTestUtils.removeTab(gBrowser.selectedTab); diff --git a/browser/base/content/test/tabs/browser_tabswitch_updatecommands.js b/browser/base/content/test/tabs/browser_tabswitch_updatecommands.js index b5d2762eec..82f9eb871b 100644 --- a/browser/base/content/test/tabs/browser_tabswitch_updatecommands.js +++ b/browser/base/content/test/tabs/browser_tabswitch_updatecommands.js @@ -8,7 +8,7 @@ add_task(async function () { let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri); let updates = []; - function countUpdates(event) { + function countUpdates() { updates.push(new Error().stack); } let updater = document.getElementById("editMenuCommandSetAll"); diff --git a/browser/base/content/test/tabs/browser_viewsource_of_data_URI_in_file_process.js b/browser/base/content/test/tabs/browser_viewsource_of_data_URI_in_file_process.js index b5ae94ce84..2c301a400d 100644 --- a/browser/base/content/test/tabs/browser_viewsource_of_data_URI_in_file_process.js +++ b/browser/base/content/test/tabs/browser_viewsource_of_data_URI_in_file_process.js @@ -33,7 +33,7 @@ add_task(async function () { // Make sure we can view-source on the data URI page. let promiseTab = BrowserTestUtils.waitForNewTab(gBrowser, DATA_URI_SOURCE); - BrowserViewSource(fileBrowser); + BrowserCommands.viewSource(fileBrowser); let viewSourceTab = await promiseTab; registerCleanupFunction(async function () { BrowserTestUtils.removeTab(viewSourceTab); diff --git a/browser/base/content/test/tabs/browser_visibleTabs_contextMenu.js b/browser/base/content/test/tabs/browser_visibleTabs_contextMenu.js index 202c43ce47..06fdd27d9c 100644 --- a/browser/base/content/test/tabs/browser_visibleTabs_contextMenu.js +++ b/browser/base/content/test/tabs/browser_visibleTabs_contextMenu.js @@ -2,11 +2,6 @@ * 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/. */ -const remoteClientsFixture = [ - { id: 1, name: "Foo" }, - { id: 2, name: "Bar" }, -]; - add_task(async function test() { // There should be one tab when we start the test let [origTab] = gBrowser.visibleTabs; @@ -16,9 +11,8 @@ add_task(async function test() { // Check the context menu with two tabs updateTabContextMenu(origTab); - is( - document.getElementById("context_closeTab").disabled, - false, + ok( + !document.getElementById("context_closeTab").disabled, "Close Tab is enabled" ); @@ -29,11 +23,14 @@ add_task(async function test() { // Check the context menu with one tab. updateTabContextMenu(testTab); - is( - document.getElementById("context_closeTab").disabled, - false, + ok( + !document.getElementById("context_closeTab").disabled, "Close Tab is enabled when more than one tab exists" ); + ok( + !document.getElementById("context_closeDuplicateTabs").disabled, + "Close duplicate tabs is enabled when more than one tab with the same URL exists" + ); // Add a tab that will get pinned // So now there's one pinned tab, one visible unpinned tab, and one hidden tab diff --git a/browser/base/content/test/tabs/browser_window_open_modifiers.js b/browser/base/content/test/tabs/browser_window_open_modifiers.js index b4376d6824..2ef951efef 100644 --- a/browser/base/content/test/tabs/browser_window_open_modifiers.js +++ b/browser/base/content/test/tabs/browser_window_open_modifiers.js @@ -97,7 +97,7 @@ add_task(async function () { BrowserTestUtils.synthesizeMouseAtCenter(id, { ...event }, browser); } else { // Make sure the keyboard activates a simple button on the page. - await ContentTask.spawn(browser, id, elementId => { + await ContentTask.spawn(browser, id, () => { content.document.querySelector("#focus-result").value = ""; content.document.querySelector("#focus-check").focus(); }); diff --git a/browser/base/content/test/tabs/common_link_in_tab_title_and_url_prefilled.js b/browser/base/content/test/tabs/common_link_in_tab_title_and_url_prefilled.js index a06b982615..bff14e5ced 100644 --- a/browser/base/content/test/tabs/common_link_in_tab_title_and_url_prefilled.js +++ b/browser/base/content/test/tabs/common_link_in_tab_title_and_url_prefilled.js @@ -244,7 +244,7 @@ async function synthesizeMouse(browser, link, event) { async function waitForNewTabWithLoadRequest() { return new Promise(resolve => gBrowser.addTabsProgressListener({ - onStateChange(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) { + onStateChange(aBrowser, aWebProgress, aRequest, aStateFlags) { if (aStateFlags & Ci.nsIWebProgressListener.STATE_START) { gBrowser.removeTabsProgressListener(this); resolve(gBrowser.getTabForBrowser(aBrowser)); diff --git a/browser/base/content/test/webextensions/browser_aboutaddons_blanktab.js b/browser/base/content/test/webextensions/browser_aboutaddons_blanktab.js index 228fe71815..1e0814ea96 100644 --- a/browser/base/content/test/webextensions/browser_aboutaddons_blanktab.js +++ b/browser/base/content/test/webextensions/browser_aboutaddons_blanktab.js @@ -8,7 +8,7 @@ add_task(async function testBlankTabReusedAboutAddons() { is(browser, gBrowser.selectedBrowser, "New tab is selected"); // Opening about:addons shouldn't change the selected tab. - BrowserOpenAddonsMgr(); + BrowserAddonUI.openAddonsMgr(); is(browser, gBrowser.selectedBrowser, "No new tab was opened"); diff --git a/browser/base/content/test/webextensions/browser_extension_sideloading.js b/browser/base/content/test/webextensions/browser_extension_sideloading.js index 4e1fe07194..5d8f82a178 100644 --- a/browser/base/content/test/webextensions/browser_extension_sideloading.js +++ b/browser/base/content/test/webextensions/browser_extension_sideloading.js @@ -16,11 +16,14 @@ const kSideloaded = true; async function createWebExtension(details) { let options = { manifest: { + manifest_version: details.manifest_version ?? 2, + browser_specific_settings: { gecko: { id: details.id } }, name: details.name, permissions: details.permissions, + host_permissions: details.host_permissions, }, }; @@ -86,9 +89,10 @@ add_task(async function test_sideloading() { const ID2 = "addon2@tests.mozilla.org"; await createWebExtension({ + manifest_version: 3, id: ID2, name: "Test 2", - permissions: ["<all_urls>"], + host_permissions: ["<all_urls>"], }); const ID3 = "addon3@tests.mozilla.org"; @@ -224,7 +228,7 @@ add_task(async function test_sideloading() { // Close the hamburger menu and go directly to the addons manager await gCUITestUtils.hideMainMenu(); - win = await BrowserOpenAddonsMgr(VIEW); + win = await BrowserAddonUI.openAddonsMgr(VIEW); await waitAboutAddonsViewLoaded(win.document); // about:addons addon entry element. @@ -293,7 +297,7 @@ add_task(async function test_sideloading() { // Close the hamburger menu and go to the detail page for this addon await gCUITestUtils.hideMainMenu(); - win = await BrowserOpenAddonsMgr( + win = await BrowserAddonUI.openAddonsMgr( `addons://detail/${encodeURIComponent(ID3)}` ); diff --git a/browser/base/content/test/webextensions/browser_extension_update_background.js b/browser/base/content/test/webextensions/browser_extension_update_background.js index 490544b2ec..5619bacb4d 100644 --- a/browser/base/content/test/webextensions/browser_extension_update_background.js +++ b/browser/base/content/test/webextensions/browser_extension_update_background.js @@ -87,7 +87,7 @@ async function backgroundUpdateTest(url, id, checkIconFn) { let addonId = addon.id; ok(addon, "Addon was installed"); - is(getBadgeStatus(), "", "Should not start out with an addon alert badge"); + is(getBadgeStatus(), null, "Should not start out with an addon alert badge"); // Trigger an update check and wait for the update for this addon // to be downloaded. @@ -156,7 +156,7 @@ async function backgroundUpdateTest(url, id, checkIconFn) { BrowserTestUtils.removeTab(tab); // Alert badge and hamburger menu items should be gone - is(getBadgeStatus(), "", "Addon alert badge should be gone"); + is(getBadgeStatus(), null, "Addon alert badge should be gone"); await gCUITestUtils.openMainMenu(); addons = PanelUI.addonNotificationContainer; @@ -205,7 +205,7 @@ async function backgroundUpdateTest(url, id, checkIconFn) { BrowserTestUtils.removeTab(tab); - is(getBadgeStatus(), "", "Addon alert badge should be gone"); + is(getBadgeStatus(), null, "Addon alert badge should be gone"); await addon.uninstall(); await SpecialPowers.popPrefEnv(); diff --git a/browser/base/content/test/webextensions/browser_extension_update_background_noprompt.js b/browser/base/content/test/webextensions/browser_extension_update_background_noprompt.js index a0b10c82e2..204e7fb44a 100644 --- a/browser/base/content/test/webextensions/browser_extension_update_background_noprompt.js +++ b/browser/base/content/test/webextensions/browser_extension_update_background_noprompt.js @@ -81,7 +81,7 @@ async function testNoPrompt(origUrl, id) { await updatePromise; // There should be no notifications about the update - is(getBadgeStatus(), "", "Should not have addon alert badge"); + is(getBadgeStatus(), null, "Should not have addon alert badge"); await gCUITestUtils.openMainMenu(); let addons = PanelUI.addonNotificationContainer; diff --git a/browser/base/content/test/webextensions/browser_legacy_webext.xpi b/browser/base/content/test/webextensions/browser_legacy_webext.xpi Binary files differindex a3bdf6f832..afd0a8bcee 100644 --- a/browser/base/content/test/webextensions/browser_legacy_webext.xpi +++ b/browser/base/content/test/webextensions/browser_legacy_webext.xpi diff --git a/browser/base/content/test/webextensions/browser_permissions_installTrigger.js b/browser/base/content/test/webextensions/browser_permissions_installTrigger.js index a227518ebb..36b4efff8b 100644 --- a/browser/base/content/test/webextensions/browser_permissions_installTrigger.js +++ b/browser/base/content/test/webextensions/browser_permissions_installTrigger.js @@ -9,6 +9,12 @@ async function installTrigger(filename) { ["extensions.InstallTriggerImpl.enabled", true], // Relax the user input requirements while running this test. ["xpinstall.userActivation.required", false], + // This test asserts that the extension icon is in the install dialog + // and so it requires the signature checks to be enabled (otherwise the + // extension icon is expected to be replaced by a warning icon) and the + // two test extension used by this test (browser_webext_nopermissions.xpi + // and browser_webext_permissions.xpi) are signed using AMO stage signatures. + ["xpinstall.signatures.dev-root", true], ], }); BrowserTestUtils.startLoadingURIString( diff --git a/browser/base/content/test/webextensions/browser_permissions_local_file.js b/browser/base/content/test/webextensions/browser_permissions_local_file.js index 7f8f256e14..731e8adea7 100644 --- a/browser/base/content/test/webextensions/browser_permissions_local_file.js +++ b/browser/base/content/test/webextensions/browser_permissions_local_file.js @@ -14,7 +14,9 @@ async function installFile(filename) { MockFilePicker.setFiles([file]); MockFilePicker.afterOpenCallback = MockFilePicker.cleanup; - let { document } = await BrowserOpenAddonsMgr("addons://list/extension"); + let { document } = await BrowserAddonUI.openAddonsMgr( + "addons://list/extension" + ); // Do the install... await waitAboutAddonsViewLoaded(document); @@ -32,9 +34,22 @@ add_task(async function test_install_extension_from_local_file() { }, }); + await SpecialPowers.pushPrefEnv({ + set: [ + // This test asserts that the extension icon is in the install dialog + // and so it requires the signature checks to be enabled (otherwise the + // extension icon is expected to be replaced by a warning icon) and the + // two test extension used by this test (browser_webext_nopermissions.xpi + // and browser_webext_permissions.xpi) are signed using AMO stage signatures. + ["xpinstall.signatures.dev-root", true], + ], + }); + // Install the add-ons. await testInstallMethod(installFile, "installLocal"); + await SpecialPowers.popPrefEnv(); + // Check we got an installId. ok( firstInstallId != null && !isNaN(firstInstallId), diff --git a/browser/base/content/test/webextensions/browser_permissions_mozAddonManager.js b/browser/base/content/test/webextensions/browser_permissions_mozAddonManager.js index 55a578221d..d54038bffe 100644 --- a/browser/base/content/test/webextensions/browser_permissions_mozAddonManager.js +++ b/browser/base/content/test/webextensions/browser_permissions_mozAddonManager.js @@ -9,6 +9,17 @@ async function installMozAM(filename) { ); await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + await SpecialPowers.pushPrefEnv({ + set: [ + // This test asserts that the extension icon is in the install dialog + // and so it requires the signature checks to be enabled (otherwise the + // extension icon is expected to be replaced by a warning icon) and the + // two test extension used by this test (browser_webext_nopermissions.xpi + // and browser_webext_permissions.xpi) are signed using AMO stage signatures. + ["xpinstall.signatures.dev-root", true], + ], + }); + await SpecialPowers.spawn( gBrowser.selectedBrowser, [`${BASE}/${filename}`], @@ -16,6 +27,8 @@ async function installMozAM(filename) { await content.wrappedJSObject.installMozAM(url); } ); + + await SpecialPowers.popPrefEnv(); } add_task(() => testInstallMethod(installMozAM, "installAmo")); diff --git a/browser/base/content/test/webextensions/browser_permissions_pointerevent.js b/browser/base/content/test/webextensions/browser_permissions_pointerevent.js index 188aa8e3bf..2809ffe9b4 100644 --- a/browser/base/content/test/webextensions/browser_permissions_pointerevent.js +++ b/browser/base/content/test/webextensions/browser_permissions_pointerevent.js @@ -9,15 +9,15 @@ add_task(async function test_pointerevent() { e.preventDefault(); }); - document.addEventListener("mousedown", e => { + document.addEventListener("mousedown", () => { browser.test.assertTrue(true, "Should receive mousedown"); }); - document.addEventListener("mouseup", e => { + document.addEventListener("mouseup", () => { browser.test.assertTrue(true, "Should receive mouseup"); }); - document.addEventListener("pointerup", e => { + document.addEventListener("pointerup", () => { browser.test.assertTrue(true, "Should receive pointerup"); browser.test.sendMessage("done"); }); diff --git a/browser/base/content/test/webextensions/browser_update_checkForUpdates.js b/browser/base/content/test/webextensions/browser_update_checkForUpdates.js index b902527cae..c9e59556e1 100644 --- a/browser/base/content/test/webextensions/browser_update_checkForUpdates.js +++ b/browser/base/content/test/webextensions/browser_update_checkForUpdates.js @@ -3,7 +3,7 @@ function checkAll(win) { triggerPageOptionsAction(win, "check-for-updates"); return new Promise(resolve => { let observer = { - observe(subject, topic, data) { + observe() { Services.obs.removeObserver(observer, "EM-update-check-finished"); resolve(); }, diff --git a/browser/base/content/test/webextensions/browser_update_interactive_noprompt.js b/browser/base/content/test/webextensions/browser_update_interactive_noprompt.js index 0b0b912503..9ad3deaae1 100644 --- a/browser/base/content/test/webextensions/browser_update_interactive_noprompt.js +++ b/browser/base/content/test/webextensions/browser_update_interactive_noprompt.js @@ -36,7 +36,7 @@ async function testUpdateNoPrompt( is(addon.version, initialVersion, "Version 1 of the addon is installed"); // Go to Extensions in about:addons - let win = await BrowserOpenAddonsMgr("addons://list/extension"); + let win = await BrowserAddonUI.openAddonsMgr("addons://list/extension"); await waitAboutAddonsViewLoaded(win.document); diff --git a/browser/base/content/test/webextensions/browser_webext_nopermissions.xpi b/browser/base/content/test/webextensions/browser_webext_nopermissions.xpi Binary files differindex ab97d96a11..87500ceb38 100644 --- a/browser/base/content/test/webextensions/browser_webext_nopermissions.xpi +++ b/browser/base/content/test/webextensions/browser_webext_nopermissions.xpi diff --git a/browser/base/content/test/webextensions/browser_webext_permissions.xpi b/browser/base/content/test/webextensions/browser_webext_permissions.xpi Binary files differindex a8c8c38ef8..8149ce7b6b 100644 --- a/browser/base/content/test/webextensions/browser_webext_permissions.xpi +++ b/browser/base/content/test/webextensions/browser_webext_permissions.xpi diff --git a/browser/base/content/test/webextensions/browser_webext_update1.xpi b/browser/base/content/test/webextensions/browser_webext_update1.xpi Binary files differindex 086b3839b9..66ad3e1b31 100644 --- a/browser/base/content/test/webextensions/browser_webext_update1.xpi +++ b/browser/base/content/test/webextensions/browser_webext_update1.xpi diff --git a/browser/base/content/test/webextensions/browser_webext_update2.xpi b/browser/base/content/test/webextensions/browser_webext_update2.xpi Binary files differindex 19967c39c0..a120a64c6d 100644 --- a/browser/base/content/test/webextensions/browser_webext_update2.xpi +++ b/browser/base/content/test/webextensions/browser_webext_update2.xpi diff --git a/browser/base/content/test/webextensions/browser_webext_update_icon1.xpi b/browser/base/content/test/webextensions/browser_webext_update_icon1.xpi Binary files differindex 24cb7616d2..040f8f8c97 100644 --- a/browser/base/content/test/webextensions/browser_webext_update_icon1.xpi +++ b/browser/base/content/test/webextensions/browser_webext_update_icon1.xpi diff --git a/browser/base/content/test/webextensions/browser_webext_update_icon2.xpi b/browser/base/content/test/webextensions/browser_webext_update_icon2.xpi Binary files differindex fd9cf7eb0e..0b13e7c7dd 100644 --- a/browser/base/content/test/webextensions/browser_webext_update_icon2.xpi +++ b/browser/base/content/test/webextensions/browser_webext_update_icon2.xpi diff --git a/browser/base/content/test/webextensions/browser_webext_update_perms1.xpi b/browser/base/content/test/webextensions/browser_webext_update_perms1.xpi Binary files differindex f4942f9082..60b6643a12 100644 --- a/browser/base/content/test/webextensions/browser_webext_update_perms1.xpi +++ b/browser/base/content/test/webextensions/browser_webext_update_perms1.xpi diff --git a/browser/base/content/test/webextensions/browser_webext_update_perms2.xpi b/browser/base/content/test/webextensions/browser_webext_update_perms2.xpi Binary files differindex 2c023edc9d..64c2afb473 100644 --- a/browser/base/content/test/webextensions/browser_webext_update_perms2.xpi +++ b/browser/base/content/test/webextensions/browser_webext_update_perms2.xpi diff --git a/browser/base/content/test/webextensions/head.js b/browser/base/content/test/webextensions/head.js index 84f7cd02d7..f364dbed88 100644 --- a/browser/base/content/test/webextensions/head.js +++ b/browser/base/content/test/webextensions/head.js @@ -302,7 +302,7 @@ function checkNotification(panel, checkIcon, permissions, sideloaded) { * * @returns {Promise} */ -async function testInstallMethod(installFn, telemetryBase) { +async function testInstallMethod(installFn) { const PERMS_XPI = "browser_webext_permissions.xpi"; const NO_PERMS_XPI = "browser_webext_nopermissions.xpi"; const ID = "permissions@test.mozilla.org"; @@ -508,7 +508,7 @@ async function interactiveUpdateTest(autoUpdate, checkFn) { ok(addon, "Addon was installed"); is(addon.version, "1.0", "Version 1 of the addon is installed"); - let win = await BrowserOpenAddonsMgr("addons://list/extension"); + let win = await BrowserAddonUI.openAddonsMgr("addons://list/extension"); await waitAboutAddonsViewLoaded(win.document); diff --git a/browser/base/content/test/webrtc/browser_devices_get_user_media_anim.js b/browser/base/content/test/webrtc/browser_devices_get_user_media_anim.js index dd20a672c3..f1052565b8 100644 --- a/browser/base/content/test/webrtc/browser_devices_get_user_media_anim.js +++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_anim.js @@ -58,7 +58,7 @@ var gTests = [ ); is( gBrowser.selectedTab.getAttribute("sharing"), - "", + null, "the new tab doesn't have the 'sharing' attribute" ); is( @@ -89,7 +89,7 @@ var gTests = [ await TestUtils.waitForCondition(() => !tab.getAttribute("sharing")); is( tab.getAttribute("sharing"), - "", + null, "the tab no longer has the 'sharing' attribute after closing the stream" ); } diff --git a/browser/base/content/test/webrtc/browser_devices_get_user_media_by_device_id.js b/browser/base/content/test/webrtc/browser_devices_get_user_media_by_device_id.js index 3e5ca0668a..9598bb565c 100644 --- a/browser/base/content/test/webrtc/browser_devices_get_user_media_by_device_id.js +++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_by_device_id.js @@ -49,7 +49,7 @@ add_task(async function test_get_user_media_by_device_id() { .filter(d => d.kind == "videoinput") .map(d => d.deviceId)[0]; - await BrowserTestUtils.withNewTab(TEST_PAGE, async browser => { + await BrowserTestUtils.withNewTab(TEST_PAGE, async () => { let promise = promisePopupNotificationShown("webRTC-shareDevices"); let observerPromise = expectObserverCalled("getUserMedia:request"); await promiseRequestDevice({ deviceId: { exact: audioId } }); diff --git a/browser/base/content/test/webrtc/browser_devices_get_user_media_grace.js b/browser/base/content/test/webrtc/browser_devices_get_user_media_grace.js index 0df69bb9da..624bc07ce0 100644 --- a/browser/base/content/test/webrtc/browser_devices_get_user_media_grace.js +++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_grace.js @@ -171,7 +171,7 @@ var gTests = [ { desc: "getUserMedia camera+mic survives page reload but not past grace", - run: async function checkAudioVideoGracePastReload(browser) { + run: async function checkAudioVideoGracePastReload() { await prompt(true, true); await allow(true, true); await closeStream(); @@ -240,7 +240,7 @@ var gTests = [ info("Open same page in a new tab"); await disableObserverVerification(); - await BrowserTestUtils.withNewTab(SAME_ORIGIN + PATH, async browser => { + await BrowserTestUtils.withNewTab(SAME_ORIGIN + PATH, async () => { info("In new tab, gUM(camera+mic) causes a prompt."); await prompt(true, true); }); @@ -329,7 +329,7 @@ var gTests = [ { desc: "getUserMedia camera+mic grace period cleared on permission block", - run: async function checkAudioVideoGraceEndsNewTab(browser) { + run: async function checkAudioVideoGraceEndsNewTab() { await SpecialPowers.pushPrefEnv({ set: [["privacy.webrtc.deviceGracePeriodTimeoutMs", 10000]], }); diff --git a/browser/base/content/test/webrtc/browser_devices_select_audio_output.js b/browser/base/content/test/webrtc/browser_devices_select_audio_output.js index fbced1f5cc..df75f39a1a 100644 --- a/browser/base/content/test/webrtc/browser_devices_select_audio_output.js +++ b/browser/base/content/test/webrtc/browser_devices_select_audio_output.js @@ -220,7 +220,7 @@ var gTests = [ gBrowser.selectedBrowser.browsingContext, "getUserMedia:response:allow", 1, - (aSubject, aTopic, aData) => { + aSubject => { const device = aSubject .QueryInterface(Ci.nsIArrayExtensions) .GetElementAt(0).wrappedJSObject; diff --git a/browser/base/content/test/webrtc/browser_webrtc_hooks.js b/browser/base/content/test/webrtc/browser_webrtc_hooks.js index e980b15286..3fb2fc9f8d 100644 --- a/browser/base/content/test/webrtc/browser_webrtc_hooks.js +++ b/browser/base/content/test/webrtc/browser_webrtc_hooks.js @@ -122,7 +122,7 @@ var gTests = [ run: async function testDeferredBlocker(browser) { Events.on(); - let blocker = params => Promise.resolve("allow"); + let blocker = () => Promise.resolve("allow"); webrtcUI.addPeerConnectionBlocker(blocker); await tryPeerConnection(browser); @@ -138,7 +138,7 @@ var gTests = [ run: async function testBlockerDeny(browser) { Events.on(); - let blocker = params => "deny"; + let blocker = () => "deny"; webrtcUI.addPeerConnectionBlocker(blocker); await tryPeerConnection(browser, "NotAllowedError"); @@ -156,14 +156,14 @@ var gTests = [ Events.on(); let blocker1Called = false, - blocker1 = params => { + blocker1 = () => { blocker1Called = true; return "allow"; }; webrtcUI.addPeerConnectionBlocker(blocker1); let blocker2Called = false, - blocker2 = params => { + blocker2 = () => { blocker2Called = true; return "allow"; }; @@ -187,14 +187,14 @@ var gTests = [ Events.on(); let blocker1Called = false, - blocker1 = params => { + blocker1 = () => { blocker1Called = true; return "allow"; }; webrtcUI.addPeerConnectionBlocker(blocker1); let blocker2Called = false, - blocker2 = params => { + blocker2 = () => { blocker2Called = true; return "deny"; }; @@ -218,14 +218,14 @@ var gTests = [ Events.on(); let blocker1Called = false, - blocker1 = params => { + blocker1 = () => { blocker1Called = true; return "deny"; }; webrtcUI.addPeerConnectionBlocker(blocker1); let blocker2Called = false, - blocker2 = params => { + blocker2 = () => { blocker2Called = true; return "allow"; }; @@ -252,14 +252,14 @@ var gTests = [ Events.on(); let blocker1Called = false, - blocker1 = params => { + blocker1 = () => { blocker1Called = true; return "allow"; }; webrtcUI.addPeerConnectionBlocker(blocker1); let blocker2Called = false, - blocker2 = params => { + blocker2 = () => { blocker2Called = true; return "allow"; }; @@ -283,14 +283,14 @@ var gTests = [ run: async function testBlockerThrows(browser) { Events.on(); let blocker1Called = false, - blocker1 = params => { + blocker1 = () => { blocker1Called = true; throw new Error("kaboom"); }; webrtcUI.addPeerConnectionBlocker(blocker1); let blocker2Called = false, - blocker2 = params => { + blocker2 = () => { blocker2Called = true; return "allow"; }; @@ -313,10 +313,10 @@ var gTests = [ run: async function testBlockerCancel(browser) { let blocker, blockerPromise = new Promise(resolve => { - blocker = params => { + blocker = () => { resolve(); // defer indefinitely - return new Promise(innerResolve => {}); + return new Promise(() => {}); }; }); webrtcUI.addPeerConnectionBlocker(blocker); diff --git a/browser/base/content/test/webrtc/head.js b/browser/base/content/test/webrtc/head.js index 639ae2e51a..694875bd21 100644 --- a/browser/base/content/test/webrtc/head.js +++ b/browser/base/content/test/webrtc/head.js @@ -146,7 +146,7 @@ async function assertWebRTCIndicatorStatus(expected) { if (!expected) { let win = Services.wm.getMostRecentWindow("Browser:WebRTCGlobalIndicator"); if (win) { - await new Promise((resolve, reject) => { + await new Promise(resolve => { win.addEventListener("unload", function listener(e) { if (e.target == win.document) { win.removeEventListener("unload", listener); @@ -308,7 +308,7 @@ function expectObserverCalledOnClose( { topic: aTopic, count: 1, - filterFunctionSource: ((subject, topic, data) => { + filterFunctionSource: ((subject, topic) => { Services.cpmm.sendAsyncMessage("WebRTCTest:ObserverCalled", { topic, }); @@ -1061,7 +1061,7 @@ async function promiseReloadFrame(aFrameId, aBrowsingContext) { let loadedPromise = BrowserTestUtils.browserLoaded( gBrowser.selectedBrowser, true, - arg => { + () => { return true; } ); diff --git a/browser/base/content/test/zoom/browser.toml b/browser/base/content/test/zoom/browser.toml index 281fb9329c..e2aa0c077a 100644 --- a/browser/base/content/test/zoom/browser.toml +++ b/browser/base/content/test/zoom/browser.toml @@ -34,7 +34,7 @@ https_first_disabled = true ["browser_sitespecific_video_zoom.js"] https_first_disabled = true -support-files = ["../general/video.ogg"] +support-files = ["../general/video.webm"] skip-if = [ "os == 'win' && debug", # Bug 1315042 "verify && debug && os == 'linux'", # Bug 1315042 diff --git a/browser/base/content/test/zoom/browser_sitespecific_video_zoom.js b/browser/base/content/test/zoom/browser_sitespecific_video_zoom.js index 589e3d09cf..94fd0dee56 100644 --- a/browser/base/content/test/zoom/browser_sitespecific_video_zoom.js +++ b/browser/base/content/test/zoom/browser_sitespecific_video_zoom.js @@ -8,7 +8,7 @@ const TEST_PAGE = "http://example.org/browser/browser/base/content/test/zoom/zoom_test.html"; const TEST_VIDEO = // eslint-disable-next-line @microsoft/sdl/no-insecure-url - "http://example.org/browser/browser/base/content/test/general/video.ogg"; + "http://example.org/browser/browser/base/content/test/general/video.webm"; var gTab1, gTab2, gLevel1; diff --git a/browser/base/content/test/zoom/browser_zoom_commands.js b/browser/base/content/test/zoom/browser_zoom_commands.js index 88b6f42059..ef49a5794e 100644 --- a/browser/base/content/test/zoom/browser_zoom_commands.js +++ b/browser/base/content/test/zoom/browser_zoom_commands.js @@ -65,7 +65,7 @@ function assertTextZoomCommandCheckedState(isChecked) { * zoom levels and/or preferences on an individual browser. */ add_task(async function test_update_browser_zoom() { - await BrowserTestUtils.withNewTab(TEST_PAGE_URL, async browser => { + await BrowserTestUtils.withNewTab(TEST_PAGE_URL, async () => { let currentZoom = await FullZoomHelper.getGlobalValue(); Assert.equal( currentZoom, @@ -136,7 +136,7 @@ add_task(async function test_update_browser_zoom() { * zoom levels when the default zoom is not at 1.0. */ add_task(async function test_update_browser_zoom() { - await BrowserTestUtils.withNewTab(TEST_PAGE_URL, async browser => { + await BrowserTestUtils.withNewTab(TEST_PAGE_URL, async () => { let currentZoom = await FullZoomHelper.getGlobalValue(); Assert.equal( currentZoom, diff --git a/browser/base/content/test/zoom/head.js b/browser/base/content/test/zoom/head.js index 4a42aed98f..272303de95 100644 --- a/browser/base/content/test/zoom/head.js +++ b/browser/base/content/test/zoom/head.js @@ -34,7 +34,7 @@ var FullZoomHelper = { parsedZoomValue, nonPrivateLoadContext, { - handleCompletion(reason) { + handleCompletion() { resolve(); }, } @@ -72,7 +72,7 @@ var FullZoomHelper = { value = parseFloat(pref.value); } }, - handleCompletion(reason) { + handleCompletion() { resolve(value); }, handleError(error) { @@ -84,7 +84,7 @@ var FullZoomHelper = { waitForLocationChange: function waitForLocationChange() { return new Promise(resolve => { - Services.obs.addObserver(function obs(subj, topic, data) { + Services.obs.addObserver(function obs(subj, topic) { Services.obs.removeObserver(obs, topic); resolve(); }, "browser-fullZoom:location-change"); @@ -124,7 +124,7 @@ var FullZoomHelper = { let didLoad = false; let didZoom = false; - promiseTabLoadEvent(tab, url).then(event => { + promiseTabLoadEvent(tab, url).then(() => { didLoad = true; if (didZoom) { resolve(); diff --git a/browser/base/content/titlebar-items.inc.xhtml b/browser/base/content/titlebar-items.inc.xhtml index 057fd522a9..4fea3a1266 100644 --- a/browser/base/content/titlebar-items.inc.xhtml +++ b/browser/base/content/titlebar-items.inc.xhtml @@ -13,7 +13,7 @@ data-l10n-id="browser-window-maximize-button" /> <toolbarbutton class="titlebar-button titlebar-restore" - oncommand="window.fullScreen ? BrowserFullScreen() : window.restore();" + oncommand="window.fullScreen ? BrowserCommands.fullScreen() : window.restore();" data-l10n-id="browser-window-restore-down-button" /> <toolbarbutton class="titlebar-button titlebar-close" diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index 5967c878b3..1d8637db2e 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -113,11 +113,6 @@ function getRootEvent(aEvent) { return BrowserUtils.getRootEvent(aEvent); } -// This is here for historical reasons. bug 1742889 covers cleaning this up. -function whereToOpenLink(e, ignoreButton, ignoreAlt) { - return BrowserUtils.whereToOpenLink(e, ignoreButton, ignoreAlt); -} - function openTrustedLinkIn(url, where, params) { URILoadingHelper.openTrustedLinkIn(window, url, where, params); } @@ -294,7 +289,7 @@ function closeMenus(node) { * to check if the close command key was pressed in aEvent. */ function eventMatchesKey(aEvent, aKey) { - let keyPressed = aKey.getAttribute("key").toLowerCase(); + let keyPressed = (aKey.getAttribute("key") || "").toLowerCase(); let keyModifiers = aKey.getAttribute("modifiers"); let modifiers = ["Alt", "Control", "Meta", "Shift"]; @@ -341,7 +336,7 @@ function gatherTextUnder(root) { } else if (HTMLImageElement.isInstance(node)) { // If it has an "alt" attribute, add that. var altText = node.getAttribute("alt"); - if (altText && altText != "") { + if (altText) { text += " " + altText; } } diff --git a/browser/base/content/webext-panels.js b/browser/base/content/webext-panels.js index e8820f4ad4..787193ab7d 100644 --- a/browser/base/content/webext-panels.js +++ b/browser/base/content/webext-panels.js @@ -125,22 +125,16 @@ function getBrowser(panel) { return readyPromise.then(initBrowser); } -// Stub tabbrowser implementation for use by the tab-modal alert code. +// Stub tabbrowser implementation to make sure that links from inside +// extension sidebar panels open in new tabs, see bug 1488055. var gBrowser = { get selectedBrowser() { return document.getElementById("webext-panels-browser"); }, - getTabForBrowser(browser) { + getTabForBrowser() { return null; }, - - getTabModalPromptBox(browser) { - if (!browser.tabModalPromptBox) { - browser.tabModalPromptBox = new TabModalPromptBox(browser); - } - return browser.tabModalPromptBox; - }, }; function updatePosition() { diff --git a/browser/base/content/webext-panels.xhtml b/browser/base/content/webext-panels.xhtml index f421d9bf80..1b97794a8d 100644 --- a/browser/base/content/webext-panels.xhtml +++ b/browser/base/content/webext-panels.xhtml @@ -28,7 +28,7 @@ <html:link rel="localization" href="toolkit/branding/brandings.ftl"/> <html:link rel="localization" href="toolkit/global/textActions.ftl"/> <html:link rel="localization" href="browser/browserContext.ftl"/> - <html:link rel="localization" href="preview/select-translations.ftl"/> + <html:link rel="localization" href="browser/translations.ftl"/> </linkset> <commandset id="mainCommandset"> diff --git a/browser/base/content/webrtcIndicator.js b/browser/base/content/webrtcIndicator.js index f38c7446ba..c19bfe1f35 100644 --- a/browser/base/content/webrtcIndicator.js +++ b/browser/base/content/webrtcIndicator.js @@ -47,7 +47,7 @@ function closingInternally() { * Main control object for the WebRTC global indicator */ const WebRTCIndicator = { - init(event) { + init() { addEventListener("load", this); addEventListener("unload", this); |