Bug 1845150 - Use moz-message-bar instead of message-bar in notificationbox.js r=webdriver-reviewers,desktop-theme-reviewers,media-playback-reviewers,karlt,whimboo,tgiles,dao,devtools-reviewers

This patch updates the `NotificationMessage` element in `notificationbox.js` so that it extends our newer `moz-message-bar` component instead of the deprecated `message-bar` component. Many of the changes are just dealing with the implications of making things async (so that we can ensure `moz-message-bar.mjs` gets imported). I tried to break out places where I modified related code and tests into separate patches to mitigate some of the review pain here.

This patch solves a longstanding issue where we were loading `in-content/common-shared.css` in the chrome since it gets used by the `message-bar` element. It also makes some small visual changes to our infobars (slight outline, icon colors, adds a bit of spacing).

Differential Revision: https://phabricator.services.mozilla.com/D189872
This commit is contained in:
Hanna Jones 2024-01-10 18:55:29 +00:00
Родитель 9c1d13a6a6
Коммит 614f900ec6
25 изменённых файлов: 392 добавлений и 341 удалений

Просмотреть файл

@ -178,11 +178,20 @@ export class PluginParent extends JSWindowActorParent {
buttons.push(submitButton);
}
// Add the "learn more" link.
let learnMoreLink = {
supportPage: "plugin-crashed-notificationbar",
label: lazy.gNavigatorBundle.GetStringFromName(
"crashedpluginsMessage.learnMore"
),
};
buttons.push(learnMoreLink);
let messageString = lazy.gNavigatorBundle.formatStringFromName(
"crashedpluginsMessage.title",
[report.pluginName]
);
notification = notificationBox.appendNotification(
notificationBox.appendNotification(
"plugin-crashed",
{
label: messageString,
@ -191,21 +200,5 @@ export class PluginParent extends JSWindowActorParent {
},
buttons
);
// Add the "learn more" link.
let link = notification.ownerDocument.createXULElement("label", {
is: "text-link",
});
link.setAttribute(
"value",
lazy.gNavigatorBundle.GetStringFromName("crashedpluginsMessage.learnMore")
);
let crashurl = Services.urlFormatter.formatURLPref("app.support.baseURL");
crashurl += "plugin-crashed-notificationbar";
link.href = crashurl;
// Append a blank text node to make sure we don't put
// the link right next to the end of the message text.
notification.messageText.appendChild(new Text(" "));
notification.messageText.appendChild(link);
}
}

Просмотреть файл

