tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 9b58c0eea14de212a0f6ac1b7522fdb2e69cf9ea
parent 09d499108aa8ab890d415aa95489d5b56337a10c
Author: mimi <nsauermann@mozilla.com>
Date:   Thu,  4 Dec 2025 21:03:28 +0000

Bug 1985131 - [MenuMessage] Allow set to default menu message to render above fxa menu item r=desktop-theme-reviewers,omc-reviewers,mviar,mconley,Itiel

Differential Revision: https://phabricator.services.mozilla.com/D272953

Diffstat:
Mbrowser/base/content/appmenu-viewcache.inc.xhtml | 2+-
Mbrowser/components/asrouter/content-src/schemas/MessagingExperiment.schema.json | 8++++++--
Mbrowser/components/asrouter/content-src/templates/OnboardingMessage/MenuMessage.schema.json | 8++++++--
Mbrowser/components/asrouter/content/components/fxa-menu-message/fxa-menu-message.css | 5+++++
Mbrowser/components/asrouter/content/components/fxa-menu-message/fxa-menu-message.stories.mjs | 21++++++++++++++++-----
Mbrowser/components/asrouter/modules/MenuMessage.sys.mjs | 72++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mbrowser/components/asrouter/tests/browser/browser_asrouter_menu_messages.js | 131++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mbrowser/components/asrouter/tests/chrome/test_fxa_menu_message.html | 7+++----
Mbrowser/themes/shared/customizableui/panelUI-shared.css | 2+-
9 files changed, 178 insertions(+), 78 deletions(-)

