Update On Fri Feb 21 19:23:37 CET 2025

This commit is contained in:
github-action[bot] 2025-02-21 19:23:38 +01:00
parent b9cd5d6777
commit 0ecb642b6f
776 changed files with 20573 additions and 12964 deletions

72
Cargo.lock generated
View file

@ -629,18 +629,6 @@ dependencies = [
"nsstring",
]
[[package]]
name = "builtins-static"
version = "0.1.0"
dependencies = [
"bindgen 0.69.4",
"mozbuild",
"mozilla-central-workspace-hack",
"nom",
"pkcs11-bindings",
"smallvec",
]
[[package]]
name = "bumpalo"
version = "3.15.4"
@ -2485,6 +2473,7 @@ dependencies = [
"signature_cache",
"static_prefs",
"storage",
"trust-anchors",
"unic-langid",
"unic-langid-ffi",
"unicode-bidi",
@ -3526,8 +3515,9 @@ dependencies = [
[[package]]
name = "libz-rs-sys"
version = "0.2.1"
source = "git+https://github.com/memorysafety/zlib-rs?rev=4aa430ccb77537d0d60dab8db993ca51bb1194c5#4aa430ccb77537d0d60dab8db993ca51bb1194c5"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a90e19106f1b2c93f1fa6cdeec2e56facbf2e403559c1e1c0ddcc6d46e979cdf"
dependencies = [
"zlib-rs",
]
@ -3995,7 +3985,7 @@ dependencies = [
[[package]]
name = "mls-platform-api"
version = "0.1.0"
source = "git+https://github.com/beurdouche/mls-platform-api?rev=19c3f18b747d13354370ba84440bb0b963932634#19c3f18b747d13354370ba84440bb0b963932634"
source = "git+https://github.com/beurdouche/mls-platform-api?rev=5d88241b9765cae3669aba21f0946bd3700f7db1#5d88241b9765cae3669aba21f0946bd3700f7db1"
dependencies = [
"bincode",
"hex",
@ -4010,8 +4000,8 @@ dependencies = [
[[package]]
name = "mls-rs"
version = "0.39.1"
source = "git+https://github.com/beurdouche/mls-rs?rev=eedb37e50e3fca51863f460755afd632137da57c#eedb37e50e3fca51863f460755afd632137da57c"
version = "0.45.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=b747d7efb85a776b97ad8afa8d1b32893fa5efa3#b747d7efb85a776b97ad8afa8d1b32893fa5efa3"
dependencies = [
"async-trait",
"cfg-if",
@ -4035,8 +4025,8 @@ dependencies = [
[[package]]
name = "mls-rs-codec"
version = "0.5.3"
source = "git+https://github.com/beurdouche/mls-rs?rev=eedb37e50e3fca51863f460755afd632137da57c#eedb37e50e3fca51863f460755afd632137da57c"
version = "0.6.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=b747d7efb85a776b97ad8afa8d1b32893fa5efa3#b747d7efb85a776b97ad8afa8d1b32893fa5efa3"
dependencies = [
"mls-rs-codec-derive",
"thiserror 1.999.999",
@ -4045,8 +4035,8 @@ dependencies = [
[[package]]
name = "mls-rs-codec-derive"
version = "0.1.1"
source = "git+https://github.com/beurdouche/mls-rs?rev=eedb37e50e3fca51863f460755afd632137da57c#eedb37e50e3fca51863f460755afd632137da57c"
version = "0.2.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=b747d7efb85a776b97ad8afa8d1b32893fa5efa3#b747d7efb85a776b97ad8afa8d1b32893fa5efa3"
dependencies = [
"darling",
"proc-macro2",
@ -4056,8 +4046,8 @@ dependencies = [
[[package]]
name = "mls-rs-core"
version = "0.18.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=eedb37e50e3fca51863f460755afd632137da57c#eedb37e50e3fca51863f460755afd632137da57c"
version = "0.21.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=b747d7efb85a776b97ad8afa8d1b32893fa5efa3#b747d7efb85a776b97ad8afa8d1b32893fa5efa3"
dependencies = [
"async-trait",
"hex",
@ -4072,8 +4062,8 @@ dependencies = [
[[package]]
name = "mls-rs-crypto-hpke"
version = "0.9.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=eedb37e50e3fca51863f460755afd632137da57c#eedb37e50e3fca51863f460755afd632137da57c"
version = "0.14.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=b747d7efb85a776b97ad8afa8d1b32893fa5efa3#b747d7efb85a776b97ad8afa8d1b32893fa5efa3"
dependencies = [
"async-trait",
"cfg-if",
@ -4087,7 +4077,7 @@ dependencies = [
[[package]]
name = "mls-rs-crypto-nss"
version = "0.1.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=eedb37e50e3fca51863f460755afd632137da57c#eedb37e50e3fca51863f460755afd632137da57c"
source = "git+https://github.com/beurdouche/mls-rs?rev=b747d7efb85a776b97ad8afa8d1b32893fa5efa3#b747d7efb85a776b97ad8afa8d1b32893fa5efa3"
dependencies = [
"getrandom",
"hex",
@ -4104,8 +4094,8 @@ dependencies = [
[[package]]
name = "mls-rs-crypto-traits"
version = "0.10.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=eedb37e50e3fca51863f460755afd632137da57c#eedb37e50e3fca51863f460755afd632137da57c"
version = "0.15.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=b747d7efb85a776b97ad8afa8d1b32893fa5efa3#b747d7efb85a776b97ad8afa8d1b32893fa5efa3"
dependencies = [
"async-trait",
"maybe-async",
@ -4114,8 +4104,8 @@ dependencies = [
[[package]]
name = "mls-rs-identity-x509"
version = "0.11.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=eedb37e50e3fca51863f460755afd632137da57c#eedb37e50e3fca51863f460755afd632137da57c"
version = "0.15.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=b747d7efb85a776b97ad8afa8d1b32893fa5efa3#b747d7efb85a776b97ad8afa8d1b32893fa5efa3"
dependencies = [
"async-trait",
"maybe-async",
@ -4126,8 +4116,8 @@ dependencies = [
[[package]]
name = "mls-rs-provider-sqlite"
version = "0.11.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=eedb37e50e3fca51863f460755afd632137da57c#eedb37e50e3fca51863f460755afd632137da57c"
version = "0.15.0"
source = "git+https://github.com/beurdouche/mls-rs?rev=b747d7efb85a776b97ad8afa8d1b32893fa5efa3#b747d7efb85a776b97ad8afa8d1b32893fa5efa3"
dependencies = [
"async-trait",
"hex",
@ -6305,7 +6295,7 @@ name = "terminal_size"
version = "0.3.999"
[[package]]
name = "test-builtins-static"
name = "test-trust-anchors-static"
version = "0.1.0"
dependencies = [
"bindgen 0.69.4",
@ -6559,6 +6549,17 @@ dependencies = [
"cache-padded",
]
[[package]]
name = "trust-anchors"
version = "0.1.0"
dependencies = [
"bindgen 0.69.4",
"mozbuild",
"nom",
"pkcs11-bindings",
"smallvec",
]
[[package]]
name = "try-lock"
version = "0.2.4"
@ -7760,5 +7761,6 @@ dependencies = [
[[package]]
name = "zlib-rs"
version = "0.2.1"
source = "git+https://github.com/memorysafety/zlib-rs?rev=4aa430ccb77537d0d60dab8db993ca51bb1194c5#4aa430ccb77537d0d60dab8db993ca51bb1194c5"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aada01553a9312bad4b9569035a1f12b05e5ec9770a1a4b323757356928944f8"

View file

@ -9,10 +9,10 @@ members = [
"js/src/rust",
"netwerk/base/idna_glue",
"netwerk/test/http3server",
"security/manager/ssl/builtins",
"security/manager/ssl/tests/unit/test_builtins",
"security/manager/ssl/ipcclientcerts",
"security/manager/ssl/osclientcerts",
"security/manager/ssl/trust_anchors",
"security/manager/ssl/tests/unit/test_trust_anchors",
"security/mls/mls_gk",
"testing/geckodriver",
"toolkit/components/uniffi-bindgen-gecko-js",

View file

@ -276,13 +276,6 @@ export class EncryptedMediaParent extends JSWindowActorParent {
}
async reportEMEDecryptionProbe() {
const isGleanReported =
await Glean.mediadrm.decryption.has_hardware_decryption.testGetValue();
if (typeof isGleanReported === "boolean") {
// Probe already exists, no need to report it again.
return;
}
let hasHardwareDecryption = false;
let hasSoftwareClearlead = false;
let hasHardwareClearlead = false;

View file

@ -525,8 +525,7 @@ pref("browser.urlbar.suggest.quicksuggest.sponsored", false, sticky);
// with their various default-branch values, the user is enrolled in over time.
pref("browser.urlbar.quicksuggest.dataCollection.enabled", false, sticky);
// Whether the Firefox Suggest contextual opt-in result is enabled. If true,
// this implicitly disables shouldShowOnboardingDialog.
// Whether the Firefox Suggest contextual opt-in result is enabled.
pref("browser.urlbar.quicksuggest.contextualOptIn", false);
// Number that the user dismissed the Firefox Suggest contextual opt-in result.
@ -544,9 +543,6 @@ pref("browser.urlbar.quicksuggest.contextualOptIn.thirdReshowAfterPeriodDays", 6
// Whether the quick suggest feature in the urlbar is enabled.
pref("browser.urlbar.quicksuggest.enabled", false);
// Whether Suggest should be hidden in the settings UI even when enabled.
pref("browser.urlbar.quicksuggest.hideSettingsUI", false);
// Ranking mode of QuickSuggest. Currently used for relevance ranking
// experimentation. It can be any of "default", "interest", and "random".
pref("browser.urlbar.quicksuggest.rankingMode", "default");
@ -555,12 +551,6 @@ pref("browser.urlbar.quicksuggest.rankingMode", "default");
// JS backend.
pref("browser.urlbar.quicksuggest.rustEnabled", true);
// Whether to show the QuickSuggest onboarding dialog.
pref("browser.urlbar.quicksuggest.shouldShowOnboardingDialog", false);
// Show QuickSuggest onboarding dialog on the nth browser restarts.
pref("browser.urlbar.quicksuggest.showOnboardingDialogAfterNRestarts", 0);
// The index of sponsored Firefox Suggest results within the Firefox Suggest
// section when "Show search suggestions ahead of browsing history in address bar
// results" is checked. When not checked, the index is hardcoded as -1. Negative
@ -1970,6 +1960,10 @@ pref("browser.newtabpage.activity-stream.discoverystream.sections.region-content
pref("browser.newtabpage.activity-stream.discoverystream.sections.cards.enabled", true);
pref("browser.newtabpage.activity-stream.discoverystream.sections.personalization.inferred.enabled", false);
pref("browser.newtabpage.activity-stream.discoverystream.sections.interestPicker.enabled", false);
pref("browser.newtabpage.activity-stream.discoverystream.sections.interestPicker.visibleSections", "");
pref("browser.newtabpage.activity-stream.discoverystream.merino-provider.endpoint", "merino.services.mozilla.com");
// List of regions that get spocs by default.

View file

@ -9,6 +9,8 @@ skip-if = [
"verify && os == 'win'",
]
["browser_selectpopup_checked.js"]
["browser_selectpopup_colors.js"]
skip-if = ["os == 'linux'"] # Bug 1329991 - test fails intermittently on Linux builds

View file

@ -0,0 +1,40 @@
const PAGE = `
<!doctype html>
<select style="width: 600px">
<option>ABC</option>
<option selected>DEFG</option>
</select>
`;
add_task(async function () {
const url = "data:text/html," + encodeURI(PAGE);
await BrowserTestUtils.withNewTab(
{
gBrowser,
url,
},
async function (browser) {
await SpecialPowers.spawn(browser, [], async function () {
ok(
content.document
.querySelector("option[selected]")
.matches(":checked"),
"Option should be selected"
);
});
let popup = await openSelectPopup("click");
await SpecialPowers.spawn(browser, [], async function () {
ok(
content.document
.querySelector("option[selected]")
.matches(":checked"),
"Option should still be selected"
);
});
popup.hidePopup();
}
);
});

View file

@ -25,6 +25,9 @@ support-files = [
["browser_sanitize-history.js"]
["browser_sanitize-offlineData.js"]
skip-if = [
"os == 'mac' && os_version == '15.30' && arch == 'aarch64' && opt", # Bug 1775635
]
["browser_sanitize-passwordDisabledHosts.js"]

View file

@ -381,9 +381,6 @@ const ignorableAllowlist = new Set([
// The following files are outside of the omni.ja file, so we only catch them
// when testing on a non-packaged build.
// toolkit/mozapps/extensions/nsBlocklistService.js
"resource://app/blocklist.xml",
// dom/media/gmp/GMPParent.cpp
"resource://gre/gmp-clearkey/0.1/manifest.json",
]);
@ -497,8 +494,15 @@ function parseManifest(manifestUri) {
Services.io.newURI(argv[0]).specIgnoringRef
);
}
} else if (type == "category" && gInterestingCategories.has(argv[0])) {
gReferencesFromCode.set(argv[2], null);
} else if (type == "category") {
if (gInterestingCategories.has(argv[0])) {
gReferencesFromCode.set(argv[2], null);
} else if (argv[1].startsWith("resource://")) {
// Assume that any resource paths immediately after the category name
// are for use with BrowserUtils.callModulesFromCategory (rather than
// having to hardcode a list of categories in this test).
gReferencesFromCode.set(argv[1], null);
}
} else if (type == "resource") {
trackResourcePrefix(argv[0]);
} else if (type == "component") {

View file

@ -22,10 +22,11 @@ prefs = [
["browser_device_controls_menus.js"]
skip-if = [
"debug", # bug 1369731
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && opt", # Bug 1775940
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # bug 1707735
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # platform migration
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1869787
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && opt", # Bug 1775940
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # bug 1707735
]
["browser_devices_get_user_media.js"]
@ -56,6 +57,7 @@ skip-if = [
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # bug 1707735
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # platform migration
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1869787
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # bug 1707735
]
["browser_devices_get_user_media_in_xorigin_frame_chain.js"]
@ -68,6 +70,7 @@ skip-if = [
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # bug 1707735
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # platform migration
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1869787
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # bug 1707735
]
["browser_devices_get_user_media_paused.js"]
@ -78,6 +81,7 @@ skip-if = [
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # bug 1707735
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # platform migration
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1869787
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # bug 1707735
]
["browser_devices_get_user_media_queue_request.js"]
@ -95,6 +99,7 @@ skip-if = [
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # platform migration
"os == 'win'", # high frequency intermittent, bug 1739107
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1869787
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # bug 1707735
]
["browser_devices_get_user_media_screen_tab_close.js"]
@ -102,6 +107,7 @@ skip-if = [
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # platform migration
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # bug 1707735
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1869787
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # bug 1707735
]
["browser_devices_get_user_media_tear_off_tab.js"]
@ -136,12 +142,14 @@ skip-if = [
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # bug 1707735
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # platform migration
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1869787
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # bug 1707735
]
["browser_macos_indicator_hiding.js"]
run-if = ["os == 'mac' && os_version >= '14.0'"]
skip-if = [
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'",
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'",
]
["browser_notification_silencing.js"]
@ -149,6 +157,7 @@ skip-if = [
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # bug 1707735
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # platform migration
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1869787
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # bug 1707735
]
["browser_stop_sharing_button.js"]
@ -156,6 +165,7 @@ skip-if = [
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # bug 1707735
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # platform migration
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1869787
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # bug 1707735
]
["browser_stop_streams_on_indicator_close.js"]
@ -163,6 +173,7 @@ skip-if = [
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # bug 1707735
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # platform migration
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1869787
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # bug 1707735
"os == 'win' && os_version == '11.26100' && ccov", # Bug 1775943
]

View file

@ -9,10 +9,44 @@
category app-startup nsBrowserGlue @mozilla.org/browser/browserglue;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110}
# Browser window lifecycle callers.
# Browser window lifecycle consumers
category browser-window-delayed-startup resource:///modules/ContentAnalysis.sys.mjs ContentAnalysis.initialize
category browser-window-delayed-startup resource:///modules/HomePage.sys.mjs HomePage.delayedStartup
category browser-window-delayed-startup resource:///modules/ReportBrokenSite.sys.mjs ReportBrokenSite.init
category browser-window-delayed-startup resource:///modules/SearchUIUtils.sys.mjs SearchUIUtils.init
# App startup consumers
category browser-idle-startup resource:///modules/PlacesUIUtils.sys.mjs PlacesUIUtils.unblockToolbars
category browser-idle-startup resource:///modules/BuiltInThemes.sys.mjs BuiltInThemes.ensureBuiltInThemes
category browser-idle-startup resource://gre/modules/RFPHelper.sys.mjs RFPHelper.init
category browser-idle-startup resource://gre/modules/Blocklist.sys.mjs Blocklist.loadBlocklistAsync
category browser-idle-startup resource:///modules/TabUnloader.sys.mjs TabUnloader.init
category browser-idle-startup resource:///modules/GenAI.sys.mjs GenAI.init
category browser-idle-startup resource:///modules/QuickSuggest.sys.mjs QuickSuggest.init
category browser-idle-startup resource:///modules/UrlbarSearchTermsPersistence.sys.mjs UrlbarSearchTermsPersistence.init
category browser-idle-startup resource:///modules/ShoppingUtils.sys.mjs ShoppingUtils.init
category browser-idle-startup resource:///modules/SearchSERPTelemetry.sys.mjs SearchSERPCategorization.init
category browser-idle-startup resource://gre/modules/ContentRelevancyManager.sys.mjs ContentRelevancyManager.init
#ifdef MOZ_UPDATER
category browser-idle-startup resource://gre/modules/UpdateListener.sys.mjs UpdateListener.maybeShowUnsupportedNotification
#endif
#ifdef XP_WIN
category browser-idle-startup resource:///modules/WindowsJumpLists.sys.mjs WinTaskbarJumpList.startup
#endif
# App shutdown consumers
category browser-quit-application-granted resource:///modules/BrowserUsageTelemetry.sys.mjs BrowserUsageTelemetry.uninit
category browser-quit-application-granted resource:///modules/Interactions.sys.mjs Interactions.uninit
category browser-quit-application-granted resource:///modules/pagedata/PageDataService.sys.mjs PageDataService.uninit
category browser-quit-application-granted resource://gre/modules/PageThumbs.sys.mjs PageThumbs.uninit
category browser-quit-application-granted resource://gre/modules/NewTabUtils.sys.mjs NewTabUtils.uninit
category browser-quit-application-granted resource://normandy/Normandy.sys.mjs Normandy.uninit
category browser-quit-application-granted resource://gre/modules/RFPHelper.sys.mjs RFPHelper.uninit
category browser-quit-application-granted resource:///modules/ShoppingUtils.sys.mjs ShoppingUtils.uninit
category browser-quit-application-granted resource:///modules/asrouter/ASRouterNewTabHook.sys.mjs ASRouterNewTabHook.destroy
#ifdef MOZ_UPDATER
category browser-quit-application-granted resource://gre/modules/UpdateListener.sys.mjs UpdateListener.reset
#endif
category browser-quit-application-granted resource:///modules/UrlbarSearchTermsPersistence.sys.mjs UrlbarSearchTermsPersistence.uninit
category search-service-notification resource:///modules/SearchUIUtils.sys.mjs SearchUIUtils.showSearchServiceNotification

View file

@ -19,7 +19,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs",
BackupService: "resource:///modules/backup/BackupService.sys.mjs",
Blocklist: "resource://gre/modules/Blocklist.sys.mjs",
BookmarkHTMLUtils: "resource://gre/modules/BookmarkHTMLUtils.sys.mjs",
BookmarkJSONUtils: "resource://gre/modules/BookmarkJSONUtils.sys.mjs",
BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.sys.mjs",
@ -30,8 +29,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
CaptchaDetectionPingUtils:
"resource://gre/modules/CaptchaDetectionPingUtils.sys.mjs",
CommonDialog: "resource://gre/modules/CommonDialog.sys.mjs",
ContentRelevancyManager:
"resource://gre/modules/ContentRelevancyManager.sys.mjs",
ContextualIdentityService:
"resource://gre/modules/ContextualIdentityService.sys.mjs",
DAPTelemetrySender: "resource://gre/modules/DAPTelemetrySender.sys.mjs",
@ -49,7 +46,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
// eslint-disable-next-line mozilla/valid-lazy
FilePickerCrashed: "resource:///modules/FilePickerCrashed.sys.mjs",
FormAutofillUtils: "resource://gre/modules/shared/FormAutofillUtils.sys.mjs",
GenAI: "resource:///modules/GenAI.sys.mjs",
HomePage: "resource:///modules/HomePage.sys.mjs",
Integration: "resource://gre/modules/Integration.sys.mjs",
Interactions: "resource:///modules/Interactions.sys.mjs",
@ -77,8 +73,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
PluginManager: "resource:///actors/PluginParent.sys.mjs",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
ProcessHangMonitor: "resource:///modules/ProcessHangMonitor.sys.mjs",
QuickSuggest: "resource:///modules/QuickSuggest.sys.mjs",
RFPHelper: "resource://gre/modules/RFPHelper.sys.mjs",
RemoteSecuritySettings:
"resource://gre/modules/psm/RemoteSecuritySettings.sys.mjs",
RemoteSettings: "resource://services-settings/remote-settings.sys.mjs",
@ -96,17 +90,13 @@ ChromeUtils.defineESModuleGetters(lazy, {
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
ShellService: "resource:///modules/ShellService.sys.mjs",
ShortcutUtils: "resource://gre/modules/ShortcutUtils.sys.mjs",
ShoppingUtils: "resource:///modules/ShoppingUtils.sys.mjs",
SpecialMessageActions:
"resource://messaging-system/lib/SpecialMessageActions.sys.mjs",
TelemetryReportingPolicy:
"resource://gre/modules/TelemetryReportingPolicy.sys.mjs",
TRRRacer: "resource:///modules/TRRPerformance.sys.mjs",
TabCrashHandler: "resource:///modules/ContentCrashHandlers.sys.mjs",
TabUnloader: "resource:///modules/TabUnloader.sys.mjs",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarSearchTermsPersistence:
"resource:///modules/UrlbarSearchTermsPersistence.sys.mjs",
UsageReporting: "resource://gre/modules/UsageReporting.sys.mjs",
WebChannel: "resource://gre/modules/WebChannel.sys.mjs",
WebProtocolHandlerRegistrar:
@ -118,24 +108,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
setTimeout: "resource://gre/modules/Timer.sys.mjs",
});
if (AppConstants.MOZ_UPDATER) {
ChromeUtils.defineESModuleGetters(lazy, {
UpdateListener: "resource://gre/modules/UpdateListener.sys.mjs",
});
XPCOMUtils.defineLazyServiceGetters(lazy, {
UpdateServiceStub: [
"@mozilla.org/updates/update-service-stub;1",
"nsIApplicationUpdateServiceStub",
],
});
}
if (AppConstants.MOZ_UPDATE_AGENT) {
ChromeUtils.defineESModuleGetters(lazy, {
BackgroundUpdate: "resource://gre/modules/BackgroundUpdate.sys.mjs",
});
}
// PluginManager is used in the listeners object below.
XPCOMUtils.defineLazyServiceGetters(lazy, {
BrowserHandler: ["@mozilla.org/browser/clh;1", "nsIBrowserHandler"],
PushService: ["@mozilla.org/push/Service;1", "nsIPushService"],
@ -1037,6 +1009,12 @@ const listeners = {
},
};
if (AppConstants.MOZ_UPDATER) {
ChromeUtils.defineESModuleGetters(lazy, {
// This listeners/observers/lazy indirection is too much for eslint:
// eslint-disable-next-line mozilla/valid-lazy
UpdateListener: "resource://gre/modules/UpdateListener.sys.mjs",
});
listeners.observers["update-downloading"] = ["UpdateListener"];
listeners.observers["update-staged"] = ["UpdateListener"];
listeners.observers["update-downloaded"] = ["UpdateListener"];
@ -2197,8 +2175,28 @@ BrowserGlue.prototype = {
/**
* Application shutdown handler.
*
* If you need new code to be called on shutdown, please use
* the category manager browser-quit-application-granted category
* instead of adding new manual code to this function.
*/
_onQuitApplicationGranted() {
function failureHandler(ex) {
if (Cu.isInAutomation) {
// This usually happens after the test harness is done collecting
// test errors, thus we can't easily add a failure to it. The only
// noticeable solution we have is crashing.
Cc["@mozilla.org/xpcom/debug;1"]
.getService(Ci.nsIDebug2)
.abort(ex.filename, ex.lineNumber);
}
}
lazy.BrowserUtils.callModulesFromCategory({
categoryName: "browser-quit-application-granted",
failureHandler,
});
let tasks = [
// This pref must be set here because SessionStore will use its value
// on quit-application.
@ -2218,28 +2216,16 @@ BrowserGlue.prototype = {
}
},
() => lazy.BrowserUsageTelemetry.uninit(),
// These should also be moved to use the category manager, but ran into
// leaking issues. Bug 1949294 tracks.
() => lazy.SearchSERPTelemetry.uninit(),
() => lazy.SearchSERPCategorization.uninit(),
() => lazy.Interactions.uninit(),
() => lazy.PageDataService.uninit(),
() => lazy.PageThumbs.uninit(),
() => lazy.NewTabUtils.uninit(),
() => lazy.Normandy.uninit(),
() => lazy.RFPHelper.uninit(),
() => lazy.ShoppingUtils.uninit(),
() => lazy.ASRouterNewTabHook.destroy(),
() => {
if (AppConstants.MOZ_UPDATER) {
lazy.UpdateListener.reset();
}
},
() => {
// bug 1839426 - The FOG service needs to be instantiated reliably so it
// can perform at-shutdown tasks later in shutdown.
Services.fog;
},
() => lazy.UrlbarSearchTermsPersistence.uninit(),
];
for (let task of tasks) {
@ -2247,14 +2233,7 @@ BrowserGlue.prototype = {
task();
} catch (ex) {
console.error(`Error during quit-application-granted: ${ex}`);
if (Cu.isInAutomation) {
// This usually happens after the test harness is done collecting
// test errors, thus we can't easily add a failure to it. The only
// noticeable solution we have is crashing.
Cc["@mozilla.org/xpcom/debug;1"]
.getService(Ci.nsIDebug2)
.abort(ex.filename, ex.lineNumber);
}
failureHandler(ex);
}
}
},
@ -2512,7 +2491,39 @@ BrowserGlue.prototype = {
* to the other ones scheduled together.
*/
_scheduleStartupIdleTasks() {
const idleTasks = [
function runIdleTasks(idleTasks) {
for (let task of idleTasks) {
if ("condition" in task && !task.condition) {
continue;
}
ChromeUtils.idleDispatch(
async () => {
if (!Services.startup.shuttingDown) {
let startTime = Cu.now();
try {
await task.task();
} catch (ex) {
console.error(ex);
} finally {
ChromeUtils.addProfilerMarker(
"startupIdleTask",
startTime,
task.name
);
}
}
},
task.timeout ? { timeout: task.timeout } : undefined
);
}
}
// Note: unless you need a timeout, please do not add new tasks here, and
// instead use the category manager. You can do this in a manifest file in
// the component that needs to run code, or in BrowserComponents.manifest
// in this folder. The callModulesFromCategory call below will call them.
const earlyTasks = [
// It's important that SafeBrowsing is initialized reasonably
// early, so we use a maximum timeout for it.
{
@ -2530,16 +2541,17 @@ BrowserGlue.prototype = {
lazy.Discovery.update();
},
},
];
{
name: "PlacesUIUtils.unblockToolbars",
task: () => {
// We postponed loading bookmarks toolbar content until startup
// has finished, so we can start loading it now:
lazy.PlacesUIUtils.unblockToolbars();
},
},
runIdleTasks(earlyTasks);
lazy.BrowserUtils.callModulesFromCategory({
categoryName: "browser-idle-startup",
profilerMarker: "startupIdleTask",
idleDispatch: true,
});
const lateTasks = [
{
name: "PlacesDBUtils.telemetry",
condition:
@ -2807,33 +2819,6 @@ BrowserGlue.prototype = {
},
},
// Install built-in themes. We already installed the active built-in
// theme, if any, before UI startup.
{
name: "BuiltInThemes.ensureBuiltInThemes",
task: async () => {
await lazy.BuiltInThemes.ensureBuiltInThemes();
},
},
{
name: "WinTaskbarJumpList.startup",
condition: AppConstants.platform == "win",
task: () => {
// For Windows 7, initialize the jump list module.
const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
if (
WINTASKBAR_CONTRACTID in Cc &&
Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available
) {
const { WinTaskbarJumpList } = ChromeUtils.importESModule(
"resource:///modules/WindowsJumpLists.sys.mjs"
);
WinTaskbarJumpList.startup();
}
},
},
// Report macOS Dock status
{
name: "MacDockSupport.isAppInDock",
@ -2893,27 +2878,6 @@ BrowserGlue.prototype = {
},
},
{
name: "RFPHelper.init",
task: () => {
lazy.RFPHelper.init();
},
},
{
name: "Blocklist.loadBlocklistAsync",
task: () => {
lazy.Blocklist.loadBlocklistAsync();
},
},
{
name: "TabUnloader.init",
task: () => {
lazy.TabUnloader.init();
},
},
// Run TRR performance measurements for DoH.
{
name: "doh-rollout.trrRacer.run",
@ -3039,22 +3003,25 @@ BrowserGlue.prototype = {
{
name: "BackgroundUpdate",
condition: AppConstants.MOZ_UPDATE_AGENT,
condition: AppConstants.MOZ_UPDATE_AGENT && AppConstants.MOZ_UPDATER,
task: async () => {
let updateServiceStub = Cc[
"@mozilla.org/updates/update-service-stub;1"
].getService(Ci.nsIApplicationUpdateServiceStub);
// Never in automation!
if (
AppConstants.MOZ_UPDATER &&
!lazy.UpdateServiceStub.updateDisabledForTesting
) {
if (!updateServiceStub.updateDisabledForTesting) {
let { BackgroundUpdate } = ChromeUtils.importESModule(
"resource://gre/modules/BackgroundUpdate.sys.mjs"
);
try {
await lazy.BackgroundUpdate.scheduleFirefoxMessagingSystemTargetingSnapshotting();
await BackgroundUpdate.scheduleFirefoxMessagingSystemTargetingSnapshotting();
} catch (e) {
console.error(
"There was an error scheduling Firefox Messaging System targeting snapshotting: ",
e
);
}
await lazy.BackgroundUpdate.maybeScheduleBackgroundUpdateTask();
await BackgroundUpdate.maybeScheduleBackgroundUpdateTask();
}
},
},
@ -3098,35 +3065,6 @@ BrowserGlue.prototype = {
},
},
{
name: "UpdateListener.maybeShowUnsupportedNotification",
condition: AppConstants.MOZ_UPDATER,
task: () => {
lazy.UpdateListener.maybeShowUnsupportedNotification();
},
},
{
name: "GenAI.init",
task() {
lazy.GenAI.init();
},
},
{
name: "QuickSuggest.init",
task: () => {
lazy.QuickSuggest.init();
},
},
{
name: "UrlbarSearchTermsPersistence initialization",
task: () => {
lazy.UrlbarSearchTermsPersistence.init();
},
},
{
name: "DAPTelemetrySender.startup",
condition:
@ -3140,13 +3078,6 @@ BrowserGlue.prototype = {
},
},
{
name: "ShoppingUtils.init",
task: () => {
lazy.ShoppingUtils.init();
},
},
{
// Starts the JSOracle process for ORB JavaScript validation, if it hasn't started already.
name: "start-orb-javascript-oracle",
@ -3155,20 +3086,6 @@ BrowserGlue.prototype = {
},
},
{
name: "SearchSERPCategorization.init",
task: () => {
lazy.SearchSERPCategorization.init();
},
},
{
name: "ContentRelevancyManager.init",
task: () => {
lazy.ContentRelevancyManager.init();
},
},
{
name: "BackupService initialization",
condition: Services.prefs.getBoolPref("browser.backup.enabled", false),
@ -3216,31 +3133,7 @@ BrowserGlue.prototype = {
// Do NOT add anything after idle tasks finished.
];
for (let task of idleTasks) {
if ("condition" in task && !task.condition) {
continue;
}
ChromeUtils.idleDispatch(
async () => {
if (!Services.startup.shuttingDown) {
let startTime = Cu.now();
try {
await task.task();
} catch (ex) {
console.error(ex);
} finally {
ChromeUtils.addProfilerMarker(
"startupIdleTask",
startTime,
task.name
);
}
}
},
task.timeout ? { timeout: task.timeout } : undefined
);
}
runIdleTasks(lateTasks);
},
/**
@ -4795,8 +4688,6 @@ BrowserGlue.prototype = {
return;
}
DefaultBrowserCheck.prompt(win);
} else if (await lazy.QuickSuggest.maybeShowOnboardingDialog()) {
return;
}
await lazy.ASRouter.waitForInitialized;
@ -5530,9 +5421,7 @@ export var DefaultBrowserCheck = {
try {
let resultEnum = buttonNumClicked * 2 + !checkboxState;
Services.telemetry
.getHistogramById("BROWSER_SET_DEFAULT_RESULT")
.add(resultEnum);
Glean.browser.setDefaultResult.accumulateSingleSample(resultEnum);
} catch (ex) {
/* Don't break if Telemetry is acting up. */
}
@ -5629,18 +5518,16 @@ export var DefaultBrowserCheck = {
try {
// Report default browser status on startup to telemetry
// so we can track whether we are the default.
Services.telemetry
.getHistogramById("BROWSER_IS_USER_DEFAULT")
.add(isDefault);
Services.telemetry
.getHistogramById("BROWSER_IS_USER_DEFAULT_ERROR")
.add(isDefaultError);
Services.telemetry
.getHistogramById("BROWSER_SET_DEFAULT_ALWAYS_CHECK")
.add(shouldCheck);
Services.telemetry
.getHistogramById("BROWSER_SET_DEFAULT_DIALOG_PROMPT_RAWCOUNT")
.add(promptCount);
Glean.browser.isUserDefault[isDefault ? "true" : "false"].add();
Glean.browser.isUserDefaultError[
isDefaultError ? "true" : "false"
].add();
Glean.browser.setDefaultAlwaysCheck[
shouldCheck ? "true" : "false"
].add();
Glean.browser.setDefaultDialogPromptRawcount.accumulateSingleSample(
promptCount
);
} catch (ex) {
/* Don't break the default prompt if telemetry is broken. */
}

View file

@ -156,9 +156,7 @@ export var AttributionCode = {
return parsed;
}
Services.telemetry
.getHistogramById("BROWSER_ATTRIBUTION_ERRORS")
.add("decode_error");
Glean.browser.attributionErrors.decode_error.add(1);
return {};
},
@ -196,16 +194,12 @@ export var AttributionCode = {
gCachedAttrData = {};
lazy.log.debug(`_getMacAttrDataAsync: null attribution string`);
Services.telemetry
.getHistogramById("BROWSER_ATTRIBUTION_ERRORS")
.add("null_error");
Glean.browser.attributionErrors.null_error.add(1);
} else if (attrStr == "") {
gCachedAttrData = {};
lazy.log.debug(`_getMacAttrDataAsync: empty attribution string`);
Services.telemetry
.getHistogramById("BROWSER_ATTRIBUTION_ERRORS")
.add("empty_error");
Glean.browser.attributionErrors.empty_error.add(1);
} else {
gCachedAttrData = this.parseAttributionCode(attrStr);
}
@ -221,9 +215,7 @@ export var AttributionCode = {
ex.result == Cr.NS_ERROR_UNEXPECTED
) {
// Bad quarantine data.
Services.telemetry
.getHistogramById("BROWSER_ATTRIBUTION_ERRORS")
.add("quarantine_error");
Glean.browser.attributionErrors.quarantine_error.add(1);
}
}
@ -313,9 +305,7 @@ export var AttributionCode = {
lazy.log.debug("Full exception is:");
lazy.log.debug(ex);
Services.telemetry
.getHistogramById("BROWSER_ATTRIBUTION_ERRORS")
.add("read_error");
Glean.browser.attributionErrors.read_error.add(1);
}
if (bytes) {
try {
@ -339,9 +329,7 @@ export var AttributionCode = {
);
} catch (ex) {
// TextDecoder can throw an error
Services.telemetry
.getHistogramById("BROWSER_ATTRIBUTION_ERRORS")
.add("decode_error");
Glean.browser.attributionErrors.decode_error.add(1);
}
}

View file

@ -59,6 +59,7 @@ https_first_disabled = true
https_first_disabled = true
skip-if = [
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # Bug 1783491
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Bug 1783491
]
["browser_restore_getCookiesWithOriginAttributes.js"]

View file

@ -559,23 +559,30 @@ export var Policies = {
"ClientSignature",
"browser.contentanalysis.client_signature"
);
if ("DefaultResult" in param) {
if (
!Number.isInteger(param.DefaultResult) ||
param.DefaultResult < 0 ||
param.DefaultResult > 2
) {
lazy.log.error(
`Non-integer or out of range value for DefaultResult: ${param.DefaultResult}`
);
let resultPrefs = [
["DefaultResult", "default_result"],
["TimeoutResult", "timeout_result"],
];
for (let pref of resultPrefs) {
if (pref[0] in param) {
if (
!Number.isInteger(param[pref[0]]) ||
param[pref[0]] < 0 ||
param[pref[0]] > 2
) {
lazy.log.error(
`Non-integer or out of range value for ${pref[0]}: ${param[pref[0]]}`
);
Services.prefs.lockPref(`browser.contentanalysis.${pref[1]}`);
} else {
setAndLockPref(
`browser.contentanalysis.${pref[1]}`,
param[pref[0]]
);
}
} else {
setAndLockPref(
"browser.contentanalysis.default_result",
param.DefaultResult
);
Services.prefs.lockPref(`browser.contentanalysis.${pref[1]}`);
}
} else {
Services.prefs.lockPref("browser.contentanalysis.default_result");
}
let boolPrefs = [
["IsPerUser", "is_per_user"],

View file

@ -268,6 +268,9 @@
"DefaultResult": {
"type": "number"
},
"TimeoutResult": {
"type": "number"
},
"BypassForSameTabOperations": {
"type": "boolean"
},

View file

@ -113,6 +113,8 @@ https_first_disabled = true
["browser_ext_browsingData_history.js"]
["browser_ext_canOpenModalPicker.js"]
["browser_ext_chrome_settings_overrides_home.js"]
["browser_ext_commands_execute_browser_action.js"]
@ -184,7 +186,10 @@ https_first_disabled = true
["browser_ext_contextMenus_srcUrl_redirect.js"]
["browser_ext_contextMenus_targetUrlPatterns.js"]
skip-if = ["os == 'mac' && os_version == '11.20' && arch == 'aarch64'"] # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
skip-if = [
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
]
tags = "bleedover"
["browser_ext_contextMenus_uninstall.js"]
@ -285,13 +290,19 @@ https_first_disabled = true
["browser_ext_menus_targetElement.js"]
["browser_ext_menus_targetElement_extension.js"]
skip-if = ["os == 'mac' && os_version == '11.20' && arch == 'aarch64'"] # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
skip-if = [
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
]
tags = "bleedover"
["browser_ext_menus_targetElement_shadow.js"]
["browser_ext_menus_viewType.js"]
skip-if = ["os == 'mac' && os_version == '11.20' && arch == 'aarch64'"] # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
skip-if = [
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
]
tags = "bleedover"
["browser_ext_menus_visible.js"]
@ -658,6 +669,7 @@ skip-if = [
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # Bug 1565738
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # Bug 1565738
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1565738
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Bug 1565738
]
["browser_ext_windows.js"]
@ -693,6 +705,7 @@ skip-if = [
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'",
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'",
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1869793
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'",
]
["browser_ext_windows_update.js"]

View file

@ -0,0 +1,200 @@
"use strict";
// This file tests the state of the browsingContext.canOpenModalPicker flag,
// which reflects whether the document within is allowed to open a file picker.
add_task(async function test_canOpenModalPicker_in_tab() {
let extension = ExtensionTestUtils.loadExtension({
files: {
"tab.html": "Nothing special here",
},
});
await extension.startup();
const extensionTabUrl = `moz-extension://${extension.uuid}/tab.html`;
let firstTab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
extensionTabUrl
);
is(
firstTab.linkedBrowser.browsingContext.canOpenModalPicker,
true,
"Focused extension tab can open modal picker"
);
await BrowserTestUtils.withNewTab(extensionTabUrl, browser => {
is(
browser.browsingContext.canOpenModalPicker,
true,
"Newly focused extension tab can open modal picker"
);
is(
firstTab.linkedBrowser.browsingContext.canOpenModalPicker,
false,
"Background tab cannot open modal picker"
);
});
is(
firstTab.linkedBrowser.browsingContext.canOpenModalPicker,
true,
"Re-focused extension tab can open modal picker"
);
BrowserTestUtils.removeTab(firstTab);
await extension.unload();
});
// This test verifies that canOpenModalPicker is set for extension sidebar
// documents iff the document is focused (regression test for bug 1949092).
// It also verifies that canOpenModalPicker of regular tab browsers are focused
// iff the tab browser is focused (unit test for bug 1837963).
add_task(async function test_canOpenModalPicker_in_sidebar() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
sidebar_action: {
default_panel: "sidebar.html",
},
},
useAddonManager: "temporary",
files: {
"sidebar.html": `
<!DOCTYPE html>
<meta charset="utf-8">
<body>
Click in this extension document to focus it and start the test.
<script src="sidebar.js"></script>
`,
"sidebar.js": () => {
document.body.onclick = () => {
browser.test.sendMessage("clicked_sidebar_ext_doc");
};
window.onload = () => {
browser.test.sendMessage("sidebar_ready");
};
},
},
});
await extension.startup();
await extension.awaitMessage("sidebar_ready");
// <browser> with webext-panels.xhtml contains <browser> with moz-extension:.
let sidebarBrowser = SidebarController.browser;
is(
sidebarBrowser.currentURI.spec,
"chrome://browser/content/webext-panels.xhtml",
"Sidebar wrapper loaded in sidebar browser"
);
let extSidebarBrowser = sidebarBrowser.contentDocument.getElementById(
"webext-panels-browser"
);
is(
extSidebarBrowser.currentURI.spec,
`moz-extension://${extension.uuid}/sidebar.html`,
"Sidebar document from extension is loaded in sidebar wrapper"
);
// Wait for layout to be stable before triggering click.
await sidebarBrowser.contentWindow.promiseDocumentFlushed(() => {});
info("Moving focus to sidebar content");
await SimpleTest.promiseFocus(extSidebarBrowser);
await BrowserTestUtils.synthesizeMouseAtCenter("body", {}, extSidebarBrowser);
await extension.awaitMessage("clicked_sidebar_ext_doc");
is(
extSidebarBrowser.browsingContext.canOpenModalPicker,
true,
"Focused sidebar can open modal picker"
);
info("Moving focus off sidebar, by opening and focusing a new tab");
await BrowserTestUtils.withNewTab("about:blank", async browser => {
is(
browser.browsingContext.canOpenModalPicker,
true,
"Focused tab can open modal picker"
);
is(
extSidebarBrowser.browsingContext.canOpenModalPicker,
false,
"Sidebar is no longer focused and cannot open modal picker"
);
});
await extension.unload();
});
// This test verifies that canOpenModalPicker is set for options_ui pages in
// about:addons iff the document is focused (regression test for bug 1949092).
add_task(async function test_canOpenModalPicker_in_options_ui() {
// Open new window for about:addons to be loaded in.
let browserWindow = await BrowserTestUtils.openNewBrowserWindow();
let extension = ExtensionTestUtils.loadExtension({
manifest: {
options_ui: {
page: "options.html",
},
},
useAddonManager: "temporary",
background() {
browser.test.log("Opening about:addons");
browser.runtime.openOptionsPage();
},
files: {
"options.html": `
<!DOCTYPE html>
<meta charset="utf-8">
<body>
Click in this extension document to focus it and start the test.
<script src="options.js"></script>
`,
"options.js": () => {
document.body.onclick = () => {
browser.test.sendMessage("clicked_options_ui_doc");
};
window.onload = () => {
browser.test.sendMessage("options_ready");
};
},
},
});
await extension.startup();
await extension.awaitMessage("options_ready");
let aboutaddonsBrowser = browserWindow.gBrowser.selectedBrowser;
is(
aboutaddonsBrowser.currentURI.spec,
"about:addons",
"openOptionsPage() opened about:addons tab"
);
let optionsBrowser = aboutaddonsBrowser.contentDocument.getElementById(
"addon-inline-options"
);
is(
optionsBrowser.currentURI.spec,
`moz-extension://${extension.uuid}/options.html`,
"options_ui document from extension is loaded in about:addons"
);
is(
optionsBrowser.browsingContext.canOpenModalPicker,
false,
"Unfocused options_ui page cannot open modal picker"
);
await SimpleTest.promiseFocus(optionsBrowser);
await BrowserTestUtils.synthesizeMouseAtCenter("body", {}, optionsBrowser);
await extension.awaitMessage("clicked_options_ui_doc");
is(
optionsBrowser.browsingContext.canOpenModalPicker,
true,
"Focused options_ui page can open modal picker"
);
await BrowserTestUtils.closeWindow(browserWindow);
await extension.unload();
});

View file

@ -755,3 +755,233 @@ primary.password:
- mtigley@mozilla.com
expires: never
telemetry_mirror: PRIMARY_PASSWORD_ENABLED
browser:
is_user_default:
type: labeled_counter
description: >
Whether Firefox is the system default browser on startup. A true value is
also recorded here, and a false value is recorded to
set_default_error, if a user clicked 'Use Firefox as my default
browser' on an in-product prompt. (Note that on Windows 8+ the latter
action opens the right settings dialog but does not actually change the
default browser without further user action.) On Windows, 'system default
browser' is operationalized as whether Firefox is the default HTTP
protocol handler.
This metric was generated to correspond to the Legacy Telemetry boolean
histogram BROWSER_IS_USER_DEFAULT.
labels:
- "false"
- "true"
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=855928
- https://bugzilla.mozilla.org/show_bug.cgi?id=1641713
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=855928
- https://bugzilla.mozilla.org/show_bug.cgi?id=1641713
notification_emails:
- application-update-telemetry-alerts@mozilla.com
expires: never
telemetry_mirror: h#BROWSER_IS_USER_DEFAULT
is_user_default_error:
type: labeled_counter
description: >
True if the browser was unable to determine if the browser was set as
default.
This metric was generated to correspond to the Legacy Telemetry boolean
histogram BROWSER_IS_USER_DEFAULT_ERROR.
labels:
- "false"
- "true"
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
notification_emails:
- application-update-telemetry-alerts@mozilla.com
expires: never
telemetry_mirror: h#BROWSER_IS_USER_DEFAULT_ERROR
set_default_dialog_prompt_rawcount:
type: custom_distribution
description: >
The number of times that a profile has seen the 'Set Default Browser'
dialog.
This metric was generated to correspond to the Legacy Telemetry
exponential histogram BROWSER_SET_DEFAULT_DIALOG_PROMPT_RAWCOUNT.
range_min: 1
range_max: 250
bucket_count: 15
histogram_type: exponential
unit: prompts
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
notification_emails:
- application-update-telemetry-alerts@mozilla.com
expires: never
telemetry_mirror: BROWSER_SET_DEFAULT_DIALOG_PROMPT_RAWCOUNT
set_default_always_check:
type: labeled_counter
description: >
True if the profile has `browser.shell.checkDefaultBrowser` set to true.
This metric was generated to correspond to the Legacy Telemetry boolean
histogram BROWSER_SET_DEFAULT_ALWAYS_CHECK.
labels:
- "false"
- "true"
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
notification_emails:
- application-update-telemetry-alerts@mozilla.com
expires: never
telemetry_mirror: h#BROWSER_SET_DEFAULT_ALWAYS_CHECK
set_default_result:
type: custom_distribution
description: >
Result of the Set Default Browser dialog. After Firefox 89 the these
values are: (0=Use Firefox + 'Don't ask again' checked, 1=Use Firefox +
'Don't ask again' unchecked, 2=Not Now + 'Don't ask again' checked, 3=Not
Now + 'Don't ask again' unchecked). Before Firefox 89 these values were:
(0=Use Firefox + 'Always perform check' unchecked, 1=Use Firefox + 'Always
perform check' checked, 2=Not Now + 'Always perform check' unchecked,
3=Not Now + 'Always perform check' checked).
This metric was generated to correspond to the Legacy Telemetry enumerated
histogram BROWSER_SET_DEFAULT_RESULT.
range_min: 0
range_max: 4
bucket_count: 5
histogram_type: linear
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
notification_emails:
- application-update-telemetry-alerts@mozilla.com
expires: never
telemetry_mirror: BROWSER_SET_DEFAULT_RESULT
set_default_error:
type: labeled_counter
description: >
True if the browser was unable to set Firefox as the default browser
This metric was generated to correspond to the Legacy Telemetry boolean
histogram BROWSER_SET_DEFAULT_ERROR.
labels:
- "false"
- "true"
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
notification_emails:
- application-update-telemetry-alerts@mozilla.com
expires: never
telemetry_mirror: h#BROWSER_SET_DEFAULT_ERROR
set_default_pdf_handler_user_choice_result:
type: labeled_counter
description: >
Result of each attempt to set the default browser with
SetDefaultExtensionHandlersUserChoice() for pdf extension
This metric was generated to correspond to the Legacy Telemetry
categorical histogram BROWSER_SET_DEFAULT_PDF_HANDLER_USER_CHOICE_RESULT.
labels:
- Success
- ErrProgID
- ErrHash
- ErrLaunchExe
- ErrExeTimeout
- ErrExeProgID
- ErrExeHash
- ErrExeRejected
- ErrExeOther
- ErrOther
- ErrBuild
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1805509
- https://bugzilla.mozilla.org/show_bug.cgi?id=1883466
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1805509
- https://bugzilla.mozilla.org/show_bug.cgi?id=1883466
notification_emails:
- application-update-telemetry-alerts@mozilla.com
expires: never
telemetry_mirror: h#BROWSER_SET_DEFAULT_PDF_HANDLER_USER_CHOICE_RESULT
set_default_user_choice_result:
type: labeled_counter
description: >
Result of each attempt to set the default browser with
SetDefaultBrowserUserChoice()
This metric was generated to correspond to the Legacy Telemetry
categorical histogram BROWSER_SET_DEFAULT_USER_CHOICE_RESULT.
labels:
- Success
- ErrProgID
- ErrHash
- ErrLaunchExe
- ErrExeTimeout
- ErrExeProgID
- ErrExeHash
- ErrExeRejected
- ErrExeOther
- ErrOther
- ErrBuild
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1703578
- https://bugzilla.mozilla.org/show_bug.cgi?id=1736631
- https://bugzilla.mozilla.org/show_bug.cgi?id=1791928
- https://bugzilla.mozilla.org/show_bug.cgi?id=1881397
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1703578
- https://bugzilla.mozilla.org/show_bug.cgi?id=1736631
- https://bugzilla.mozilla.org/show_bug.cgi?id=1791928
- https://bugzilla.mozilla.org/show_bug.cgi?id=1881397
notification_emails:
- application-update-telemetry-alerts@mozilla.com
expires: never
telemetry_mirror: h#BROWSER_SET_DEFAULT_USER_CHOICE_RESULT
attribution_errors:
type: labeled_counter
description: >
Count for the number of errors encountered trying to determine attribution
data: on Windows, from the installers (stub and full); on macOS, from an
extended attributed on the .app bundle.
This metric was generated to correspond to the Legacy Telemetry
categorical histogram BROWSER_ATTRIBUTION_ERRORS.
labels:
- read_error
- decode_error
- write_error
- quarantine_error
- empty_error
- null_error
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1621402
- https://bugzilla.mozilla.org/show_bug.cgi?id=1525076
- https://bugzilla.mozilla.org/show_bug.cgi?id=1874944
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1621402
- https://bugzilla.mozilla.org/show_bug.cgi?id=1525076
- https://bugzilla.mozilla.org/show_bug.cgi?id=1874944
notification_emails:
- aoprea@mozilla.com
expires: never
telemetry_mirror: h#BROWSER_ATTRIBUTION_ERRORS

View file

@ -92,7 +92,7 @@ XPCOM_MANIFESTS += [
"components.conf",
]
EXTRA_COMPONENTS += [
EXTRA_PP_COMPONENTS += [
"BrowserComponents.manifest",
]

View file

@ -82,9 +82,9 @@ function searchBookmarks(event) {
}
function updateTelemetry(urlsOpened = []) {
Services.telemetry
.getHistogramById("PLACES_BOOKMARKS_SEARCHBAR_CUMULATIVE_SEARCHES")
.add(gCumulativeSearches);
Glean.bookmarksSidebar.cumulativeSearches.accumulateSingleSample(
gCumulativeSearches
);
clearCumulativeCounter();
Glean.sidebar.link.bookmarks.add(urlsOpened.length);

View file

@ -826,7 +826,7 @@ class PlacesViewBase {
*/
class PlacesToolbar extends PlacesViewBase {
constructor(placesUrl, rootElt, viewElt) {
let startTime = Date.now();
let timerId = Glean.bookmarksToolbar.init.start();
super(placesUrl, rootElt, viewElt);
this._addEventListeners(this._dragRoot, this._cbEvents, false);
this._addEventListeners(
@ -852,9 +852,7 @@ class PlacesToolbar extends PlacesViewBase {
);
}
Services.telemetry
.getHistogramById("FX_BOOKMARKS_TOOLBAR_INIT_MS")
.add(Date.now() - startTime);
Glean.bookmarksToolbar.init.stopAndAccumulate(timerId);
}
// Called by PlacesViewBase so we can init properties that class

View file

@ -59,10 +59,7 @@ window.addEventListener("load", () => {
let viewButton = document.getElementById("viewButton");
gHistoryGrouping = viewButton.getAttribute("selectedsort");
this.groupHistogram = Services.telemetry.getHistogramById(
"PLACES_SEARCHBAR_FILTER_TYPE"
);
this.groupHistogram.add(gHistoryGrouping);
Glean.historySidebar.filterType[gHistoryGrouping].add(1);
if (gHistoryGrouping == "site") {
document.getElementById("bysite").setAttribute("checked", "true");
@ -97,7 +94,7 @@ window.addEventListener("load", () => {
function GroupBy(groupingType) {
if (groupingType != gHistoryGrouping) {
this.groupHistogram.add(groupingType);
Glean.historySidebar.filterType[groupingType].add(1);
}
gHistoryGrouping = groupingType;
gCumulativeFilterCount++;
@ -105,12 +102,12 @@ function GroupBy(groupingType) {
}
function updateTelemetry(urlsOpened = []) {
Services.telemetry
.getHistogramById("PLACES_SEARCHBAR_CUMULATIVE_SEARCHES")
.add(gCumulativeSearches);
Services.telemetry
.getHistogramById("PLACES_SEARCHBAR_CUMULATIVE_FILTER_COUNT")
.add(gCumulativeFilterCount);
Glean.historySidebar.cumulativeSearches.accumulateSingleSample(
gCumulativeSearches
);
Glean.historySidebar.cumulativeFilterCount.accumulateSingleSample(
gCumulativeFilterCount
);
clearCumulativeCounters();
Glean.sidebar.link.history.add(urlsOpened.length);
@ -158,8 +155,9 @@ function searchHistory(aInput) {
options.resultType = resultType;
options.includeHidden = !!aInput;
let timerId;
if (gHistoryGrouping == "lastvisited") {
TelemetryStopwatch.start("HISTORY_LASTVISITED_TREE_QUERY_TIME_MS");
timerId = Glean.historySidebar.lastvisitedTreeQueryTime.start();
}
// call load() on the tree manually
@ -177,7 +175,7 @@ function searchHistory(aInput) {
}
if (gHistoryGrouping == "lastvisited") {
TelemetryStopwatch.finish("HISTORY_LASTVISITED_TREE_QUERY_TIME_MS");
Glean.historySidebar.lastvisitedTreeQueryTime.stopAndAccumulate(timerId);
}
}

View file

@ -35,8 +35,6 @@ var { AppConstants } = ChromeUtils.importESModule(
);
const RESTORE_FILEPICKER_FILTER_EXT = "*.json;*.jsonlz4";
const HISTORY_LIBRARY_SEARCH_TELEMETRY =
"PLACES_HISTORY_LIBRARY_SEARCH_TIME_MS";
const SORTBY_L10N_IDS = new Map([
["title", "places-view-sortby-name"],
@ -963,9 +961,9 @@ var PlacesSearchBox = {
options.includeHidden = true;
currentView.load([query], options);
} else {
TelemetryStopwatch.start(HISTORY_LIBRARY_SEARCH_TELEMETRY);
let timerId = Glean.library.historySearchTime.start();
currentView.applyFilter(filterString, null, true);
TelemetryStopwatch.finish(HISTORY_LIBRARY_SEARCH_TELEMETRY);
Glean.library.historySearchTime.stopAndAccumulate(timerId);
Glean.library.search.history.add(1);
this.cumulativeHistorySearches++;
}
@ -1069,9 +1067,9 @@ function updateTelemetry(urlsOpened) {
link => !link.isBookmark && !PlacesUtils.nodeIsBookmark(link)
);
if (!historyLinks.length) {
Services.telemetry
.getHistogramById("PLACES_LIBRARY_CUMULATIVE_BOOKMARK_SEARCHES")
.add(PlacesSearchBox.cumulativeBookmarkSearches);
Glean.library.cumulativeBookmarkSearches.accumulateSingleSample(
PlacesSearchBox.cumulativeBookmarkSearches
);
// Clear cumulative search counter
PlacesSearchBox.cumulativeBookmarkSearches = 0;
@ -1081,9 +1079,9 @@ function updateTelemetry(urlsOpened) {
}
// Record cumulative search count before selecting History link from Library
Services.telemetry
.getHistogramById("PLACES_LIBRARY_CUMULATIVE_HISTORY_SEARCHES")
.add(PlacesSearchBox.cumulativeHistorySearches);
Glean.library.cumulativeHistorySearches.accumulateSingleSample(
PlacesSearchBox.cumulativeHistorySearches
);
// Clear cumulative search counter
PlacesSearchBox.cumulativeHistorySearches = 0;

View file

@ -58,3 +58,186 @@ library:
- firefox-view-engineers@mozilla.com
expires: never
telemetry_mirror: LIBRARY_SEARCH
history_search_time:
type: timing_distribution
description: >
PLACES: Time to search the history library (ms)
This metric was generated to correspond to the Legacy Telemetry
exponential histogram PLACES_HISTORY_LIBRARY_SEARCH_TIME_MS.
time_unit: millisecond
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
notification_emails:
- firefox-view-engineers@mozilla.com
expires: never
telemetry_mirror: PLACES_HISTORY_LIBRARY_SEARCH_TIME_MS
cumulative_history_searches:
type: custom_distribution
description: >
Cumulative no. of History-specific searches performed before selecting a
History link in Library.
This metric was generated to correspond to the Legacy Telemetry enumerated
histogram PLACES_LIBRARY_CUMULATIVE_HISTORY_SEARCHES.
range_min: 0
range_max: 20
bucket_count: 21
histogram_type: linear
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1815906
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1815906
notification_emails:
- kcochrane@mozilla.com
- firefox-view-engineers@mozilla.com
expires: never
telemetry_mirror: PLACES_LIBRARY_CUMULATIVE_HISTORY_SEARCHES
cumulative_bookmark_searches:
type: custom_distribution
description: >
Cumulative no. of Bookmark-specific searches performed before selecting a
bookmark link in Library.
This metric was generated to correspond to the Legacy Telemetry enumerated
histogram PLACES_LIBRARY_CUMULATIVE_BOOKMARK_SEARCHES.
range_min: 0
range_max: 20
bucket_count: 21
histogram_type: linear
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1819081
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1819081
notification_emails:
- firefox-view-engineers@mozilla.com
expires: never
telemetry_mirror: PLACES_LIBRARY_CUMULATIVE_BOOKMARK_SEARCHES
history_sidebar:
filter_type:
type: labeled_counter
description: >
The type of search filters used for the sidebar search.
This metric was generated to correspond to the Legacy Telemetry
categorical histogram PLACES_SEARCHBAR_FILTER_TYPE.
labels:
- visited
- lastvisited
- dayandsite
- site
- day
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1801290
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1801290
notification_emails:
- pguruprasad@mozilla.com
- rfambro@mozilla.com
expires: never
telemetry_mirror: h#PLACES_SEARCHBAR_FILTER_TYPE
cumulative_searches:
type: custom_distribution
description: >
Cumulative no. of searches performed before selecting a link.
This metric was generated to correspond to the Legacy Telemetry enumerated
histogram PLACES_SEARCHBAR_CUMULATIVE_SEARCHES.
range_min: 0
range_max: 20
bucket_count: 21
histogram_type: linear
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1801290
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1801290
notification_emails:
- pguruprasad@mozilla.com
- rfambro@mozilla.com
expires: never
telemetry_mirror: PLACES_SEARCHBAR_CUMULATIVE_SEARCHES
cumulative_filter_count:
type: custom_distribution
description: >
Cumulative no. of search filters applied performed before selecting a
link.
This metric was generated to correspond to the Legacy Telemetry enumerated
histogram PLACES_SEARCHBAR_CUMULATIVE_FILTER_COUNT.
range_min: 0
range_max: 20
bucket_count: 21
histogram_type: linear
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1801290
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1801290
notification_emails:
- pguruprasad@mozilla.com
- rfambro@mozilla.com
expires: never
telemetry_mirror: PLACES_SEARCHBAR_CUMULATIVE_FILTER_COUNT
lastvisited_tree_query_time:
type: timing_distribution
description: >
PLACES: Time to load the sidebar history tree sorted by last visit (ms)
This metric was generated to correspond to the Legacy Telemetry
exponential histogram HISTORY_LASTVISITED_TREE_QUERY_TIME_MS.
time_unit: millisecond
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1944631
notification_emails:
- firefox-view-engineers@mozilla.com
expires: never
telemetry_mirror: HISTORY_LASTVISITED_TREE_QUERY_TIME_MS
bookmarks_sidebar:
cumulative_searches:
type: custom_distribution
description: >
Cumulative no. bookmark of searches performed before selecting a link.
This metric was generated to correspond to the Legacy Telemetry enumerated
histogram PLACES_BOOKMARKS_SEARCHBAR_CUMULATIVE_SEARCHES.
range_min: 0
range_max: 20
bucket_count: 21
histogram_type: linear
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1819081
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1819081
notification_emails:
- firefox-view-engineers@mozilla.com
expires: never
telemetry_mirror: PLACES_BOOKMARKS_SEARCHBAR_CUMULATIVE_SEARCHES
bookmarks_toolbar:
init:
type: timing_distribution
description: >
Firefox: Time to initialize the bookmarks toolbar view (ms)
This metric was generated to correspond to the Legacy Telemetry
exponential histogram FX_BOOKMARKS_TOOLBAR_INIT_MS.
time_unit: millisecond
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=723165
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=723165
notification_emails:
- mak@mozilla.com
expires: never
telemetry_mirror: FX_BOOKMARKS_TOOLBAR_INIT_MS

View file

@ -186,7 +186,6 @@
<groupbox data-category="paneGeneral"
hidden="true">
<label><html:h2 data-l10n-id="browser-layout-header"/></label>
#ifdef NIGHTLY_BUILD
<radiogroup id="browserLayoutRadioGroup" preference="sidebar.verticalTabs">
<radio id="browserLayoutHorizontalTabs" data-l10n-id="browser-layout-horizontal-tabs" value="false"/>
<description class="indent" data-l10n-id="browser-layout-horizontal-tabs-desc"></description>
@ -194,7 +193,6 @@
<radio id="browserLayoutVerticalTabs" data-l10n-id="browser-layout-vertical-tabs" value="true" />
<description class="indent" data-l10n-id="browser-layout-vertical-tabs-desc"></description>
</radiogroup>
#endif
<checkbox id="browserLayoutShowSidebar" data-l10n-id="browser-layout-show-sidebar"
preference="sidebar.revamp"/>
<description class="indent" data-l10n-id="browser-layout-show-sidebar-desc"></description>

View file

@ -89,7 +89,11 @@ https_first_disabled = true
["browser_dynamical_window_rounding.js"]
https_first_disabled = true
skip-if = ["os == 'mac'"] # Bug 1775698
skip-if = [
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # Bug 1775698
"os == 'mac' && os_version == '11.20' && arch == 'aarch64' && opt", # Bug 1775698
"os == 'mac' && os_version == '15.30' && arch == 'aarch64' && opt", # Bug 1775698
]
["browser_exslt_time_precision.js"]

View file

@ -5,6 +5,10 @@ const SECURE_CONTAINER_URL =
"https://example.com/browser/browser/components/safebrowsing/content/test/empty_file.html";
add_task(async function testNormalBrowsing() {
await SpecialPowers.pushPrefEnv({
set: [["browser.safebrowsing.only_top_level", false]],
});
await BrowserTestUtils.withNewTab(
SECURE_CONTAINER_URL,
async function (browser) {

View file

@ -190,6 +190,7 @@ skip-if = [
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && asan", # Bug 1775605
"os == 'mac' && os_version == '10.15' && processor == 'x86_64' && opt", # Bug 1638958
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
"os == 'win' && os_version == '11.2009' && processor == 'x86' && opt", # Bug 1775605
"os == 'win' && os_version == '11.2009' && processor == 'x86_64' && opt", # Bug 1775605
"os == 'win' && os_version == '11.26100' && processor == 'x86_64' && opt", # Bug 1775605

View file

@ -284,11 +284,7 @@ let ShellServiceInternal = {
throw ex;
} finally {
try {
Services.telemetry
.getHistogramById("BROWSER_SET_DEFAULT_USER_CHOICE_RESULT")
.add(telemetryResult);
} catch (ex) {}
Glean.browser.setDefaultUserChoiceResult[telemetryResult].add(1);
}
},
@ -318,13 +314,9 @@ let ShellServiceInternal = {
throw ex;
} finally {
try {
Services.telemetry
.getHistogramById(
"BROWSER_SET_DEFAULT_PDF_HANDLER_USER_CHOICE_RESULT"
)
.add(telemetryResult);
} catch (ex) {}
Glean.browser.setDefaultPdfHandlerUserChoiceResult[telemetryResult].add(
1
);
}
},
@ -377,16 +369,12 @@ let ShellServiceInternal = {
setAsDefaultError = true;
console.error(ex);
}
// Here BROWSER_IS_USER_DEFAULT and BROWSER_SET_USER_DEFAULT_ERROR appear
// Here isUserDefault and setUserDefaultError appear
// to be inverse of each other, but that is only because this function is
// called when the browser is set as the default. During startup we record
// the BROWSER_IS_USER_DEFAULT value without recording BROWSER_SET_USER_DEFAULT_ERROR.
Services.telemetry
.getHistogramById("BROWSER_IS_USER_DEFAULT")
.add(!setAsDefaultError);
Services.telemetry
.getHistogramById("BROWSER_SET_DEFAULT_ERROR")
.add(setAsDefaultError);
// the isUserDefault value without recording setUserDefaultError.
Glean.browser.isUserDefault[!setAsDefaultError ? "true" : "false"].add();
Glean.browser.setDefaultError[setAsDefaultError ? "true" : "false"].add();
},
setAsDefaultPDFHandler(onlyIfKnownBrowser = false) {

View file

@ -541,6 +541,10 @@ var SidebarController = {
}
await this.promiseInitialized;
this._state.loadInitialState(state);
if (this.revampComponentsLoaded) {
await this.sidebarMain.updateComplete;
}
this.updateToolbarButton();
this.uiStateInitialized = true;
},
@ -922,7 +926,7 @@ var SidebarController = {
* True if the sidebar is currently open.
*/
get isOpen() {
return !this._box.hidden;
return this._box ? !this._box.hidden : false;
},
/**
@ -1150,6 +1154,7 @@ var SidebarController = {
if (this.sidebarRevampVisibility === "expand-on-hover") {
this.toggleExpandOnHover(initialExpandedValue);
}
this.updateToolbarButton();
},
/**
@ -2022,6 +2027,9 @@ XPCOMUtils.defineLazyPreferenceGetter(
SidebarController._animateSidebarMain();
}
const forceExpand = isVerticalTabs && newValue === "always-show";
// horizontal tabs and hide-sidebar = visible initially.
// vertical tab and hide-sidebar = not visible initally.
SidebarController._state.updateVisibility(
(newValue != "hide-sidebar" && isVerticalTabs) || !isVerticalTabs,
false,

View file

@ -162,6 +162,7 @@ add_task(async function test_keyboard_navigation_vertical_tabs() {
SpecialPowers.pushPrefEnv({
set: [["sidebar.verticalTabs", true]],
});
await waitForTabstripOrientation("vertical");
const sidebar = document.querySelector("sidebar-main");
const toolButtons = await TestUtils.waitForCondition(
() => sidebar.toolButtons,

View file

@ -196,6 +196,7 @@ add_task(async function test_customize_position_setting() {
{},
win.SidebarController.browser.contentWindow
);
await panel.updateComplete;
ok(panel.positionInput.checked, "Sidebar is positioned on the right");
const newWin = await BrowserTestUtils.openNewBrowserWindow();
@ -222,6 +223,8 @@ add_task(async function test_customize_visibility_setting() {
await SpecialPowers.pushPrefEnv({
set: [[TAB_DIRECTION_PREF, true]],
});
await waitForTabstripOrientation("vertical");
const deferredPrefChange = Promise.withResolvers();
const prefObserver = () => deferredPrefChange.resolve();
Services.prefs.addObserver(SIDEBAR_VISIBILITY_PREF, prefObserver);
@ -241,6 +244,7 @@ add_task(async function test_customize_visibility_setting() {
{},
win.SidebarController.browser.contentWindow
);
await panel.updateComplete;
ok(panel.visibilityInput.checked, "Hide sidebar is enabled.");
ok(
win.SidebarController.sidebarContainer.hidden,
@ -266,14 +270,8 @@ add_task(async function test_customize_visibility_setting() {
});
add_task(async function test_vertical_tabs_setting() {
const deferredPrefChange = Promise.withResolvers();
const prefObserver = () => deferredPrefChange.resolve();
Services.prefs.addObserver(TAB_DIRECTION_PREF, prefObserver);
registerCleanupFunction(() =>
Services.prefs.removeObserver(TAB_DIRECTION_PREF, prefObserver)
);
const win = await BrowserTestUtils.openNewBrowserWindow();
await waitForTabstripOrientation("horizontal", win);
const panel = await showCustomizePanel(win);
ok(
!panel.verticalTabsInput.checked,
@ -284,12 +282,15 @@ add_task(async function test_vertical_tabs_setting() {
{},
win.SidebarController.browser.contentWindow
);
await panel.updateComplete;
ok(panel.verticalTabsInput.checked, "Vertical tabs is enabled.");
await deferredPrefChange.promise;
await waitForTabstripOrientation("vertical", win);
const newPrefValue = Services.prefs.getBoolPref(TAB_DIRECTION_PREF);
is(newPrefValue, true, "Vertical tabs pref updated.");
const newWin = await BrowserTestUtils.openNewBrowserWindow();
await waitForTabstripOrientation("vertical", newWin);
const newPanel = await showCustomizePanel(newWin);
ok(newPanel.verticalTabsInput.checked, "Vertical tabs setting persists.");
@ -313,6 +314,8 @@ add_task(async function test_keyboard_navigation_away_from_settings_link() {
"Settings link is focused"
);
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true }, win);
await panel.updateComplete;
Assert.notEqual(
panel.shadowRoot.activeElement,
manageSettingsLink,

View file

@ -12,6 +12,7 @@ add_setup(async () => {
DOMFullscreenTestUtils.init(this, window);
win = await BrowserTestUtils.openNewBrowserWindow();
await waitForBrowserWindowActive(win);
await waitForTabstripOrientation("vertical");
});
registerCleanupFunction(async () => {

View file

@ -11,6 +11,7 @@ async function test_sidebar_hidden_on_popup() {
await SpecialPowers.pushPrefEnv({
set: [["sidebar.verticalTabs", true]],
});
await waitForTabstripOrientation("vertical");
const win = await BrowserTestUtils.openNewBrowserWindow();
const { document } = win;

View file

@ -16,6 +16,7 @@ add_setup(async () => {
launcherExpanded: false,
launcherVisible: true,
});
await waitForTabstripOrientation("vertical");
});
registerCleanupFunction(async () => {
@ -123,7 +124,9 @@ add_task(async function test_resize_after_toggling_revamp() {
["sidebar.verticalTabs", false],
],
});
await waitForTabstripOrientation("horizontal");
await SpecialPowers.popPrefEnv();
await waitForTabstripOrientation("vertical");
info("Resize the vertical tab strip.");
const originalWidth = getLauncherWidth();

View file

@ -7,6 +7,7 @@ add_setup(async () => {
await SpecialPowers.pushPrefEnv({
set: [["sidebar.verticalTabs", true]],
});
await waitForTabstripOrientation("vertical");
Assert.equal(
Services.prefs.getStringPref("sidebar.visibility"),
"always-show",

View file

@ -252,6 +252,7 @@ add_task(async function test_toggle_vertical_tabs_from_tab_strip() {
await SpecialPowers.pushPrefEnv({
set: [["sidebar.verticalTabs", false]],
});
await waitForTabstripOrientation("horizontal");
Assert.equal(
Services.prefs.getStringPref("sidebar.visibility"),
"hide-sidebar",
@ -278,6 +279,7 @@ add_task(async function test_toggle_vertical_tabs_from_tab_strip() {
toggleMenuItem.click();
}
);
await waitForTabstripOrientation("vertical");
await TestUtils.waitForCondition(
() => gBrowser.tabContainer.verticalMode,
"Vertical tabs are enabled."
@ -316,6 +318,7 @@ add_task(async function test_toggle_vertical_tabs_from_tab_strip() {
toggleMenuItem.click();
}
);
await waitForTabstripOrientation("horizontal");
await TestUtils.waitForCondition(
() => !gBrowser.tabContainer.verticalMode,
"Vertical tabs are disabled."

View file

@ -9,11 +9,13 @@ add_task(async function test_customize_sidebar_actions() {
SpecialPowers.pushPrefEnv({
set: [[TAB_DIRECTION_PREF, true]],
});
await waitForTabstripOrientation("vertical");
const win = await BrowserTestUtils.openNewBrowserWindow();
await waitForTabstripOrientation("vertical", win);
const { document } = win;
const sidebar = document.querySelector("sidebar-main");
ok(sidebar, "Sidebar is shown.");
await sidebar.updateComplete;
await toggleSidebarPanel(win, "viewCustomizeSidebar");
const initialViewportOuterWidth = win.outerWidth;

View file

@ -154,8 +154,8 @@ add_task(async function test_tool_pref_change() {
*/
add_task(async function test_flip_revamp_pref() {
const win = await BrowserTestUtils.openNewBrowserWindow();
await waitForTabstripOrientation("horizontal", win);
const sidebar = win.document.querySelector("sidebar-main");
await sidebar.updateComplete;
let verticalTabs = win.document.querySelector("#vertical-tabs");
ok(
@ -166,6 +166,7 @@ add_task(async function test_flip_revamp_pref() {
await toggleSidebarPanel(win, "viewHistorySidebar");
await SpecialPowers.pushPrefEnv({ set: [["sidebar.verticalTabs", true]] });
await waitForTabstripOrientation("vertical", win);
ok(BrowserTestUtils.isVisible(verticalTabs), "Vertical tabs slot is visible");
ok(sidebar, "Revamped sidebar is shown initially.");
@ -176,6 +177,7 @@ add_task(async function test_flip_revamp_pref() {
);
await SpecialPowers.pushPrefEnv({ set: [["sidebar.revamp", false]] });
await waitForTabstripOrientation("horizontal", win);
await TestUtils.waitForCondition(() => {
let isSidebarMainShown =

View file

@ -21,10 +21,11 @@ add_setup(async () => {
[SIDEBAR_BUTTON_INTRODUCED_PREF, false],
],
});
await waitForTabstripOrientation("vertical");
Assert.equal(
Services.prefs.getStringPref(SIDEBAR_VISIBILITY_PREF),
"always-show",
"Sanity check the visibilty pref when verticalTabs are enabled"
"Sanity check the visibility pref when verticalTabs are enabled"
);
let navbarDefaults = gAreas.get("nav-bar").get("defaultPlacements");
@ -51,19 +52,26 @@ add_setup(async () => {
0,
"sidebar-button"
);
if (window.SidebarController.sidebarMain?.expanded) {
info("In setup, the sidebar is currently expanded. Collapsing it");
await window.SidebarController.initializeUIState({
launcherExpanded: false,
});
await window.SidebarController.sidebarMain.updateComplete;
}
ok(
window.SidebarController.sidebarMain?.expanded,
"With verticalTabs enabled, the launcher should be initially expanded"
);
ok(
BrowserTestUtils.isVisible(window.SidebarController.sidebarMain),
"Sidebar launcher is visible at setup"
);
});
async function waitUntilSidebarIsStable(win = window) {
const tasks = [
win.SidebarController.sidebarMain.updateComplete,
...win.SidebarController._ongoingAnimations.map(
animation => animation.finished
),
];
return Promise.allSettled(tasks);
}
add_task(async function test_toolbar_sidebar_button() {
ok(
document.getElementById("sidebar-button"),
@ -88,11 +96,8 @@ add_task(async function test_toolbar_sidebar_button() {
});
add_task(async function test_expanded_state_for_always_show() {
const win = await BrowserTestUtils.openNewBrowserWindow();
const { SidebarController, document } = win;
const { sidebarMain, toolbarButton } = SidebarController;
await SidebarController.promiseInitialized;
await flushTaskQueue(win);
await waitForTabstripOrientation("vertical");
const { sidebarMain, toolbarButton } = window.SidebarController;
const checkExpandedState = async (
expanded,
@ -128,67 +133,73 @@ add_task(async function test_expanded_state_for_always_show() {
? "Toolbar button expanded attribute is present."
: "Toolbar button expanded attribute is absent."
);
await flushTaskQueue(win);
};
info("Set default expanded state.");
await SidebarController.initializeUIState({
launcherVisible: true,
launcherExpanded: false,
});
await checkExpandedState(false);
await checkExpandedState(true);
info("Toggle expanded state via toolbar button.");
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
await checkExpandedState(true);
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, window);
await waitUntilSidebarIsStable(window);
await checkExpandedState(false);
info("Don't collapse the sidebar by loading a tool.");
await SidebarController.initializeUIState({ launcherExpanded: true });
await sidebarMain.updateComplete;
await waitUntilSidebarIsStable(window);
const toolButton = sidebarMain.toolButtons[0];
EventUtils.synthesizeMouseAtCenter(toolButton, {}, win);
EventUtils.synthesizeMouseAtCenter(toolButton, {}, window);
await waitUntilSidebarIsStable(window);
await checkExpandedState(true);
info("Load and unload a tool with the sidebar collapsed to begin with.");
await SidebarController.initializeUIState({ launcherExpanded: false });
await sidebarMain.updateComplete;
EventUtils.synthesizeMouseAtCenter(toolButton, {}, win);
await checkExpandedState(false);
EventUtils.synthesizeMouseAtCenter(toolButton, {}, win);
await waitUntilSidebarIsStable(window);
EventUtils.synthesizeMouseAtCenter(toolButton, {}, window);
await waitUntilSidebarIsStable(window);
await checkExpandedState(false);
info("Check expanded state on a new window.");
await SidebarController.initializeUIState({ launcherExpanded: true });
await sidebarMain.updateComplete;
await waitUntilSidebarIsStable(window);
const newWin = await BrowserTestUtils.openNewBrowserWindow();
await waitForTabstripOrientation("vertical", newWin);
await checkExpandedState(
true,
newWin.SidebarController.sidebarMain,
newWin.SidebarController.toolbarButton
);
await BrowserTestUtils.closeWindow(win);
await BrowserTestUtils.closeWindow(newWin);
await SpecialPowers.popPrefEnv();
});
add_task(async function test_states_for_hide_sidebar() {
// With horizontal tabs and visibiliy set to "hide-sidebar", check launcher is initially visible
// With horizontal tabs and visibility set to "hide-sidebar", check launcher is initially visible
await SpecialPowers.pushPrefEnv({
set: [[SIDEBAR_TAB_DIRECTION_PREF, false]],
});
await waitForTabstripOrientation("horizontal");
Assert.equal(
Services.prefs.getStringPref(SIDEBAR_VISIBILITY_PREF),
"hide-sidebar",
"Sanity check the visibilty pref when verticalTabs are disabled"
"Sanity check the visibility pref when verticalTabs are disabled"
);
// The sidebar launcher should be initially visible when visibility is "hide-sidebar"
Assert.ok(
!window.SidebarController.sidebarContainer.hidden,
"The launcher is initially visible"
);
Assert.ok(
window.SidebarController.toolbarButton.checked,
"The toolbar button is initially checked"
);
const win = await BrowserTestUtils.openNewBrowserWindow();
const { SidebarController } = win;
const { sidebarContainer, sidebarMain, toolbarButton } = SidebarController;
await waitForTabstripOrientation("horizontal", win);
const checkStates = async (
{ hidden },
@ -225,7 +236,6 @@ add_task(async function test_states_for_hide_sidebar() {
() => !button.hasAttribute("expanded"),
"Toolbar button expanded attribute is absent."
);
await flushTaskQueue(win);
};
info("Check the launcher is initially visible");
@ -234,29 +244,48 @@ add_task(async function test_states_for_hide_sidebar() {
info("Hide sidebar using the toolbar button.");
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
await checkStates({ hidden: true });
Assert.ok(
!toolbarButton.checked,
"The toolbar button becomes unchecked when clicking it hides the launcher"
);
await checkStates({ hidden: true });
info("Check states on a new window.");
const newWin = await BrowserTestUtils.openNewBrowserWindow();
await waitForTabstripOrientation("horizontal", newWin);
await checkStates(
{ hidden: true },
newWin.SidebarController.sidebarContainer,
newWin.SidebarController.sidebarMain,
newWin.SidebarController.toolbarButton
);
Assert.ok(
!newWin.SidebarController.toolbarButton.checked,
"The toolbar button in the new window is unchecked when the launcher is hidden"
);
await BrowserTestUtils.closeWindow(win);
await BrowserTestUtils.closeWindow(newWin);
await SpecialPowers.popPrefEnv();
await waitForTabstripOrientation("vertical");
});
add_task(async function test_states_for_hide_sidebar_vertical() {
info(
`starting test with pref values: verticalTabs: ${Services.prefs.getBoolPref("sidebar.verticalTabs")}, visibility: ${Services.prefs.getStringPref("sidebar.visibility")}`
);
await waitForTabstripOrientation("vertical", window);
await SpecialPowers.pushPrefEnv({
set: [
[SIDEBAR_TAB_DIRECTION_PREF, true],
[SIDEBAR_VISIBILITY_PREF, "hide-sidebar"],
],
set: [["sidebar.visibility", "hide-sidebar"]],
});
await window.SidebarController.sidebarMain.updateComplete;
ok(
window.SidebarController.sidebarContainer.hidden,
"Sidebar is hidden when visibility is set to hide-sidebar"
);
info("Initial state ok, opening a new browser window");
const win = await BrowserTestUtils.openNewBrowserWindow();
await waitForTabstripOrientation("vertical", win);
const { SidebarController } = win;
const { sidebarContainer, sidebarMain, toolbarButton } = SidebarController;
@ -297,11 +326,10 @@ add_task(async function test_states_for_hide_sidebar_vertical() {
? "Toolbar button expanded attribute is present."
: "Toolbar button expanded attribute is absent."
);
await flushTaskQueue(win);
};
// Check initial sidebar state - it should be hidden
info("Check default hidden state.");
info("Check default hidden state in the new window.");
await checkStates({ hidden: true, expanded: false });
info("Show expanded sidebar using the toolbar button.");
EventUtils.synthesizeMouseAtCenter(toolbarButton, {}, win);
@ -310,7 +338,11 @@ add_task(async function test_states_for_hide_sidebar_vertical() {
info("Don't collapse the sidebar by loading a tool.");
const toolButton = sidebarMain.toolButtons[0];
EventUtils.synthesizeMouseAtCenter(toolButton, {}, win);
ok(SidebarController.isOpen, "Panel is open.");
await TestUtils.waitForCondition(
() => SidebarController.isOpen,
"Panel is open"
);
await checkStates({ hidden: false, expanded: true });
info("Close a panel using the toolbar button.");

View file

@ -75,6 +75,8 @@ function getExpectedElements(win, tabstripOrientation = "horizontal") {
}
add_task(async function test_toggle_vertical_tabs() {
await waitForTabstripOrientation("horizontal");
const sidebar = document.querySelector("sidebar-main");
ok(sidebar, "Sidebar is shown.");
@ -129,6 +131,7 @@ add_task(async function test_toggle_vertical_tabs() {
// flip the pref to move the tabstrip into the sidebar
await SpecialPowers.pushPrefEnv({ set: [["sidebar.verticalTabs", true]] });
await waitForTabstripOrientation("vertical");
for (let selector of expectedElementsWhenVertical) {
let elem = document.querySelector(selector);
@ -159,10 +162,6 @@ add_task(async function test_toggle_vertical_tabs() {
// make sure the tab context menu still works
const contextMenu = document.getElementById("tabContextMenu");
gBrowser.selectedTab.focus();
EventUtils.synthesizeMouseAtCenter(gBrowser.selectedTab, {
type: "contextmenu",
button: 2,
});
info("Open a new tab using the context menu.");
await openAndWaitForContextMenu(contextMenu, gBrowser.selectedTab, () => {
@ -328,6 +327,7 @@ add_task(async function test_toggle_vertical_tabs() {
// flip the pref to move the tabstrip horizontally
await SpecialPowers.pushPrefEnv({ set: [["sidebar.verticalTabs", false]] });
await waitForTabstripOrientation("horizontal");
ok(
!BrowserTestUtils.isVisible(verticalTabs),
@ -362,6 +362,7 @@ add_task(async function test_toggle_vertical_tabs() {
add_task(async function test_enabling_vertical_tabs_enables_sidebar_revamp() {
await SpecialPowers.pushPrefEnv({ set: [["sidebar.revamp", false]] });
await waitForTabstripOrientation("horizontal");
ok(
!Services.prefs.getBoolPref("sidebar.revamp", false),
"sidebar.revamp pref is false initially."
@ -372,6 +373,7 @@ add_task(async function test_enabling_vertical_tabs_enables_sidebar_revamp() {
);
await SpecialPowers.pushPrefEnv({ set: [["sidebar.verticalTabs", true]] });
await waitForTabstripOrientation("vertical");
ok(
Services.prefs.getBoolPref("sidebar.verticalTabs", false),
"sidebar.verticalTabs pref is enabled after we've enabled it."
@ -383,6 +385,7 @@ add_task(async function test_enabling_vertical_tabs_enables_sidebar_revamp() {
});
add_task(async function test_vertical_tabs_overflow() {
await waitForTabstripOrientation("vertical");
const numTabs = 50;
const winData = {
tabs: Array.from({ length: numTabs }, (_, i) => ({
@ -433,18 +436,21 @@ add_task(async function test_vertical_tabs_expanded() {
["sidebar.verticalTabs", true],
],
});
await waitForTabstripOrientation("vertical");
info("Disable revamped sidebar.");
Services.prefs.setBoolPref("sidebar.revamp", false);
await TestUtils.waitForCondition(
() => BrowserTestUtils.isHidden(document.getElementById("sidebar-main")),
await waitForTabstripOrientation("horizontal");
ok(
BrowserTestUtils.isHidden(document.getElementById("sidebar-main")),
"Sidebar launcher is hidden."
);
info("Enable vertical tabs.");
Services.prefs.setBoolPref("sidebar.verticalTabs", true);
await TestUtils.waitForCondition(
() => BrowserTestUtils.isVisible(document.getElementById("sidebar-main")),
await waitForTabstripOrientation("vertical");
ok(
BrowserTestUtils.isVisible(document.getElementById("sidebar-main")),
"Sidebar launcher is shown."
);
// We expect the launcher to be expanded by default when enabling vertical tabs
@ -464,23 +470,21 @@ add_task(async function test_vertical_tabs_min_width() {
await SpecialPowers.pushPrefEnv({
set: [["sidebar.verticalTabs", true]],
});
await waitForTabstripOrientation("vertical");
await TestUtils.waitForCondition(
() => BrowserTestUtils.isVisible(SidebarController.sidebarMain),
ok(
BrowserTestUtils.isVisible(SidebarController.sidebarMain),
"Sidebar launcher is shown."
);
await SidebarController.initializeUIState({ launcherExpanded: false });
await SidebarController.sidebarMain.updateComplete;
// We expect the launcher to be collapsed
// We expect the launcher to be expanded by default when enabling vertical tabs
const expandedStateValues = [
SidebarController.getUIState().launcherExpanded,
SidebarController.sidebarMain.expanded,
gBrowser.tabContainer.hasAttribute("expanded"),
];
for (const val of expandedStateValues) {
is(val, false, "Launcher is not expanded.");
is(val, true, "Launcher is expanded.");
}
is(
@ -493,12 +497,9 @@ add_task(async function test_vertical_tabs_min_width() {
await SpecialPowers.pushPrefEnv({
set: [["sidebar.verticalTabs", false]],
});
await waitForTabstripOrientation("horizontal");
let tabbrowserTabs = document.getElementById("tabbrowser-tabs");
await TestUtils.waitForCondition(() => {
return tabbrowserTabs.getAttribute("orient") === "horizontal";
}, "Horizontal tabs are enabled.");
let tabStyles = window.getComputedStyle(tabbrowserTabs);
let tabMinWidthVal = tabStyles.getPropertyValue("--tab-min-width-pref");

View file

@ -142,6 +142,26 @@ async function toggleSidebarPanel(win, commandID) {
await promiseFocused;
}
async function waitForTabstripOrientation(
toOrientation = "vertical",
win = window
) {
await win.SidebarController.promiseInitialized;
// We use the orient attribute on the tabstrip element as a reliable signal that
// tabstrip orientation has changed/is settled into the given orientation
info(
`waitForTabstripOrientation: waiting for orient attribute to be "${toOrientation}"`
);
await BrowserTestUtils.waitForMutationCondition(
win.gBrowser.tabContainer,
{ attributes: true, attributeFilter: ["orient"] },
() => win.gBrowser.tabContainer.getAttribute("orient") == toOrientation
);
// This change is followed by a update/render step for the lit elements.
// We need to wait for that too
await win.SidebarController.sidebarMain?.updateComplete;
}
// Reset the Glean events after each test.
registerCleanupFunction(() => {
Services.fog.testResetFOG();

View file

@ -104,14 +104,17 @@ export class GroupsPanel {
);
let totalItemCount = savedGroups.length + openGroups.length;
if (totalItemCount) {
let showAll = this.#showAll || totalItemCount <= MAX_INITIAL_ITEMS;
if (totalItemCount && !showAll) {
let header = this.doc.createElement("h2");
header.setAttribute("class", "subview-subheader");
this.doc.l10n.setAttributes(header, "tab-group-menu-header");
this.doc.l10n.setAttributes(
header,
"all-tabs-menu-recent-tab-groups-header"
);
fragment.appendChild(header);
}
let showAll = this.#showAll || totalItemCount <= MAX_INITIAL_ITEMS;
let itemCount = 1; // Start with 1 to account for "show more" button
for (let groupData of openGroups) {
if (itemCount >= MAX_INITIAL_ITEMS && !showAll) {

View file

@ -47,7 +47,9 @@
</vbox>
</panelview>
<panelview id="allTabsMenu-groupsSubView" class="PanelUI-subView">
<panelview id="allTabsMenu-groupsSubView"
class="PanelUI-subView"
data-l10n-id="all-tabs-menu-tab-groups-sub-view">
<vbox id="allTabsMenu-groupsSubView-body" class="panel-subview-body"/>
</panelview>
</html:template>

View file

@ -5794,8 +5794,10 @@
this._handleTabMove(tab, () => {
if (dropBefore) {
this.tabContainer.insertBefore(tab, targetElement);
} else {
} else if (targetElement) {
targetElement.after(tab);
} else {
this.tabContainer.appendChild(tab);
}
});
}

View file

@ -19,14 +19,14 @@
* @returns {boolean}
* `true` if element is a `<tab>`
*/
const isTab = element => element.tagName == "tab";
const isTab = element => !!(element?.tagName == "tab");
/**
* @param {MozTabbrowserTab|MozTabbrowserTabGroup} element
* @returns {boolean}
* `true` if element is a `<tab-group>`
*/
const isTabGroup = element => element.tagName == "tab-group";
const isTabGroup = element => !!(element?.tagName == "tab-group");
/**
* @param {MozTabbrowserTab|MozTextLabel} element
@ -34,7 +34,7 @@
* `true` if element is the `<label>` in a `<tab-group>`
*/
const isTabGroupLabel = element =>
element.classList?.contains("tab-group-label") ?? false;
!!element?.classList?.contains("tab-group-label");
class MozTabbrowserTabs extends MozElements.TabsBase {
static observedAttributes = ["orient"];
@ -1043,7 +1043,7 @@
} else {
let isPinned = draggedTab.pinned;
let numPinned = gBrowser.pinnedTabCount;
let tabs = this.visibleTabs.slice(
let tabs = this.ariaFocusableItems.slice(
isPinned ? 0 : numPinned,
isPinned ? numPinned : undefined
);
@ -1134,7 +1134,7 @@
dropIndex++;
}
}
} else if (dropElement) {
} else {
gBrowser.dropTabs(movingTabs, dropElement, dropBefore);
}
});
@ -2498,24 +2498,29 @@
};
let dropElement = getOverlappedElement();
if (!dropElement) {
dropElement = this.ariaFocusableItems[oldDropElementIndex];
}
let newDropElementIndex = dropElement
? dropElement.elementIndex
: oldDropElementIndex;
let dropBefore = !screenForward;
let moveOverThreshold;
let firstMovingTabPos;
let dropElementScreen;
let overlapPercent;
if (dropElement) {
let dropElementForOverlap = isTabGroupLabel(dropElement)
? dropElement.parentElement
: dropElement;
let dropElementPosition = dropElementForOverlap[screenAxis];
let dropElementTabShift = getTabShift(dropElement, oldDropElementIndex);
dropElementScreen = dropElementForOverlap[screenAxis];
let dropElementSize = bounds(dropElementForOverlap)[size];
firstMovingTabPos = firstMovingTabScreen + translate;
overlapPercent = greatestOverlap(
firstMovingTabScreen + translate,
firstMovingTabPos,
shiftSize,
dropElementPosition + dropElementTabShift,
dropElementScreen + dropElementTabShift,
dropElementSize
);
@ -2526,21 +2531,31 @@
: 0.5;
moveOverThreshold = Math.min(1, Math.max(0, moveOverThreshold));
let shouldMoveOver = overlapPercent > moveOverThreshold;
if (logicalForward) {
if (shouldMoveOver) {
newDropElementIndex++;
if (logicalForward && shouldMoveOver) {
newDropElementIndex++;
} else if (!logicalForward && !shouldMoveOver) {
newDropElementIndex++;
if (newDropElementIndex > oldDropElementIndex) {
// FIXME: Not quite sure what's going on here, but this check
// prevents jittery back-and-forth movement of background tabs
// in certain cases.
return;
}
dropBefore = !shouldMoveOver;
} else {
if (!shouldMoveOver) {
newDropElementIndex++;
}
dropBefore = shouldMoveOver;
}
}
let shouldCreateGroupOnDrop;
if (dropElement && gBrowser._tabGroupsEnabled && !isPinned) {
let dropBefore;
if (dropElement) {
let dropElementPos =
dropElementScreen + getTabShift(dropElement, newDropElementIndex);
dropBefore = firstMovingTabPos < dropElementPos;
if (this.#rtlMode) {
dropBefore = !dropBefore;
}
}
if (gBrowser._tabGroupsEnabled && !isPinned) {
let dragOverGroupingThreshold =
Services.prefs.getIntPref(
"browser.tabs.groups.dragOverThresholdPercent"
@ -2555,7 +2570,7 @@
shouldCreateGroupOnDrop =
dropElement != draggedTab &&
isTab(dropElement) &&
!dropElement.group &&
!dropElement?.group &&
overlapPercent > dragOverGroupingThreshold;
if (shouldCreateGroupOnDrop) {
@ -2593,16 +2608,17 @@
if (dropBefore) {
// Dropping right before the tab group.
dropElement = dropElementGroup;
colorCode = undefined;
} else if (dropElementGroup.collapsed) {
// Dropping right after the collapsed tab group.
dropElement = dropElementGroup;
colorCode = undefined;
} else {
// Dropping right before the first tab in the tab group.
dropElement = dropElementGroup.tabs[0];
dropBefore = true;
}
}
this.#setDragOverGroupColor(colorCode);
this.toggleAttribute("movingtab-ungroup", !colorCode);
}
@ -2619,9 +2635,9 @@
}
if (
newDropElementIndex == oldDropElementIndex ||
// FIXME: This seems bogus, not sure what's going on with the indexes here:
(!logicalForward && newDropElementIndex > oldDropElementIndex)
newDropElementIndex == oldDropElementIndex &&
dropBefore == dragData.dropBefore &&
dropElement == dragData.dropElement
) {
return;
}

View file

@ -305,6 +305,7 @@ skip-if = [
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # Bug 1872477
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # Bug 1872477
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1929417
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Bug 1872477
"vertical_tab", # Bug 1936170
]
tags = "vertical-tabs"
@ -448,6 +449,7 @@ tags = "vertical-tabs"
skip-if = [
"os == 'mac' && os_version == '10.15' && processor == 'x86_64' && vertical_tab", # Bug 1938525
"os == 'mac' && os_version == '11.20' && arch == 'aarch64' && vertical_tab", # Bug 1928146
"os == 'mac' && os_version == '15.30' && arch == 'aarch64' && vertical_tab", # Bug 1928146
]
["browser_tabReorder_vertical.js"]
@ -488,6 +490,7 @@ skip-if = [
"os == 'mac' && os_version == '14.70' && processor == 'x86_64' && opt", # Bug 1929417 (secondary)
"os == 'mac' && os_version == '10.15' && processor == 'x86_64' && vertical_tab", # Bug 1928146
"os == 'mac' && os_version == '11.20' && arch == 'aarch64' && vertical_tab", # Bug 1928146
"os == 'mac' && os_version == '15.30' && arch == 'aarch64' && vertical_tab", # Bug 1928146
"win11_2009 && debug", # Bug 1928146 - frequent leaked window
"os == 'win' && os_version == '11.26100' && debug", # Bug 1928146
]
@ -538,6 +541,7 @@ tags = "vertical-tabs"
skip-if = [
"os == 'mac' && os_version == '10.15' && processor == 'x86_64' && vertical_tab", # Bug 1928146
"os == 'mac' && os_version == '11.20' && arch == 'aarch64' && vertical_tab", # Bug 1928146
"os == 'mac' && os_version == '15.30' && arch == 'aarch64' && vertical_tab", # Bug 1928146
]
["browser_tab_tooltips.js"]
@ -545,6 +549,7 @@ tags = "vertical-tabs"
skip-if = [
"os == 'mac' && os_version == '10.15' && processor == 'x86_64' && vertical_tab", # Bug 1928146
"os == 'mac' && os_version == '11.20' && arch == 'aarch64' && vertical_tab", # Bug 1928146
"os == 'mac' && os_version == '15.30' && arch == 'aarch64' && vertical_tab", # Bug 1928146
]
["browser_tabfocus.js"]
@ -608,4 +613,5 @@ tags = "vertical-tabs"
skip-if = [
"os == 'mac' && os_version == '10.15' && processor == 'x86_64' && vertical_tab", # Bug 1928146
"os == 'mac' && os_version == '11.20' && arch == 'aarch64' && vertical_tab", # Bug 1928146
"os == 'mac' && os_version == '15.30' && arch == 'aarch64' && vertical_tab", # Bug 1928146
]

View file

@ -39,7 +39,13 @@ const perfMetadata = {
lowerIsBetter: false,
},
{
name: "total-memory-usage",
name: "peak-memory-usage",
unit: "MiB",
shouldAlert: true,
lowerIsBetter: true,
},
{
name: "stabilized-memory-usage",
unit: "MiB",
shouldAlert: true,
lowerIsBetter: true,
@ -60,9 +66,9 @@ const perfMetadata = {
};
/**
* Request 2x longer timeout for this test.
* Request 4x longer timeout for this test.
*/
requestLongerTimeout(2);
requestLongerTimeout(4);
/**
* Runs the translations benchmark tests from Spanish to English.
@ -70,8 +76,10 @@ requestLongerTimeout(2);
add_task(async function test_translations_performance_es_en() {
await TranslationsBencher.benchmarkTranslation({
page: SPANISH_BENCHMARK_PAGE_URL,
runCount: 5,
sourceLanguage: "es",
targetLanguage: "en",
speedBenchCount: 5,
memoryBenchCount: 5,
memorySampleInterval: 10,
});
});

View file

@ -404,11 +404,30 @@ class TranslationsBencher {
static METRIC_TOKENS_PER_SECOND = "tokens-per-second";
/**
* The metric base name for total memory usage in the inference process.
* The metric base name for peak memory usage in the inference process.
*
* We often see a spike in memory usage when models initialize that eventually
* stabilizes as the inference process continues running. As such, it is important
* that we collect two memory metrics during our benchmarks.
*
* @see {TranslationsBencher.METRIC_STABILIZED_MEMORY_USAGE}
*
* @type {string}
*/
static METRIC_TOTAL_MEMORY_USAGE = "total-memory-usage";
static METRIC_PEAK_MEMORY_USAGE = "peak-memory-usage";
/**
* The metric base name for stabilized memory usage in the inference process.
*
* We often see a spike in memory usage when models initialize that eventually
* stabilizes as the inference process continues running. As such, it is important
* that we collect two memory metrics during our benchmarks.
*
* @see {TranslationsBencher.METRIC_PEAK_MEMORY_USAGE}
*
* @type {string}
*/
static METRIC_STABILIZED_MEMORY_USAGE = "stabilized-memory-usage";
/**
* The metric base name for total translation time.
@ -437,6 +456,12 @@ class TranslationsBencher {
* A class that gathers and reports metrics to perftest.
*/
static Journal = class {
/**
* A map of collected metrics, where the key is the metric name
* and the value is an array of all recorded values.
*
* @type {Record<string, number[]>}
*/
#metrics = {};
/**
@ -449,7 +474,8 @@ class TranslationsBencher {
if (!this.#metrics[metricName]) {
this.#metrics[metricName] = [];
}
this.#metrics[metricName].push(value);
this.#metrics[metricName].push(Number(value.toFixed(3)));
}
/**
@ -483,21 +509,122 @@ class TranslationsBencher {
};
/**
* Benchmarks the translation process and reports metrics to perftest.
* A class to track peak memory usage during translation via sampled intervals.
*/
static PeakMemorySampler = class {
/**
* The peak recorded memory in mebibytes (MiB).
*
* @type {number}
*/
#peakMemoryMiB = 0;
/**
* The interval id for the memory sample timer.
*
* @type {number|null}
*/
#intervalId = null;
/**
* The interval at which memory usage is sampled in milliseconds.
*
* @type {number}
*/
#interval;
/**
* Constructs a PeakMemorySampler.
*
* @param {number} interval - The interval in milliseconds between memory samples.
*/
constructor(interval) {
this.#interval = interval;
}
/**
* Collects the current inference process memory usage and updates
* the peak memory measurement if the current usage exceeds the previous peak.
*
* @returns {Promise<void>}
*/
async #collectMemorySample() {
const currentMemoryMiB =
await TranslationsBencher.#getInferenceProcessTotalMemoryUsage();
if (currentMemoryMiB > this.#peakMemoryMiB) {
this.#peakMemoryMiB = currentMemoryMiB;
}
}
/**
* Starts the interval timer to begin sampling a new peak memory usage.
*/
start() {
if (this.#intervalId !== null) {
throw new Error(
"Attempt to start a PeakMemorySampler that was already running."
);
}
this.#peakMemoryMiB = 0;
this.#intervalId = setInterval(() => {
this.#collectMemorySample().catch(console.error);
}, this.#interval);
}
/**
* Stops the interval timer from continuing to sample peak memory usage.
*/
stop() {
if (this.#intervalId === null) {
throw new Error(
"Attempt to stop a PeakMemorySampler that was not running."
);
}
clearInterval(this.#intervalId);
this.#intervalId = null;
this.#collectMemorySample();
}
/**
* Returns the peak recorded memory usage in mebibytes (MiB).
*
* @returns {number}
*/
getPeakRecordedMemoryUsage() {
if (this.#intervalId) {
throw new Error(
"Attempt to retrieve peak recorded memory usage while the memory sampler is running."
);
}
return this.#peakMemoryMiB;
}
};
/**
* Benchmarks the translation process (both memory usage and speed)
* and reports metrics to perftest. It runs one full translation for
* each memory sample, and then one full translation for each speed sample.
*
* @param {object} options - The benchmark options.
* @param {string} options.page - The URL of the page to test.
* @param {number} options.runCount - The number of runs to perform.
* @param {string} options.sourceLanguage - The BCP-47 language tag for the source language.
* @param {string} options.targetLanguage - The BCP-47 language tag for the target language.
* @param {number} options.speedBenchCount - The number of speed-sampling runs to perform.
* @param {number} options.memoryBenchCount - The number of memory-sampling runs to perform.
* @param {number} [options.memorySampleInterval] - The interval in milliseconds between memory usage samples.
*
* @returns {Promise<void>} Resolves when benchmarking is complete.
*/
static async benchmarkTranslation({
page,
runCount,
sourceLanguage,
targetLanguage,
speedBenchCount,
memoryBenchCount,
memorySampleInterval = 10,
}) {
const { wordCount, tokenCount, pageLanguage } =
TranslationsBencher.#PAGE_DATA[page] ?? {};
@ -540,7 +667,135 @@ class TranslationsBencher {
const journal = new TranslationsBencher.Journal();
for (let runNumber = 0; runNumber < runCount; ++runNumber) {
await TranslationsBencher.#benchmarkTranslationMemory({
page,
journal,
sourceLanguage,
targetLanguage,
memoryBenchCount,
memorySampleInterval,
});
await TranslationsBencher.#benchmarkTranslationSpeed({
page,
journal,
sourceLanguage,
targetLanguage,
wordCount,
tokenCount,
speedBenchCount,
});
journal.reportMetrics();
}
/**
* Benchmarks memory usage by measuring peak and stabilized memory usage
* across multiple runs of the translation process.
*
* @param {object} options - The benchmark options.
* @param {string} options.page - The URL of the page to test.
* @param {TranslationsBencher.Journal} options.journal - The shared metrics journal.
* @param {string} options.sourceLanguage - The BCP-47 language tag for the source language.
* @param {string} options.targetLanguage - The BCP-47 language tag for the target language.
* @param {number} options.memoryBenchCount - The number of runs to perform for memory sampling.
* @param {number} options.memorySampleInterval - The interval in milliseconds between memory samples.
*
* @returns {Promise<void>} Resolves when memory benchmarking is complete.
*/
static async #benchmarkTranslationMemory({
page,
journal,
sourceLanguage,
targetLanguage,
memoryBenchCount,
memorySampleInterval,
}) {
for (let runNumber = 0; runNumber < memoryBenchCount; ++runNumber) {
const { cleanup, runInPage } = await loadTestPage({
page,
endToEndTest: true,
languagePairs: [
{ fromLang: sourceLanguage, toLang: "en" },
{ fromLang: "en", toLang: targetLanguage },
],
prefs: [["browser.translations.logLevel", "Error"]],
});
// Create a new PeakMemorySampler using the provided interval.
const peakMemorySampler = new TranslationsBencher.PeakMemorySampler(
memorySampleInterval
);
await TranslationsBencher.#injectTranslationCompleteObserver(runInPage);
await FullPageTranslationsTestUtils.assertTranslationsButton(
{ button: true, circleArrows: false, locale: false, icon: true },
"The button is available."
);
await FullPageTranslationsTestUtils.openPanel({
onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault,
});
await FullPageTranslationsTestUtils.changeSelectedFromLanguage({
langTag: sourceLanguage,
});
await FullPageTranslationsTestUtils.changeSelectedToLanguage({
langTag: targetLanguage,
});
const translationCompleteTimestampPromise =
TranslationsBencher.#getTranslationCompleteTimestampPromise(runInPage);
peakMemorySampler.start();
await FullPageTranslationsTestUtils.clickTranslateButton();
await translationCompleteTimestampPromise;
peakMemorySampler.stop();
const peakMemoryMiB = peakMemorySampler.getPeakRecordedMemoryUsage();
const stabilizedMemoryMiB =
await TranslationsBencher.#getInferenceProcessTotalMemoryUsage();
journal.pushMetrics([
[TranslationsBencher.METRIC_PEAK_MEMORY_USAGE, peakMemoryMiB],
[
TranslationsBencher.METRIC_STABILIZED_MEMORY_USAGE,
stabilizedMemoryMiB,
],
]);
await cleanup();
}
}
/**
* Benchmarks speed by measuring engine init time, words per second, tokens per second,
* and total translation time across multiple runs.
*
* @param {object} options - The benchmark options.
* @param {string} options.page - The URL of the page to test.
* @param {TranslationsBencher.Journal} options.journal - The shared metrics journal.
* @param {string} options.sourceLanguage - The BCP-47 language tag for the source language.
* @param {string} options.targetLanguage - The BCP-47 language tag for the target language.
* @param {number} options.wordCount - The total word count of the page.
* @param {number} options.tokenCount - The total token count of the page.
* @param {number} options.speedBenchCount - The number of runs to perform for speed sampling.
*
* @returns {Promise<void>} Resolves when speed benchmarking is complete.
*/
static async #benchmarkTranslationSpeed({
page,
journal,
sourceLanguage,
targetLanguage,
wordCount,
tokenCount,
speedBenchCount,
}) {
for (let runNumber = 0; runNumber < speedBenchCount; ++runNumber) {
const { tab, cleanup, runInPage } = await loadTestPage({
page,
endToEndTest: true,
@ -589,37 +844,18 @@ class TranslationsBencher {
const wordsPerSecond = wordCount / translationTimeSeconds;
const tokensPerSecond = tokenCount / translationTimeSeconds;
const totalMemoryMB =
await TranslationsBencher.#getInferenceProcessTotalMemoryUsage();
const decimalPrecision = 3;
journal.pushMetrics([
[
TranslationsBencher.METRIC_ENGINE_INIT_TIME,
Number(initTimeMilliseconds.toFixed(decimalPrecision)),
],
[
TranslationsBencher.METRIC_WORDS_PER_SECOND,
Number(wordsPerSecond.toFixed(decimalPrecision)),
],
[
TranslationsBencher.METRIC_TOKENS_PER_SECOND,
Number(tokensPerSecond.toFixed(decimalPrecision)),
],
[
TranslationsBencher.METRIC_TOTAL_MEMORY_USAGE,
Number(totalMemoryMB.toFixed(decimalPrecision)),
],
[TranslationsBencher.METRIC_ENGINE_INIT_TIME, initTimeMilliseconds],
[TranslationsBencher.METRIC_WORDS_PER_SECOND, wordsPerSecond],
[TranslationsBencher.METRIC_TOKENS_PER_SECOND, tokensPerSecond],
[
TranslationsBencher.METRIC_TOTAL_TRANSLATION_TIME,
Number(translationTimeSeconds.toFixed(decimalPrecision)),
translationTimeSeconds,
],
]);
await cleanup();
}
journal.reportMetrics();
}
/**
@ -702,43 +938,13 @@ class TranslationsBencher {
}
/**
* Returns the total memory used by the inference process in megabytes.
* Returns the total memory used by the inference process in mebibytes (MiB).
*
* @returns {Promise<number>} The total memory usage in megabytes.
* @returns {Promise<number>} The total memory usage in mebibytes.
*/
static async #getInferenceProcessTotalMemoryUsage() {
let memoryReporterManager = Cc[
"@mozilla.org/memory-reporter-manager;1"
].getService(Ci.nsIMemoryReporterManager);
let totalBytes = 0;
const handleReport = (
aProcess,
aPath,
_aKind,
_aUnits,
aAmount,
_aDescription
) => {
if (aProcess.startsWith("inference")) {
if (aPath.startsWith("explicit")) {
totalBytes += aAmount;
}
}
};
await new Promise(resolve =>
memoryReporterManager.getReports(
handleReport,
null, // handleReportData
resolve, // finishReporting
null, // finishReportingData
false // anonymized
)
);
return bytesToMebibytes(totalBytes);
const inferenceProcessInfo = await fetchInferenceProcessInfo();
return bytesToMebibytes(inferenceProcessInfo.memory);
}
}

View file

@ -20,9 +20,6 @@ const SEARCH_PARAMS = {
const SESSION_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
const HISTOGRAM_LATENCY = "FX_URLBAR_MERINO_LATENCY_MS";
const HISTOGRAM_RESPONSE = "FX_URLBAR_MERINO_RESPONSE";
/**
* Client class for querying the Merino server. Each instance maintains its own
* session state including a session ID and sequence number that is included in
@ -116,8 +113,7 @@ export class MerinoClient {
/**
* @returns {string}
* A string that indicates the status of the last fetch. The values are the
* same as the labels used in the `FX_URLBAR_MERINO_RESPONSE` histogram:
* A string that indicates the status of the last fetch. Possible values:
* success, timeout, network_error, http_error
*/
get lastFetchStatus() {
@ -139,12 +135,6 @@ export class MerinoClient {
* Timeout in milliseconds. This method will return once the timeout
* elapses, a response is received, or an error occurs, whichever happens
* first.
* @param {string} options.extraLatencyHistogram
* If specified, the fetch's latency will be recorded in this histogram in
* addition to the usual Merino latency histogram.
* @param {string} options.extraResponseHistogram
* If specified, the fetch's response will be recorded in this histogram in
* addition to the usual Merino response histogram.
* @param {object} options.otherParams
* If specified, the otherParams will be added as a query params. Currently
* used for accuweather's location autocomplete endpoint
@ -156,8 +146,6 @@ export class MerinoClient {
query,
providers = null,
timeoutMs = lazy.UrlbarPrefs.get("merinoTimeoutMs"),
extraLatencyHistogram = null,
extraResponseHistogram = null,
otherParams = {},
}) {
this.logger.debug("Fetch start", { query });
@ -257,12 +245,6 @@ export class MerinoClient {
let recordResponse = category => {
this.logger.debug("Fetch done", { status: category });
Services.telemetry.getHistogramById(HISTOGRAM_RESPONSE).add(category);
if (extraResponseHistogram) {
Services.telemetry
.getHistogramById(extraResponseHistogram)
.add(category);
}
this.#lastFetchStatus = category;
recordResponse = null;
};
@ -291,11 +273,6 @@ export class MerinoClient {
// Do the fetch.
let response;
let controller = (this.#fetchController = new AbortController());
let stopwatchInstance = (this.#latencyStopwatchInstance = {});
TelemetryStopwatch.start(HISTOGRAM_LATENCY, stopwatchInstance);
if (extraLatencyHistogram) {
TelemetryStopwatch.start(extraLatencyHistogram, stopwatchInstance);
}
await Promise.race([
timer.promise,
(async () => {
@ -309,10 +286,6 @@ export class MerinoClient {
// the response from this inner function and assuming it will also be
// returned by `Promise.race`.
response = await fetch(url, { signal: controller.signal });
TelemetryStopwatch.finish(HISTOGRAM_LATENCY, stopwatchInstance);
if (extraLatencyHistogram) {
TelemetryStopwatch.finish(extraLatencyHistogram, stopwatchInstance);
}
this.logger.debug("Got response", {
status: response.status,
...details,
@ -321,10 +294,6 @@ export class MerinoClient {
recordResponse?.("http_error");
}
} catch (error) {
TelemetryStopwatch.cancel(HISTOGRAM_LATENCY, stopwatchInstance);
if (extraLatencyHistogram) {
TelemetryStopwatch.cancel(extraLatencyHistogram, stopwatchInstance);
}
if (error.name != "AbortError") {
this.logger.error("Fetch error", error);
recordResponse?.("network_error");
@ -449,10 +418,6 @@ export class MerinoClient {
return this.#fetchController;
}
get _test_latencyStopwatchInstance() {
return this.#latencyStopwatchInstance;
}
// State related to the current session.
#sessionID = null;
#sequenceNumber = 0;
@ -462,7 +427,6 @@ export class MerinoClient {
#name;
#timeoutTimer = null;
#fetchController = null;
#latencyStopwatchInstance = null;
#lastFetchStatus = null;
#nextResponseDeferred = null;
#nextSessionResetDeferred = null;

View file

@ -5,7 +5,6 @@
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
Region: "resource://gre/modules/Region.sys.mjs",
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.sys.mjs",
@ -42,22 +41,6 @@ const FEATURES = {
YelpSuggestions: "resource:///modules/urlbar/private/YelpSuggestions.sys.mjs",
};
// Values returned by the onboarding dialog depending on the user's response.
// These values are used in telemetry events, so be careful about changing them.
const ONBOARDING_CHOICE = {
ACCEPT_2: "accept_2",
CLOSE_1: "close_1",
DISMISS_1: "dismiss_1",
DISMISS_2: "dismiss_2",
LEARN_MORE_1: "learn_more_1",
LEARN_MORE_2: "learn_more_2",
NOT_NOW_2: "not_now_2",
REJECT_2: "reject_2",
};
const ONBOARDING_URI =
"chrome://browser/content/urlbar/quicksuggestOnboarding.html";
/**
* This class manages Firefox Suggest and has related helpers.
*/
@ -124,14 +107,6 @@ class _QuickSuggest {
};
}
get ONBOARDING_CHOICE() {
return { ...ONBOARDING_CHOICE };
}
get ONBOARDING_URI() {
return ONBOARDING_URI;
}
/**
* @returns {Promise}
* Resolved when Suggest initialization finishes.
@ -441,105 +416,6 @@ class _QuickSuggest {
: url == result.payload.url;
}
/**
* An onboarding dialog can be shown to the users who are enrolled into
* the Suggest experiments or rollouts. This behavior is controlled
* by the pref `browser.urlbar.quicksuggest.shouldShowOnboardingDialog`
* which can be remotely configured by Nimbus.
*
* Given that the release may overlap with another onboarding dialog, we may
* wait for a few restarts before showing the Suggest dialog. This can
* be remotely configured by Nimbus through
* `quickSuggestShowOnboardingDialogAfterNRestarts`, the default is 0.
*
* @returns {boolean}
* True if the dialog was shown and false if not.
*/
async maybeShowOnboardingDialog() {
// The call to this method races initialization, and the Nimbus variables we
// rely on below depend on init, so wait for it.
await this.initPromise;
// If the feature is disabled, the user has already seen the dialog, or the
// user has already opted in, don't show the onboarding.
if (
!lazy.UrlbarPrefs.get("quickSuggestEnabled") ||
lazy.UrlbarPrefs.get("quicksuggest.showedOnboardingDialog") ||
lazy.UrlbarPrefs.get("quicksuggest.dataCollection.enabled")
) {
return false;
}
// Wait a number of restarts before showing the dialog.
let restartsSeen = lazy.UrlbarPrefs.get("quicksuggest.seenRestarts");
if (
restartsSeen <
lazy.UrlbarPrefs.get("quickSuggestShowOnboardingDialogAfterNRestarts")
) {
lazy.UrlbarPrefs.set("quicksuggest.seenRestarts", restartsSeen + 1);
return false;
}
let win = lazy.BrowserWindowTracker.getTopWindow();
// Don't show the dialog on top of about:welcome for new users.
if (win.gBrowser?.currentURI?.spec == "about:welcome") {
return false;
}
if (
!lazy.UrlbarPrefs.get("quickSuggestShouldShowOnboardingDialog") ||
lazy.UrlbarPrefs.get("quicksuggest.contextualOptIn")
) {
return false;
}
let variationType;
try {
// An error happens if the pref is not in user prefs.
variationType = lazy.UrlbarPrefs.get(
"quickSuggestOnboardingDialogVariation"
).toLowerCase();
} catch (e) {}
let params = { choice: undefined, variationType, visitedMain: false };
await win.gDialogBox.open(ONBOARDING_URI, params);
lazy.UrlbarPrefs.set("quicksuggest.showedOnboardingDialog", true);
lazy.UrlbarPrefs.set(
"quicksuggest.onboardingDialogVersion",
JSON.stringify({ version: 1, variation: variationType })
);
// Record the user's opt-in choice on the user branch. This pref is sticky,
// so it will retain its user-branch value regardless of what the particular
// default was at the time.
let optedIn = params.choice == ONBOARDING_CHOICE.ACCEPT_2;
lazy.UrlbarPrefs.set("quicksuggest.dataCollection.enabled", optedIn);
switch (params.choice) {
case ONBOARDING_CHOICE.LEARN_MORE_1:
case ONBOARDING_CHOICE.LEARN_MORE_2:
win.openTrustedLinkIn(this.HELP_URL, "tab");
break;
case ONBOARDING_CHOICE.ACCEPT_2:
case ONBOARDING_CHOICE.REJECT_2:
case ONBOARDING_CHOICE.NOT_NOW_2:
case ONBOARDING_CHOICE.CLOSE_1:
// No other action required.
break;
default:
params.choice = params.visitedMain
? ONBOARDING_CHOICE.DISMISS_2
: ONBOARDING_CHOICE.DISMISS_1;
break;
}
lazy.UrlbarPrefs.set("quicksuggest.onboardingDialogChoice", params.choice);
return true;
}
/**
* Sets appropriate default-branch values of Suggest prefs depending on
* whether Suggest should be enabled by default.

View file

@ -1484,8 +1484,10 @@ export class UrlbarInput {
// like transforming a url into a search.
// This choice also makes it easier to copy the full url of a result.
// For autofilled results, the value that should be canonized is not the
// autofilled value but the value that the user typed.
// We are supporting canonization of any result, in particular this allows
// for single word search suggestions to be converted to a .com URL.
// For autofilled results, the value to canonize is the user typed string,
// not the autofilled value.
let canonizedUrl = this._maybeCanonizeURL(
event,
result.autofill ? this._lastSearchString : this.value
@ -3009,6 +3011,22 @@ export class UrlbarInput {
: trimmedValue;
}
/**
* Returns whether the passed-in event may represents a canonization request.
*
* @param {DOMEvent} event a KeyboardEvent to examine.
* @returns {boolean} Whether the event is a canonization one.
*/
#isCanonizeKeyboardEvent(event) {
return (
KeyboardEvent.isInstance(event) &&
event.keyCode == KeyEvent.DOM_VK_RETURN &&
(AppConstants.platform == "macosx" ? event.metaKey : event.ctrlKey) &&
!event._disableCanonization &&
lazy.UrlbarPrefs.get("ctrlCanonizesURLs")
);
}
/**
* If appropriate, this prefixes a search string with 'www.' and suffixes it
* with browser.fixup.alternate.suffix prior to navigating.
@ -3024,10 +3042,7 @@ export class UrlbarInput {
// Only add the suffix when the URL bar value isn't already "URL-like",
// and only if we get a keyboard event, to match user expectations.
if (
!KeyboardEvent.isInstance(event) ||
event._disableCanonization ||
!event.ctrlKey ||
!lazy.UrlbarPrefs.get("ctrlCanonizesURLs") ||
!this.#isCanonizeKeyboardEvent(event) ||
!/^\s*[^.:\/\s]+(?:\/.*|\s*)$/i.test(value)
) {
return null;
@ -3341,13 +3356,9 @@ export class UrlbarInput {
// We support using 'alt' to open in a tab, because ctrl/shift
// might be used for canonizing URLs:
where = event.shiftKey ? "tabshifted" : "tab";
} else if (
isKeyboardEvent &&
event.ctrlKey &&
lazy.UrlbarPrefs.get("ctrlCanonizesURLs")
) {
// If we're allowing canonization, and this is a key event with ctrl
// pressed, open in current tab to allow ctrl-enter to canonize URL.
} else if (this.#isCanonizeKeyboardEvent(event)) {
// If we're allowing canonization, and this is a canonization key event,
// open in current tab to avoid handling as new tab modifier.
where = "current";
} else {
where = lazy.BrowserUtils.whereToOpenLink(event, false, false);
@ -4028,6 +4039,8 @@ export class UrlbarInput {
this._keyDownEnterDeferred = null;
}
this._isKeyDownWithCtrl = false;
this._isKeyDownWithMeta = false;
this._isKeyDownWithMetaAndLeft = false;
Services.obs.notifyObservers(null, "urlbar-blur");
}
@ -4581,20 +4594,32 @@ export class UrlbarInput {
if (!event.repeat) {
this.#allTextSelectedOnKeyDown = this.#allTextSelected;
this._isKeyDownWithMetaAndLeft =
event.keyCode == KeyEvent.DOM_VK_LEFT &&
event.metaKey &&
!event.shiftKey;
if (event.keyCode === KeyEvent.DOM_VK_RETURN) {
if (this._keyDownEnterDeferred) {
this._keyDownEnterDeferred.reject();
}
this._keyDownEnterDeferred = Promise.withResolvers();
event._disableCanonization = this._isKeyDownWithCtrl;
} else if (event.keyCode !== KeyEvent.DOM_VK_CONTROL && event.ctrlKey) {
event._disableCanonization =
AppConstants.platform == "macosx"
? this._isKeyDownWithMeta
: this._isKeyDownWithCtrl;
}
// Now set the keydown trackers for the current event, anything that wants
// to check the previous events should have happened before this point.
// The previously value is persisted until keyup, as we check if the
// modifiers were down, even if other keys are pressed in the meanwhile.
if (event.ctrlKey && event.keyCode != KeyEvent.DOM_VK_CONTROL) {
this._isKeyDownWithCtrl = true;
}
if (event.metaKey && event.keyCode != KeyEvent.DOM_VK_META) {
this._isKeyDownWithMeta = true;
}
// This is used in keyup, so it can be set every time.
this._isKeyDownWithMetaAndLeft =
this._isKeyDownWithMeta &&
!event.shiftKey &&
event.keyCode == KeyEvent.DOM_VK_LEFT;
this._toggleActionOverride(event);
}
@ -4631,6 +4656,7 @@ export class UrlbarInput {
this.#maybeUntrimUrl({ moveCursorToStart });
}
if (event.keyCode === KeyEvent.DOM_VK_META) {
this._isKeyDownWithMeta = false;
this._isKeyDownWithMetaAndLeft = false;
}
if (event.keyCode === KeyEvent.DOM_VK_CONTROL) {

View file

@ -238,8 +238,7 @@ const PREF_URLBAR_DEFAULTS = new Map([
// JSON'ed array of blocked quick suggest URL digests.
["quicksuggest.blockedDigests", ""],
// Whether the Firefox Suggest data collection opt-in result is enabled. If
// true, this implicitly disables shouldShowOnboardingDialog.
// Whether the Firefox Suggest data collection opt-in result is enabled.
["quicksuggest.contextualOptIn", false],
// The last time (as ISO string) the user dismissed the Firefox Suggest
@ -268,9 +267,6 @@ const PREF_URLBAR_DEFAULTS = new Map([
// Comma-separated list of Suggest exposure suggestion types to enable.
["quicksuggest.exposureSuggestionTypes", ""],
// Whether Suggest should be hidden in the settings UI even when enabled.
["quicksuggest.hideSettingsUI", false],
// Whether non-sponsored quick suggest results are subject to impression
// frequency caps. This pref is a fallback for the Nimbus variable
// `quickSuggestImpressionCapsNonSponsoredEnabled`.
@ -307,12 +303,6 @@ const PREF_URLBAR_DEFAULTS = new Map([
// Whether Suggest will use the ML backend in addition to Rust.
["quicksuggest.mlEnabled", false],
// The user's response to the Firefox Suggest online opt-in dialog.
["quicksuggest.onboardingDialogChoice", ""],
// The version of dialog user saw.
["quicksuggest.onboardingDialogVersion", ""],
// Whether Firefox Suggest will use the new Rust backend instead of the
// original JS backend.
["quicksuggest.rustEnabled", true],
@ -323,15 +313,6 @@ const PREF_URLBAR_DEFAULTS = new Map([
// the interval used by the desktop remote settings client.
["quicksuggest.rustIngestIntervalSeconds", 60 * 60 * 24],
// Count the restarts before showing the onboarding dialog.
["quicksuggest.seenRestarts", 0],
// Whether to show the quick suggest onboarding dialog.
["quicksuggest.shouldShowOnboardingDialog", false],
// Whether the user has seen the onboarding dialog.
["quicksuggest.showedOnboardingDialog", false],
// We only show recent searches within the past 3 days by default.
// Stored as a string as some code handle timestamp sized int's.
["recentsearches.expirationMs", (1000 * 60 * 60 * 24 * 3).toString()],

View file

@ -1,311 +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/. */
/**
* When making changes, follow the example of the AboutWelcome messaging surface for font sizes, line heights,
* etc. See: https://searchfox.org/mozilla-central/source/browser/components/aboutwelcome/content-src/aboutwelcome.scss
*/
:root {
--introduction-magglass-logo-height: 128px;
--introduction-firefox-logo-height: 72px;
--introduction-image-height: 224px;
--main-magglass-logo-height: 64px;
--main-firefox-logo-height: 50px;
--x-large-margin: 40px;
--large-margin: 24px;
--large-margin-const: 24px;
--small-margin: 16px;
--small-margin-const: 16px;
--x-small-margin-const: 8px;
--section-vertical-padding: 32px;
--section-horizontal-padding: 64px;
}
body.compact {
--introduction-image-height: 183px;
--main-magglass-logo-height: 48px;
--main-firefox-logo-height: 32px;
--x-large-margin: 20px;
--large-margin: 12px;
--small-margin: 8px;
--section-vertical-padding: 16px;
--section-horizontal-padding: 32px;
/* 15px is the non-compact font-size. */
font-size: 13px;
}
body,
section {
width: 536px;
}
section {
display: flex;
align-items: stretch;
justify-content: center;
flex-direction: column;
text-align: center;
padding: var(--section-vertical-padding) var(--section-horizontal-padding);
/* This is the largest approximate natural height of the main section across
platforms and dialog variations, erring on the side of being slightly
larger than necessary. If you change this, also update COMPACT_MODE_HEIGHT
in the JS. */
min-height: 650px;
}
body.compact section {
/* This is the largest approximate natural height of the main section across
platforms and dialog variations in compact mode, erring on the side of
being slightly larger than necessary. */
min-height: 510px;
}
a {
cursor: pointer;
font-weight: normal;
}
.title {
font-size: 1.6em;
font-weight: 600;
line-height: 1.5;
white-space: pre-line;
}
.logo {
background-repeat: no-repeat;
background-position: center;
background-size: contain;
border: none;
}
.description-section {
/* The effective visual margin between the description and first option should
be --large-margin-const. Each child in the description has a bottom margin
of --small-margin, so subtract it from --large-margin-const. */
margin-block: 0 calc(var(--large-margin-const) - var(--small-margin));
}
.description {
font-size: 1.1em;
font-weight: 400;
line-height: 1.6;
margin-block: 0 var(--small-margin);
white-space: pre-line;
}
.privacy-first {
font-size: 1.1em;
font-weight: 700;
margin-block: 0 var(--small-margin);
}
.pager > span {
display: inline-block;
border-radius: 3px;
width: 6px;
height: 6px;
background-color: var(--in-content-border-color);
margin-inline: 4px;
}
.pager > .current {
background-color: var(--in-content-primary-button-background);
}
#introduction-section .logo {
background-image: url("quicksuggestOnboarding_magglass.svg");
height: var(--introduction-magglass-logo-height);
margin-block-end: var(--large-margin);
}
#introduction-section .logo.firefox {
background-image: url("chrome://branding/content/about-logo.svg");
height: var(--introduction-firefox-logo-height);
}
@media (prefers-reduced-motion: no-preference) {
#introduction-section .logo {
background-image: url("quicksuggestOnboarding_magglass_animation.svg");
}
}
#introduction-section .title {
margin-block-end: var(--x-large-margin);
}
#introduction-image {
height: var(--introduction-image-height);
background-image: url("suggest-example.svg");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
margin-block: var(--large-margin);
}
/* fx100 layout */
#introduction-section.layout-100 .logo {
height: var(--main-firefox-logo-height);
}
#introduction-section.layout-100 .title {
margin-block: 0 var(--small-margin);
}
#introduction-section:not(.layout-100) .description-section {
display: none;
}
#onboardingClose {
position: absolute;
top: 0;
inset-inline-end: 0;
margin: 16px;
padding: 0;
line-height: 0;
min-width: 20px;
min-height: 20px;
}
#onboardingClose img {
-moz-context-properties: fill;
fill: currentColor;
}
#main-section:not(.active) {
display: none;
}
#main-section .logo {
background-image: url("quicksuggestOnboarding_magglass.svg");
height: var(--main-magglass-logo-height);
margin-block-end: var(--large-margin);
}
#main-section .logo.firefox {
background-image: url("chrome://branding/content/about-logo.svg");
height: var(--main-firefox-logo-height);
}
#main-section .title {
margin-block: 0 var(--small-margin);
}
#main-section .privacy-first:not(.active) {
display: none;
}
#main-section .option {
border-radius: 4px;
border: 2px solid var(--in-content-box-info-background);
display: flex;
text-align: start;
/* Use --small-margin-const for the horizontal padding to make the option's
horizontal padding larger than the vertical padding in compact mode. The
radio button and text are too close to the left and right edges of the
option's border otherwise. */
padding: var(--small-margin) var(--small-margin-const);
flex-direction: row;
}
#main-section .option.selected {
border-color: var(--in-content-primary-button-background);
}
#main-section .option.accept {
margin-block-end: var(--small-margin);
}
#main-section .option.reject {
margin-block-end: var(--large-margin-const);
}
#main-section .option > label {
/* Make the whole option area selectable for the radio button. 22px is the
width of the radio button and its inline margin. */
padding-block: var(--small-margin);
padding-inline-start: calc(22px + var(--small-margin-const));
padding-inline-end: var(--small-margin-const);
margin-block: calc(-1 * var(--small-margin));
margin-inline-start: calc(-1 * (22px + var(--small-margin-const)));
margin-inline-end: calc(-1 * var(--small-margin-const));
}
body:not(.compact) #main-section .option > input {
/* Vertically align the radio button with the .option-label. */
margin-block-start: 0.25em;
}
#main-section .option-label {
font-size: 1.1em;
font-weight: 600;
margin-block-end: 2px;
}
#main-section .option-description {
font-size: 1em;
}
.buttonBox {
display: flex;
flex-direction: column;
align-items: center;
}
button {
margin-block-end: var(--large-margin);
}
#onboardingSkipLink {
margin-block-end: var(--x-small-margin-const);
}
/* transition from introduction to main */
#introduction-section.inactive {
/* Avoid including this section size */
position: fixed;
pointer-events: none;
animation: fadeout 0.3s forwards;
}
#main-section.active {
animation: fadein 0.3s forwards;
}
@keyframes fadeout {
0% {
opacity: 1;
}
100% {
visibility: hidden;
opacity: 0;
}
}
@keyframes fadein {
0% {
opacity: 0;
}
100% {
pointer-events: initial;
opacity: 1;
}
}
/* Show main only without transition */
body.skip-introduction #introduction-section.inactive {
animation: none;
display: none;
}
body.skip-introduction #main-section.active {
animation: none;
pointer-events: initial;
}
body.skip-introduction .pager {
display: none;
}

View file

@ -1,109 +0,0 @@
<!DOCTYPE html>
<!-- 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/. -->
<html>
<head>
<meta http-equiv="Content-Security-Policy"
content="default-src chrome:; object-src 'none'">
<meta name="referrer" content="no-referrer">
<link rel="stylesheet" type="text/css"
href="chrome://global/skin/in-content/common.css">
<link rel="stylesheet" type="text/css"
href="chrome://browser/content/urlbar/quicksuggestOnboarding.css">
<link rel="localization" href="branding/brand.ftl">
<link rel="localization" href="toolkit/branding/brandings.ftl"/>
<link rel="localization" href="preview/enUS-searchFeatures.ftl">
<script src="chrome://browser/content/urlbar/quicksuggestOnboarding.js"></script>
</head>
<body id="onboardingDialog" role="dialog" aria-labelledby="introduction-title">
<section id="introduction-section">
<button id="onboardingClose"
class="ghost-button"
tabindex="3"
data-l10n-id="firefox-suggest-onboarding-introduction-close-button">
<img src="chrome://global/skin/icons/close.svg" />
</button>
<span class="logo" role="presentation"></span>
<h1 id="introduction-title" class="title"></h1>
<div class="description-section">
<h2 id="introduction-description"
class="description"
tabindex="-1"
data-l10n-id="firefox-suggest-onboarding-main-description-9">
<a id="onboardingLearnMoreOnIntroduction"
tabindex="2"
data-l10n-name="learn-more-link"></a>
</h2>
<h3 id="introduction-privacy-first"
class="privacy-first"
tabindex="-1"
data-l10n-id="firefox-suggest-onboarding-main-privacy-first"></h2>
<div id="introduction-image" role="presentation"></div>
</div>
<div class="buttonBox">
<button id="onboardingNext" class="primary" tabindex="1"></button>
<div class="pager">
<span class="current"></span>
<span></span>
</div>
</div>
</section>
<section id="main-section">
<span class="logo" role="presentation"></span>
<h1 id="main-title" class="title"></h1>
<div class="description-section">
<h2 id="main-description" class="description" tabindex="-1">
<a id="onboardingLearnMore"
tabindex="4"
data-l10n-name="learn-more-link"></a>
</h2>
<h3 id="main-privacy-first"
class="privacy-first"
tabindex="-1"
data-l10n-id="firefox-suggest-onboarding-main-privacy-first"></h2>
</div>
<div class="option accept">
<input id="onboardingAccept"
type="radio"
tabindex="5"
name="search-experience"></input>
<label for="onboardingAccept">
<div id="main-accept-option-label" class="option-label">
<a id="onboardingLearnMore"
tabindex="6"
data-l10n-name="learn-more-link"></a>
</div>
<div id="main-accept-option-description" class="option-description"></div>
</label>
</div>
<div class="option reject">
<input id="onboardingReject"
type="radio"
tabindex="7"
name="search-experience"></input>
<label for="onboardingReject">
<div id="main-reject-option-label" class="option-label">
</div>
<div id="main-reject-option-description" class="option-description"></div>
</label>
</div>
<div class="buttonBox">
<button id="onboardingSubmit"
class="primary"
disabled="true"
tabindex="8"
data-l10n-id="firefox-suggest-onboarding-main-submit-button"></button>
<a id="onboardingSkipLink"
tabindex="9"
data-l10n-id="firefox-suggest-onboarding-main-skip-link"></a>
<div class="pager">
<span></span>
<span class="current"></span>
</div>
</div>
</section>
</body>
</html>

View file

@ -1,338 +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/. */
"use strict";
const { QuickSuggest } = ChromeUtils.importESModule(
"resource:///modules/QuickSuggest.sys.mjs"
);
const { ONBOARDING_CHOICE } = QuickSuggest;
const VARIATION_MAP = {
a: {
l10nUpdates: {
onboardingNext: "firefox-suggest-onboarding-introduction-next-button-1",
"introduction-title": "firefox-suggest-onboarding-introduction-title-1",
"main-title": "firefox-suggest-onboarding-main-title-1",
"main-description": "firefox-suggest-onboarding-main-description-1",
"main-accept-option-label":
"firefox-suggest-onboarding-main-accept-option-label",
"main-accept-option-description":
"firefox-suggest-onboarding-main-accept-option-description-1",
"main-reject-option-label":
"firefox-suggest-onboarding-main-reject-option-label",
"main-reject-option-description":
"firefox-suggest-onboarding-main-reject-option-description-1",
},
},
b: {
l10nUpdates: {
onboardingNext: "firefox-suggest-onboarding-introduction-next-button-1",
"introduction-title": "firefox-suggest-onboarding-introduction-title-2",
"main-title": "firefox-suggest-onboarding-main-title-2",
"main-description": "firefox-suggest-onboarding-main-description-2",
"main-accept-option-label":
"firefox-suggest-onboarding-main-accept-option-label",
"main-accept-option-description":
"firefox-suggest-onboarding-main-accept-option-description-1",
"main-reject-option-label":
"firefox-suggest-onboarding-main-reject-option-label",
"main-reject-option-description":
"firefox-suggest-onboarding-main-reject-option-description-1",
},
},
c: {
logoType: "firefox",
l10nUpdates: {
onboardingNext: "firefox-suggest-onboarding-introduction-next-button-1",
"introduction-title": "firefox-suggest-onboarding-introduction-title-3",
"main-title": "firefox-suggest-onboarding-main-title-3",
"main-description": "firefox-suggest-onboarding-main-description-3",
"main-accept-option-label":
"firefox-suggest-onboarding-main-accept-option-label",
"main-accept-option-description":
"firefox-suggest-onboarding-main-accept-option-description-1",
"main-reject-option-label":
"firefox-suggest-onboarding-main-reject-option-label",
"main-reject-option-description":
"firefox-suggest-onboarding-main-reject-option-description-1",
},
},
d: {
l10nUpdates: {
onboardingNext: "firefox-suggest-onboarding-introduction-next-button-1",
"introduction-title": "firefox-suggest-onboarding-introduction-title-4",
"main-title": "firefox-suggest-onboarding-main-title-4",
"main-description": "firefox-suggest-onboarding-main-description-4",
"main-accept-option-label":
"firefox-suggest-onboarding-main-accept-option-label",
"main-accept-option-description":
"firefox-suggest-onboarding-main-accept-option-description-2",
"main-reject-option-label":
"firefox-suggest-onboarding-main-reject-option-label",
"main-reject-option-description":
"firefox-suggest-onboarding-main-reject-option-description-2",
},
},
e: {
logoType: "firefox",
l10nUpdates: {
onboardingNext: "firefox-suggest-onboarding-introduction-next-button-1",
"introduction-title": "firefox-suggest-onboarding-introduction-title-5",
"main-title": "firefox-suggest-onboarding-main-title-5",
"main-description": "firefox-suggest-onboarding-main-description-5",
"main-accept-option-label":
"firefox-suggest-onboarding-main-accept-option-label",
"main-accept-option-description":
"firefox-suggest-onboarding-main-accept-option-description-2",
"main-reject-option-label":
"firefox-suggest-onboarding-main-reject-option-label",
"main-reject-option-description":
"firefox-suggest-onboarding-main-reject-option-description-2",
},
},
f: {
l10nUpdates: {
onboardingNext: "firefox-suggest-onboarding-introduction-next-button-2",
"introduction-title": "firefox-suggest-onboarding-introduction-title-6",
"main-title": "firefox-suggest-onboarding-main-title-6",
"main-description": "firefox-suggest-onboarding-main-description-6",
"main-accept-option-label":
"firefox-suggest-onboarding-main-accept-option-label",
"main-accept-option-description":
"firefox-suggest-onboarding-main-accept-option-description-2",
"main-reject-option-label":
"firefox-suggest-onboarding-main-reject-option-label",
"main-reject-option-description":
"firefox-suggest-onboarding-main-reject-option-description-2",
},
},
g: {
mainPrivacyFirst: true,
l10nUpdates: {
onboardingNext: "firefox-suggest-onboarding-introduction-next-button-1",
"introduction-title": "firefox-suggest-onboarding-introduction-title-7",
"main-title": "firefox-suggest-onboarding-main-title-7",
"main-description": "firefox-suggest-onboarding-main-description-7",
"main-accept-option-label":
"firefox-suggest-onboarding-main-accept-option-label",
"main-accept-option-description":
"firefox-suggest-onboarding-main-accept-option-description-2",
"main-reject-option-label":
"firefox-suggest-onboarding-main-reject-option-label",
"main-reject-option-description":
"firefox-suggest-onboarding-main-reject-option-description-2",
},
},
h: {
logoType: "firefox",
l10nUpdates: {
onboardingNext: "firefox-suggest-onboarding-introduction-next-button-1",
"introduction-title": "firefox-suggest-onboarding-introduction-title-2",
"main-title": "firefox-suggest-onboarding-main-title-8",
"main-description": "firefox-suggest-onboarding-main-description-8",
"main-accept-option-label":
"firefox-suggest-onboarding-main-accept-option-label",
"main-accept-option-description":
"firefox-suggest-onboarding-main-accept-option-description-1",
"main-reject-option-label":
"firefox-suggest-onboarding-main-reject-option-label",
"main-reject-option-description":
"firefox-suggest-onboarding-main-reject-option-description-1",
},
},
"100-a": {
introductionLayout: "layout-100",
mainPrivacyFirst: true,
logoType: "firefox",
l10nUpdates: {
onboardingNext: "firefox-suggest-onboarding-introduction-next-button-3",
"introduction-title": "firefox-suggest-onboarding-main-title-9",
"main-title": "firefox-suggest-onboarding-main-title-9",
"main-description": "firefox-suggest-onboarding-main-description-9",
"main-accept-option-label":
"firefox-suggest-onboarding-main-accept-option-label-2",
"main-accept-option-description":
"firefox-suggest-onboarding-main-accept-option-description-3",
"main-reject-option-label":
"firefox-suggest-onboarding-main-reject-option-label-2",
"main-reject-option-description":
"firefox-suggest-onboarding-main-reject-option-description-3",
},
},
"100-b": {
mainPrivacyFirst: true,
logoType: "firefox",
l10nUpdates: {
"main-title": "firefox-suggest-onboarding-main-title-9",
"main-description": "firefox-suggest-onboarding-main-description-9",
"main-accept-option-label":
"firefox-suggest-onboarding-main-accept-option-label-2",
"main-accept-option-description":
"firefox-suggest-onboarding-main-accept-option-description-3",
"main-reject-option-label":
"firefox-suggest-onboarding-main-reject-option-label-2",
"main-reject-option-description":
"firefox-suggest-onboarding-main-reject-option-description-3",
},
skipIntroduction: true,
},
};
// If the window height is smaller than this value when the dialog opens, then
// the dialog will open in compact mode. The dialog will not change modes while
// it's open even if the window height changes.
const COMPACT_MODE_HEIGHT =
650 + // section min-height (non-compact mode)
2 * 32 + // 2 * --section-vertical-padding (non-compact mode)
44; // approximate height of the browser window's tab bar
// Used for test only. If links or buttons may be clicked or typed Key_Enter
// while translating l10n, cannot capture the events since not register listeners
// yet. To avoid the issue, add this flag to know the listeners are ready.
let resolveOnboardingReady;
window._quicksuggestOnboardingReady = new Promise(r => {
resolveOnboardingReady = r;
});
document.addEventListener("DOMContentLoaded", async () => {
await document.l10n.ready;
const variation =
VARIATION_MAP[window.arguments[0].variationType] || VARIATION_MAP.a;
document.l10n.pauseObserving();
try {
await applyVariation(variation);
} finally {
document.l10n.resumeObserving();
}
addSubmitListener(document.getElementById("onboardingClose"), () => {
window.arguments[0].choice = ONBOARDING_CHOICE.CLOSE_1;
window.close();
});
addSubmitListener(document.getElementById("onboardingNext"), () => {
gotoMain(variation);
});
addSubmitListener(document.getElementById("onboardingLearnMore"), () => {
window.arguments[0].choice = ONBOARDING_CHOICE.LEARN_MORE_2;
window.close();
});
addSubmitListener(
document.getElementById("onboardingLearnMoreOnIntroduction"),
() => {
window.arguments[0].choice = ONBOARDING_CHOICE.LEARN_MORE_1;
window.close();
}
);
addSubmitListener(document.getElementById("onboardingSkipLink"), () => {
window.arguments[0].choice = ONBOARDING_CHOICE.NOT_NOW_2;
window.close();
});
const onboardingSubmit = document.getElementById("onboardingSubmit");
const onboardingAccept = document.getElementById("onboardingAccept");
const onboardingReject = document.getElementById("onboardingReject");
function optionChangeListener() {
onboardingSubmit.removeAttribute("disabled");
onboardingAccept
.closest(".option")
.classList.toggle("selected", onboardingAccept.checked);
onboardingReject
.closest(".option")
.classList.toggle("selected", !onboardingAccept.checked);
}
onboardingAccept.addEventListener("change", optionChangeListener);
onboardingReject.addEventListener("change", optionChangeListener);
function submitListener() {
if (!onboardingAccept.checked && !onboardingReject.checked) {
return;
}
window.arguments[0].choice = onboardingAccept.checked
? ONBOARDING_CHOICE.ACCEPT_2
: ONBOARDING_CHOICE.REJECT_2;
window.close();
}
addSubmitListener(onboardingSubmit, submitListener);
onboardingAccept.addEventListener("keydown", e => {
if (e.keyCode == e.DOM_VK_RETURN) {
submitListener();
}
});
onboardingReject.addEventListener("keydown", e => {
if (e.keyCode == e.DOM_VK_RETURN) {
submitListener();
}
});
if (window.outerHeight < COMPACT_MODE_HEIGHT) {
document.body.classList.add("compact");
}
resolveOnboardingReady();
});
function gotoMain(variation) {
window.arguments[0].visitedMain = true;
document.getElementById("introduction-section").classList.add("inactive");
document.getElementById("main-section").classList.add("active");
document.body.setAttribute("aria-labelledby", "main-title");
let ariaDescribedBy = "main-description";
if (variation.mainPrivacyFirst) {
ariaDescribedBy += " main-privacy-first";
}
document.body.setAttribute("aria-describedby", ariaDescribedBy);
}
async function applyVariation(variation) {
if (variation.logoType) {
for (const logo of document.querySelectorAll(".logo")) {
logo.classList.add(variation.logoType);
}
}
if (variation.mainPrivacyFirst) {
const label = document.querySelector("#main-section .privacy-first");
label.classList.add("active");
}
if (variation.l10nUpdates) {
const translatedElements = [];
for (const [id, newL10N] of Object.entries(variation.l10nUpdates)) {
const element = document.getElementById(id);
document.l10n.setAttributes(element, newL10N);
translatedElements.push(element);
}
await document.l10n.translateElements(translatedElements);
}
if (variation.skipIntroduction) {
document.body.classList.add("skip-introduction");
gotoMain(variation);
}
if (variation.introductionLayout) {
document
.getElementById("introduction-section")
.classList.add(variation.introductionLayout);
}
}
function addSubmitListener(element, listener) {
if (!element) {
console.warn("Element is null on addSubmitListener");
return;
}
element.addEventListener("click", listener);
element.addEventListener("keydown", e => {
if (e.keyCode == e.DOM_VK_RETURN) {
listener();
}
});
}

View file

@ -1,34 +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 https://mozilla.org/MPL/2.0/. -->
<svg width="158" height="115" viewBox="0 0 158 115" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M120.886 24.4352C120.885 24.1852 120.798 23.9433 120.639 23.7507C120.479 23.558 120.258 23.4268 120.013 23.3792C117.928 23.0168 112.136 21.6535 110.178 19.6977C108.223 17.7418 106.859 11.9768 106.5 9.8665C106.452 9.62121 106.32 9.40009 106.128 9.24045C105.936 9.0808 105.694 8.99243 105.444 8.99023V24.4352H120.886Z" fill="#AB71FF"/>
<path d="M105.525 8.99023C105.27 8.99295 105.025 9.0852 104.831 9.25084C104.637 9.41649 104.507 9.645 104.465 9.89644C104.128 11.9657 102.834 17.6552 100.868 19.7528C98.9015 21.8489 93.1081 23.0893 90.8827 23.4549C90.6355 23.5018 90.4123 23.6333 90.2516 23.8269C90.0908 24.0204 90.0025 24.2639 90.0017 24.5156H105.525V8.99023Z" fill="#9158FF"/>
<path d="M105.347 24.4375V39.9597C105.598 39.9582 105.841 39.8698 106.035 39.7095C106.228 39.5492 106.36 39.3269 106.409 39.0802C106.77 36.9605 108.139 31.0583 110.106 29.0946C112.075 27.1262 117.87 25.8323 119.966 25.4966C120.217 25.4547 120.445 25.3255 120.611 25.1318C120.776 24.9381 120.868 24.6922 120.87 24.4375H105.347Z" fill="#7542E5"/>
<path d="M90 24.4375C89.9977 24.6935 90.0883 24.9417 90.2549 25.1362C90.4215 25.3306 90.6529 25.4581 90.9063 25.495C93.0024 25.8323 98.8998 27.1262 100.867 29.093C102.832 31.0583 104.126 36.8549 104.462 39.0519C104.54 39.5783 104.993 39.9644 105.524 39.9581V24.4375H90Z" fill="#592ACB"/>
<circle cx="73.3988" cy="63.9893" r="50.5" fill="#F9F9FB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M70.3502 73.7613C62.6751 73.7613 56.4299 67.516 56.4299 59.8408C56.4299 52.1656 62.6751 45.9204 70.3502 45.9204C78.0253 45.9204 84.2705 52.1656 84.2705 59.8408C84.2705 67.516 78.0253 73.7613 70.3502 73.7613ZM100.322 86.6639L84.8051 71.1465C87.2528 68.0238 88.725 64.106 88.725 59.8408C88.725 49.709 80.482 41.4658 70.3502 41.4658C60.2185 41.4658 51.9754 49.709 51.9754 59.8408C51.9754 69.9727 60.2185 78.2158 70.3502 78.2158C74.6154 78.2158 78.5354 76.7414 81.6557 74.2958L97.173 89.8132C97.6073 90.2476 98.1775 90.4658 98.7476 90.4658C99.3178 90.4658 99.888 90.2476 100.322 89.8132C101.193 88.9424 101.193 87.5347 100.322 86.6639Z" fill="url(#paint0_linear_4224_71674)"/>
<path d="M157.809 77.9766C157.816 77.5423 157.667 77.1198 157.39 76.7854C157.113 76.4509 156.725 76.2267 156.297 76.153C152.758 75.5333 142.84 73.1814 139.486 69.8275C136.131 66.4713 133.798 56.5153 133.158 52.9786C133.084 52.5508 132.86 52.1634 132.526 51.8862C132.192 51.6089 131.77 51.4599 131.336 51.466V77.9766H157.809Z" fill="#AB71FF"/>
<path d="M131.449 51.4689C131.011 51.4628 130.585 51.6144 130.25 51.8959C129.914 52.1775 129.691 52.5703 129.622 53.0027C129.038 56.5439 126.829 66.4753 123.489 69.8159C120.146 73.1565 110.142 75.5117 106.492 76.1872C106.063 76.2612 105.675 76.4857 105.397 76.8204C105.119 77.1551 104.97 77.578 104.976 78.013H131.449V51.4689Z" fill="#7542E5"/>
<path d="M131.372 77.9379V104.375C131.807 104.381 132.229 104.232 132.563 103.955C132.897 103.677 133.121 103.289 133.195 102.861C133.816 99.2152 136.186 89.2247 139.521 85.8686C142.859 82.5146 152.777 80.3087 156.315 79.7425C157.206 79.5976 157.857 78.8218 157.845 77.9189H131.372V77.9379Z" fill="#7542E5"/>
<path d="M104.976 77.9346C104.97 78.3695 105.119 78.7924 105.397 79.1271C105.675 79.4618 106.063 79.6863 106.492 79.7603C110.142 80.3266 120.128 82.5536 123.489 85.8942C126.847 89.2348 128.964 99.2944 129.621 102.889C129.691 103.322 129.914 103.715 130.249 103.996C130.585 104.278 131.01 104.43 131.448 104.424V77.9346H104.976Z" fill="#592ACB"/>
<path d="M62.7863 7.25688C62.7861 7.15433 62.7502 7.05505 62.6849 6.97603C62.6195 6.897 62.5288 6.84313 62.4281 6.82364C61.5726 6.67491 59.1962 6.11558 58.3931 5.31312C57.5907 4.51065 57.0313 2.14528 56.8839 1.27945C56.8641 1.17881 56.8102 1.08808 56.7313 1.02258C56.6523 0.957082 56.5532 0.920822 56.4507 0.919922V7.25688H62.7863Z" fill="#AB71FF"/>
<path d="M56.4841 0.919922C56.3794 0.921037 56.2785 0.958884 56.199 1.02685C56.1194 1.09481 56.0663 1.18857 56.0489 1.29173C55.9105 2.14076 55.3796 4.47508 54.5733 5.33575C53.7663 6.19576 51.3893 6.70466 50.4762 6.85468C50.3748 6.87391 50.2832 6.92787 50.2173 7.00729C50.1513 7.08671 50.1151 7.18662 50.1148 7.28986H56.4841V0.919922Z" fill="#9158FF"/>
<path d="M56.4107 7.25781V13.6265C56.5138 13.6258 56.6135 13.5896 56.693 13.5238C56.7724 13.4581 56.8267 13.3668 56.8465 13.2656C56.9946 12.3959 57.5565 9.9743 58.3635 9.1686C59.1711 8.36096 61.5488 7.83008 62.4088 7.69235C62.5119 7.67516 62.6056 7.62216 62.6735 7.54268C62.7414 7.46321 62.7791 7.36233 62.78 7.25781H56.4107Z" fill="#7542E5"/>
<path d="M50.1141 7.25781C50.1131 7.36286 50.1503 7.46469 50.2187 7.54446C50.287 7.62424 50.382 7.67654 50.4859 7.6917C51.3459 7.83008 53.7656 8.36096 54.5726 9.16795C55.3789 9.9743 55.9098 12.3526 56.0476 13.254C56.0799 13.47 56.2655 13.6284 56.4834 13.6258V7.25781H50.1141Z" fill="#592ACB"/>
<path d="M49.8614 99.9389C49.861 99.7694 49.8018 99.6053 49.6938 99.4747C49.5858 99.3441 49.4358 99.2551 49.2694 99.2229C47.8555 98.9771 43.9281 98.0527 42.6008 96.7264C41.2746 95.4002 40.3502 91.491 40.1065 90.06C40.0738 89.8937 39.9847 89.7437 39.8543 89.6355C39.7238 89.5272 39.56 89.4673 39.3905 89.4658V99.9389H49.8614Z" fill="#AB71FF"/>
<path d="M39.4457 89.4658C39.2728 89.4677 39.106 89.5302 38.9746 89.6425C38.8431 89.7549 38.7553 89.9098 38.7265 90.0803C38.4978 91.4835 37.6204 95.3414 36.2878 96.7638C34.9541 98.1852 31.0256 99.0262 29.5166 99.2741C29.349 99.3059 29.1977 99.3951 29.0886 99.5264C28.9796 99.6576 28.9197 99.8227 28.9192 99.9934H39.4457V89.4658Z" fill="#9158FF"/>
<path d="M39.3244 99.9404V110.466C39.4949 110.465 39.6597 110.405 39.791 110.296C39.9223 110.188 40.0119 110.037 40.0447 109.87C40.2894 108.432 41.2181 104.43 42.5518 103.098C43.8866 101.764 47.8162 100.886 49.2375 100.659C49.4079 100.63 49.5628 100.543 49.675 100.411C49.7872 100.28 49.8495 100.113 49.8509 99.9404H39.3244Z" fill="#7542E5"/>
<path d="M28.9181 99.9404C28.9165 100.114 28.9779 100.282 29.0909 100.414C29.2039 100.546 29.3608 100.632 29.5326 100.658C30.9539 100.886 34.9529 101.764 36.2866 103.097C37.6193 104.43 38.4967 108.361 38.7243 109.85C38.7777 110.207 39.0844 110.469 39.4446 110.465V99.9404H28.9181Z" fill="#592ACB"/>
<path d="M29.8933 41.3729C29.896 41.1298 29.8106 40.894 29.6529 40.709C29.4951 40.524 29.2758 40.4024 29.0354 40.3666C27.0422 40.0118 21.4518 38.6895 19.5705 36.7887C17.6891 34.888 16.3475 29.3341 15.9926 27.3238C15.957 27.0833 15.8355 26.8638 15.6505 26.7061C15.4654 26.5483 15.2295 26.463 14.9864 26.4659V41.3729H29.8933Z" fill="#AB71FF"/>
<path d="M15.0596 26.4668C14.8179 26.468 14.5843 26.5548 14.4005 26.7119C14.2167 26.869 14.0945 27.0861 14.0556 27.3248C13.7179 29.3179 12.4709 34.9072 10.5885 36.7896C8.70712 38.671 3.02431 40.0127 1.0129 40.3675C0.772374 40.4031 0.552898 40.5247 0.395144 40.7097C0.23739 40.8947 0.152054 41.1306 0.154948 41.3738H15.0596V26.4668Z" fill="#7542E5"/>
<path d="M14.9864 41.3037V56.2084C15.2294 56.2111 15.4652 56.1256 15.6502 55.9679C15.8352 55.8102 15.9568 55.5909 15.9926 55.3505C16.3475 53.3379 17.6891 47.6562 19.5705 45.7737C21.4518 43.8924 27.024 42.6454 29.0354 42.3077C29.2739 42.2686 29.4909 42.1464 29.648 41.9626C29.805 41.7789 29.8919 41.5454 29.8933 41.3037H14.9864Z" fill="#7542E5"/>
<path d="M0.154877 41.3037C0.156279 41.5454 0.243199 41.7789 0.400235 41.9626C0.557272 42.1464 0.774287 42.2686 1.01283 42.3077C3.04249 42.6454 8.70705 43.8924 10.5884 45.7737C12.4709 47.6562 13.7179 53.3197 14.0556 55.3505C14.1354 55.8445 14.561 56.205 15.0596 56.2084V41.3037H0.154877Z" fill="#592ACB"/>
<defs>
<linearGradient id="paint0_linear_4224_71674" x1="51.9754" y1="41.4658" x2="100.975" y2="41.4658" gradientUnits="userSpaceOnUse">
<stop stop-color="#9059FF"/>
<stop offset="0.520833" stop-color="#FF4AA2"/>
<stop offset="1" stop-color="#FFBD4F"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 7.9 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 72 KiB

View file

@ -32,7 +32,11 @@ Changelog
Firefox 93.0
Introduced. [Bug 1727799_]
Firefox 137.0
Removed. [Bug 1946922_]
.. _1727799: https://bugzilla.mozilla.org/show_bug.cgi?id=1727799
.. _1946922: https://bugzilla.mozilla.org/show_bug.cgi?id=1946922
FX_URLBAR_MERINO_LATENCY_WEATHER_MS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -46,7 +50,11 @@ Changelog
Firefox 110.0
Introduced. [Bug 1804536_]
Firefox 137.0
Removed. [Bug 1946922_]
.. _1804536: https://bugzilla.mozilla.org/show_bug.cgi?id=1804536
.. _1946922: https://bugzilla.mozilla.org/show_bug.cgi?id=1946922
FX_URLBAR_MERINO_RESPONSE
~~~~~~~~~~~~~~~~~~~~~~~~~
@ -81,8 +89,12 @@ Changelog
timeout elapsed" to "The fetch completed without any error before the
timeout elapsed and it included at least one suggestion." [Bug 1804536_]
Firefox 137.0
Removed. [Bug 1946922_]
.. _1737923: https://bugzilla.mozilla.org/show_bug.cgi?id=1737923
.. _1804536: https://bugzilla.mozilla.org/show_bug.cgi?id=1804536
.. _1946922: https://bugzilla.mozilla.org/show_bug.cgi?id=1946922
FX_URLBAR_MERINO_RESPONSE_WEATHER
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -110,7 +122,11 @@ Changelog
Firefox 110.0
Introduced. [Bug 1804536_]
Firefox 137.0
Removed. [Bug 1946922_]
.. _1804536: https://bugzilla.mozilla.org/show_bug.cgi?id=1804536
.. _1946922: https://bugzilla.mozilla.org/show_bug.cgi?id=1946922
FX_URLBAR_QUICK_SUGGEST_REMOTE_SETTINGS_LATENCY_MS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -129,7 +145,11 @@ Changelog
Firefox 94.0.2
Introduced. [Bug 1737651_]
Firefox 135.0
Removed. [Bug 1932502_]
.. _1737651: https://bugzilla.mozilla.org/show_bug.cgi?id=1737651
.. _1932502: https://bugzilla.mozilla.org/show_bug.cgi?id=1932502
Scalars
-------
@ -1275,9 +1295,13 @@ Changelog
Firefox 100.0
Added ``learn_more_1``. [Bug 1761171_]
Firefox 137.0
Removed. [Bug 1936455_]
.. _1734447: https://bugzilla.mozilla.org/show_bug.cgi?id=1734447
.. _1745026: https://bugzilla.mozilla.org/show_bug.cgi?id=1745026
.. _1761171: https://bugzilla.mozilla.org/show_bug.cgi?id=1761171
.. _1936455: https://bugzilla.mozilla.org/show_bug.cgi?id=1936455
browser.urlbar.quicksuggest.dataCollection.enabled
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -177,9 +177,6 @@ browser.urlbar.quicksuggest.enabled (boolean, default: false)
browser.urlbar.quicksuggest.dataCollection.enabled (boolean, default: false)
Whether data collection is enabled for quick suggest results.
browser.urlbar.quicksuggest.shouldShowOnboardingDialog (boolean, default: false)
Whether to show the quick suggest onboarding dialog.
browser.urlbar.richSuggestions.tail (boolean, default: true)
If true, we show tail search suggestions when available.

View file

@ -1,11 +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/.
browser.jar:
content/browser/urlbar/quicksuggestOnboarding.html (content/quicksuggestOnboarding.html)
content/browser/urlbar/quicksuggestOnboarding.js (content/quicksuggestOnboarding.js)
content/browser/urlbar/quicksuggestOnboarding.css (content/quicksuggestOnboarding.css)
content/browser/urlbar/quicksuggestOnboarding_magglass_animation.svg (content/quicksuggestOnboarding_magglass_animation.svg)
content/browser/urlbar/quicksuggestOnboarding_magglass.svg (content/quicksuggestOnboarding_magglass.svg)
content/browser/urlbar/suggest-example.svg (content/suggest-example.svg)

View file

@ -5,8 +5,6 @@
with Files("**"):
BUG_COMPONENT = ("Firefox", "Address Bar")
JAR_MANIFESTS += ["jar.mn"]
DIRS += [
"unitconverters",
]

View file

@ -20,9 +20,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
const MERINO_PROVIDER = "accuweather";
const MERINO_TIMEOUT_MS = 5000; // 5s
const HISTOGRAM_LATENCY = "FX_URLBAR_MERINO_LATENCY_WEATHER_MS";
const HISTOGRAM_RESPONSE = "FX_URLBAR_MERINO_RESPONSE_WEATHER";
// Cache period for Merino's weather response. This is intentionally a small
// amount of time. See the `cachePeriodMs` discussion in `MerinoClient`. In
// addition, caching also helps prevent the weather suggestion from flickering
@ -227,8 +224,6 @@ export class WeatherSuggestions extends SuggestProvider {
otherParams,
providers: [MERINO_PROVIDER],
timeoutMs: this.#timeoutMs,
extraLatencyHistogram: HISTOGRAM_LATENCY,
extraResponseHistogram: HISTOGRAM_RESPONSE,
});
if (fetchInstance != this.#fetchInstance || merino != this.#merino) {
return null;

View file

@ -701,6 +701,7 @@ skip-if = [
"os == 'mac' && os_version == '10.15' && processor == 'x86_64'", # bug 1570474
"os == 'mac' && os_version == '11.20' && arch == 'aarch64'", # bug 1570474
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # bug 1869788
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # bug 1570474
]
["browser_urlbar_telemetry.js"]

View file

@ -55,11 +55,18 @@ add_task(async function () {
});
await test_autocomplete({
desc: "CTRL+ENTER on the autofilled part should bypass autofill",
desc: "Canonization on the autofilled part should bypass autofill",
typed: "exam",
autofilled: "example.com/",
modified: UrlbarTestUtils.trimURL("https://www.exam.com"),
waitForUrl: "https://www.exam.com/",
keys: [["KEY_Enter", { ctrlKey: true }]],
keys: [
[
"KEY_Enter",
AppConstants.platform == "macosx"
? { metaKey: true }
: { ctrlKey: true },
],
],
});
});

View file

@ -9,7 +9,12 @@ requestLongerTimeout(2);
const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
add_task(async function checkCtrlWorks() {
const CANONIZE_MODIFIERS =
AppConstants.platform == "macosx" ? { metaKey: true } : { ctrlKey: true };
const MODIFIER_KEY =
AppConstants.platform == "macosx" ? "VK_META" : "VK_CONTROL";
add_task(async function checkCanonizeWorks() {
registerCleanupFunction(async function () {
await PlacesUtils.history.clear();
await UrlbarTestUtils.formHistory.clear();
@ -23,28 +28,28 @@ add_task(async function checkCtrlWorks() {
let defaultEngine = await Services.search.getDefault();
let testcases = [
["example", "https://www.example.com/", { ctrlKey: true }],
["example", "https://www.example.com/", CANONIZE_MODIFIERS],
// Check that a direct load is not overwritten by a previous canonization.
["http://example.com/test/", "http://example.com/test/", {}],
["ex-ample", "https://www.ex-ample.com/", { ctrlKey: true }],
[" example ", "https://www.example.com/", { ctrlKey: true }],
[" example/foo ", "https://www.example.com/foo", { ctrlKey: true }],
["ex-ample", "https://www.ex-ample.com/", CANONIZE_MODIFIERS],
[" example ", "https://www.example.com/", CANONIZE_MODIFIERS],
[" example/foo ", "https://www.example.com/foo", CANONIZE_MODIFIERS],
[
" example/foo bar ",
"https://www.example.com/foo%20bar",
{ ctrlKey: true },
CANONIZE_MODIFIERS,
],
["example.net", "http://example.net/", { ctrlKey: true }],
["http://example", "http://example/", { ctrlKey: true }],
["example:8080", "http://example:8080/", { ctrlKey: true }],
["ex-ample.foo", "http://ex-ample.foo/", { ctrlKey: true }],
["example.foo/bar ", "http://example.foo/bar", { ctrlKey: true }],
["1.1.1.1", "http://1.1.1.1/", { ctrlKey: true }],
["ftp.example.bar", "http://ftp.example.bar/", { ctrlKey: true }],
["example.net", "http://example.net/", CANONIZE_MODIFIERS],
["http://example", "http://example/", CANONIZE_MODIFIERS],
["example:8080", "http://example:8080/", CANONIZE_MODIFIERS],
["ex-ample.foo", "http://ex-ample.foo/", CANONIZE_MODIFIERS],
["example.foo/bar ", "http://example.foo/bar", CANONIZE_MODIFIERS],
["1.1.1.1", "http://1.1.1.1/", CANONIZE_MODIFIERS],
["ftp.example.bar", "http://ftp.example.bar/", CANONIZE_MODIFIERS],
[
"ex ample",
defaultEngine.getSubmission("ex ample", null, "keyword").uri.spec,
{ ctrlKey: true },
CANONIZE_MODIFIERS,
],
];
@ -97,43 +102,28 @@ add_task(async function checkPrefTurnsOffCanonize() {
});
let newURL = "http://mochi.test:8888/?terms=example";
// On MacOS CTRL+Enter is not supposed to open in a new tab, because it uses
// CMD+Enter for that.
let promiseLoaded =
AppConstants.platform == "macosx"
? BrowserTestUtils.browserLoaded(
win.gBrowser.selectedBrowser,
false,
newURL
)
: BrowserTestUtils.waitForNewTab(win.gBrowser);
let promiseLoaded = BrowserTestUtils.waitForNewTab(win.gBrowser);
win.gURLBar.focus();
win.gURLBar.selectionStart = win.gURLBar.selectionEnd =
win.gURLBar.value.length;
win.gURLBar.value = "exampl";
EventUtils.sendString("e", win);
EventUtils.synthesizeKey("KEY_Enter", { ctrlKey: true }, win);
EventUtils.synthesizeKey("KEY_Enter", CANONIZE_MODIFIERS, win);
await promiseLoaded;
if (AppConstants.platform == "macosx") {
Assert.equal(
initialTab.linkedBrowser.currentURI.spec,
newURL,
"Original tab should have navigated"
);
} else {
Assert.equal(
initialTab.linkedBrowser.currentURI.spec,
"about:mozilla",
"Original tab shouldn't have navigated"
);
Assert.equal(
win.gBrowser.selectedBrowser.currentURI.spec,
newURL,
"New tab should have navigated"
);
}
Assert.equal(
initialTab.linkedBrowser.currentURI.spec,
"about:mozilla",
"Original tab shouldn't have navigated"
);
Assert.equal(
win.gBrowser.selectedBrowser.currentURI.spec,
newURL,
"New tab should have navigated"
);
while (win.gBrowser.tabs.length > 1) {
win.gBrowser.removeTab(win.gBrowser.selectedTab, { animate: false });
}
@ -169,11 +159,11 @@ add_task(async function autofill() {
]);
let testcases = [
["ex", "https://www.ex.com/", { ctrlKey: true }],
["ex", "https://www.ex.com/", CANONIZE_MODIFIERS],
// Check that a direct load is not overwritten by a previous canonization.
["ex", "https://example.com/", {}],
// search alias
["@goo", "https://www.goo.com/", { ctrlKey: true }],
["@goo", "https://www.goo.com/", CANONIZE_MODIFIERS],
];
for (let [inputValue, expectedURL, options] of testcases) {
@ -205,7 +195,7 @@ add_task(async function autofill() {
add_task(async function () {
info(
"Test whether canonization is disabled until the ctrl key is releasing if the key was used to paste text into urlbar"
"Test whether canonization is disabled until the modifier key is releasing if the key was used to paste text into urlbar"
);
await SpecialPowers.pushPrefEnv({
@ -219,21 +209,23 @@ add_task(async function () {
simulatePastingToUrlbar(testWord, win);
is(win.gURLBar.value, testWord, "Paste the test word correctly");
info("Send enter key while pressing the ctrl key");
EventUtils.synthesizeKey("VK_RETURN", { ctrlKey: true }, win);
info("Send enter key while pressing the canonization modifier");
EventUtils.synthesizeKey("VK_RETURN", CANONIZE_MODIFIERS, win);
await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
is(
win.gBrowser.selectedBrowser.documentURI.spec,
`http://mochi.test:8888/?terms=${testWord}`,
"The loaded url is not canonized"
);
EventUtils.synthesizeKey("VK_CONTROL", { type: "keyup" }, win);
EventUtils.synthesizeKey(MODIFIER_KEY, { type: "keyup" }, win);
await BrowserTestUtils.closeWindow(win);
});
add_task(async function () {
info("Test whether canonization is enabled again after releasing the ctrl");
info(
"Test whether canonization is enabled again after releasing the modifier key"
);
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.ctrlCanonizesURLs", true]],
@ -246,10 +238,10 @@ add_task(async function () {
simulatePastingToUrlbar(testWord, win);
is(win.gURLBar.value, testWord, "Paste the test word correctly");
info("Release the ctrl key befoer typing Enter key");
EventUtils.synthesizeKey("VK_CONTROL", { type: "keyup" }, win);
info("Release the canonization modifier before typing Enter key");
EventUtils.synthesizeKey(MODIFIER_KEY, { type: "keyup" }, win);
info("Send enter key with the ctrl");
info("Send enter key with the canonization modifier");
const onLoad = BrowserTestUtils.waitForDocLoadAndStopIt(
`https://www.${testWord}.com/`,
win.gBrowser.selectedBrowser
@ -259,7 +251,8 @@ add_task(async function () {
undefined,
true
);
EventUtils.synthesizeKey("VK_RETURN", { ctrlKey: true }, win);
EventUtils.synthesizeKey("VK_RETURN", CANONIZE_MODIFIERS, win);
await Promise.all([onLoad, onStop]);
info("The loaded url is canonized");
@ -275,7 +268,9 @@ function simulatePastingToUrlbar(text, win) {
.toLowerCase();
EventUtils.synthesizeKey(
keyForPaste,
{ type: "keydown", ctrlKey: true },
AppConstants.platform == "macosx"
? { type: "keydown", metaKey: true }
: { type: "keydown", ctrlKey: true },
win
);

View file

@ -129,10 +129,10 @@ add_task(async function plainEnterOnSuggestion() {
await testPressEnterOnSuggestion();
});
add_task(async function ctrlEnterOnSuggestion() {
await testPressEnterOnSuggestion("https://www.foofoo.com/", {
ctrlKey: true,
});
add_task(async function canonizeSuggestion() {
let modifiers =
AppConstants.platform == "macosx" ? { metaKey: true } : { ctrlKey: true };
await testPressEnterOnSuggestion("https://www.foofoo.com/", modifiers);
});
add_task(async function copySuggestionText() {

View file

@ -5,7 +5,6 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
MerinoClient: "resource:///modules/MerinoClient.sys.mjs",
TelemetryTestUtils: "resource://testing-common/TelemetryTestUtils.sys.mjs",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
});
@ -41,19 +40,6 @@ const REQUIRED_SEARCH_PARAMS = [
// before the default timeout.
const CLIENT_TIMEOUT_MS = 2000;
const HISTOGRAM_LATENCY = "FX_URLBAR_MERINO_LATENCY_MS";
const HISTOGRAM_RESPONSE = "FX_URLBAR_MERINO_RESPONSE";
// Maps from string labels of the `FX_URLBAR_MERINO_RESPONSE` histogram to their
// numeric values.
const RESPONSE_HISTOGRAM_VALUES = {
success: 0,
timeout: 1,
network_error: 2,
http_error: 3,
no_suggestion: 4,
};
const WEATHER_SUGGESTION = {
title: "Weather for San Francisco",
url: "https://example.com/weather",
@ -200,138 +186,6 @@ class _MerinoTestUtils {
return this.#server;
}
/**
* Clears the Merino-related histograms and returns them.
*
* @param {object} options
* Options
* @param {string} options.extraLatency
* The name of another latency histogram you expect to be updated.
* @param {string} options.extraResponse
* The name of another response histogram you expect to be updated.
* @returns {object}
* An object of histograms: `{ latency, response }`
* `latency` and `response` are both arrays of Histogram objects.
*/
getAndClearHistograms({
extraLatency = undefined,
extraResponse = undefined,
} = {}) {
let histograms = {
latency: [
lazy.TelemetryTestUtils.getAndClearHistogram(HISTOGRAM_LATENCY),
],
response: [
lazy.TelemetryTestUtils.getAndClearHistogram(HISTOGRAM_RESPONSE),
],
};
if (extraLatency) {
histograms.latency.push(
lazy.TelemetryTestUtils.getAndClearHistogram(extraLatency)
);
}
if (extraResponse) {
histograms.response.push(
lazy.TelemetryTestUtils.getAndClearHistogram(extraResponse)
);
}
return histograms;
}
/**
* Asserts the Merino-related histograms are updated as expected. Clears the
* histograms before returning.
*
* @param {object} options
* Options object
* @param {MerinoClient} options.client
* The relevant `MerinoClient` instance. This is used to check the latency
* stopwatch.
* @param {object} options.histograms
* The histograms object returned from `getAndClearHistograms()`.
* @param {string} options.response
* The expected string label for the `response` histogram. If the histogram
* should not be recorded, pass null.
* @param {boolean} options.latencyRecorded
* Whether the latency histogram is expected to contain a value.
* @param {boolean} options.latencyStopwatchRunning
* Whether the latency stopwatch is expected to be running.
*/
checkAndClearHistograms({
client,
histograms,
response,
latencyRecorded,
latencyStopwatchRunning = false,
}) {
// Check the response histograms.
if (response) {
this.Assert.ok(
RESPONSE_HISTOGRAM_VALUES.hasOwnProperty(response),
"Sanity check: Expected response is valid: " + response
);
for (let histogram of histograms.response) {
lazy.TelemetryTestUtils.assertHistogram(
histogram,
RESPONSE_HISTOGRAM_VALUES[response],
1
);
}
} else {
for (let histogram of histograms.response) {
this.Assert.strictEqual(
histogram.snapshot().sum,
0,
"Response histogram not updated: " + histogram.name()
);
}
}
// Check the latency histograms.
if (latencyRecorded) {
// There should be a single value across all buckets.
for (let histogram of histograms.latency) {
this.Assert.deepEqual(
Object.values(histogram.snapshot().values).filter(v => v > 0),
[1],
"Latency histogram updated: " + histogram.name()
);
}
} else {
for (let histogram of histograms.latency) {
this.Assert.strictEqual(
histogram.snapshot().sum,
0,
"Latency histogram not updated: " + histogram.name()
);
}
}
// Check the latency stopwatch.
if (!client) {
this.Assert.ok(
!latencyStopwatchRunning,
"Client is null, latency stopwatch should not be expected to be running"
);
} else {
this.Assert.equal(
TelemetryStopwatch.running(
HISTOGRAM_LATENCY,
client._test_latencyStopwatchInstance
),
latencyStopwatchRunning,
"Latency stopwatch running as expected"
);
}
// Clear histograms.
for (let histogramArray of Object.values(histograms)) {
for (let histogram of histogramArray) {
histogram.clear();
}
}
}
/**
* Initializes the quick suggest weather feature and mock Merino server.
*/

View file

@ -29,9 +29,6 @@ prefs = ["browser.bookmarks.testing.skipDefaultBookmarksImport=true"]
["browser_quicksuggest_merinoSessions.js"]
["browser_quicksuggest_onboardingDialog.js"]
skip-if = ["os == 'linux' && os_version == '18.04' && processor == 'x86_64' && opt && a11y_checks && swgl"] # Bug 1773830
["browser_quicksuggest_ping_amp.js"]
tags = "search-telemetry"

View file

@ -57,8 +57,6 @@ add_task(async function name() {
// Does a successful fetch.
add_task(async function success() {
let histograms = MerinoTestUtils.getAndClearHistograms();
await fetchAndCheckSuggestions({
expected: EXPECTED_MERINO_SUGGESTIONS,
});
@ -68,12 +66,6 @@ add_task(async function success() {
"success",
"The request successfully finished"
);
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "success",
latencyRecorded: true,
client: gClient,
});
});
// Does a successful fetch that doesn't return any suggestions.
@ -81,8 +73,6 @@ add_task(async function noSuggestions() {
let { suggestions } = MerinoTestUtils.server.response.body;
MerinoTestUtils.server.response.body.suggestions = [];
let histograms = MerinoTestUtils.getAndClearHistograms();
await fetchAndCheckSuggestions({
expected: [],
});
@ -92,12 +82,6 @@ add_task(async function noSuggestions() {
"no_suggestion",
"The request successfully finished without suggestions"
);
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "no_suggestion",
latencyRecorded: true,
client: gClient,
});
MerinoTestUtils.server.response.body.suggestions = suggestions;
});
@ -269,8 +253,6 @@ async function doFetchAndGetCalls(client, fetchArgs) {
// Checks a response that's valid but also has some unexpected properties.
add_task(async function unexpectedResponseProperties() {
let histograms = MerinoTestUtils.getAndClearHistograms();
MerinoTestUtils.server.response.body.unexpectedString = "some value";
MerinoTestUtils.server.response.body.unexpectedArray = ["a", "b", "c"];
MerinoTestUtils.server.response.body.unexpectedObject = { foo: "bar" };
@ -284,18 +266,10 @@ add_task(async function unexpectedResponseProperties() {
"success",
"The request successfully finished"
);
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "success",
latencyRecorded: true,
client: gClient,
});
});
// Checks some responses with unexpected response bodies.
add_task(async function unexpectedResponseBody() {
let histograms = MerinoTestUtils.getAndClearHistograms();
let responses = [
{ body: {} },
{ body: { bogus: [] } },
@ -316,12 +290,6 @@ add_task(async function unexpectedResponseBody() {
"no_suggestion",
"The request successfully finished without suggestions"
);
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "no_suggestion",
latencyRecorded: true,
client: gClient,
});
}
MerinoTestUtils.server.reset();
@ -329,8 +297,6 @@ add_task(async function unexpectedResponseBody() {
// Tests with a network error.
add_task(async function networkError() {
let histograms = MerinoTestUtils.getAndClearHistograms();
// This promise will be resolved when the client processes the network error.
let responsePromise = gClient.waitForNextResponse();
@ -354,18 +320,10 @@ add_task(async function networkError() {
"network_error",
"The request failed with a network error"
);
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "network_error",
latencyRecorded: false,
client: gClient,
});
});
// Tests with an HTTP error.
add_task(async function httpError() {
let histograms = MerinoTestUtils.getAndClearHistograms();
MerinoTestUtils.server.response = { status: 500 };
await fetchAndCheckSuggestions({ expected: [] });
@ -374,12 +332,6 @@ add_task(async function httpError() {
"http_error",
"The request failed with an HTTP error"
);
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "http_error",
latencyRecorded: true,
client: gClient,
});
MerinoTestUtils.server.reset();
});
@ -430,8 +382,6 @@ async function doClientTimeoutTest({
fetchArgs = { query: "search" },
expectedResponseStatus = 200,
} = {}) {
let histograms = MerinoTestUtils.getAndClearHistograms();
let originalPrefTimeoutMs = UrlbarPrefs.get("merino.timeoutMs");
UrlbarPrefs.set("merino.timeoutMs", prefTimeoutMs);
@ -462,16 +412,6 @@ async function doClientTimeoutTest({
"fetchController is not aborted"
);
// The latency histogram should not be updated since the response has not been
// received.
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "timeout",
latencyRecorded: false,
latencyStopwatchRunning: true,
client: gClient,
});
// Wait for the client to receive the response.
let httpResponse = await responsePromise;
Assert.ok(httpResponse, "Response was received");
@ -480,15 +420,6 @@ async function doClientTimeoutTest({
// The client should have nulled out the fetch controller.
Assert.ok(!gClient._test_fetchController, "fetchController no longer exists");
// The `checkAndClearHistograms()` call above cleared the histograms. After
// that, nothing else should have been recorded for the response.
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: null,
latencyRecorded: true,
client: gClient,
});
MerinoTestUtils.server.reset();
UrlbarPrefs.set("merino.timeoutMs", originalPrefTimeoutMs);
}
@ -498,8 +429,6 @@ async function doClientTimeoutTest({
// the client should abort the first so that there is at most one fetch at a
// time.
add_task(async function newFetchAbortsPrevious() {
let histograms = MerinoTestUtils.getAndClearHistograms();
// Make the server return a very delayed response so that it would time out
// and we can start a second fetch that will abort the first fetch.
MerinoTestUtils.server.response.delay =
@ -531,16 +460,6 @@ add_task(async function newFetchAbortsPrevious() {
"fetchController is not aborted"
);
// The latency histogram should not be updated since the fetch is still
// ongoing.
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "timeout",
latencyRecorded: false,
latencyStopwatchRunning: true,
client: gClient,
});
// Do the second fetch. This time don't delay the response.
delete MerinoTestUtils.server.response.delay;
await fetchAndCheckSuggestions({
@ -565,13 +484,6 @@ add_task(async function newFetchAbortsPrevious() {
"timeoutTimer does not exist after second fetch finished"
);
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "success",
latencyRecorded: true,
client: gClient,
});
MerinoTestUtils.server.reset();
});

View file

@ -70,8 +70,6 @@ add_task(async function merinoDisabled() {
// by also matching an RS suggestion with the same or higher score.
await QuickSuggestTestUtils.setRemoteSettingsRecords([]);
let histograms = MerinoTestUtils.getAndClearHistograms();
let context = createContext(SEARCH_STRING, {
providers: [UrlbarProviderQuickSuggest.name],
isPrivate: false,
@ -81,13 +79,6 @@ add_task(async function merinoDisabled() {
matches: [],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: null,
latencyRecorded: false,
client: merinoClient(),
});
UrlbarPrefs.set("merino.endpointURL", mockEndpointUrl);
await QuickSuggestTestUtils.setRemoteSettingsRecords([
@ -130,8 +121,6 @@ add_task(async function dataCollectionDisabled() {
add_task(async function higherScore() {
UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true);
let histograms = MerinoTestUtils.getAndClearHistograms();
MerinoTestUtils.server.response.body.suggestions[0].score =
2 * DEFAULT_SUGGESTION_SCORE;
@ -144,13 +133,6 @@ add_task(async function higherScore() {
matches: [EXPECTED_MERINO_URLBAR_RESULT],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "success",
latencyRecorded: true,
client: merinoClient(),
});
MerinoTestUtils.server.reset();
merinoClient().resetSession();
});
@ -160,8 +142,6 @@ add_task(async function higherScore() {
add_task(async function lowerScore() {
UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true);
let histograms = MerinoTestUtils.getAndClearHistograms();
MerinoTestUtils.server.response.body.suggestions[0].score =
DEFAULT_SUGGESTION_SCORE / 2;
@ -174,77 +154,6 @@ add_task(async function lowerScore() {
matches: [EXPECTED_REMOTE_SETTINGS_URLBAR_RESULT],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "success",
latencyRecorded: true,
client: merinoClient(),
});
MerinoTestUtils.server.reset();
merinoClient().resetSession();
});
// When the Merino and remote settings suggestions have the same score, the
// remote settings suggestion should be used.
add_task(async function sameScore() {
UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true);
let histograms = MerinoTestUtils.getAndClearHistograms();
MerinoTestUtils.server.response.body.suggestions[0].score =
DEFAULT_SUGGESTION_SCORE;
let context = createContext(SEARCH_STRING, {
providers: [UrlbarProviderQuickSuggest.name],
isPrivate: false,
});
await check_results({
context,
matches: [EXPECTED_REMOTE_SETTINGS_URLBAR_RESULT],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "success",
latencyRecorded: true,
client: merinoClient(),
});
MerinoTestUtils.server.reset();
merinoClient().resetSession();
});
// When the Merino suggestion does not include a score, the remote settings
// suggestion should be used.
add_task(async function noMerinoScore() {
UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true);
let histograms = MerinoTestUtils.getAndClearHistograms();
Assert.equal(
typeof MerinoTestUtils.server.response.body.suggestions[0].score,
"number",
"Sanity check: First suggestion has a score"
);
delete MerinoTestUtils.server.response.body.suggestions[0].score;
let context = createContext(SEARCH_STRING, {
providers: [UrlbarProviderQuickSuggest.name],
isPrivate: false,
});
await check_results({
context,
matches: [EXPECTED_REMOTE_SETTINGS_URLBAR_RESULT],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "success",
latencyRecorded: true,
client: merinoClient(),
});
MerinoTestUtils.server.reset();
merinoClient().resetSession();
});
@ -254,8 +163,6 @@ add_task(async function noMerinoScore() {
add_task(async function noSuggestion_remoteSettings() {
UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true);
let histograms = MerinoTestUtils.getAndClearHistograms();
let context = createContext("this doesn't match remote settings", {
providers: [UrlbarProviderQuickSuggest.name],
isPrivate: false,
@ -265,13 +172,6 @@ add_task(async function noSuggestion_remoteSettings() {
matches: [EXPECTED_MERINO_URLBAR_RESULT],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "success",
latencyRecorded: true,
client: merinoClient(),
});
MerinoTestUtils.server.reset();
merinoClient().resetSession();
});
@ -281,8 +181,6 @@ add_task(async function noSuggestion_remoteSettings() {
add_task(async function noSuggestion_merino() {
UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true);
let histograms = MerinoTestUtils.getAndClearHistograms();
MerinoTestUtils.server.response.body.suggestions = [];
let context = createContext(SEARCH_STRING, {
@ -294,13 +192,6 @@ add_task(async function noSuggestion_merino() {
matches: [EXPECTED_REMOTE_SETTINGS_URLBAR_RESULT],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "no_suggestion",
latencyRecorded: true,
client: merinoClient(),
});
MerinoTestUtils.server.reset();
merinoClient().resetSession();
});
@ -310,8 +201,6 @@ add_task(async function noSuggestion_merino() {
add_task(async function multipleMerinoSuggestions() {
UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true);
let histograms = MerinoTestUtils.getAndClearHistograms();
MerinoTestUtils.server.response.body.suggestions = [
{
provider: "adm",
@ -381,13 +270,6 @@ add_task(async function multipleMerinoSuggestions() {
],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "success",
latencyRecorded: true,
client: merinoClient(),
});
MerinoTestUtils.server.reset();
merinoClient().resetSession();
});
@ -445,8 +327,6 @@ add_task(async function suggestedDisabled_dataCollectionEnabled() {
UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", false);
UrlbarPrefs.set("suggest.quicksuggest.sponsored", false);
let histograms = MerinoTestUtils.getAndClearHistograms();
let context = createContext("test", {
providers: [UrlbarProviderQuickSuggest.name],
isPrivate: false,
@ -467,13 +347,6 @@ add_task(async function suggestedDisabled_dataCollectionEnabled() {
},
]);
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "success",
latencyRecorded: true,
client: merinoClient(),
});
UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
await QuickSuggestTestUtils.forceSync();

View file

@ -10,7 +10,6 @@
const DEFAULT_PREFS = {
"quicksuggest.enabled": true,
"quicksuggest.dataCollection.enabled": false,
"quicksuggest.shouldShowOnboardingDialog": false,
"suggest.quicksuggest.nonsponsored": true,
"suggest.quicksuggest.sponsored": true,
};

View file

@ -16,9 +16,6 @@ ChromeUtils.defineESModuleGetters(this, {
UrlbarProviderPlaces: "resource:///modules/UrlbarProviderPlaces.sys.mjs",
});
const HISTOGRAM_LATENCY = "FX_URLBAR_MERINO_LATENCY_WEATHER_MS";
const HISTOGRAM_RESPONSE = "FX_URLBAR_MERINO_RESPONSE_WEATHER";
const { WEATHER_SUGGESTION } = MerinoTestUtils;
let gWeather;
@ -73,11 +70,6 @@ async function doBasicDisableAndEnableTest(pref) {
matches: [],
});
let histograms = MerinoTestUtils.getAndClearHistograms({
extraLatency: HISTOGRAM_LATENCY,
extraResponse: HISTOGRAM_RESPONSE,
});
// Re-enable the feature.
info("Re-enable the feature");
UrlbarPrefs.set(pref, true);
@ -91,22 +83,10 @@ async function doBasicDisableAndEnableTest(pref) {
context,
matches: [QuickSuggestTestUtils.weatherResult()],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "success",
latencyRecorded: true,
client: gWeather._test_merino,
});
}
// Tests a Merino fetch that doesn't return a suggestion.
add_task(async function noSuggestion() {
let histograms = MerinoTestUtils.getAndClearHistograms({
extraLatency: HISTOGRAM_LATENCY,
extraResponse: HISTOGRAM_RESPONSE,
});
let { suggestions } = MerinoTestUtils.server.response.body;
MerinoTestUtils.server.response.body.suggestions = [];
@ -119,13 +99,6 @@ add_task(async function noSuggestion() {
matches: [],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "no_suggestion",
latencyRecorded: true,
client: gWeather._test_merino,
});
MerinoTestUtils.server.response.body.suggestions = suggestions;
});
@ -182,119 +155,6 @@ add_task(async function urlAlreadyInHistory() {
await PlacesUtils.history.clear();
});
// Tests a Merino fetch that fails with a network error.
add_task(async function networkError() {
// This task is unreliable on Windows. See the comment in
// `MerinoTestUtils.withNetworkError()`.
if (AppConstants.platform == "win") {
Assert.ok(true, "Skipping this task on Windows");
return;
}
let histograms = MerinoTestUtils.getAndClearHistograms({
extraLatency: HISTOGRAM_LATENCY,
extraResponse: HISTOGRAM_RESPONSE,
});
await MerinoTestUtils.server.withNetworkError(async () => {
let context = createContext("weather", {
providers: [UrlbarProviderQuickSuggest.name],
isPrivate: false,
});
await check_results({
context,
matches: [],
});
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "network_error",
latencyRecorded: false,
client: gWeather._test_merino,
});
});
// Tests a Merino fetch that fails with an HTTP error.
add_task(async function httpError() {
let histograms = MerinoTestUtils.getAndClearHistograms({
extraLatency: HISTOGRAM_LATENCY,
extraResponse: HISTOGRAM_RESPONSE,
});
MerinoTestUtils.server.response = { status: 500 };
let context = createContext("weather", {
providers: [UrlbarProviderQuickSuggest.name],
isPrivate: false,
});
await check_results({
context,
matches: [],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "http_error",
latencyRecorded: true,
client: gWeather._test_merino,
});
MerinoTestUtils.server.reset();
MerinoTestUtils.server.response.body.suggestions = [WEATHER_SUGGESTION];
});
// Tests a Merino fetch that fails due to a client timeout.
add_task(async function clientTimeout() {
let histograms = MerinoTestUtils.getAndClearHistograms({
extraLatency: HISTOGRAM_LATENCY,
extraResponse: HISTOGRAM_RESPONSE,
});
// Make the server return a delayed response so the Merino client times out
// waiting for it.
MerinoTestUtils.server.response.delay = 400;
// Make the client time out immediately.
gWeather._test_setTimeoutMs(1);
// Set up a promise that will be resolved when the client finally receives the
// response.
let responsePromise = gWeather._test_merino.waitForNextResponse();
let context = createContext("weather", {
providers: [UrlbarProviderQuickSuggest.name],
isPrivate: false,
});
await check_results({
context,
matches: [],
});
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: "timeout",
latencyRecorded: false,
latencyStopwatchRunning: true,
client: gWeather._test_merino,
});
// Await the response.
await responsePromise;
// The `checkAndClearHistograms()` call above cleared the histograms. After
// that, nothing else should have been recorded for the response.
MerinoTestUtils.checkAndClearHistograms({
histograms,
response: null,
latencyRecorded: true,
client: gWeather._test_merino,
});
gWeather._test_setTimeoutMs(-1);
delete MerinoTestUtils.server.response.delay;
});
// Locale task for when this test runs on an en-US OS.
add_task(async function locale_enUS() {
await doLocaleTest({

View file

@ -31,7 +31,7 @@ module.exports = {
"content-src/components/CustomizeMenu/**",
"content-src/components/WallpapersSection/**",
"content-src/components/DiscoveryStreamComponents/TopicSelection/TopicSelection.jsx",
"content-src/components/DiscoveryStreamComponents/InlineTopicSelection/InlineTopicSelection.jsx",
"content-src/components/DiscoveryStreamComponents/InterestPicker/InterestPicker.jsx",
],
rules: {
"jsx-a11y/anchor-has-content": "off",

View file

@ -9,7 +9,7 @@ import { useSelector } from "react-redux";
import { actionCreators as ac, actionTypes as at } from "common/Actions.mjs";
import { useIntersectionObserver } from "../../../lib/hooks";
import { SectionContextMenu } from "../SectionContextMenu/SectionContextMenu";
import { InlineTopicSelection } from "../InlineTopicSelection/InlineTopicSelection";
import { InterestPicker } from "../InterestPicker/InterestPicker";
// Prefs
const PREF_SECTIONS_CARDS_ENABLED = "discoverystream.sections.cards.enabled";
@ -23,10 +23,10 @@ const PREF_FOLLOWED_SECTIONS = "discoverystream.sections.following";
const PREF_BLOCKED_SECTIONS = "discoverystream.sections.blocked";
const PREF_TOPICS_AVAILABLE = "discoverystream.topicSelection.topics";
const PREF_THUMBS_UP_DOWN_ENABLED = "discoverystream.thumbsUpDown.enabled";
const PREF_TOPIC_SELECTION_ENABLED =
"discoverystream.sections.topicSelection.enabled";
const PREF_TOPIC_SELECTION_POSITION =
"discoverystream.sections.topicSelection.position";
const PREF_INTEREST_PICKER_ENABLED =
"discoverystream.sections.interestPicker.enabled";
const PREF_VISIBLE_SECTIONS =
"discoverystream.sections.interestPicker.visibleSections";
function getLayoutData(responsiveLayouts, index) {
let layoutData = {
@ -73,13 +73,14 @@ function getMaxTiles(responsiveLayouts) {
}
/**
* Transforms a comma-separated string of topics in user preferences
* Transforms a comma-separated string in user preferences
* into a cleaned-up array.
*
* @param pref
* @returns string[]
* @param {string} pref - The comma-separated pref to be converted.
* @returns {string[]} An array of trimmed strings, excluding empty values.
*/
const getTopics = pref => {
const prefToArray = (pref = "") => {
return pref
.split(",")
.map(item => item.trim())
@ -115,9 +116,9 @@ function CardSection({
const { sectionKey, title, subtitle } = section;
const { responsiveLayouts } = section.layout;
const followedSections = getTopics(followedSectionsPref);
const followedSections = prefToArray(followedSectionsPref);
const following = followedSections.includes(sectionKey);
const blockedSections = getTopics(blockedSectionsPref);
const blockedSections = prefToArray(blockedSectionsPref);
const handleIntersection = useCallback(() => {
dispatch(
@ -322,55 +323,66 @@ function CardSections({
}) {
const prefs = useSelector(state => state.Prefs.values);
const personalizationEnabled = prefs[PREF_SECTIONS_PERSONALIZATION_ENABLED];
const topicSelectionEnabled = prefs[PREF_TOPIC_SELECTION_ENABLED];
const topicSelectionPosition = prefs[PREF_TOPIC_SELECTION_POSITION];
const interestPickerEnabled = prefs[PREF_INTEREST_PICKER_ENABLED];
// Handle a render before feed has been fetched by displaying nothing
if (!data) {
return null;
}
// Retrieve blocked sections
const blockedSections = getTopics(prefs[PREF_BLOCKED_SECTIONS] || "");
const visibleSections = prefToArray(prefs[PREF_VISIBLE_SECTIONS]);
const blockedSections = prefToArray(prefs[PREF_BLOCKED_SECTIONS] || "");
const { interestPicker } = data;
// Only show sections that haven't been blocked by the user
const sections = data.sections.filter(
let filteredSections = data.sections.filter(
section => !blockedSections.includes(section.sectionKey)
);
const isEmpty = sections.length === 0;
if (interestPickerEnabled && visibleSections.length) {
filteredSections = visibleSections.reduce((acc, visibleSection) => {
const found = filteredSections.find(
({ sectionKey }) => sectionKey === visibleSection
);
if (found) {
acc.push(found);
}
return acc;
}, []);
}
let sectionsToRender = filteredSections.map((section, sectionPosition) => (
<CardSection
key={`section-${section.sectionKey}`}
sectionPosition={sectionPosition}
section={section}
dispatch={dispatch}
type={type}
firstVisibleTimestamp={firstVisibleTimestamp}
is_collection={is_collection}
spocMessageVariant={spocMessageVariant}
ctaButtonVariant={ctaButtonVariant}
ctaButtonSponsors={ctaButtonSponsors}
/>
));
if (interestPickerEnabled && personalizationEnabled && interestPicker) {
const index = interestPicker.receivedFeedRank - 1;
sectionsToRender.splice(
Math.min(sectionsToRender.length - 1, index),
0,
<InterestPicker data={interestPicker} />
);
}
const isEmpty = sectionsToRender.length === 0;
return isEmpty ? (
<div className="ds-card-grid empty">
<DSEmptyState status={data.status} dispatch={dispatch} feed={feed} />
</div>
) : (
<div className="ds-section-wrapper">
{sections.map((section, sectionPosition) => {
const shouldRenderTopicSelection =
sectionPosition === topicSelectionPosition &&
personalizationEnabled &&
topicSelectionEnabled;
return (
<>
{shouldRenderTopicSelection && <InlineTopicSelection />}
<CardSection
key={`section-${section.sectionKey}`}
sectionPosition={sectionPosition}
section={section}
dispatch={dispatch}
type={type}
firstVisibleTimestamp={firstVisibleTimestamp}
is_collection={is_collection}
spocMessageVariant={spocMessageVariant}
ctaButtonVariant={ctaButtonVariant}
ctaButtonSponsors={ctaButtonSponsors}
/>
</>
);
})}
</div>
<div className="ds-section-wrapper">{sectionsToRender}</div>
);
}

View file

@ -6,10 +6,6 @@ $excerpt-line-height: 20;
$ds-card-image-gradient-fade: rgba(0, 0, 0, 0%);
$ds-card-image-gradient-solid: rgba(0, 0, 0, 100%);
:root {
--newtab-font-size-xsmall: 11px;
}
.ds-card {
display: flex;
flex-direction: column;
@ -480,7 +476,7 @@ $ds-card-image-gradient-solid: rgba(0, 0, 0, 100%);
.source {
color: var(--newtab-text-secondary-text);
font-size: var(--newtab-font-size-xsmall);
font-size: var(--font-size-small);
}
// Sponsored by text
@ -498,7 +494,7 @@ $ds-card-image-gradient-solid: rgba(0, 0, 0, 100%);
.story-sponsored-label {
line-height: unset;
font-size: var(--newtab-font-size-xsmall);
font-size: var(--font-size-small);
}
}
@ -512,7 +508,7 @@ $ds-card-image-gradient-solid: rgba(0, 0, 0, 100%);
display: grid;
align-content: center;
height: 28px;
font-size: var(--newtab-font-size-xsmall);
font-size: var(--font-size-small);
color: var(--newtab-text-topic-label-color);
margin: initial;
padding: initial;

View file

@ -7,8 +7,8 @@ import { useDispatch, useSelector } from "react-redux";
import { actionCreators as ac, actionTypes as at } from "common/Actions.mjs";
import { useIntersectionObserver } from "../../../lib/hooks";
const PREF_FOLLOWED_SECTIONS = "discoverystream.sections.following";
const PREF_TOPIC_SELECTION_POSITION =
"discoverystream.sections.topicSelection.position";
const PREF_VISIBLE_SECTIONS =
"discoverystream.sections.interestPicker.visibleSections";
/**
* Shows a list of recommended topics with visual indication whether
@ -17,40 +17,34 @@ const PREF_TOPIC_SELECTION_POSITION =
*
* @returns {React.Element}
*/
function InlineTopicSelection() {
function InterestPicker({ data }) {
const dispatch = useDispatch();
const focusedRef = useRef(null);
const focusRef = useRef(null);
const [focusedIndex, setFocusedIndex] = useState(0);
const prefs = useSelector(state => state.Prefs.values);
const visibleSections = prefs[PREF_VISIBLE_SECTIONS]?.split(",")
.map(item => item.trim())
.filter(item => item);
const { title, subtitle, receivedFeedRank, sections } = data;
// if undefined or null, assign as empty array to avoid an error
const interests = sections ?? [];
const following = prefs[PREF_FOLLOWED_SECTIONS]
? prefs[PREF_FOLLOWED_SECTIONS].split(", ")
? prefs[PREF_FOLLOWED_SECTIONS].split(",")
: [];
// Stub out topics, will replace with server topics
const topics = [
{ label: "Politics", id: "government" },
{ label: "Sports", id: "sports" },
{ label: "Life Hacks", id: "society" },
{ label: "Food", id: "food" },
{ label: "Tech", id: "tech" },
{ label: "Travel", id: "travel" },
{ label: "Health", id: "health" },
{ label: "Money", id: "finance" },
{ label: "Science", id: "education-science" },
{ label: "Home & Garden", id: "home" },
{ label: "Entertainment", id: "arts" },
];
const handleIntersection = useCallback(() => {
dispatch(
ac.AlsoToMain({
type: at.INLINE_SELECTION_IMPRESSION,
data: {
position: prefs[PREF_TOPIC_SELECTION_POSITION],
position: receivedFeedRank,
},
})
);
}, [dispatch, prefs]);
}, [dispatch, receivedFeedRank]);
const ref = useIntersectionObserver(handleIntersection);
@ -95,6 +89,12 @@ function InlineTopicSelection() {
updatedTopics = updatedTopics.length
? [...updatedTopics, topic]
: [topic];
if (!visibleSections.includes(topic)) {
// add section to visible sections and place after the inline picker
// subtract 1 from the rank so that it is normalized with array index
visibleSections.splice(receivedFeedRank - 1, 0, topic);
dispatch(ac.SetPref(PREF_VISIBLE_SECTIONS, visibleSections.join(",")));
}
} else {
updatedTopics = updatedTopics.filter(t => t !== topic);
}
@ -105,13 +105,12 @@ function InlineTopicSelection() {
topic,
is_followed: checked,
topic_position: index,
position: prefs[PREF_TOPIC_SELECTION_POSITION],
position: receivedFeedRank,
},
})
);
dispatch(ac.SetPref(PREF_FOLLOWED_SECTIONS, updatedTopics.join(", ")));
dispatch(ac.SetPref(PREF_FOLLOWED_SECTIONS, updatedTopics.join(",")));
}
return (
<section
className="inline-selection-wrapper"
@ -120,27 +119,26 @@ function InlineTopicSelection() {
}}
>
{/* Will replace copy here to copy sent from over the server */}
<h2>Follow topics to personalize your feed</h2>
<p className="inline-selection-copy">
We will bring you personalized content, all while respecting your
privacy. You'll have powerful control over what content you see and what
you don't.
</p>
<h2>{title}</h2>
<p className="inline-selection-copy">{subtitle}</p>
<ul
className="topic-list"
onFocus={onWrapperFocus}
onBlur={onWrapperBlur}
ref={focusRef}
>
{topics.map((topic, index) => {
const checked = following.includes(topic.id);
{interests.map((interest, index) => {
const checked = following.includes(interest.sectionId);
return (
<li key={topic.id} ref={index === focusedIndex ? focusedRef : null}>
<li
key={interest.id}
ref={index === focusedIndex ? focusedRef : null}
>
<label>
<input
type="checkbox"
id={topic.id}
name={topic.id}
id={interest.sectionId}
name={interest.sectionId}
checked={checked}
aria-checked={checked}
onChange={e => handleChange(e, index)}
@ -149,7 +147,10 @@ function InlineTopicSelection() {
onItemFocus(index);
}}
/>
<span className="topic-item-label">{topic.label}</span>
<span
className="topic-item-label"
data-l10n-id={`newtab-topic-label-${interest.sectionId}`}
/>
<div
className={`topic-item-icon icon ${checked ? "icon-check-filled" : "icon-add-circle-fill"}`}
></div>
@ -168,4 +169,4 @@ function InlineTopicSelection() {
);
}
export { InlineTopicSelection };
export { InterestPicker };

View file

@ -33,8 +33,6 @@ $shadow-image-inset: inset 0 0 0 0.5px $black-15;
--newtab-background-card: #{$newtab-background-card};
--newtab-text-topic-label-color: #45278D;
--newtab-text-secondary-text: #15141AB0;
// Non-design system font size for extra small text. Orginially used on ds-card refresh UI
--newtab-font-size-xsmall: 11px;
// We need to be careful about the contrast of text over newtab wallpapers, which might not match the theme.
// --newtab-text-primary-color is set in contextTheme.js and reacts to possible installed addon themes.
// If we use that variable here, with light-dark, we can retain that addon theme text color,

View file

@ -201,6 +201,6 @@ input {
@import '../components/DiscoveryStreamComponents/ListFeed/ListFeed';
@import '../components/DiscoveryStreamComponents/AdBanner/AdBanner';
@import '../components/DiscoveryStreamComponents/SectionContextMenu/SectionContextMenu';
@import '../components/DiscoveryStreamComponents/InlineTopicSelection/InlineTopicSelection';
@import '../components/DiscoveryStreamComponents/InterestPicker/InterestPicker';
// stylelint-enable no-invalid-position-at-import-rule

View file

@ -40,7 +40,6 @@ input {
--newtab-background-card: rgba(255, 255, 255, 0.8);
--newtab-text-topic-label-color: #45278D;
--newtab-text-secondary-text: #15141AB0;
--newtab-font-size-xsmall: 11px;
--newtab-contextual-text-primary-color: light-dark(var(--newtab-text-primary-color), #fbfbfe);
--newtab-primary-action-background: light-dark(#0061e0, #00ddff);
--newtab-primary-action-background-pocket: #008078;
@ -6079,10 +6078,6 @@ main section {
transition-delay: 333ms;
}
:root {
--newtab-font-size-xsmall: 11px;
}
.ds-card {
display: flex;
flex-direction: column;
@ -6453,7 +6448,7 @@ main section {
}
.ds-card-grid .sections-card-ui .meta .source {
color: var(--newtab-text-secondary-text);
font-size: var(--newtab-font-size-xsmall);
font-size: var(--font-size-small);
}
.ds-card-grid .sections-card-ui .meta .story-footer {
justify-content: flex-start;
@ -6467,7 +6462,7 @@ main section {
}
.ds-card-grid .sections-card-ui .meta .story-sponsored-label {
line-height: unset;
font-size: var(--newtab-font-size-xsmall);
font-size: var(--font-size-small);
}
.ds-card-grid .sections-card-ui .sections-card-footer {
margin-block-start: var(--space-small);
@ -6478,7 +6473,7 @@ main section {
display: grid;
align-content: center;
height: 28px;
font-size: var(--newtab-font-size-xsmall);
font-size: var(--font-size-small);
color: var(--newtab-text-topic-label-color);
margin: initial;
padding: initial;

View file

@ -10062,7 +10062,7 @@ function SectionContextMenu({
}
}));
}
;// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/InlineTopicSelection/InlineTopicSelection.jsx
;// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/InterestPicker/InterestPicker.jsx
/* 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/. */
@ -10072,7 +10072,7 @@ function SectionContextMenu({
const PREF_FOLLOWED_SECTIONS = "discoverystream.sections.following";
const PREF_TOPIC_SELECTION_POSITION = "discoverystream.sections.topicSelection.position";
const PREF_VISIBLE_SECTIONS = "discoverystream.sections.interestPicker.visibleSections";
/**
* Shows a list of recommended topics with visual indication whether
@ -10081,56 +10081,32 @@ const PREF_TOPIC_SELECTION_POSITION = "discoverystream.sections.topicSelection.p
*
* @returns {React.Element}
*/
function InlineTopicSelection() {
function InterestPicker({
data
}) {
const dispatch = (0,external_ReactRedux_namespaceObject.useDispatch)();
const focusedRef = (0,external_React_namespaceObject.useRef)(null);
const focusRef = (0,external_React_namespaceObject.useRef)(null);
const [focusedIndex, setFocusedIndex] = (0,external_React_namespaceObject.useState)(0);
const prefs = (0,external_ReactRedux_namespaceObject.useSelector)(state => state.Prefs.values);
const following = prefs[PREF_FOLLOWED_SECTIONS] ? prefs[PREF_FOLLOWED_SECTIONS].split(", ") : [];
// Stub out topics, will replace with server topics
const topics = [{
label: "Politics",
id: "government"
}, {
label: "Sports",
id: "sports"
}, {
label: "Life Hacks",
id: "society"
}, {
label: "Food",
id: "food"
}, {
label: "Tech",
id: "tech"
}, {
label: "Travel",
id: "travel"
}, {
label: "Health",
id: "health"
}, {
label: "Money",
id: "finance"
}, {
label: "Science",
id: "education-science"
}, {
label: "Home & Garden",
id: "home"
}, {
label: "Entertainment",
id: "arts"
}];
const visibleSections = prefs[PREF_VISIBLE_SECTIONS]?.split(",").map(item => item.trim()).filter(item => item);
const {
title,
subtitle,
receivedFeedRank,
sections
} = data;
// if undefined or null, assign as empty array to avoid an error
const interests = sections ?? [];
const following = prefs[PREF_FOLLOWED_SECTIONS] ? prefs[PREF_FOLLOWED_SECTIONS].split(",") : [];
const handleIntersection = (0,external_React_namespaceObject.useCallback)(() => {
dispatch(actionCreators.AlsoToMain({
type: actionTypes.INLINE_SELECTION_IMPRESSION,
data: {
position: prefs[PREF_TOPIC_SELECTION_POSITION]
position: receivedFeedRank
}
}));
}, [dispatch, prefs]);
}, [dispatch, receivedFeedRank]);
const ref = useIntersectionObserver(handleIntersection);
const onKeyDown = (0,external_React_namespaceObject.useCallback)(e => {
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
@ -10166,6 +10142,12 @@ function InlineTopicSelection() {
let updatedTopics = following;
if (checked) {
updatedTopics = updatedTopics.length ? [...updatedTopics, topic] : [topic];
if (!visibleSections.includes(topic)) {
// add section to visible sections and place after the inline picker
// subtract 1 from the rank so that it is normalized with array index
visibleSections.splice(receivedFeedRank - 1, 0, topic);
dispatch(actionCreators.SetPref(PREF_VISIBLE_SECTIONS, visibleSections.join(",")));
}
} else {
updatedTopics = updatedTopics.filter(t => t !== topic);
}
@ -10175,32 +10157,32 @@ function InlineTopicSelection() {
topic,
is_followed: checked,
topic_position: index,
position: prefs[PREF_TOPIC_SELECTION_POSITION]
position: receivedFeedRank
}
}));
dispatch(actionCreators.SetPref(PREF_FOLLOWED_SECTIONS, updatedTopics.join(", ")));
dispatch(actionCreators.SetPref(PREF_FOLLOWED_SECTIONS, updatedTopics.join(",")));
}
return /*#__PURE__*/external_React_default().createElement("section", {
className: "inline-selection-wrapper",
ref: el => {
ref.current = [el];
}
}, /*#__PURE__*/external_React_default().createElement("h2", null, "Follow topics to personalize your feed"), /*#__PURE__*/external_React_default().createElement("p", {
}, /*#__PURE__*/external_React_default().createElement("h2", null, title), /*#__PURE__*/external_React_default().createElement("p", {
className: "inline-selection-copy"
}, "We will bring you personalized content, all while respecting your privacy. You'll have powerful control over what content you see and what you don't."), /*#__PURE__*/external_React_default().createElement("ul", {
}, subtitle), /*#__PURE__*/external_React_default().createElement("ul", {
className: "topic-list",
onFocus: onWrapperFocus,
onBlur: onWrapperBlur,
ref: focusRef
}, topics.map((topic, index) => {
const checked = following.includes(topic.id);
}, interests.map((interest, index) => {
const checked = following.includes(interest.sectionId);
return /*#__PURE__*/external_React_default().createElement("li", {
key: topic.id,
key: interest.id,
ref: index === focusedIndex ? focusedRef : null
}, /*#__PURE__*/external_React_default().createElement("label", null, /*#__PURE__*/external_React_default().createElement("input", {
type: "checkbox",
id: topic.id,
name: topic.id,
id: interest.sectionId,
name: interest.sectionId,
checked: checked,
"aria-checked": checked,
onChange: e => handleChange(e, index),
@ -10209,8 +10191,9 @@ function InlineTopicSelection() {
onItemFocus(index);
}
}), /*#__PURE__*/external_React_default().createElement("span", {
className: "topic-item-label"
}, topic.label), /*#__PURE__*/external_React_default().createElement("div", {
className: "topic-item-label",
"data-l10n-id": `newtab-topic-label-${interest.sectionId}`
}), /*#__PURE__*/external_React_default().createElement("div", {
className: `topic-item-icon icon ${checked ? "icon-check-filled" : "icon-add-circle-fill"}`
})));
})), /*#__PURE__*/external_React_default().createElement("p", {
@ -10245,8 +10228,8 @@ const CardSections_PREF_FOLLOWED_SECTIONS = "discoverystream.sections.following"
const PREF_BLOCKED_SECTIONS = "discoverystream.sections.blocked";
const CardSections_PREF_TOPICS_AVAILABLE = "discoverystream.topicSelection.topics";
const CardSections_PREF_THUMBS_UP_DOWN_ENABLED = "discoverystream.thumbsUpDown.enabled";
const PREF_TOPIC_SELECTION_ENABLED = "discoverystream.sections.topicSelection.enabled";
const CardSections_PREF_TOPIC_SELECTION_POSITION = "discoverystream.sections.topicSelection.position";
const PREF_INTEREST_PICKER_ENABLED = "discoverystream.sections.interestPicker.enabled";
const CardSections_PREF_VISIBLE_SECTIONS = "discoverystream.sections.interestPicker.visibleSections";
function getLayoutData(responsiveLayouts, index) {
let layoutData = {
classNames: [],
@ -10286,13 +10269,14 @@ function getMaxTiles(responsiveLayouts) {
}
/**
* Transforms a comma-separated string of topics in user preferences
* Transforms a comma-separated string in user preferences
* into a cleaned-up array.
*
* @param pref
* @returns string[]
* @param {string} pref - The comma-separated pref to be converted.
* @returns {string[]} An array of trimmed strings, excluding empty values.
*/
const getTopics = pref => {
const prefToArray = (pref = "") => {
return pref.split(",").map(item => item.trim()).filter(item => item);
};
function CardSection({
@ -10327,9 +10311,9 @@ function CardSection({
const {
responsiveLayouts
} = section.layout;
const followedSections = getTopics(followedSectionsPref);
const followedSections = prefToArray(followedSectionsPref);
const following = followedSections.includes(sectionKey);
const blockedSections = getTopics(blockedSectionsPref);
const blockedSections = prefToArray(blockedSectionsPref);
const handleIntersection = (0,external_React_namespaceObject.useCallback)(() => {
dispatch(actionCreators.AlsoToMain({
type: actionTypes.CARD_SECTION_IMPRESSION,
@ -10497,20 +10481,48 @@ function CardSections({
}) {
const prefs = (0,external_ReactRedux_namespaceObject.useSelector)(state => state.Prefs.values);
const personalizationEnabled = prefs[PREF_SECTIONS_PERSONALIZATION_ENABLED];
const topicSelectionEnabled = prefs[PREF_TOPIC_SELECTION_ENABLED];
const topicSelectionPosition = prefs[CardSections_PREF_TOPIC_SELECTION_POSITION];
const interestPickerEnabled = prefs[PREF_INTEREST_PICKER_ENABLED];
// Handle a render before feed has been fetched by displaying nothing
if (!data) {
return null;
}
// Retrieve blocked sections
const blockedSections = getTopics(prefs[PREF_BLOCKED_SECTIONS] || "");
// Only show sections that haven't been blocked by the user
const sections = data.sections.filter(section => !blockedSections.includes(section.sectionKey));
const isEmpty = sections.length === 0;
const visibleSections = prefToArray(prefs[CardSections_PREF_VISIBLE_SECTIONS]);
const blockedSections = prefToArray(prefs[PREF_BLOCKED_SECTIONS] || "");
const {
interestPicker
} = data;
let filteredSections = data.sections.filter(section => !blockedSections.includes(section.sectionKey));
if (interestPickerEnabled && visibleSections.length) {
filteredSections = visibleSections.reduce((acc, visibleSection) => {
const found = filteredSections.find(({
sectionKey
}) => sectionKey === visibleSection);
if (found) {
acc.push(found);
}
return acc;
}, []);
}
let sectionsToRender = filteredSections.map((section, sectionPosition) => /*#__PURE__*/external_React_default().createElement(CardSection, {
key: `section-${section.sectionKey}`,
sectionPosition: sectionPosition,
section: section,
dispatch: dispatch,
type: type,
firstVisibleTimestamp: firstVisibleTimestamp,
is_collection: is_collection,
spocMessageVariant: spocMessageVariant,
ctaButtonVariant: ctaButtonVariant,
ctaButtonSponsors: ctaButtonSponsors
}));
if (interestPickerEnabled && personalizationEnabled && interestPicker) {
const index = interestPicker.receivedFeedRank - 1;
sectionsToRender.splice(Math.min(sectionsToRender.length - 1, index), 0, /*#__PURE__*/external_React_default().createElement(InterestPicker, {
data: interestPicker
}));
}
const isEmpty = sectionsToRender.length === 0;
return isEmpty ? /*#__PURE__*/external_React_default().createElement("div", {
className: "ds-card-grid empty"
}, /*#__PURE__*/external_React_default().createElement(DSEmptyState, {
@ -10519,21 +10531,7 @@ function CardSections({
feed: feed
})) : /*#__PURE__*/external_React_default().createElement("div", {
className: "ds-section-wrapper"
}, sections.map((section, sectionPosition) => {
const shouldRenderTopicSelection = sectionPosition === topicSelectionPosition && personalizationEnabled && topicSelectionEnabled;
return /*#__PURE__*/external_React_default().createElement((external_React_default()).Fragment, null, shouldRenderTopicSelection && /*#__PURE__*/external_React_default().createElement(InlineTopicSelection, null), /*#__PURE__*/external_React_default().createElement(CardSection, {
key: `section-${section.sectionKey}`,
sectionPosition: sectionPosition,
section: section,
dispatch: dispatch,
type: type,
firstVisibleTimestamp: firstVisibleTimestamp,
is_collection: is_collection,
spocMessageVariant: spocMessageVariant,
ctaButtonVariant: ctaButtonVariant,
ctaButtonSponsors: ctaButtonSponsors
}));
}));
}, sectionsToRender);
}
;// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamBase/DiscoveryStreamBase.jsx
@ -10919,7 +10917,7 @@ const SectionsMgmtPanel_PREF_BLOCKED_SECTIONS = "discoverystream.sections.blocke
* @returns string[]
*/
// TODO: DRY Issue: Import function from CardSections.jsx?
const SectionsMgmtPanel_getTopics = pref => {
const getTopics = pref => {
return pref.split(",").map(item => item.trim()).filter(item => item);
};
function SectionsMgmtPanel({
@ -10943,8 +10941,8 @@ function SectionsMgmtPanel({
}
const followedSectionsPref = prefs[SectionsMgmtPanel_PREF_FOLLOWED_SECTIONS] || "";
const blockedSectionsPref = prefs[SectionsMgmtPanel_PREF_BLOCKED_SECTIONS] || "";
const followedSections = SectionsMgmtPanel_getTopics(followedSectionsPref);
const blockedSections = SectionsMgmtPanel_getTopics(blockedSectionsPref);
const followedSections = getTopics(followedSectionsPref);
const blockedSections = getTopics(blockedSectionsPref);
const [followedSectionsState, setFollowedSectionsState] = (0,external_React_namespaceObject.useState)(followedSectionsPref); // State management with useState
const [blockedSectionsState, setBlockedSectionsState] = (0,external_React_namespaceObject.useState)(blockedSectionsPref); // State management with useState

View file

@ -187,7 +187,7 @@ module.exports = function (config) {
/**
* Tests for inline topic selection are coming in a follow-up task
*/
"content-src/components/DiscoveryStreamComponents/InlineTopicSelection/*.jsx":
"content-src/components/DiscoveryStreamComponents/InterestPicker/*.jsx":
{
statements: 0,
lines: 0,
@ -203,9 +203,9 @@ module.exports = function (config) {
},
"content-src/components/DiscoveryStreamComponents/CardSections/CardSections.jsx":
{
statements: 93.62,
lines: 93.48,
functions: 92.31,
statements: 90.82,
lines: 90.53,
functions: 87.5,
branches: 60,
},
"content-src/components/DiscoveryStreamComponents/SectionContextMenu/SectionContextMenu.jsx":

View file

@ -587,17 +587,17 @@ export const PREFS_CONFIG = new Map([
},
],
[
"discoverystream.sections.topicSelection.enabled",
"discoverystream.sections.interestPicker.enabled",
{
title: "Boolean flag to enable inline topic selection",
title: "Boolean flag to enable the inline interest picker",
value: false,
},
],
[
"discoverystream.sections.topicSelection.position",
"discoverystream.sections.interestPicker.visibleSections",
{
title: "index position of inline topic selection",
value: 1,
title: "comma separated string of sections that are visible",
value: "",
},
],
[

View file

@ -121,6 +121,10 @@ const PREF_CONTEXTUAL_CONTENT_FAKESPOT_CTA_URL =
const PREF_SECTIONS_ENABLED = "discoverystream.sections.enabled";
const PREF_SECTIONS_FOLLOWING = "discoverystream.sections.following";
const PREF_SECTIONS_BLOCKED = "discoverystream.sections.blocked";
const PREF_INTEREST_PICKER_ENABLED =
"discoverystream.sections.interestPicker.enabled";
const PREF_VISIBLE_SECTIONS =
"discoverystream.sections.interestPicker.visibleSections";
let getHardcodedLayout;
@ -1704,6 +1708,8 @@ export class DiscoveryStreamFeed {
subtitle: sectionData.subtitle || "",
receivedRank: sectionData.receivedFeedRank,
layout: sectionData.layout,
// property if initially shown (with interest picker)
visible: sectionData.isInitiallyVisible,
});
}
}
@ -1725,6 +1731,20 @@ export class DiscoveryStreamFeed {
"feed"
);
if (sections.length) {
const visibleSections = sections
.filter(({ visible }) => visible)
.sort((a, b) => a.receivedRank - b.receivedRank)
.map(section => section.sectionKey)
.join(",");
// after the request only show the sections that are
// initially visible and only keep the initial order (determined by the server)
this.store.dispatch(
ac.SetPref(PREF_VISIBLE_SECTIONS, visibleSections)
);
}
// We can cleanup any impressions we have that are old before we rotate.
// In theory we can do this anywhere, but doing it just before rotate is optimal.
// Rotate is also the only place that uses these impressions.
@ -1740,6 +1760,7 @@ export class DiscoveryStreamFeed {
data: {
settings,
sections,
interestPicker: feedResponse.interestPicker || {},
recommendations: filteredResults,
status: "success",
},
@ -1844,6 +1865,9 @@ export class DiscoveryStreamFeed {
isBlocked: blockedSections.includes(section),
}));
// To display the inline interest picker pass `enableInterestPicker` into the request
const interestPickerEnabled = prefs[PREF_INTEREST_PICKER_ENABLED];
headers.append("content-type", "application/json");
let body = {
...(prefMerinoFeedExperiment ? this.getExperimentInfo() : {}),
@ -1851,6 +1875,7 @@ export class DiscoveryStreamFeed {
region: this.region,
topics,
sections,
enableInterestPicker: !!interestPickerEnabled,
};
const sectionsEnabled = prefs[PREF_SECTIONS_ENABLED];
@ -2360,6 +2385,7 @@ export class DiscoveryStreamFeed {
case PREF_CONTEXTUAL_CONTENT_ENABLED:
case PREF_CONTEXTUAL_CONTENT_SELECTED_FEED:
case PREF_SECTIONS_ENABLED:
case PREF_INTEREST_PICKER_ENABLED:
// This is a config reset directly related to Discovery Stream pref.
this.configReset();
break;

View file

@ -3518,6 +3518,7 @@ describe("DiscoveryStreamFeed", () => {
data: {
settings: {},
sections: [],
interestPicker: {},
recommendations: [
{
id: 1234,

View file

@ -296,7 +296,7 @@
},
"interventions": [
{
"platforms": ["desktop"],
"platforms": ["all"],
"ua_string": ["add_Chrome"]
}
]
@ -1333,6 +1333,10 @@
"1944323": {
"issue": "firefox-blocked-completely",
"matches": ["*://*.yabbycasino.com/*"]
},
"1947963": {
"issue": "firefox-blocked-completely",
"matches": ["*://*.slotmadness.com/*"]
}
},
"interventions": [
@ -1377,23 +1381,6 @@
}
]
},
"1830813": {
"label": "onstove.com",
"bugs": {
"1898966": {
"issue": "unsupported-warning",
"matches": ["*://*.onstove.com/*"]
}
},
"interventions": [
{
"platforms": ["desktop"],
"content_scripts": {
"css": ["bug1830813-page.onstove.com-hide-unsupported.css"]
}
}
]
},
"1830821_90981": {
"label": "enjoy.point.auone.jp",
"bugs": {
@ -2195,6 +2182,21 @@
}
]
},
"1898909": {
"label": "remotasks.com",
"bugs": {
"1898909": {
"issue": "firefox-blocked-completely",
"matches": ["*://*.remotasks.com/*"]
}
},
"interventions": [
{
"platforms": ["all"],
"ua_string": ["add_Chrome"]
}
]
},
"1898923": {
"label": "trade-in.vodafone.com",
"bugs": {
@ -2589,6 +2591,21 @@
}
]
},
"1914327": {
"label": "media.qdnd.vn",
"bugs": {
"1914327": {
"issue": "broken-videos",
"matches": ["*://media.qdnd.vn/*"]
}
},
"interventions": [
{
"platforms": ["android"],
"ua_string": ["Chrome"]
}
]
},
"1921410": {
"label": "beta.maps.apple.com",
"bugs": {
@ -2787,6 +2804,23 @@
}
]
},
"1943920": {
"label": "add.org",
"bugs": {
"1943920": {
"issue": "broken-layout",
"matches": ["*://add.org/adhd-facts*"]
}
},
"interventions": [
{
"platforms": ["android"],
"content_scripts": {
"css": ["bug1943920-add.org-fix-overlapping-menu.css"]
}
}
]
},
"1941530": {
"label": "climate.rutgers.edu",
"bugs": {
@ -2853,6 +2887,21 @@
}
]
},
"1944518": {
"label": "app.powerbi.com",
"bugs": {
"1944518": {
"issue": "broken-scrolling",
"matches": ["*://app.powerbi.com/view*"]
}
},
"interventions": [
{
"platforms": ["mac"],
"ua_string": ["add_Chrome"]
}
]
},
"1944727": {
"label": "linkedin.com",
"bugs": {
@ -2905,5 +2954,52 @@
}
}
]
},
"1947105": {
"label": "pexels.com",
"bugs": {
"1947105": {
"issue": "broken-layout",
"matches": ["*://*.pexels.com/photo/*"]
}
},
"interventions": [
{
"platforms": ["all"],
"content_scripts": {
"css": ["bug1947105-pexels.com-nudge-thanks-popup-onscreen.css"]
}
}
]
},
"1947407": {
"label": "y.qq.com",
"bugs": {
"1947407": {
"issue": "firefox-blocked-completely",
"matches": ["*://y.qq.com/artists*"]
}
},
"interventions": [
{
"platforms": ["desktop"],
"ua_string": ["add_Chrome"]
}
]
},
"1948723": {
"label": "babel.com",
"bugs": {
"1948723": {
"issue": "firefox-blocked-completely",
"matches": ["*://*.babel.com/*"]
}
},
"interventions": [
{
"platforms": ["all"],
"ua_string": ["Chrome"]
}
]
}
}

View file

@ -1,19 +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/. */
/**
* onstove.com - Unsupported message
* Bug #1830813 - https://bugzilla.mozilla.org/show_bug.cgi?id=1830813
* WebCompat issue #116760 - https://github.com/webcompat/web-bugs/issues/116760
*/
.gnb-alerts.gnb-old-browser {
max-height: 0 !important;
height: 0 !important;
}
.isCampaign .gnb-stove.gnb-default-fixed,
.isCampaign .layout.layout-base .layout-header {
height: 68px !important;
}

View file

@ -0,0 +1,14 @@
/* 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/. */
/**
* add.org/adhd-facts - mobile menu is permanently open
* Bug #1943920 - https://bugzilla.mozilla.org/show_bug.cgi?id=1943920
* WebCompat issue #147170 - https://webcompat.com/issues/147170
*
* The site is using a faulty -moz-transform rule, which we can unset.
*/
.mobile-menu-wrapper {
transform: translate(100%, 0);
}

View file

@ -0,0 +1,14 @@
/* 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/. */
/**
* add.org/adhd-facts - mobile menu is permanently open
* Bug #1943920 - https://bugzilla.mozilla.org/show_bug.cgi?id=1943920
* WebCompat issue #147170 - https://webcompat.com/issues/147170
*
* The site is using a faulty -moz-transform rule, which we can unset.
*/
[class*=Modal_overlay][class*=Modal_positionContentCenter]:has([class*=after-open]) {
justify-content: unset;
}

View file

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "Web Compatibility Interventions",
"description": "Urgent post-release fixes for web compatibility.",
"version": "137.2.0",
"version": "137.3.0",
"browser_specific_settings": {
"gecko": {
"id": "webcompat@mozilla.org",

View file

@ -60,7 +60,6 @@ FINAL_TARGET_FILES.features["webcompat@mozilla.org"]["injections"]["css"] += [
"injections/css/bug1819678-nppes.cms.hhs.gov-unsupported-banner.css",
"injections/css/bug1830752-afisha.ru-slider-pointer-events.css",
"injections/css/bug1830796-copyleaks.com-hide-unsupported.css",
"injections/css/bug1830813-page.onstove.com-hide-unsupported.css",
"injections/css/bug1836103-autostar-novoross.ru-make-map-taller.css",
"injections/css/bug1836105-cnn.com-fix-blank-pages-when-printing.css",
"injections/css/bug1836872-docs.google.com-font-submenus-inaccessible.css",
@ -83,8 +82,10 @@ FINAL_TARGET_FILES.features["webcompat@mozilla.org"]["injections"]["css"] += [
"injections/css/bug1934567-www.port8.fi-scrolling-fix.css",
"injections/css/bug1941530-climate.rutgers.edu-fix-broken-images.css",
"injections/css/bug1942292-beterbed.nl-scrollbar-fix.css",
"injections/css/bug1943920-add.org-fix-overlapping-menu.css",
"injections/css/bug1944727-www.linkedin.com-fix-dark-overlay.css",
"injections/css/bug1945830-aliexpress.com-country-flags-fix.css",
"injections/css/bug1947105-pexels.com-nudge-thanks-popup-onscreen.css",
]
FINAL_TARGET_FILES.features["webcompat@mozilla.org"]["injections"]["js"] += [

View file

@ -0,0 +1,3 @@
#!/bin/bash
export TMPDIR=$XDG_CACHE_HOME/tmp
exec /app/lib/firefox/firefox --name org.mozilla.firefox "$@"

View file

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>org.mozilla.firefox</id>
<launchable type="desktop-id">org.mozilla.firefox.desktop</launchable>
<name>Firefox</name>
<developer_name>Mozilla</developer_name>
<summary>Fast, Private &amp; Safe Web Browser</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>MPL-2.0</project_license>
<description>
<p>When it comes to your life online, you have a choice: accept the factory settings or put your privacy first. When you choose Firefox as your default browser, youre choosing to protect your data while supporting an independent tech company. Firefox is also the only major browser backed by a non-profit fighting to give you more openness, transparency and control of your life online. Join hundreds of millions of people who choose to protect what's important by choosing Firefox - a web browser designed to be fast, easy to use, customizable and private.</p>
</description>
<releases>
<release version="$VERSION" date="$DATE"/>
</releases>
<keywords>
<keyword>mozilla</keyword>
<keyword>internet</keyword>
<keyword>web</keyword>
</keywords>
<content_rating type="oars-1.1" />
<url type="homepage">https://www.mozilla.org/firefox/</url>
<url type="donation">https://donate.mozilla.org/</url>
<url type="bugtracker">https://bugzilla.mozilla.org/</url>
<url type="help">https://support.mozilla.org/</url>
<url type="translate">https://wiki.mozilla.org/L10n:Starting_a_localization</url>
<screenshots>
<screenshot type="default">
<image type="source">https://raw.githubusercontent.com/mozilla-releng/scriptworker-scripts/master/pushflatpakscript/media/screenshots/image1.png</image>
<caption>The “New Tab” page</caption>
</screenshot>
<screenshot>
<image type="source">https://raw.githubusercontent.com/mozilla-releng/scriptworker-scripts/master/pushflatpakscript/media/screenshots/image2.png</image>
<caption>A Wikipedia article displayed in Firefox</caption>
</screenshot>
<screenshot>
<image type="source">https://raw.githubusercontent.com/mozilla-releng/scriptworker-scripts/master/pushflatpakscript/media/screenshots/image3.png</image>
<caption>The “Welcome to Firefox” page: “Open up an amazing internet”</caption>
</screenshot>
</screenshots>
<custom>
<value key="flathub::manifest">https://hg.mozilla.org/mozilla-central/file/tip/browser/installer/linux/app/flatpak</value>
</custom>
</component>

View file

@ -0,0 +1,6 @@
<!-- 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/. -->
<svg id="Assets" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M190.368 150.591c0.157 0.009 0.079 0.003 0 0zm-57.874-28.933c0.158 0.008 0.079 0.003 0 0zm346.228 44.674c-10.445-25.123-31.6-52.248-48.211-60.82 13.52 26.5 21.345 53.093 24.335 72.935 0 0.04 0.015 0.136 0.047 0.4-27.175-67.732-73.254-95.047-110.886-154.512-1.9-3.008-3.805-6.022-5.661-9.2a73.237 73.237 0 0 1-2.646-4.972 43.757 43.757 0 0 1-3.585-9.5 0.625 0.625 0 0 0-0.546-0.644 0.8 0.8 0 0 0-0.451 0c-0.033 0.011-0.084 0.051-0.119 0.065-0.053 0.02-0.12 0.069-0.176 0.095 0.026-0.036 0.083-0.117 0.1-0.135-53.437 31.3-75.587 86.093-81.282 120.97a128.057 128.057 0 0 0-47.624 12.153 6.144 6.144 0 0 0-3.041 7.63 6.034 6.034 0 0 0 8.192 3.525 116.175 116.175 0 0 1 41.481-10.826c0.468-0.033 0.937-0.062 1.405-0.1a117.624 117.624 0 0 1 5.932-0.211 120.831 120.831 0 0 1 34.491 4.777c0.654 0.192 1.295 0.414 1.946 0.616a120.15 120.15 0 0 1 5.539 1.842 121.852 121.852 0 0 1 3.992 1.564c1.074 0.434 2.148 0.868 3.206 1.331a118.453 118.453 0 0 1 4.9 2.307c0.743 0.368 1.485 0.735 2.217 1.117a120.535 120.535 0 0 1 4.675 2.587 107.785 107.785 0 0 1 2.952 1.776 123.018 123.018 0 0 1 42.028 43.477c-12.833-9.015-35.81-17.918-57.947-14.068 86.441 43.214 63.234 192.027-56.545 186.408a106.7 106.7 0 0 1-31.271-6.031 132.461 132.461 0 0 1-7.059-2.886c-1.356-0.618-2.711-1.243-4.051-1.935-29.349-15.168-53.583-43.833-56.611-78.643 0 0 11.093-41.335 79.433-41.335 7.388 0 28.508-20.614 28.9-26.593-0.09-1.953-41.917-18.59-58.223-34.656-8.714-8.585-12.851-12.723-16.514-15.829a71.7 71.7 0 0 0-6.225-4.7 111.335 111.335 0 0 1-0.675-58.733c-24.687 11.242-43.89 29.011-57.849 44.7h-0.111c-9.528-12.067-8.855-51.873-8.312-60.184-0.114-0.516-7.107 3.63-8.024 4.254a175.21 175.21 0 0 0-23.486 20.12 210.5 210.5 0 0 0-22.443 26.913c0 0.012-0.007 0.025-0.011 0.037 0-0.012 0.007-0.025 0.011-0.038a202.837 202.837 0 0 0-32.244 72.81c-0.058 0.265-2.29 10.054-3.92 22.147a265.794 265.794 0 0 0-0.769 5.651c-0.558 3.636-0.992 7.6-1.42 13.767-0.019 0.239-0.031 0.474-0.048 0.712a591.152 591.152 0 0 0-0.481 7.995c0 0.411-0.025 0.816-0.025 1.227 0 132.709 107.6 240.29 240.324 240.29 118.865 0 217.559-86.288 236.882-199.63 0.407-3.075 0.732-6.168 1.092-9.27 4.777-41.21-0.53-84.525-15.588-120.747zm-164.068 72.1z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -0,0 +1,19 @@
[Application]
name=org.mozilla.firefox
runtime=org.freedesktop.Platform/${ARCH}/${FREEDESKTOP_VERSION}
sdk=org.freedesktop.Sdk/${ARCH}/${FREEDESKTOP_VERSION}
base=app/org.mozilla.firefox.BaseApp/${ARCH}/${FIREFOX_BASEAPP_CHANNEL}
[Extension org.mozilla.firefox.Locale]
directory=share/runtime/langpack
autodelete=true
locale-subset=true
[Extension org.freedesktop.Platform.ffmpeg-full]
directory=lib/ffmpeg
add-ld-path=.
no-autodownload=true
version=${FREEDESKTOP_VERSION}
[Extension org.mozilla.firefox.systemconfig]
directory=etc/firefox
no-autodownload=true

Some files were not shown because too many files have changed in this diff Show more