@ -40,7 +40,7 @@ var gDataNotificationInfoBar = {
return gNotificationBox.getNotificationWithValue(name);
},
_displayDataPolicyInfoBar(request) {
async _displayDataPolicyInfoBar(request) {
if (this._getDataReportingNotification()) {
return;
}
@ -59,7 +59,7 @@ var gDataNotificationInfoBar = {
];
this._log.info("Creating data reporting policy notification.");
gNotificationBox.appendNotification(
await gNotificationBox.appendNotification(
this._DATA_REPORTING_NOTIFICATION,
{
label: {

Просмотреть файл

@ -1106,7 +1106,7 @@ const gStoragePressureObserver = {
}
messageFragment.appendChild(message);
gNotificationBox.appendNotification(
await gNotificationBox.appendNotification(
NOTIFICATION_VALUE,
{
label: messageFragment,
@ -1122,7 +1122,7 @@ const gStoragePressureObserver = {
};
var gPopupBlockerObserver = {
handleEvent(aEvent) {
async handleEvent(aEvent) {
if (aEvent.originalTarget != gBrowser.selectedBrowser) {
return;
}
@ -1158,23 +1158,31 @@ var gPopupBlockerObserver = {
let notificationBox = gBrowser.getNotificationBox();
let notification =
notificationBox.getNotificationWithValue("popup-blocked");
notificationBox.getNotificationWithValue("popup-blocked") ||
(await this.notificationPromise);
if (notification) {
notification.label = label;
} else {
const image = "chrome://browser/skin/notification-icons/popup.svg";
const priority = notificationBox.PRIORITY_INFO_MEDIUM;
notificationBox.appendNotification(
"popup-blocked",
{ label, image, priority },
[
{
"l10n-id": "popup-warning-button",
popup: "blockedPopupOptions",
callback: null,
},
]
);
try {
this.notificationPromise = notificationBox.appendNotification(
"popup-blocked",
{ label, image, priority },
[
{
"l10n-id": "popup-warning-button",
popup: "blockedPopupOptions",
callback: null,
},
]
);
await this.notificationPromise;
} catch (err) {
console.warn(err);
} finally {
this.notificationPromise = null;
}
}
}
@ -1402,7 +1410,7 @@ var gKeywordURIFixup = {
let asciiHost = fixedURI.asciiHost;
let onLookupCompleteListener = {
onLookupComplete(request, record, status) {
async onLookupComplete(request, record, status) {
let browserRef = weakBrowser.get();
if (!Components.isSuccessCode(status) || !browserRef) {
return;
@ -1457,7 +1465,7 @@ var gKeywordURIFixup = {
},
},
];
let notification = notificationBox.appendNotification(
let notification = await notificationBox.appendNotification(
"keyword-uri-fixup",
{
label: message,
@ -3334,22 +3342,9 @@ function PageProxyClickHandler(aEvent) {
* us via async messaging.
*/
var BrowserOnClick = {
ignoreWarningLink(reason, blockedInfo, browsingContext) {
let triggeringPrincipal =
blockedInfo.triggeringPrincipal ||
_createNullPrincipalFromTabUserContextId();
// Allow users to override and continue through to the site,
// but add a notify bar as a reminder, so that they don't lose
// track after, e.g., tab switching.
// Note that we have to use the passed URI info and can't just
// rely on the document URI, because the latter contains
// additional query parameters that should be stripped.
browsingContext.fixupAndLoadURIString(blockedInfo.uri, {
triggeringPrincipal,
flags: Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CLASSIFIER,
});
async ignoreWarningLink(reason, blockedInfo, browsingContext) {
// Add a notify bar before allowing the user to continue through to the
// site, so that they don't lose track after, e.g., tab switching.
// We can't use browser.contentPrincipal which is principal of about:blocked
// Create one from uri with current principal origin attributes
let principal = Services.scriptSecurityManager.createContentPrincipal(
@ -3424,7 +3419,20 @@ var BrowserOnClick = {
// provide a URL endpoint for these reports.
}
SafeBrowsingNotificationBox.show(title, buttons);
await SafeBrowsingNotificationBox.show(title, buttons);
// Allow users to override and continue through to the site.
// Note that we have to use the passed URI info and can't just
// rely on the document URI, because the latter contains
// additional query parameters that should be stripped.
let triggeringPrincipal =
blockedInfo.triggeringPrincipal ||
_createNullPrincipalFromTabUserContextId();
browsingContext.fixupAndLoadURIString(blockedInfo.uri, {
triggeringPrincipal,
flags: Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CLASSIFIER,
});
},
};
@ -9059,7 +9067,7 @@ var PanicButtonNotifier = {
const SafeBrowsingNotificationBox = {
_currentURIBaseDomain: null,
show(title, buttons) {
async show(title, buttons) {
let uri = gBrowser.currentURI;
// start tracking host so that we know when we leave the domain
@ -9080,7 +9088,7 @@ const SafeBrowsingNotificationBox = {
notificationBox.removeNotification(previousNotification);
}
let notification = notificationBox.appendNotification(
let notification = await notificationBox.appendNotification(
value,
{
label: title,

Просмотреть файл

@ -176,6 +176,7 @@ add_task(async function test_single_window() {
// Wait for the infobar to be displayed.
triggerInfoBar(10 * 1000);
await alertShownPromise;
await promiseNextTick();
Assert.equal(
gNotificationBox.allNotifications.length,

Просмотреть файл

@ -187,21 +187,23 @@ add_task(async function test_can_update_notification() {
// should have fired, so the notification should be visible.
let notificationBox = gBrowser.getNotificationBox(browser);
let notification = notificationBox.currentNotification;
let [redirectLabel, refreshLabel] = await document.l10n.formatValues([
{ id: "refresh-blocked-redirect-label" },
{ id: "refresh-blocked-refresh-label" },
]);
let message = notification.messageText.querySelector("span");
is(
message.dataset.l10nId,
"refresh-blocked-redirect-label",
notification.messageText.textContent.trim(),
redirectLabel,
"Should be showing the redirect message"
);
// Next, attempt a refresh
await attemptFakeRefresh(browser, false);
message = notification.messageText.querySelector("span");
is(
message.dataset.l10nId,
"refresh-blocked-refresh-label",
notification.messageText.textContent.trim(),
refreshLabel,
"Should be showing the refresh message"
);
}

Просмотреть файл

@ -31,15 +31,16 @@ add_task(async function showNotification() {
verifyTelemetry("initial", 0, 0, 0, 0, 0, 0);
let notif3 = box3.appendNotification("infobar-testtwo-value", {
let notif3 = await box3.appendNotification("infobar-testtwo-value", {
label: "Message for tab 3",
priority: box3.PRIORITY_INFO_HIGH,
telemetry: TELEMETRY_BASE + "testtwo",
});
await notif3.updateComplete;
verifyTelemetry("first notification", 0, 0, 0, 0, 0, 1);
let notif1 = box1.appendNotification(
let notif1 = await box1.appendNotification(
"infobar-testone-value",
{
label: "Message for tab 1",
@ -60,6 +61,7 @@ add_task(async function showNotification() {
},
]
);
await notif1.updateComplete;
verifyTelemetry("second notification", 0, 0, 0, 0, 0, 1);
await BrowserTestUtils.switchTab(gBrowser, tab1);
@ -89,7 +91,7 @@ add_task(async function showNotification() {
notif3.dismiss();
verifyTelemetry("dismiss notification for box 3", 1, 1, 1, 1, 1, 1, 1);
let notif4 = box1.appendNotification(
let notif4 = await box1.appendNotification(
"infobar-testtwo-value",
{
label: "Additional message for tab 1",
@ -103,13 +105,14 @@ add_task(async function showNotification() {
},
]
);
await notif4.updateComplete;
verifyTelemetry("show first filtered notification", 2, 1, 1, 1, 1, 1, 1);
notif4.buttonContainer.lastElementChild.click();
notif4.dismiss();
verifyTelemetry("dismiss first filtered notification", 2, 1, 1, 1, 1, 1, 1);
let notif5 = box1.appendNotification(
let notif5 = await box1.appendNotification(
"infobar-testtwo-value",
{
label: "Dimissed additional message for tab 1",
@ -123,13 +126,14 @@ add_task(async function showNotification() {
},
]
);
await notif5.updateComplete;
verifyTelemetry("show second filtered notification", 2, 1, 1, 1, 1, 1, 1);
notif5.buttonContainer.lastElementChild.click();
notif5.dismiss();
verifyTelemetry("dismiss second filtered notification", 2, 1, 1, 1, 2, 1, 1);
let notif6 = box1.appendNotification(
let notif6 = await box1.appendNotification(
"infobar-testtwo-value",
{
label: "Dimissed additional message for tab 1",
@ -144,6 +148,7 @@ add_task(async function showNotification() {
},
]
);
await notif6.updateComplete;
verifyTelemetry("show third filtered notification", 2, 1, 1, 1, 2, 1, 1);
notif6.buttonContainer.lastElementChild.click();

Просмотреть файл

@ -32,9 +32,9 @@ function assertNotificationBoxShown(reason, browser) {
is(selectedViewName, name, `Box is shown ${reason}`);
}
function createNotification({ browser, label, value, priority }) {
async function createNotification({ browser, label, value, priority }) {
let notificationBox = gBrowser.getNotificationBox(browser);
let notification = notificationBox.appendNotification(value, {
let notification = await notificationBox.appendNotification(value, {
label,
priority: notificationBox[priority],
});
@ -52,7 +52,7 @@ add_task(async function testNotificationInBackgroundTab() {
gBrowser.selectedTab = firstTab;
assertNotificationBoxHidden("initial first tab");
createNotification({
await createNotification({
browser,
label: "My notification body",
value: "test-notification",
@ -69,7 +69,7 @@ add_task(async function testNotificationInActiveTab() {
await BrowserTestUtils.withNewTab("about:blank", async browser => {
ok(!gBrowser.readNotificationBox(browser), "No notifications for new tab");
createNotification({
await createNotification({
browser,
label: "Notification!",
value: "test-notification",
@ -108,7 +108,7 @@ add_task(async function testNotificationMultipleTabs() {
assertNotificationBoxHidden("after open", browserTwo);
assertNotificationBoxHidden("after open", browserThree);
createNotification({
await createNotification({
browser: browserTwo,
label: "Test blank",
value: "blank",
@ -121,7 +121,7 @@ add_task(async function testNotificationMultipleTabs() {
assertNotificationBoxHidden("hidden create", browserTwo);
assertNotificationBoxHidden("other create", browserThree);
createNotification({
await createNotification({
browser: browserThree,
label: "Test active tab",
value: "active",

Просмотреть файл

@ -36,6 +36,11 @@ add_task(async function test_drm_prompt_shows_for_toplevel() {
// Turn off EME and Widevine CDM.
Services.prefs.setBoolPref("media.eme.enabled", false);
Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", false);
let notificationShownPromise = BrowserTestUtils.waitForNotificationBar(
gBrowser,
browser,
"drmContentDisabled"
);
// Have content request access to Widevine, UI should drop down to
// prompt user to enable DRM.
@ -64,7 +69,9 @@ add_task(async function test_drm_prompt_shows_for_toplevel() {
// Verify the UI prompt showed.
let box = gBrowser.getNotificationBox(browser);
await notificationShownPromise;
let notification = box.currentNotification;
await notification.updateComplete;
ok(notification, "Notification should be visible");
is(
@ -152,6 +159,11 @@ add_task(async function test_drm_prompt_shows_for_cross_origin_iframe() {
// Turn off EME and Widevine CDM.
Services.prefs.setBoolPref("media.eme.enabled", false);
Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", false);
let notificationShownPromise = BrowserTestUtils.waitForNotificationBar(
gBrowser,
browser,
"drmContentDisabled"
);
// Have content request access to Widevine, UI should drop down to
// prompt user to enable DRM.
@ -198,7 +210,9 @@ add_task(async function test_drm_prompt_shows_for_cross_origin_iframe() {
// Verify the UI prompt showed.
let box = gBrowser.getNotificationBox(browser);
await notificationShownPromise;
let notification = box.currentNotification;
await notification.updateComplete;
ok(notification, "Notification should be visible");
is(

Просмотреть файл

@ -54,7 +54,7 @@ add_task(async function () {
"Correct priority."
);
is(
notification.messageText.textContent,
notification.messageText.textContent.trim(),
"The GlobalTestPlugin plugin has crashed.",
"Correct message."
);

Просмотреть файл

@ -3736,12 +3736,12 @@ BrowserGlue.prototype = {
* Show the notificationBox for a locked places database.
*/
_showPlacesLockedNotificationBox:
function BG__showPlacesLockedNotificationBox() {
async function BG__showPlacesLockedNotificationBox() {
var win = lazy.BrowserWindowTracker.getTopWindow();
var buttons = [{ supportPage: "places-locked" }];
var notifyBox = win.gBrowser.getNotificationBox();
var notification = notifyBox.appendNotification(
var notification = await notifyBox.appendNotification(
"places-locked",
{
label: { "l10n-id": "places-locked-prompt" },
@ -4616,7 +4616,7 @@ BrowserGlue.prototype = {
];
const notifyBox = win.gBrowser.getNotificationBox();
const notification = notifyBox.appendNotification(
const notification = await notifyBox.appendNotification(
"startup-restore-session-suggestion",
{
label: messageFragment,

Просмотреть файл

@ -40,16 +40,9 @@ add_task(async function () {
"info",
"We expect this notification to have the type of 'info'."
);
// Make sure the CSS is fully loaded...
ok(
await TestUtils.waitForCondition(
() =>
notification.ownerGlobal.getComputedStyle(
notification.messageImage,
"::after"
).backgroundImage == 'url("chrome://global/skin/icons/info-filled.svg")'
),
is(
notification.messageImage.getAttribute("src"),
"chrome://global/skin/icons/info-filled.svg",
"We expect this notification to have an icon."
);

Просмотреть файл

@ -46,7 +46,7 @@ addRDMTask(
const notificationEl = box.currentNotification;
ok(notificationEl, "Notification should be visible");
is(
notificationEl.messageText.textContent,
notificationEl.messageText.textContent.trim(),
"The device pixel ratio was reduced to 1 as the resulting image was too large",
"The expected warning was displayed"
);

Просмотреть файл

@ -112,7 +112,7 @@ async function test_decoder_doctor_notification(
label = await document.l10n.formatValue(label.l10nId);
}
if (isLink) {
let link = notification.messageText.querySelector("a");
let link = notification.supportLinkEls[0];
if (link) {
// Seems to be a Windows specific quirk, but without this
// mutation observer the notification.messageText.textContent
@ -126,13 +126,13 @@ async function test_decoder_doctor_notification(
}
}
is(
notification.messageText.textContent,
notificationMessage + (isLink && label ? ` ${label}` : ""),
notification.messageText.textContent.trim(),
notificationMessage,
"notification message should match expectation"
);
let button = notification.buttonContainer.querySelector("button");
let link = notification.messageText.querySelector("a");
let link = notification.supportLinkEls[0];
if (!label) {
ok(!button, "There should not be a button");
ok(!link, "There should not be a link");
@ -141,7 +141,7 @@ async function test_decoder_doctor_notification(
if (isLink) {
ok(!button, "There should not be a button");
is(link.innerText, label, `notification link should be '${label}'`);
is(link.textContent, label, `notification link should be '${label}'`);
ok(
!link.hasAttribute("accesskey"),
"notification link should not have accesskey"

Просмотреть файл

@ -123,7 +123,7 @@ class TestSafeBrowsingNotificationBar(WindowManagerMixin, MarionetteTestCase):
message = notification_box.find_element(
By.CSS_SELECTOR, "notification-message[value=blocked-badware-page]"
)
button = message.get_property("closeButton")
button = message.get_property("closeButtonEl")
button.click()
Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(

Просмотреть файл

@ -106,6 +106,7 @@ toolkit.jar:
content/global/elements/moz-toggle.css (widgets/moz-toggle/moz-toggle.css)
content/global/elements/moz-toggle.mjs (widgets/moz-toggle/moz-toggle.mjs)
content/global/elements/named-deck.js (widgets/named-deck.js)
content/global/elements/infobar.css (widgets/infobar.css)
content/global/elements/notificationbox.js (widgets/notificationbox.js)
content/global/elements/panel.js (widgets/panel.js)
content/global/elements/panel-item.css (widgets/panel-list/panel-item.css)

Просмотреть файл

@ -28,14 +28,14 @@ function completeAnimation(nextTest) {
setTimeout(completeAnimation, 50, nextTest);
}
function test() {
async function test() {
SimpleTest.waitForExplicitFinish();
gNotificationBox = new MozElements.NotificationBox(e => {
document.getElementById("nb").appendChild(e);
});
is(gNotificationBox.allNotifications.length, 0, "There should be no initial notifications");
gNotificationBox.appendNotification("notification1",
await gNotificationBox.appendNotification("notification1",
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
is(gNotificationBox.allNotifications.length, 1, "Notification exists while animating in");
let notification = gNotificationBox.getNotificationWithValue("notification1");
@ -46,7 +46,7 @@ function test() {
}
// Tests that a notification that is fully animated in gets removed immediately
function test1() {
async function test1() {
let notification = gNotificationBox.getNotificationWithValue("notification1");
gNotificationBox.removeNotification(notification);
notification = gNotificationBox.getNotificationWithValue("notification1");
@ -59,8 +59,8 @@ function test1() {
}
// Tests that a notification that is animating in gets removed immediately
function test2() {
let notification = gNotificationBox.appendNotification("notification2",
async function test2() {
let notification = await gNotificationBox.appendNotification("notification2",
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
gNotificationBox.removeNotification(notification);
notification = gNotificationBox.getNotificationWithValue("notification2");
@ -74,10 +74,10 @@ function test2() {
}
// Tests that a background notification goes away immediately
function test3() {
let notification = gNotificationBox.appendNotification("notification3",
async function test3() {
let notification = await gNotificationBox.appendNotification("notification3",
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
let notification2 = gNotificationBox.appendNotification("notification4",
let notification2 = await gNotificationBox.appendNotification("notification4",
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
is(gNotificationBox.allNotifications.length, 2, "Test 3 should show 2 notifications present");
gNotificationBox.removeNotification(notification);
@ -96,10 +96,10 @@ function test3() {
}
// Tests that a foreground notification hiding a background one goes away
function test4() {
let notification = gNotificationBox.appendNotification("notification5",
async function test4() {
let notification = await gNotificationBox.appendNotification("notification5",
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
let notification2 = gNotificationBox.appendNotification("notification6",
let notification2 = await gNotificationBox.appendNotification("notification6",
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
gNotificationBox.removeNotification(notification2);
notification2 = gNotificationBox.getNotificationWithValue("notification6");
@ -118,10 +118,10 @@ function test4() {
}
// Tests that removeAllNotifications gets rid of everything
function test5() {
let notification = gNotificationBox.appendNotification("notification7",
async function test5() {
let notification = await gNotificationBox.appendNotification("notification7",
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
let notification2 = gNotificationBox.appendNotification("notification8",
let notification2 = await gNotificationBox.appendNotification("notification8",
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
gNotificationBox.removeAllNotifications();
notification = gNotificationBox.getNotificationWithValue("notification7");
@ -131,7 +131,7 @@ function test5() {
ok(!gNotificationBox.currentNotification, "Test 5 said there was still a current notification");
is(gNotificationBox.allNotifications.length, 0, "Test 5 should show 0 notifications present");
gNotificationBox.appendNotification("notification9",
await gNotificationBox.appendNotification("notification9",
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
// Wait for the notificaton to finish displaying
@ -139,7 +139,7 @@ function test5() {
}
// Tests whether removing an already removed notification doesn't break things
function test6() {
async function test6() {
let notification = gNotificationBox.getNotificationWithValue("notification9");
ok(notification, "Test 6 should have an initial notification");
gNotificationBox.removeNotification(notification);
@ -147,7 +147,7 @@ function test6() {
ok(!gNotificationBox.currentNotification, "Test 6 shouldn't be any current notification");
is(gNotificationBox.allNotifications.length, 0, "Test 6 allNotifications.length should be 0");
notification = gNotificationBox.appendNotification("notification10",
notification = await gNotificationBox.appendNotification("notification10",
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
is(notification, gNotificationBox.currentNotification, "Test 6 should have made the current notification");
gNotificationBox.removeNotification(notification);

Просмотреть файл

@ -20,7 +20,7 @@
var gNotificationBox;
// Tests that a notification that is added in an hidden box didn't throw the animation
function test() {
async function test() {
SimpleTest.waitForExplicitFinish();
gNotificationBox = new MozElements.NotificationBox(e => {
document.getElementById("nb").appendChild(e);
@ -28,7 +28,7 @@ function test() {
is(gNotificationBox.allNotifications.length, 0, "There should be no initial notifications");
gNotificationBox.appendNotification("notification1",
await gNotificationBox.appendNotification("notification1",
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
is(gNotificationBox.allNotifications.length, 1, "Notification exists");

Просмотреть файл

@ -138,18 +138,15 @@ function testtag_notification_eventCallback(expectedEvents, ntf, testName)
var tests =
[
{
test(nb, ntf) {
ntf = nb.appendNotification("mutable", {
async test(nb, ntf) {
ntf = await nb.appendNotification("mutable", {
label: "Original",
priority: nb.PRIORITY_INFO_LOW,
}, testtag_notificationbox_buttons);
ntf.label = "Changed string";
SimpleTest.is(ntf.messageText.textContent, "Changed string", "set notification label with string");
ntf.label = { "l10n-id": "foo-bar" };
const message = ntf.messageText.querySelector("span");
SimpleTest.is(message.dataset.l10nId, "foo-bar", "set notification label with l10n id");
await ntf.updateComplete;
SimpleTest.is(ntf.messageText.textContent.trim(), "Changed string", "set notification label with string");
return ntf;
},
result(nb, ntf) {
@ -162,8 +159,8 @@ var tests =
label attribute set correctly.
*/
{
test(nb, ntf) {
ntf = nb.appendNotification("note", {
async test(nb, ntf) {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_LOW,
@ -183,8 +180,8 @@ var tests =
Ensures that buttons created with the "l10n-id" parameter have
their "l10n-id" assigned correctly.
*/
test(nb, ntf) {
ntf = nb.appendNotification("note", {
async test(nb, ntf) {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_LOW,
@ -200,9 +197,9 @@ var tests =
}
},
{
test(nb, ntf) {
async test(nb, ntf) {
// append a new notification
ntf = nb.appendNotification("note", {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_LOW,
@ -235,9 +232,9 @@ var tests =
}
},
{
test(nb, ntf) {
async test(nb, ntf) {
// append a new notification, but now with an event callback
ntf = nb.appendNotification("note", {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_LOW,
@ -265,8 +262,8 @@ var tests =
}
},
{
test(nb, ntf) {
ntf = nb.appendNotification("note", {
async test(nb, ntf) {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_MEDIUM,
@ -299,8 +296,8 @@ var tests =
}
},
{
test(nb, ntf) {
ntf = nb.appendNotification("note", {
async test(nb, ntf) {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_WARNING_LOW,
@ -321,13 +318,13 @@ var tests =
},
{
repeat: true,
test(nb, arr) {
async test(nb, arr) {
var idx = arr[0];
var ntf = arr[1];
switch (idx) {
case 1:
// append a new notification
ntf = nb.appendNotification("note", {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_LOW,
@ -373,9 +370,9 @@ var tests =
}
},
{
test(nb, ntf) {
async test(nb, ntf) {
// append another notification
ntf = nb.appendNotification("note", {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_MEDIUM,
@ -402,8 +399,8 @@ var tests =
}
},
{
test(nb, ntf) {
ntf = nb.appendNotification("note", {
async test(nb, ntf) {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_HIGH,
@ -419,8 +416,8 @@ var tests =
}
},
{
test(nb, ntf) {
ntf = nb.appendNotification("note", {
async test(nb, ntf) {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_LOW,
@ -437,7 +434,7 @@ var tests =
SimpleTest.is(button.localName, "button", "button is a button");
SimpleTest.ok(!button.href, "button href is not set");
let link = ntf.messageText.lastElementChild;
let link = ntf.querySelector(".notification-link");
SimpleTest.is(link.localName, "label", "link is a label");
SimpleTest.is(link.href, "about:mozilla", "link href is correct");
@ -445,9 +442,9 @@ var tests =
}
},
{
test(nb, ntf) {
async test(nb, ntf) {
// append a new notification
ntf = nb.appendNotification("note", {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_LOW,
@ -473,20 +470,21 @@ var tests =
}
},
{
test(nb, ntf) {
ntf = nb.appendNotification("note", {
async test(nb, ntf) {
ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_LOW,
eventCallback: notification_eventCallback,
}, testtag_notificationbox_supportpage);
await ntf.updateComplete;
SimpleTest.is(ntf && ntf.localName == NOTIFICATION_LOCAL_NAME, true, "append support page notification");
return ntf;
},
result(nb, ntf) {
testtag_notificationbox_State(nb, "append link with callback", ntf, 1);
let link = ntf.messageText.firstElementChild;
let link = ntf.querySelector(".notification-link");
SimpleTest.is(link.localName, "a", "link 1 is an anchor");
SimpleTest.is(link.dataset.l10nId, "moz-support-link-text", "link 1 Fluent ID is set");
SimpleTest.ok(link.href.endsWith("/test1"), "link 1 href is set");
@ -512,20 +510,20 @@ var tests =
}
},
{
test(nb, unused) {
async test(nb, unused) {
// add a number of notifications and check that they are added in order
nb.appendNotification("4", { label: "Four", priority: nb.PRIORITY_INFO_HIGH },
await nb.appendNotification("4", { label: "Four", priority: nb.PRIORITY_INFO_HIGH },
testtag_notificationbox_buttons);
nb.appendNotification("7", { label: "Seven", priority: nb.PRIORITY_WARNING_HIGH },
await nb.appendNotification("7", { label: "Seven", priority: nb.PRIORITY_WARNING_HIGH },
testtag_notificationbox_buttons);
nb.appendNotification("2", { label: "Two", priority: nb.PRIORITY_INFO_LOW });
nb.appendNotification("8", { label: "Eight", priority: nb.PRIORITY_CRITICAL_LOW });
nb.appendNotification("5", { label: "Five", priority: nb.PRIORITY_WARNING_LOW });
nb.appendNotification("6", { label: "Six", priority: nb.PRIORITY_WARNING_HIGH });
nb.appendNotification("1", { label: "One", priority: nb.PRIORITY_INFO_LOW });
nb.appendNotification("9", { label: "Nine", priority: nb.PRIORITY_CRITICAL_MEDIUM });
let ntf = nb.appendNotification("10", { label: "Ten", priority: nb.PRIORITY_CRITICAL_HIGH });
nb.appendNotification("3", { label: "Three", priority: nb.PRIORITY_INFO_MEDIUM });
await nb.appendNotification("2", { label: "Two", priority: nb.PRIORITY_INFO_LOW });
await nb.appendNotification("8", { label: "Eight", priority: nb.PRIORITY_CRITICAL_LOW });
await nb.appendNotification("5", { label: "Five", priority: nb.PRIORITY_WARNING_LOW });
await nb.appendNotification("6", { label: "Six", priority: nb.PRIORITY_WARNING_HIGH });
await nb.appendNotification("1", { label: "One", priority: nb.PRIORITY_INFO_LOW });
await nb.appendNotification("9", { label: "Nine", priority: nb.PRIORITY_CRITICAL_MEDIUM });
let ntf = await nb.appendNotification("10", { label: "Ten", priority: nb.PRIORITY_CRITICAL_HIGH });
await nb.appendNotification("3", { label: "Three", priority: nb.PRIORITY_INFO_MEDIUM });
return ntf;
},
result(nb, ntf) {
@ -558,16 +556,16 @@ var tests =
}
},
{
test(nb, ntf) {
async test(nb, ntf) {
var exh = false;
try {
nb.appendNotification("no", { label: "no", priority: -1 });
await nb.appendNotification("no", { label: "no", priority: -1 });
} catch (ex) { exh = true; }
SimpleTest.is(exh, true, "appendNotification priority too low");
exh = false;
try {
nb.appendNotification("no", { label: "no", priority: 11 });
await nb.appendNotification("no", { label: "no", priority: 11 });
} catch (ex) { exh = true; }
SimpleTest.is(exh, true, "appendNotification priority too high");
@ -579,8 +577,8 @@ var tests =
var appendPriorityTests = [
{
test(nb, priority) {
let ntf = nb.appendNotification("note", {
async test(nb, priority) {
let ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority,
@ -598,9 +596,9 @@ var appendPriorityTests = [
nb.removeCurrentNotification();
return priority;
},
result(nb, priority) {
async result(nb, priority) {
if (priority == nb.PRIORITY_CRITICAL_HIGH) {
let ntf = nb.appendNotification("note", {
let ntf = await nb.appendNotification("note", {
label: "Notification",
image: "happy.png",
priority: nb.PRIORITY_INFO_LOW,
@ -623,7 +621,7 @@ function testtag_notificationbox_State(nb, testid, expecteditem, expectedcount)
function testtag_notification_State(nb, ntf, testid, label, value, image, priority)
{
is(ntf.messageText.textContent, label, testid + " notification label");
is(ntf.messageText.textContent.trim(), label, testid + " notification label");
is(ntf.getAttribute("value"), value, testid + " notification value");
is(ntf.priority, priority, testid + " notification priority");
@ -654,7 +652,7 @@ function testtag_notification_State(nb, ntf, testid, label, value, image, priori
critical: "chrome://global/skin/icons/error.svg",
};
let icon = icons[type];
is(getComputedStyle(ntf.messageImage, "::after").backgroundImage, `url("${icon}")`, "notification image is set");
is(ntf.messageImage.src, icon, "notification image is set");
}
function checkPopupTest(nb, ntf)
@ -697,7 +695,7 @@ function checkPopupClosed()
* function as its arg. The result function may also return a value which
* will be passed to the next repetition or the next test in the array.
*/
function runTimedTests(tests, idx, element, arg)
async function runTimedTests(tests, idx, element, arg)
{
if (idx >= 0 && "result" in tests[idx])
arg = tests[idx].result(element, arg);
@ -707,7 +705,7 @@ function runTimedTests(tests, idx, element, arg)
idx++;
if (idx < tests.length) {
var result = tests[idx].test(element, arg);
let result = await tests[idx].test(element, arg);
setTimeout(runTimedTestsWait, 50, tests, idx, element, result);
}
}

Просмотреть файл

@ -0,0 +1,99 @@
/* 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/. */
:host(.infobar) {
--info-bar-background-color: light-dark(var(--color-white), rgb(66, 65, 77));
--info-bar-text-color: light-dark(var(--color-gray-100), var(--color-gray-05));
position: relative;
&::before {
content: "";
display: block;
width: 2px;
position: absolute;
top: 0;
inset-inline-start: 0;
height: 100%;
border-start-start-radius: 4px;
border-end-start-radius: 4px;
}
.container {
/* Don't let lwthemes set a text-shadow. */
text-shadow: none;
padding-block: 3px;
align-items: center;
}
.content {
gap: 0 12px;
height: fit-content;
}
.close {
margin-block: 4px;
margin-inline-start: 8px;
background-size: 12px;
height: 24px;
width: 24px;
align-self: flex-start;
}
}
@media (prefers-contrast) {
:host(.infobar)::before {
background-color: CanvasText;
}
}
@media not (prefers-contrast) {
:host(.infobar) {
box-shadow: 0 1px 2px rgba(58, 57, 68, 0.1);
background-color: var(--info-bar-background-color);
color: var(--info-bar-text-color);
&::before {
background-image: linear-gradient(0deg, #9059ff 0%, #ff4aa2 52.08%, #ffbd4f 100%);
}
}
}
:host([message-bar-type=infobar]:first-of-type) {
margin-top: 4px;
}
:host([message-bar-type=infobar]) {
margin: 0 4px 4px;
}
::slotted(.notification-button-container) {
gap: 8px;
display: inline-flex;
}
::slotted(.text-link) {
margin: 0 !important;
}
img.inline-icon {
/* Align inline icon images in the message content */
vertical-align: middle;
/* Ensure they get the right fill color. */
-moz-context-properties: fill;
fill: currentColor;
}
strong {
font-weight: var(--font-weight-bold);
}
/* type="system" infobar styles */
:host([type=system]) .icon {
display: none;
}
:host([type=system]) .content {
margin-inline-start: 0;
}

Просмотреть файл

@ -13,10 +13,6 @@
--close-icon-size: 28px;
}
:host([message-bar-type=infobar]) {
--close-icon-size: 28px;
}
:host {
--message-bar-background-color: var(--in-content-box-info-background);
--message-bar-text-color: var(--in-content-text-color);
@ -28,7 +24,7 @@
--message-bar-icon-url: var(--warn-icon-url);
}
:host([type=success]:not([message-bar-type=infobar])) {
:host([type=success]) {
--message-bar-icon-url: var(--success-icon-url);
}
@ -125,26 +121,23 @@
min-height: auto;
width: var(--close-icon-size);
height: var(--close-icon-size);
margin: 0;
padding: 0;
flex-shrink: 0;
margin: 4px 8px;
background-size: 12px;
}
@media (prefers-contrast) {
:host {
border-color: CanvasText;
}
.container.infobar::before {
background-color: CanvasText;
}
}
@media not (prefers-contrast) {
/* MessageBar colors by message type */
/* Colors from: https://design.firefox.com/photon/components/message-bars.html#type-specific-style */
:host([type=warning]:not([message-bar-type=infobar])) {
:host([type=warning]) {
/* Ensure colors within the bar are adjusted and controls are readable */
color-scheme: light;
@ -158,7 +151,7 @@
--close-fill-color: var(--message-bar-text-color);
}
:host([type=success]:not([message-bar-type=infobar])) {
:host([type=success]) {
/* Ensure colors within the bar are adjusted and controls are readable */
color-scheme: light;
@ -170,7 +163,7 @@
--in-content-button-background-active: var(--green-80);
}
:host([type=error]:not([message-bar-type=infobar])) {
:host([type=error]) {
--message-bar-background-color: var(--red-60);
--message-bar-text-color: #ffffff;
@ -191,15 +184,6 @@
color: rgb(226,40,80);
}
.container.infobar {
box-shadow: 0 1px 2px rgba(58, 57, 68, 0.1);
background: var(--in-content-page-background);
}
.container.infobar::before {
background-image: linear-gradient(0deg, #9059ff 0%, #ff4aa2 52.08%, #ffbd4f 100%);
}
.close {
fill: var(--close-fill-color);
}
@ -207,10 +191,6 @@
@media (prefers-color-scheme: dark) {
/* Don't set the background in prefers-contrast mode or macOS can end up
* with black on black text. */
.container.infobar {
background: rgb(66,65,77);
}
:host([type=info]) .icon {
color: rgb(128,235,255);
}
@ -225,81 +205,6 @@
}
}
:host([message-bar-type=infobar]:first-of-type) {
margin-top: 4px;
}
:host([message-bar-type=infobar]) {
margin: 0 4px 4px;
}
.container.infobar {
/* Don't let lwthemes set a text-shadow. */
text-shadow: none;
padding: 0;
}
.container.infobar::before {
content: "";
display: block;
width: 2px;
position: absolute;
top: 0;
inset-inline-start: 0;
height: 100%;
border-start-start-radius: 4px;
border-end-start-radius: 4px;
}
.container.infobar {
align-items: flex-start;
}
/* Infobars styling. */
.notification-content {
margin: 0;
margin-inline-start: 8px;
padding-block: 3px;
}
.notification-message {
padding-block: 8px;
margin-inline-end: 20px;
/* Prevent misalignment issue in the infobar on Linux */
@media (-moz-platform: linux) {
padding-block-start: 6px;
}
}
.notification-button-container,
.notification-message {
display: inline-block;
vertical-align: middle;
}
.container.infobar > .notification-content > .notification-message img.inline-icon {
/* Align inline icon images in the message content */
vertical-align: middle;
/* Ensure they get the right fill color. */
-moz-context-properties: fill;
fill: currentColor;
}
.close {
margin: 4px 8px;
background-size: 12px;
}
.notification-button {
align-items: center;
margin: 0 4px;
}
.notification-button:first-of-type {
/* When the buttons wrap to their own line we want to match the 8px on the message. */
margin-inline-start: 0;
}
strong {
font-weight: 600;
}
@ -308,20 +213,6 @@ strong {
cursor: pointer;
}
.infobar > .icon {
padding: 0;
margin: 10px 0;
}
.infobar > .icon,
:host([type=system]) .notification-content {
margin-inline-start: 16px;
}
:host([type=system]) .icon {
display: none;
}
@keyframes spin {
from { transform: rotate(0); }
to { transform: rotate(360deg); }

Просмотреть файл

@ -177,26 +177,27 @@
:host([type=warning]) {
--message-bar-background-color: var(--color-background-warning);
.icon {
--message-bar-icon-color: var(--icon-color-warning);
}
}
:host([type=success]) {
--message-bar-background-color: var(--color-background-success);
.icon {
--message-bar-icon-color: var(--icon-color-success);
}
}
:host([type=error]) {
:host([type=error]),
:host([type=critical]) {
--message-bar-background-color: var(--color-background-critical);
}
:host([type=success]) .icon {
--message-bar-icon-color: var(--icon-color-success);
}
:host([type=warning]) .icon {
--message-bar-icon-color: var(--icon-color-warning);
}
:host([type=error]) .icon {
--message-bar-icon-color: var(--icon-color-critical);
.icon {
--message-bar-icon-color: var(--icon-color-critical);
}
}
.close {

Просмотреть файл

@ -22,6 +22,10 @@ const messageTypeToIconData = {
iconSrc: "chrome://global/skin/icons/error.svg",
l10nId: "moz-message-bar-icon-error",
},
critical: {
iconSrc: "chrome://global/skin/icons/error.svg",
l10nId: "moz-message-bar-icon-error",
},
};
/**
@ -33,6 +37,8 @@ const messageTypeToIconData = {
* @property {string} heading - The heading of the message.
* @property {string} message - The message text.
* @property {boolean} dismissable - Whether or not the element is dismissable.
* @property {string} messageL10nId - l10n ID for the message.
* @property {string} messageL10nArgs - Any args needed for the message l10n ID.
* @fires message-bar:close
* Custom event indicating that message bar was closed.
* @fires message-bar:user-dismissed
@ -44,6 +50,7 @@ export default class MozMessageBar extends MozLitElement {
actionsSlotEl: "slot[name=actions]",
actionsEl: ".actions",
closeButtonEl: "button.close",
supportLinkSlotEl: "slot[name=support-link]",
};
static properties = {
@ -51,6 +58,8 @@ export default class MozMessageBar extends MozLitElement {
heading: { type: String },
message: { type: String },
dismissable: { type: Boolean },
messageL10nId: { type: String },
messageL10nArgs: { type: String },
};
constructor() {
@ -75,6 +84,10 @@ export default class MozMessageBar extends MozLitElement {
this.dispatchEvent(new CustomEvent("message-bar:close"));
}
get supportLinkEls() {
return this.supportLinkSlotEl.assignedElements();
}
iconTemplate() {
let iconData = messageTypeToIconData[this.type];
if (iconData) {
@ -126,7 +139,15 @@ export default class MozMessageBar extends MozLitElement {
<div class="text-content">
${this.headingTemplate()}
<div>
<span class="message">${ifDefined(this.message)}</span>
<span
class="message"
data-l10n-id=${ifDefined(this.messageL10nId)}
data-l10n-args=${ifDefined(
JSON.stringify(this.messageL10nArgs)
)}
>
${this.message}
</span>
<span class="link">
<slot name="support-link"></slot>
</span>

Просмотреть файл

@ -144,7 +144,7 @@
*
* @return The <notification> element that is shown.
*/
appendNotification(aType, aNotification, aButtons) {
async appendNotification(aType, aNotification, aButtons) {
if (
aNotification.priority < this.PRIORITY_SYSTEM ||
aNotification.priority > this.PRIORITY_CRITICAL_HIGH
@ -157,12 +157,19 @@
MozXULElement.insertFTLIfNeeded("toolkit/global/notification.ftl");
// Create the Custom Element and connect it to the document immediately.
var newitem;
let newitem;
if (!aNotification.notificationIs) {
if (!customElements.get("notification-message")) {
// There's some weird timing stuff when this element is created at
// script load time, we don't need it until now anyway so be lazy.
createNotificationMessageElement();
// Wrapped in a try/catch to handle rare cases where we start creating
// a notification but then the window gets closed/goes away.
try {
await createNotificationMessageElement();
} catch (err) {
console.warn(err);
throw err;
}
}
newitem = document.createElement("notification-message");
newitem.setAttribute("message-bar-type", "infobar");
@ -182,8 +189,10 @@
this.stack.append(newitem);
}
// Custom notification classes may not have the messageText property.
if (newitem.messageText) {
if (newitem.localName === "notification-message" && aNotification.label) {
newitem.label = aNotification.label;
} else if (newitem.messageText) {
// Custom notification classes may not have the messageText property.
// Can't use instanceof in case this was created from a different document:
if (
aNotification.label &&
@ -241,6 +250,10 @@
newitem.style.top = "100%";
newitem.style.marginTop = "-15px";
newitem.style.opacity = "0";
// Ensure the DOM has been created for the Lit-based notification-message
// element so that we add the .animated class + it animates as expected.
await newitem.updateComplete;
this._showNotification(newitem, true);
// Fire event for accessibility APIs
@ -607,53 +620,56 @@
customElements.define("notification", MozElements.Notification);
function createNotificationMessageElement() {
// Get a reference to MessageBarElement from a created element so the import
// gets handled automatically if needed.
class NotificationMessage extends document.createElement("message-bar")
.constructor {
async function createNotificationMessageElement() {
await window.ensureCustomElements("moz-message-bar");
let MozMessageBar = customElements.get("moz-message-bar");
class NotificationMessage extends MozMessageBar {
static queries = {
...MozMessageBar.queries,
messageText: ".message",
messageImage: ".icon",
};
constructor() {
super();
this.persistence = 0;
this.priority = 0;
this.timeout = 0;
this.telemetry = null;
this.dismissable = true;
this._shown = false;
this.addEventListener("click", this);
this.addEventListener("command", this);
}
connectedCallback() {
this.toggleAttribute("dismissable", true);
this.closeButton.classList.add("notification-close");
super.connectedCallback();
this.#setStyles();
this.container = this.shadowRoot.querySelector(".container");
this.container.classList.add("infobar");
this.classList.add("infobar");
this.setAlertRole();
let messageContent = this.shadowRoot.querySelector(".content");
messageContent.classList.add("notification-content");
// Remove the <slot>, API surface is `set label()` and `setButtons()`.
messageContent.textContent = "";
// A 'label' allows screen readers to detect the text of the alert.
this.messageText = document.createElement("label");
this.messageText.classList.add("notification-message");
this.buttonContainer = document.createElement("span");
this.buttonContainer.classList.add("notification-button-container");
this.messageImage = this.shadowRoot.querySelector(".icon");
messageContent.append(this.messageText, this.buttonContainer);
this.shadowRoot.addEventListener("click", this);
this.shadowRoot.addEventListener("command", this);
this.buttonContainer.setAttribute("slot", "actions");
this.appendChild(this.buttonContainer);
}
disconnectedCallback() {
super.disconnectedCallback();
if (this.eventCallback) {
this.eventCallback("disconnected");
}
}
#setStyles() {
let style = document.createElement("link");
style.rel = "stylesheet";
style.href = "chrome://global/content/elements/infobar.css";
this.renderRoot.append(style);
}
_doTelemetry(type) {
if (
this.telemetry &&
@ -686,10 +702,10 @@
setAlertRole() {
// Wait a little for this to render before setting the role for more
// consistent alerts to screen readers.
this.container.removeAttribute("role");
this.removeAttribute("role");
window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
this.container.setAttribute("role", "alert");
this.setAttribute("role", "alert");
});
});
}
@ -736,18 +752,10 @@
*/
set label(value) {
if (value && typeof value == "object" && "l10n-id" in value) {
const message = document.createElement("span");
document.l10n.setAttributes(
message,
value["l10n-id"],
value["l10n-args"]
);
while (this.messageText.firstChild) {
this.messageText.firstChild.remove();
}
this.messageText.appendChild(message);
this.messageL10nId = value["l10n-id"];
this.messageL10nArgs = value["l10n-args"];
} else {
this.messageText.textContent = value;
this.message = value;
}
this.setAlertRole();
}
@ -777,7 +785,11 @@
"button",
button.is ? { is: button.is } : {}
);
buttonElem.classList.add("notification-button", "small-button");
buttonElem.classList.add(
"notification-button",
"small-button",
"footer-button"
);
if (button.primary) {
buttonElem.classList.add("primary");
@ -794,7 +806,8 @@
}
if (link) {
this.messageText.append(new Text(" "), buttonElem);
buttonElem.setAttribute("slot", "support-link");
this.appendChild(buttonElem);
} else {
this.buttonContainer.appendChild(buttonElem);
}
@ -811,6 +824,8 @@
super.dismiss();
}
}
customElements.define("notification-message", NotificationMessage);
if (!customElements.get("notification-message")) {
customElements.define("notification-message", NotificationMessage);
}
}
}

Просмотреть файл

@ -93,6 +93,7 @@
/** Size **/
--size-item-small: 16px;
--size-item-medium: 28px;
--size-item-large: 32px;
/** Spacing **/

Просмотреть файл

@ -225,12 +225,19 @@ button.text-link .button-text {
color: var(--button-color, inherit);
background-color: var(--button-bgcolor, color-mix(in srgb, currentColor 13%, transparent));
padding: .45em 1em;
min-height: 32px;
min-height: var(--size-item-large);
font-weight: 600;
min-width: 0;
margin-inline: 8px 0;
margin-bottom: 0;
&.small-button {
margin: 0;
min-height: var(--size-item-medium);
padding: .6em 1em;
font-size: var(--font-size-small);
}
&[disabled] {
opacity: 0.4;
}
@ -247,7 +254,8 @@ button.text-link .button-text {
&:hover:active {
background-color: var(--button-active-bgcolor, color-mix(in srgb, currentColor 30%, transparent));
}
&[default] {
&[default],
&.primary {
color: var(--button-primary-color);
background-color: var(--button-primary-bgcolor);