diff --git a/browser/base/content/appmenu-viewcache.inc.xhtml b/browser/base/content/appmenu-viewcache.inc.xhtml @@ -11,7 +11,7 @@ wrap="true" hidden="true"/> - <toolbaritem id="appMenu-fxa-menu-message" + <toolbaritem id="appMenu-menu-message" closemenu="none"> </toolbaritem> <toolbaritem id="appMenu-fxa-status2" diff --git a/browser/components/asrouter/content-src/schemas/MessagingExperiment.schema.json b/browser/components/asrouter/content-src/schemas/MessagingExperiment.schema.json @@ -923,7 +923,7 @@ "properties": { "messageType": { "type": "string", - "description": "The subtype of the message. 'fxa_cta' is used for Firefox Accounts messaging and is only visible when signed out, unless 'allowWhenSignedIn' property is provided. 'default_cta' is used for general messages, regardless of sign in state and only visible within the App Menu.", + "description": "The subtype of the message. 'fxa_cta' is used for Firefox Accounts messaging and is only visible when signed out, unless 'allowWhenSignedIn' property is provided. It replaces the fxa menu item when displayed. 'default_cta' is used for general messages, regardless of sign in state and only visible within the App Menu.", "enum": [ "fxa_cta", "default_cta" @@ -935,7 +935,7 @@ }, "secondaryText": { "$ref": "chrome://browser/content/asrouter/schemas/MessagingExperiment.schema.json#/$defs/localizableText", - "description": "The second text for the message, which offers more detail on the value proposition to the user." + "description": "The secondary text for the message, which offers more detail on the value proposition to the user. Not displayed when layout is 'simple'." }, "closeAction": { "type": "object", @@ -1011,6 +1011,10 @@ "type": "number", "description": "The container's margin-block-end value in pixels. Used to visually offset the image in 'row' layouts when 'imageVerticalBottomOffset' is applied." }, + "containerPaddingBottom": { + "type": "number", + "description": "The container's padding-block-end value in pixels." + }, "layout": { "type": "string", "description": "The layout of the message content and illustration. Row displays the image inline to the right of the text, column displays the image above the text. Simple layout only displays primary text and primary button on one row.", diff --git a/browser/components/asrouter/content-src/templates/OnboardingMessage/MenuMessage.schema.json b/browser/components/asrouter/content-src/templates/OnboardingMessage/MenuMessage.schema.json @@ -15,7 +15,7 @@ "properties": { "messageType": { "type": "string", - "description": "The subtype of the message. 'fxa_cta' is used for Firefox Accounts messaging and is only visible when signed out, unless 'allowWhenSignedIn' property is provided. 'default_cta' is used for general messages, regardless of sign in state and only visible within the App Menu.", + "description": "The subtype of the message. 'fxa_cta' is used for Firefox Accounts messaging and is only visible when signed out, unless 'allowWhenSignedIn' property is provided. It replaces the fxa menu item when displayed. 'default_cta' is used for general messages, regardless of sign in state and only visible within the App Menu.", "enum": ["fxa_cta", "default_cta"] }, "primaryText": { @@ -24,7 +24,7 @@ }, "secondaryText": { "$ref": "file:///FxMSCommon.schema.json#/$defs/localizableText", - "description": "The second text for the message, which offers more detail on the value proposition to the user." + "description": "The secondary text for the message, which offers more detail on the value proposition to the user. Not displayed when layout is 'simple'." }, "closeAction": { "type": "object", @@ -93,6 +93,10 @@ "type": "number", "description": "The container's margin-block-end value in pixels. Used to visually offset the image in 'row' layouts when 'imageVerticalBottomOffset' is applied." }, + "containerPaddingBottom": { + "type": "number", + "description": "The container's padding-block-end value in pixels." + }, "layout": { "type": "string", "description": "The layout of the message content and illustration. Row displays the image inline to the right of the text, column displays the image above the text. Simple layout only displays primary text and primary button on one row.", diff --git a/browser/components/asrouter/content/components/fxa-menu-message/fxa-menu-message.css b/browser/components/asrouter/content/components/fxa-menu-message/fxa-menu-message.css @@ -20,6 +20,7 @@ border-radius: var(--border-radius-small); padding-block: var(--arrowpanel-menuitem-padding-block, var(--space-small)); padding-inline: var(--arrowpanel-menuitem-padding-inline, var(--space-small)); + padding-block-end: var(--container-padding-block-end, var(--arrowpanel-menuitem-padding-block)); margin-block-start: var(--space-small); color: var(--text-color); } @@ -110,3 +111,7 @@ font-size: 1em; font-weight: initial; } + +#container[layout="simple"] #primary-button { + margin-inline-start: var(--space-medium); +} diff --git a/browser/components/asrouter/content/components/fxa-menu-message/fxa-menu-message.stories.mjs b/browser/components/asrouter/content/components/fxa-menu-message/fxa-menu-message.stories.mjs @@ -23,6 +23,7 @@ const Template = ({ imageVerticalTopOffset, imageVerticalBottomOffset, containerVerticalBottomOffset, + containerPaddingBottom, layout, imageWidth, logoWidth, @@ -36,11 +37,20 @@ const Template = ({ imageURL=${imageURL} logoURL=${logoURL} style=" - --illustration-margin-block-start-offset: ${imageVerticalTopOffset}px; - --illustration-margin-block-end-offset: ${imageVerticalBottomOffset}px; - --container-margin-block-end-offset: ${containerVerticalBottomOffset}px; - --image-width: ${imageWidth}px; - --logo-width: ${logoWidth}px; + ${imageVerticalTopOffset !== undefined + ? `--illustration-margin-block-start-offset: ${imageVerticalTopOffset}px;` + : ""} + ${imageVerticalBottomOffset !== undefined + ? `--illustration-margin-block-end-offset: ${imageVerticalBottomOffset}px;` + : ""} + ${containerVerticalBottomOffset !== undefined + ? `--container-margin-block-end-offset: ${containerVerticalBottomOffset}px;` + : ""} + ${imageWidth !== undefined ? `--image-width: ${imageWidth}px;` : ""} + ${logoWidth !== undefined ? `--logo-width: ${logoWidth}px;` : ""} + ${containerPaddingBottom !== undefined + ? `--container-padding-block-end: ${containerPaddingBottom}px;` + : ""} " layout=${layout} > @@ -61,6 +71,7 @@ Default.args = { imageVerticalTopOffset: -20, imageVerticalBottomOffset: 0, containerVerticalBottomOffset: 0, + containerPaddingBottom: 8, layout: "column", imageWidth: 120, logoWidth: 18, diff --git a/browser/components/asrouter/modules/MenuMessage.sys.mjs b/browser/components/asrouter/modules/MenuMessage.sys.mjs @@ -32,6 +32,7 @@ export const MenuMessage = { pxi_menu: new Set(["fxa_cta"]), }), SHOWING_FXA_MENU_MESSAGE_ATTR: "showing-fxa-menu-message", + SHOWING_SET_TO_DEFAULT_MENU_MESSAGE_ATTR: "showing-default-cta-menu-message", async showMenuMessage(browser, message, trigger, force) { if (!browser) { @@ -123,6 +124,7 @@ export const MenuMessage = { async showAppMenuMessage(browser, message, force) { const win = browser.ownerGlobal; const msgContainer = this.hideAppMenuMessage(browser); + const type = message?.content?.messageType; // This version of the browser only supports the fxa_cta and // default_cta versions of this message in the AppMenu. @@ -136,21 +138,21 @@ export const MenuMessage = { return; } - win.PanelUI.mainView.setAttribute( - MenuMessage.SHOWING_FXA_MENU_MESSAGE_ATTR, - message.id - ); + const menuMessageAttribute = + type === this.MESSAGE_TYPES.DEFAULT_CTA + ? MenuMessage.SHOWING_SET_TO_DEFAULT_MENU_MESSAGE_ATTR + : MenuMessage.SHOWING_FXA_MENU_MESSAGE_ATTR; - let msgElement = await this.constructFxAMessage( + let msgElement = await this.constructMenuMessage( win, message, MenuMessage.SOURCES.APP_MENU ); + win.PanelUI.mainView.setAttribute(menuMessageAttribute, message.id); + msgElement.addEventListener("MenuMessage:Close", () => { - win.PanelUI.mainView.removeAttribute( - MenuMessage.SHOWING_FXA_MENU_MESSAGE_ATTR - ); + win.PanelUI.mainView.removeAttribute(menuMessageAttribute); }); msgElement.addEventListener("MenuMessage:PrimaryButton", () => { @@ -169,12 +171,15 @@ export const MenuMessage = { const document = browser.ownerDocument; const msgContainer = lazy.PanelMultiView.getViewNode( document, - "appMenu-fxa-menu-message" + "appMenu-menu-message" ); msgContainer.innerHTML = ""; win.PanelUI.mainView.removeAttribute( MenuMessage.SHOWING_FXA_MENU_MESSAGE_ATTR ); + win.PanelUI.mainView.removeAttribute( + MenuMessage.SHOWING_SET_TO_DEFAULT_MENU_MESSAGE_ATTR + ); return msgContainer; }, @@ -195,7 +200,7 @@ export const MenuMessage = { message.id ); - let msgElement = await this.constructFxAMessage( + let msgElement = await this.constructMenuMessage( win, message, MenuMessage.SOURCES.PXI_MENU @@ -235,7 +240,7 @@ export const MenuMessage = { return msgContainer; }, - async constructFxAMessage(win, message, source) { + async constructMenuMessage(win, message, source) { let { document, gBrowser } = win; win.MozXULElement.insertFTLIfNeeded("browser/newtab/asrouter.ftl"); @@ -252,9 +257,12 @@ export const MenuMessage = { msgElement.primaryText = await lazy.RemoteL10n.formatLocalizableText( message.content.primaryText ); - msgElement.secondaryText = await lazy.RemoteL10n.formatLocalizableText( - message.content.secondaryText - ); + // Simple layout does not support secondary text + if (message.content.layout !== "simple" && message.content.secondaryText) { + msgElement.secondaryText = await lazy.RemoteL10n.formatLocalizableText( + message.content.secondaryText + ); + } msgElement.dataset.navigableWithTabOnly = "true"; if (message.content.imageWidth !== undefined) { msgElement.style.setProperty( @@ -268,18 +276,30 @@ export const MenuMessage = { `${message.content.logoWidth}px` ); } - msgElement.style.setProperty( - "--illustration-margin-block-start-offset", - `${message.content.imageVerticalTopOffset}px` - ); - msgElement.style.setProperty( - "--illustration-margin-block-end-offset", - `${message.content.imageVerticalBottomOffset}px` - ); - msgElement.style.setProperty( - "--container-margin-block-end-offset", - `${message.content.containerVerticalBottomOffset}px` - ); + if (message.content.imageVerticalTopOffset !== undefined) { + msgElement.style.setProperty( + "--illustration-margin-block-start-offset", + `${message.content.imageVerticalTopOffset}px` + ); + } + if (message.content.imageVerticalBottomOffset !== undefined) { + msgElement.style.setProperty( + "--illustration-margin-block-end-offset", + `${message.content.imageVerticalBottomOffset}px` + ); + } + if (message.content.containerVerticalBottomOffset !== undefined) { + msgElement.style.setProperty( + "--container-margin-block-end-offset", + `${message.content.containerVerticalBottomOffset}px` + ); + } + if (message.content.containerPaddingBottom !== undefined) { + msgElement.style.setProperty( + "--container-padding-block-end", + `${message.content.containerPaddingBottom}px` + ); + } msgElement.addEventListener("MenuMessage:Close", () => { msgElement.remove(); diff --git a/browser/components/asrouter/tests/browser/browser_asrouter_menu_messages.js b/browser/components/asrouter/tests/browser/browser_asrouter_menu_messages.js @@ -189,18 +189,38 @@ async function assertMessageInMenuSource(source, message, win = window) { if (source === MenuMessage.SOURCES.APP_MENU) { // The zap gradient and the default sign-in button should be hidden. - Assert.ok( - BrowserTestUtils.isHidden( - win.PanelUI.mainView.querySelector("#appMenu-fxa-separator") - ), - "Zap gradient separator is hidden in the AppMenu." - ); - Assert.ok( - BrowserTestUtils.isHidden( - win.PanelUI.mainView.querySelector("#appMenu-fxa-status2") - ), - "Default FxA sign-in button is hidden in the AppMenu." - ); + const isFxAMessage = + message.content.messageType === MenuMessage.MESSAGE_TYPES.FXA_CTA; + + if (isFxAMessage) { + // fxa_cta replaces the FxA row in the App Menu. + Assert.ok( + BrowserTestUtils.isHidden( + win.PanelUI.mainView.querySelector("#appMenu-fxa-separator") + ), + "Zap gradient separator is hidden in the AppMenu for fxa_cta." + ); + Assert.ok( + BrowserTestUtils.isHidden( + win.PanelUI.mainView.querySelector("#appMenu-fxa-status2") + ), + "Default FxA sign-in button is hidden in the AppMenu for fxa_cta." + ); + } else { + // default_cta should not replace fxa row in the App menu. + Assert.ok( + BrowserTestUtils.isVisible( + win.PanelUI.mainView.querySelector("#appMenu-fxa-separator") + ), + "Zap gradient separator is visible in the AppMenu for default_cta." + ); + Assert.ok( + BrowserTestUtils.isVisible( + win.PanelUI.mainView.querySelector("#appMenu-fxa-status2") + ), + "Default FxA sign-in button is visible in the AppMenu for default_cta." + ); + } } else if (source === MenuMessage.SOURCES.PXI_MENU) { Assert.ok( BrowserTestUtils.isHidden( @@ -424,6 +444,31 @@ add_setup(async function () { }); }); +function buildDefaultCtaMessage({ + id = "TEST_DEFAULT_CTA", + layout = "column", +} = {}) { + return { + id, + template: "menu_message", + content: { + layout, + messageType: "default_cta", + primaryText: "Firefox is not your default browser", + primaryActionText: "Set as default", + primaryButtonSize: "small", + logoURL: "chrome://branding/content/about-logo.svg", + secondaryText: + "Make Firefox your default browser to open links from other apps.", + primaryAction: {}, + closeAction: {}, + }, + targeting: "true", + trigger: { id: "menuOpened" }, + groups: [], + }; +} + /** * Tests that opening each menu source causes the menuOpened trigger to fire. * We stub ASRouter to return no messages so this test is message-free. @@ -717,31 +762,6 @@ add_task(async function test_fxa_cta_notification_precedence() { sandbox.restore(); }); -function buildDefaultCtaMessage({ - id = "TEST_DEFAULT_CTA", - layout = "column", -} = {}) { - return { - id, - template: "menu_message", - content: { - layout, - messageType: "default_cta", - primaryText: "Firefox is not your default browser", - primaryActionText: "Set as default", - primaryButtonSize: "small", - logoURL: "chrome://branding/content/about-logo.svg", - secondaryText: - "Make Firefox your default browser to open links from other apps.", - primaryAction: {}, - closeAction: {}, - }, - targeting: "true", - trigger: { id: "menuOpened" }, - groups: [], - }; -} - add_task(async function test_default_cta_allowed_sources() { let sandbox = sinon.createSandbox(); @@ -798,3 +818,40 @@ add_task(async function test_message_type_suppression_rules() { signedInStub.restore?.(); sandbox.restore(); }); + +/** + * 'default_cta' messages shown in the App Menu should not replace the FxA + * sign-in row and should appear as its own banner above it. + */ +add_task(async function test_default_cta_does_not_replace_fxa_row() { + let sandbox = sinon.createSandbox(); + + const defaultMsg = buildDefaultCtaMessage({ + id: "TEST_DEFAULT_CTA_SIMPLE_LAYOUT", + layout: "simple", + }); + + await withTestMessage(sandbox, defaultMsg, async () => { + await reopenMenuSource( + MenuMessage.SOURCES.APP_MENU, + defaultMsg, + window, + async (_msgEl, panel) => { + const view = panel.ownerGlobal.PanelUI.mainView; + const separator = view.querySelector("#appMenu-fxa-separator"); + const fxaRow = view.querySelector("#appMenu-fxa-status2"); + + Assert.ok( + BrowserTestUtils.isVisible(separator), + "FxA separator remains visible for default_cta." + ); + Assert.ok( + BrowserTestUtils.isVisible(fxaRow), + "FxA sign-in row remains visible for default_cta." + ); + } + ); + }); + + sandbox.restore(); +}); diff --git a/browser/components/asrouter/tests/chrome/test_fxa_menu_message.html b/browser/components/asrouter/tests/chrome/test_fxa_menu_message.html @@ -277,9 +277,8 @@ message.buttonText = "Set as default"; message.primaryText = "Firefox is not your default browser"; message.secondaryText = "You should not see me!"; - // Provide URLs to ensure imgage exist but are hidden by the CSS - message.logoURL = - "chrome://branding/content/about-logo.svg"; + // Provide URLs to ensure images exist but are hidden by the CSS + message.logoURL = "chrome://branding/content/about-logo.svg"; message.imageURL = "chrome://browser/content/asrouter/assets/fox-with-devices.svg"; @@ -320,7 +319,7 @@ ); } message.remove(); - }); + }); </script> </head> <body> diff --git a/browser/themes/shared/customizableui/panelUI-shared.css b/browser/themes/shared/customizableui/panelUI-shared.css @@ -663,7 +663,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="panel"] > .toolbarbutton-badg /* Handle different UI states. */ -#appMenu-mainView:not([showing-fxa-menu-message]) #appMenu-fxa-menu-message, +#appMenu-mainView:not([showing-fxa-menu-message], [showing-default-cta-menu-message]) #appMenu-menu-message, #PanelUI-fxa:not([showing-fxa-menu-message]) #PanelUI-fxa-menu-message { display: none; }