зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
9c1d13a6a6
Коммит
614f900ec6
|
@ -178,11 +178,20 @@ export class PluginParent extends JSWindowActorParent {
|
||||||
buttons.push(submitButton);
|
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(
|
let messageString = lazy.gNavigatorBundle.formatStringFromName(
|
||||||
"crashedpluginsMessage.title",
|
"crashedpluginsMessage.title",
|
||||||
[report.pluginName]
|
[report.pluginName]
|
||||||
);
|
);
|
||||||
notification = notificationBox.appendNotification(
|
notificationBox.appendNotification(
|
||||||
"plugin-crashed",
|
"plugin-crashed",
|
||||||
{
|
{
|
||||||
label: messageString,
|
label: messageString,
|
||||||
|
@ -191,21 +200,5 @@ export class PluginParent extends JSWindowActorParent {
|
||||||
},
|
},
|
||||||
buttons
|
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);
|
return gNotificationBox.getNotificationWithValue(name);
|
||||||
},
|
},
|
||||||
|
|
||||||
_displayDataPolicyInfoBar(request) {
|
async _displayDataPolicyInfoBar(request) {
|
||||||
if (this._getDataReportingNotification()) {
|
if (this._getDataReportingNotification()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ var gDataNotificationInfoBar = {
|
||||||
];
|
];
|
||||||
|
|
||||||
this._log.info("Creating data reporting policy notification.");
|
this._log.info("Creating data reporting policy notification.");
|
||||||
gNotificationBox.appendNotification(
|
await gNotificationBox.appendNotification(
|
||||||
this._DATA_REPORTING_NOTIFICATION,
|
this._DATA_REPORTING_NOTIFICATION,
|
||||||
{
|
{
|
||||||
label: {
|
label: {
|
||||||
|
|
|
@ -1106,7 +1106,7 @@ const gStoragePressureObserver = {
|
||||||
}
|
}
|
||||||
messageFragment.appendChild(message);
|
messageFragment.appendChild(message);
|
||||||
|
|
||||||
gNotificationBox.appendNotification(
|
await gNotificationBox.appendNotification(
|
||||||
NOTIFICATION_VALUE,
|
NOTIFICATION_VALUE,
|
||||||
{
|
{
|
||||||
label: messageFragment,
|
label: messageFragment,
|
||||||
|
@ -1122,7 +1122,7 @@ const gStoragePressureObserver = {
|
||||||
};
|
};
|
||||||
|
|
||||||
var gPopupBlockerObserver = {
|
var gPopupBlockerObserver = {
|
||||||
handleEvent(aEvent) {
|
async handleEvent(aEvent) {
|
||||||
if (aEvent.originalTarget != gBrowser.selectedBrowser) {
|
if (aEvent.originalTarget != gBrowser.selectedBrowser) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1158,23 +1158,31 @@ var gPopupBlockerObserver = {
|
||||||
|
|
||||||
let notificationBox = gBrowser.getNotificationBox();
|
let notificationBox = gBrowser.getNotificationBox();
|
||||||
let notification =
|
let notification =
|
||||||
notificationBox.getNotificationWithValue("popup-blocked");
|
notificationBox.getNotificationWithValue("popup-blocked") ||
|
||||||
|
(await this.notificationPromise);
|
||||||
if (notification) {
|
if (notification) {
|
||||||
notification.label = label;
|
notification.label = label;
|
||||||
} else {
|
} else {
|
||||||
const image = "chrome://browser/skin/notification-icons/popup.svg";
|
const image = "chrome://browser/skin/notification-icons/popup.svg";
|
||||||
const priority = notificationBox.PRIORITY_INFO_MEDIUM;
|
const priority = notificationBox.PRIORITY_INFO_MEDIUM;
|
||||||
notificationBox.appendNotification(
|
try {
|
||||||
"popup-blocked",
|
this.notificationPromise = notificationBox.appendNotification(
|
||||||
{ label, image, priority },
|
"popup-blocked",
|
||||||
[
|
{ label, image, priority },
|
||||||
{
|
[
|
||||||
"l10n-id": "popup-warning-button",
|
{
|
||||||
popup: "blockedPopupOptions",
|
"l10n-id": "popup-warning-button",
|
||||||
callback: null,
|
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 asciiHost = fixedURI.asciiHost;
|
||||||
|
|
||||||
let onLookupCompleteListener = {
|
let onLookupCompleteListener = {
|
||||||
onLookupComplete(request, record, status) {
|
async onLookupComplete(request, record, status) {
|
||||||
let browserRef = weakBrowser.get();
|
let browserRef = weakBrowser.get();
|
||||||
if (!Components.isSuccessCode(status) || !browserRef) {
|
if (!Components.isSuccessCode(status) || !browserRef) {
|
||||||
return;
|
return;
|
||||||
|
@ -1457,7 +1465,7 @@ var gKeywordURIFixup = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
let notification = notificationBox.appendNotification(
|
let notification = await notificationBox.appendNotification(
|
||||||
"keyword-uri-fixup",
|
"keyword-uri-fixup",
|
||||||
{
|
{
|
||||||
label: message,
|
label: message,
|
||||||
|
@ -3334,22 +3342,9 @@ function PageProxyClickHandler(aEvent) {
|
||||||
* us via async messaging.
|
* us via async messaging.
|
||||||
*/
|
*/
|
||||||
var BrowserOnClick = {
|
var BrowserOnClick = {
|
||||||
ignoreWarningLink(reason, blockedInfo, browsingContext) {
|
async ignoreWarningLink(reason, blockedInfo, browsingContext) {
|
||||||
let triggeringPrincipal =
|
// Add a notify bar before allowing the user to continue through to the
|
||||||
blockedInfo.triggeringPrincipal ||
|
// site, so that they don't lose track after, e.g., tab switching.
|
||||||
_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,
|
|
||||||
});
|
|
||||||
|
|
||||||
// We can't use browser.contentPrincipal which is principal of about:blocked
|
// We can't use browser.contentPrincipal which is principal of about:blocked
|
||||||
// Create one from uri with current principal origin attributes
|
// Create one from uri with current principal origin attributes
|
||||||
let principal = Services.scriptSecurityManager.createContentPrincipal(
|
let principal = Services.scriptSecurityManager.createContentPrincipal(
|
||||||
|
@ -3424,7 +3419,20 @@ var BrowserOnClick = {
|
||||||
// provide a URL endpoint for these reports.
|
// 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 = {
|
const SafeBrowsingNotificationBox = {
|
||||||
_currentURIBaseDomain: null,
|
_currentURIBaseDomain: null,
|
||||||
show(title, buttons) {
|
async show(title, buttons) {
|
||||||
let uri = gBrowser.currentURI;
|
let uri = gBrowser.currentURI;
|
||||||
|
|
||||||
// start tracking host so that we know when we leave the domain
|
// start tracking host so that we know when we leave the domain
|
||||||
|
@ -9080,7 +9088,7 @@ const SafeBrowsingNotificationBox = {
|
||||||
notificationBox.removeNotification(previousNotification);
|
notificationBox.removeNotification(previousNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
let notification = notificationBox.appendNotification(
|
let notification = await notificationBox.appendNotification(
|
||||||
value,
|
value,
|
||||||
{
|
{
|
||||||
label: title,
|
label: title,
|
||||||
|
|
|
@ -176,6 +176,7 @@ add_task(async function test_single_window() {
|
||||||
// Wait for the infobar to be displayed.
|
// Wait for the infobar to be displayed.
|
||||||
triggerInfoBar(10 * 1000);
|
triggerInfoBar(10 * 1000);
|
||||||
await alertShownPromise;
|
await alertShownPromise;
|
||||||
|
await promiseNextTick();
|
||||||
|
|
||||||
Assert.equal(
|
Assert.equal(
|
||||||
gNotificationBox.allNotifications.length,
|
gNotificationBox.allNotifications.length,
|
||||||
|
|
|
@ -187,21 +187,23 @@ add_task(async function test_can_update_notification() {
|
||||||
// should have fired, so the notification should be visible.
|
// should have fired, so the notification should be visible.
|
||||||
let notificationBox = gBrowser.getNotificationBox(browser);
|
let notificationBox = gBrowser.getNotificationBox(browser);
|
||||||
let notification = notificationBox.currentNotification;
|
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(
|
is(
|
||||||
message.dataset.l10nId,
|
notification.messageText.textContent.trim(),
|
||||||
"refresh-blocked-redirect-label",
|
redirectLabel,
|
||||||
"Should be showing the redirect message"
|
"Should be showing the redirect message"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Next, attempt a refresh
|
// Next, attempt a refresh
|
||||||
await attemptFakeRefresh(browser, false);
|
await attemptFakeRefresh(browser, false);
|
||||||
|
|
||||||
message = notification.messageText.querySelector("span");
|
|
||||||
is(
|
is(
|
||||||
message.dataset.l10nId,
|
notification.messageText.textContent.trim(),
|
||||||
"refresh-blocked-refresh-label",
|
refreshLabel,
|
||||||
"Should be showing the refresh message"
|
"Should be showing the refresh message"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,15 +31,16 @@ add_task(async function showNotification() {
|
||||||
|
|
||||||
verifyTelemetry("initial", 0, 0, 0, 0, 0, 0);
|
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",
|
label: "Message for tab 3",
|
||||||
priority: box3.PRIORITY_INFO_HIGH,
|
priority: box3.PRIORITY_INFO_HIGH,
|
||||||
telemetry: TELEMETRY_BASE + "testtwo",
|
telemetry: TELEMETRY_BASE + "testtwo",
|
||||||
});
|
});
|
||||||
|
await notif3.updateComplete;
|
||||||
|
|
||||||
verifyTelemetry("first notification", 0, 0, 0, 0, 0, 1);
|
verifyTelemetry("first notification", 0, 0, 0, 0, 0, 1);
|
||||||
|
|
||||||
let notif1 = box1.appendNotification(
|
let notif1 = await box1.appendNotification(
|
||||||
"infobar-testone-value",
|
"infobar-testone-value",
|
||||||
{
|
{
|
||||||
label: "Message for tab 1",
|
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);
|
verifyTelemetry("second notification", 0, 0, 0, 0, 0, 1);
|
||||||
|
|
||||||
await BrowserTestUtils.switchTab(gBrowser, tab1);
|
await BrowserTestUtils.switchTab(gBrowser, tab1);
|
||||||
|
@ -89,7 +91,7 @@ add_task(async function showNotification() {
|
||||||
notif3.dismiss();
|
notif3.dismiss();
|
||||||
verifyTelemetry("dismiss notification for box 3", 1, 1, 1, 1, 1, 1, 1);
|
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",
|
"infobar-testtwo-value",
|
||||||
{
|
{
|
||||||
label: "Additional message for tab 1",
|
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);
|
verifyTelemetry("show first filtered notification", 2, 1, 1, 1, 1, 1, 1);
|
||||||
|
|
||||||
notif4.buttonContainer.lastElementChild.click();
|
notif4.buttonContainer.lastElementChild.click();
|
||||||
notif4.dismiss();
|
notif4.dismiss();
|
||||||
verifyTelemetry("dismiss first filtered notification", 2, 1, 1, 1, 1, 1, 1);
|
verifyTelemetry("dismiss first filtered notification", 2, 1, 1, 1, 1, 1, 1);
|
||||||
|
|
||||||
let notif5 = box1.appendNotification(
|
let notif5 = await box1.appendNotification(
|
||||||
"infobar-testtwo-value",
|
"infobar-testtwo-value",
|
||||||
{
|
{
|
||||||
label: "Dimissed additional message for tab 1",
|
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);
|
verifyTelemetry("show second filtered notification", 2, 1, 1, 1, 1, 1, 1);
|
||||||
|
|
||||||
notif5.buttonContainer.lastElementChild.click();
|
notif5.buttonContainer.lastElementChild.click();
|
||||||
notif5.dismiss();
|
notif5.dismiss();
|
||||||
verifyTelemetry("dismiss second filtered notification", 2, 1, 1, 1, 2, 1, 1);
|
verifyTelemetry("dismiss second filtered notification", 2, 1, 1, 1, 2, 1, 1);
|
||||||
|
|
||||||
let notif6 = box1.appendNotification(
|
let notif6 = await box1.appendNotification(
|
||||||
"infobar-testtwo-value",
|
"infobar-testtwo-value",
|
||||||
{
|
{
|
||||||
label: "Dimissed additional message for tab 1",
|
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);
|
verifyTelemetry("show third filtered notification", 2, 1, 1, 1, 2, 1, 1);
|
||||||
|
|
||||||
notif6.buttonContainer.lastElementChild.click();
|
notif6.buttonContainer.lastElementChild.click();
|
||||||
|
|
|
@ -32,9 +32,9 @@ function assertNotificationBoxShown(reason, browser) {
|
||||||
is(selectedViewName, name, `Box is shown ${reason}`);
|
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 notificationBox = gBrowser.getNotificationBox(browser);
|
||||||
let notification = notificationBox.appendNotification(value, {
|
let notification = await notificationBox.appendNotification(value, {
|
||||||
label,
|
label,
|
||||||
priority: notificationBox[priority],
|
priority: notificationBox[priority],
|
||||||
});
|
});
|
||||||
|
@ -52,7 +52,7 @@ add_task(async function testNotificationInBackgroundTab() {
|
||||||
gBrowser.selectedTab = firstTab;
|
gBrowser.selectedTab = firstTab;
|
||||||
assertNotificationBoxHidden("initial first tab");
|
assertNotificationBoxHidden("initial first tab");
|
||||||
|
|
||||||
createNotification({
|
await createNotification({
|
||||||
browser,
|
browser,
|
||||||
label: "My notification body",
|
label: "My notification body",
|
||||||
value: "test-notification",
|
value: "test-notification",
|
||||||
|
@ -69,7 +69,7 @@ add_task(async function testNotificationInActiveTab() {
|
||||||
await BrowserTestUtils.withNewTab("about:blank", async browser => {
|
await BrowserTestUtils.withNewTab("about:blank", async browser => {
|
||||||
ok(!gBrowser.readNotificationBox(browser), "No notifications for new tab");
|
ok(!gBrowser.readNotificationBox(browser), "No notifications for new tab");
|
||||||
|
|
||||||
createNotification({
|
await createNotification({
|
||||||
browser,
|
browser,
|
||||||
label: "Notification!",
|
label: "Notification!",
|
||||||
value: "test-notification",
|
value: "test-notification",
|
||||||
|
@ -108,7 +108,7 @@ add_task(async function testNotificationMultipleTabs() {
|
||||||
assertNotificationBoxHidden("after open", browserTwo);
|
assertNotificationBoxHidden("after open", browserTwo);
|
||||||
assertNotificationBoxHidden("after open", browserThree);
|
assertNotificationBoxHidden("after open", browserThree);
|
||||||
|
|
||||||
createNotification({
|
await createNotification({
|
||||||
browser: browserTwo,
|
browser: browserTwo,
|
||||||
label: "Test blank",
|
label: "Test blank",
|
||||||
value: "blank",
|
value: "blank",
|
||||||
|
@ -121,7 +121,7 @@ add_task(async function testNotificationMultipleTabs() {
|
||||||
assertNotificationBoxHidden("hidden create", browserTwo);
|
assertNotificationBoxHidden("hidden create", browserTwo);
|
||||||
assertNotificationBoxHidden("other create", browserThree);
|
assertNotificationBoxHidden("other create", browserThree);
|
||||||
|
|
||||||
createNotification({
|
await createNotification({
|
||||||
browser: browserThree,
|
browser: browserThree,
|
||||||
label: "Test active tab",
|
label: "Test active tab",
|
||||||
value: "active",
|
value: "active",
|
||||||
|
|
|
@ -36,6 +36,11 @@ add_task(async function test_drm_prompt_shows_for_toplevel() {
|
||||||
// Turn off EME and Widevine CDM.
|
// Turn off EME and Widevine CDM.
|
||||||
Services.prefs.setBoolPref("media.eme.enabled", false);
|
Services.prefs.setBoolPref("media.eme.enabled", false);
|
||||||
Services.prefs.setBoolPref("media.gmp-widevinecdm.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
|
// Have content request access to Widevine, UI should drop down to
|
||||||
// prompt user to enable DRM.
|
// prompt user to enable DRM.
|
||||||
|
@ -64,7 +69,9 @@ add_task(async function test_drm_prompt_shows_for_toplevel() {
|
||||||
|
|
||||||
// Verify the UI prompt showed.
|
// Verify the UI prompt showed.
|
||||||
let box = gBrowser.getNotificationBox(browser);
|
let box = gBrowser.getNotificationBox(browser);
|
||||||
|
await notificationShownPromise;
|
||||||
let notification = box.currentNotification;
|
let notification = box.currentNotification;
|
||||||
|
await notification.updateComplete;
|
||||||
|
|
||||||
ok(notification, "Notification should be visible");
|
ok(notification, "Notification should be visible");
|
||||||
is(
|
is(
|
||||||
|
@ -152,6 +159,11 @@ add_task(async function test_drm_prompt_shows_for_cross_origin_iframe() {
|
||||||
// Turn off EME and Widevine CDM.
|
// Turn off EME and Widevine CDM.
|
||||||
Services.prefs.setBoolPref("media.eme.enabled", false);
|
Services.prefs.setBoolPref("media.eme.enabled", false);
|
||||||
Services.prefs.setBoolPref("media.gmp-widevinecdm.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
|
// Have content request access to Widevine, UI should drop down to
|
||||||
// prompt user to enable DRM.
|
// 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.
|
// Verify the UI prompt showed.
|
||||||
let box = gBrowser.getNotificationBox(browser);
|
let box = gBrowser.getNotificationBox(browser);
|
||||||
|
await notificationShownPromise;
|
||||||
let notification = box.currentNotification;
|
let notification = box.currentNotification;
|
||||||
|
await notification.updateComplete;
|
||||||
|
|
||||||
ok(notification, "Notification should be visible");
|
ok(notification, "Notification should be visible");
|
||||||
is(
|
is(
|
||||||
|
|
|
@ -54,7 +54,7 @@ add_task(async function () {
|
||||||
"Correct priority."
|
"Correct priority."
|
||||||
);
|
);
|
||||||
is(
|
is(
|
||||||
notification.messageText.textContent,
|
notification.messageText.textContent.trim(),
|
||||||
"The GlobalTestPlugin plugin has crashed.",
|
"The GlobalTestPlugin plugin has crashed.",
|
||||||
"Correct message."
|
"Correct message."
|
||||||
);
|
);
|
||||||
|
|
|
@ -3736,12 +3736,12 @@ BrowserGlue.prototype = {
|
||||||
* Show the notificationBox for a locked places database.
|
* Show the notificationBox for a locked places database.
|
||||||
*/
|
*/
|
||||||
_showPlacesLockedNotificationBox:
|
_showPlacesLockedNotificationBox:
|
||||||
function BG__showPlacesLockedNotificationBox() {
|
async function BG__showPlacesLockedNotificationBox() {
|
||||||
var win = lazy.BrowserWindowTracker.getTopWindow();
|
var win = lazy.BrowserWindowTracker.getTopWindow();
|
||||||
var buttons = [{ supportPage: "places-locked" }];
|
var buttons = [{ supportPage: "places-locked" }];
|
||||||
|
|
||||||
var notifyBox = win.gBrowser.getNotificationBox();
|
var notifyBox = win.gBrowser.getNotificationBox();
|
||||||
var notification = notifyBox.appendNotification(
|
var notification = await notifyBox.appendNotification(
|
||||||
"places-locked",
|
"places-locked",
|
||||||
{
|
{
|
||||||
label: { "l10n-id": "places-locked-prompt" },
|
label: { "l10n-id": "places-locked-prompt" },
|
||||||
|
@ -4616,7 +4616,7 @@ BrowserGlue.prototype = {
|
||||||
];
|
];
|
||||||
|
|
||||||
const notifyBox = win.gBrowser.getNotificationBox();
|
const notifyBox = win.gBrowser.getNotificationBox();
|
||||||
const notification = notifyBox.appendNotification(
|
const notification = await notifyBox.appendNotification(
|
||||||
"startup-restore-session-suggestion",
|
"startup-restore-session-suggestion",
|
||||||
{
|
{
|
||||||
label: messageFragment,
|
label: messageFragment,
|
||||||
|
|
|
@ -40,16 +40,9 @@ add_task(async function () {
|
||||||
"info",
|
"info",
|
||||||
"We expect this notification to have the type of 'info'."
|
"We expect this notification to have the type of 'info'."
|
||||||
);
|
);
|
||||||
|
is(
|
||||||
// Make sure the CSS is fully loaded...
|
notification.messageImage.getAttribute("src"),
|
||||||
ok(
|
"chrome://global/skin/icons/info-filled.svg",
|
||||||
await TestUtils.waitForCondition(
|
|
||||||
() =>
|
|
||||||
notification.ownerGlobal.getComputedStyle(
|
|
||||||
notification.messageImage,
|
|
||||||
"::after"
|
|
||||||
).backgroundImage == 'url("chrome://global/skin/icons/info-filled.svg")'
|
|
||||||
),
|
|
||||||
"We expect this notification to have an icon."
|
"We expect this notification to have an icon."
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ addRDMTask(
|
||||||
const notificationEl = box.currentNotification;
|
const notificationEl = box.currentNotification;
|
||||||
ok(notificationEl, "Notification should be visible");
|
ok(notificationEl, "Notification should be visible");
|
||||||
is(
|
is(
|
||||||
notificationEl.messageText.textContent,
|
notificationEl.messageText.textContent.trim(),
|
||||||
"The device pixel ratio was reduced to 1 as the resulting image was too large",
|
"The device pixel ratio was reduced to 1 as the resulting image was too large",
|
||||||
"The expected warning was displayed"
|
"The expected warning was displayed"
|
||||||
);
|
);
|
||||||
|
|
|
@ -112,7 +112,7 @@ async function test_decoder_doctor_notification(
|
||||||
label = await document.l10n.formatValue(label.l10nId);
|
label = await document.l10n.formatValue(label.l10nId);
|
||||||
}
|
}
|
||||||
if (isLink) {
|
if (isLink) {
|
||||||
let link = notification.messageText.querySelector("a");
|
let link = notification.supportLinkEls[0];
|
||||||
if (link) {
|
if (link) {
|
||||||
// Seems to be a Windows specific quirk, but without this
|
// Seems to be a Windows specific quirk, but without this
|
||||||
// mutation observer the notification.messageText.textContent
|
// mutation observer the notification.messageText.textContent
|
||||||
|
@ -126,13 +126,13 @@ async function test_decoder_doctor_notification(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is(
|
is(
|
||||||
notification.messageText.textContent,
|
notification.messageText.textContent.trim(),
|
||||||
notificationMessage + (isLink && label ? ` ${label}` : ""),
|
notificationMessage,
|
||||||
"notification message should match expectation"
|
"notification message should match expectation"
|
||||||
);
|
);
|
||||||
|
|
||||||
let button = notification.buttonContainer.querySelector("button");
|
let button = notification.buttonContainer.querySelector("button");
|
||||||
let link = notification.messageText.querySelector("a");
|
let link = notification.supportLinkEls[0];
|
||||||
if (!label) {
|
if (!label) {
|
||||||
ok(!button, "There should not be a button");
|
ok(!button, "There should not be a button");
|
||||||
ok(!link, "There should not be a link");
|
ok(!link, "There should not be a link");
|
||||||
|
@ -141,7 +141,7 @@ async function test_decoder_doctor_notification(
|
||||||
|
|
||||||
if (isLink) {
|
if (isLink) {
|
||||||
ok(!button, "There should not be a button");
|
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(
|
ok(
|
||||||
!link.hasAttribute("accesskey"),
|
!link.hasAttribute("accesskey"),
|
||||||
"notification link should not have accesskey"
|
"notification link should not have accesskey"
|
||||||
|
|
|
@ -123,7 +123,7 @@ class TestSafeBrowsingNotificationBar(WindowManagerMixin, MarionetteTestCase):
|
||||||
message = notification_box.find_element(
|
message = notification_box.find_element(
|
||||||
By.CSS_SELECTOR, "notification-message[value=blocked-badware-page]"
|
By.CSS_SELECTOR, "notification-message[value=blocked-badware-page]"
|
||||||
)
|
)
|
||||||
button = message.get_property("closeButton")
|
button = message.get_property("closeButtonEl")
|
||||||
button.click()
|
button.click()
|
||||||
|
|
||||||
Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
|
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.css (widgets/moz-toggle/moz-toggle.css)
|
||||||
content/global/elements/moz-toggle.mjs (widgets/moz-toggle/moz-toggle.mjs)
|
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/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/notificationbox.js (widgets/notificationbox.js)
|
||||||
content/global/elements/panel.js (widgets/panel.js)
|
content/global/elements/panel.js (widgets/panel.js)
|
||||||
content/global/elements/panel-item.css (widgets/panel-list/panel-item.css)
|
content/global/elements/panel-item.css (widgets/panel-list/panel-item.css)
|
||||||
|
|
|
@ -28,14 +28,14 @@ function completeAnimation(nextTest) {
|
||||||
setTimeout(completeAnimation, 50, nextTest);
|
setTimeout(completeAnimation, 50, nextTest);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test() {
|
async function test() {
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
gNotificationBox = new MozElements.NotificationBox(e => {
|
gNotificationBox = new MozElements.NotificationBox(e => {
|
||||||
document.getElementById("nb").appendChild(e);
|
document.getElementById("nb").appendChild(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
is(gNotificationBox.allNotifications.length, 0, "There should be no initial notifications");
|
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 });
|
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
||||||
is(gNotificationBox.allNotifications.length, 1, "Notification exists while animating in");
|
is(gNotificationBox.allNotifications.length, 1, "Notification exists while animating in");
|
||||||
let notification = gNotificationBox.getNotificationWithValue("notification1");
|
let notification = gNotificationBox.getNotificationWithValue("notification1");
|
||||||
|
@ -46,7 +46,7 @@ function test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that a notification that is fully animated in gets removed immediately
|
// Tests that a notification that is fully animated in gets removed immediately
|
||||||
function test1() {
|
async function test1() {
|
||||||
let notification = gNotificationBox.getNotificationWithValue("notification1");
|
let notification = gNotificationBox.getNotificationWithValue("notification1");
|
||||||
gNotificationBox.removeNotification(notification);
|
gNotificationBox.removeNotification(notification);
|
||||||
notification = gNotificationBox.getNotificationWithValue("notification1");
|
notification = gNotificationBox.getNotificationWithValue("notification1");
|
||||||
|
@ -59,8 +59,8 @@ function test1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that a notification that is animating in gets removed immediately
|
// Tests that a notification that is animating in gets removed immediately
|
||||||
function test2() {
|
async function test2() {
|
||||||
let notification = gNotificationBox.appendNotification("notification2",
|
let notification = await gNotificationBox.appendNotification("notification2",
|
||||||
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
||||||
gNotificationBox.removeNotification(notification);
|
gNotificationBox.removeNotification(notification);
|
||||||
notification = gNotificationBox.getNotificationWithValue("notification2");
|
notification = gNotificationBox.getNotificationWithValue("notification2");
|
||||||
|
@ -74,10 +74,10 @@ function test2() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that a background notification goes away immediately
|
// Tests that a background notification goes away immediately
|
||||||
function test3() {
|
async function test3() {
|
||||||
let notification = gNotificationBox.appendNotification("notification3",
|
let notification = await gNotificationBox.appendNotification("notification3",
|
||||||
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
{ 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 });
|
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
||||||
is(gNotificationBox.allNotifications.length, 2, "Test 3 should show 2 notifications present");
|
is(gNotificationBox.allNotifications.length, 2, "Test 3 should show 2 notifications present");
|
||||||
gNotificationBox.removeNotification(notification);
|
gNotificationBox.removeNotification(notification);
|
||||||
|
@ -96,10 +96,10 @@ function test3() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that a foreground notification hiding a background one goes away
|
// Tests that a foreground notification hiding a background one goes away
|
||||||
function test4() {
|
async function test4() {
|
||||||
let notification = gNotificationBox.appendNotification("notification5",
|
let notification = await gNotificationBox.appendNotification("notification5",
|
||||||
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
{ 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 });
|
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
||||||
gNotificationBox.removeNotification(notification2);
|
gNotificationBox.removeNotification(notification2);
|
||||||
notification2 = gNotificationBox.getNotificationWithValue("notification6");
|
notification2 = gNotificationBox.getNotificationWithValue("notification6");
|
||||||
|
@ -118,10 +118,10 @@ function test4() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that removeAllNotifications gets rid of everything
|
// Tests that removeAllNotifications gets rid of everything
|
||||||
function test5() {
|
async function test5() {
|
||||||
let notification = gNotificationBox.appendNotification("notification7",
|
let notification = await gNotificationBox.appendNotification("notification7",
|
||||||
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
{ 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 });
|
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
||||||
gNotificationBox.removeAllNotifications();
|
gNotificationBox.removeAllNotifications();
|
||||||
notification = gNotificationBox.getNotificationWithValue("notification7");
|
notification = gNotificationBox.getNotificationWithValue("notification7");
|
||||||
|
@ -131,7 +131,7 @@ function test5() {
|
||||||
ok(!gNotificationBox.currentNotification, "Test 5 said there was still a current notification");
|
ok(!gNotificationBox.currentNotification, "Test 5 said there was still a current notification");
|
||||||
is(gNotificationBox.allNotifications.length, 0, "Test 5 should show 0 notifications present");
|
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 });
|
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
||||||
|
|
||||||
// Wait for the notificaton to finish displaying
|
// Wait for the notificaton to finish displaying
|
||||||
|
@ -139,7 +139,7 @@ function test5() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests whether removing an already removed notification doesn't break things
|
// Tests whether removing an already removed notification doesn't break things
|
||||||
function test6() {
|
async function test6() {
|
||||||
let notification = gNotificationBox.getNotificationWithValue("notification9");
|
let notification = gNotificationBox.getNotificationWithValue("notification9");
|
||||||
ok(notification, "Test 6 should have an initial notification");
|
ok(notification, "Test 6 should have an initial notification");
|
||||||
gNotificationBox.removeNotification(notification);
|
gNotificationBox.removeNotification(notification);
|
||||||
|
@ -147,7 +147,7 @@ function test6() {
|
||||||
|
|
||||||
ok(!gNotificationBox.currentNotification, "Test 6 shouldn't be any current notification");
|
ok(!gNotificationBox.currentNotification, "Test 6 shouldn't be any current notification");
|
||||||
is(gNotificationBox.allNotifications.length, 0, "Test 6 allNotifications.length should be 0");
|
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 });
|
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
||||||
is(notification, gNotificationBox.currentNotification, "Test 6 should have made the current notification");
|
is(notification, gNotificationBox.currentNotification, "Test 6 should have made the current notification");
|
||||||
gNotificationBox.removeNotification(notification);
|
gNotificationBox.removeNotification(notification);
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
var gNotificationBox;
|
var gNotificationBox;
|
||||||
|
|
||||||
// Tests that a notification that is added in an hidden box didn't throw the animation
|
// Tests that a notification that is added in an hidden box didn't throw the animation
|
||||||
function test() {
|
async function test() {
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
gNotificationBox = new MozElements.NotificationBox(e => {
|
gNotificationBox = new MozElements.NotificationBox(e => {
|
||||||
document.getElementById("nb").appendChild(e);
|
document.getElementById("nb").appendChild(e);
|
||||||
|
@ -28,7 +28,7 @@ function test() {
|
||||||
|
|
||||||
is(gNotificationBox.allNotifications.length, 0, "There should be no initial notifications");
|
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 });
|
{ label: "Test notification", priority: gNotificationBox.PRIORITY_INFO_LOW });
|
||||||
|
|
||||||
is(gNotificationBox.allNotifications.length, 1, "Notification exists");
|
is(gNotificationBox.allNotifications.length, 1, "Notification exists");
|
||||||
|
|
|
@ -138,18 +138,15 @@ function testtag_notification_eventCallback(expectedEvents, ntf, testName)
|
||||||
var tests =
|
var tests =
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
test(nb, ntf) {
|
async test(nb, ntf) {
|
||||||
ntf = nb.appendNotification("mutable", {
|
ntf = await nb.appendNotification("mutable", {
|
||||||
label: "Original",
|
label: "Original",
|
||||||
priority: nb.PRIORITY_INFO_LOW,
|
priority: nb.PRIORITY_INFO_LOW,
|
||||||
}, testtag_notificationbox_buttons);
|
}, testtag_notificationbox_buttons);
|
||||||
|
|
||||||
ntf.label = "Changed string";
|
ntf.label = "Changed string";
|
||||||
SimpleTest.is(ntf.messageText.textContent, "Changed string", "set notification label with string");
|
await ntf.updateComplete;
|
||||||
|
SimpleTest.is(ntf.messageText.textContent.trim(), "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");
|
|
||||||
return ntf;
|
return ntf;
|
||||||
},
|
},
|
||||||
result(nb, ntf) {
|
result(nb, ntf) {
|
||||||
|
@ -162,8 +159,8 @@ var tests =
|
||||||
label attribute set correctly.
|
label attribute set correctly.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
test(nb, ntf) {
|
async test(nb, ntf) {
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_LOW,
|
priority: nb.PRIORITY_INFO_LOW,
|
||||||
|
@ -183,8 +180,8 @@ var tests =
|
||||||
Ensures that buttons created with the "l10n-id" parameter have
|
Ensures that buttons created with the "l10n-id" parameter have
|
||||||
their "l10n-id" assigned correctly.
|
their "l10n-id" assigned correctly.
|
||||||
*/
|
*/
|
||||||
test(nb, ntf) {
|
async test(nb, ntf) {
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_LOW,
|
priority: nb.PRIORITY_INFO_LOW,
|
||||||
|
@ -200,9 +197,9 @@ var tests =
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test(nb, ntf) {
|
async test(nb, ntf) {
|
||||||
// append a new notification
|
// append a new notification
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_LOW,
|
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
|
// append a new notification, but now with an event callback
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_LOW,
|
priority: nb.PRIORITY_INFO_LOW,
|
||||||
|
@ -265,8 +262,8 @@ var tests =
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test(nb, ntf) {
|
async test(nb, ntf) {
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_MEDIUM,
|
priority: nb.PRIORITY_INFO_MEDIUM,
|
||||||
|
@ -299,8 +296,8 @@ var tests =
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test(nb, ntf) {
|
async test(nb, ntf) {
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_WARNING_LOW,
|
priority: nb.PRIORITY_WARNING_LOW,
|
||||||
|
@ -321,13 +318,13 @@ var tests =
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
repeat: true,
|
repeat: true,
|
||||||
test(nb, arr) {
|
async test(nb, arr) {
|
||||||
var idx = arr[0];
|
var idx = arr[0];
|
||||||
var ntf = arr[1];
|
var ntf = arr[1];
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
case 1:
|
case 1:
|
||||||
// append a new notification
|
// append a new notification
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_LOW,
|
priority: nb.PRIORITY_INFO_LOW,
|
||||||
|
@ -373,9 +370,9 @@ var tests =
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test(nb, ntf) {
|
async test(nb, ntf) {
|
||||||
// append another notification
|
// append another notification
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_MEDIUM,
|
priority: nb.PRIORITY_INFO_MEDIUM,
|
||||||
|
@ -402,8 +399,8 @@ var tests =
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test(nb, ntf) {
|
async test(nb, ntf) {
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_HIGH,
|
priority: nb.PRIORITY_INFO_HIGH,
|
||||||
|
@ -419,8 +416,8 @@ var tests =
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test(nb, ntf) {
|
async test(nb, ntf) {
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_LOW,
|
priority: nb.PRIORITY_INFO_LOW,
|
||||||
|
@ -437,7 +434,7 @@ var tests =
|
||||||
SimpleTest.is(button.localName, "button", "button is a button");
|
SimpleTest.is(button.localName, "button", "button is a button");
|
||||||
SimpleTest.ok(!button.href, "button href is not set");
|
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.localName, "label", "link is a label");
|
||||||
SimpleTest.is(link.href, "about:mozilla", "link href is correct");
|
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
|
// append a new notification
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_LOW,
|
priority: nb.PRIORITY_INFO_LOW,
|
||||||
|
@ -473,20 +470,21 @@ var tests =
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test(nb, ntf) {
|
async test(nb, ntf) {
|
||||||
ntf = nb.appendNotification("note", {
|
ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_LOW,
|
priority: nb.PRIORITY_INFO_LOW,
|
||||||
eventCallback: notification_eventCallback,
|
eventCallback: notification_eventCallback,
|
||||||
}, testtag_notificationbox_supportpage);
|
}, testtag_notificationbox_supportpage);
|
||||||
|
await ntf.updateComplete;
|
||||||
SimpleTest.is(ntf && ntf.localName == NOTIFICATION_LOCAL_NAME, true, "append support page notification");
|
SimpleTest.is(ntf && ntf.localName == NOTIFICATION_LOCAL_NAME, true, "append support page notification");
|
||||||
return ntf;
|
return ntf;
|
||||||
},
|
},
|
||||||
result(nb, ntf) {
|
result(nb, ntf) {
|
||||||
testtag_notificationbox_State(nb, "append link with callback", ntf, 1);
|
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.localName, "a", "link 1 is an anchor");
|
||||||
SimpleTest.is(link.dataset.l10nId, "moz-support-link-text", "link 1 Fluent ID is set");
|
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");
|
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
|
// 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);
|
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);
|
testtag_notificationbox_buttons);
|
||||||
nb.appendNotification("2", { label: "Two", priority: nb.PRIORITY_INFO_LOW });
|
await nb.appendNotification("2", { label: "Two", priority: nb.PRIORITY_INFO_LOW });
|
||||||
nb.appendNotification("8", { label: "Eight", priority: nb.PRIORITY_CRITICAL_LOW });
|
await nb.appendNotification("8", { label: "Eight", priority: nb.PRIORITY_CRITICAL_LOW });
|
||||||
nb.appendNotification("5", { label: "Five", priority: nb.PRIORITY_WARNING_LOW });
|
await nb.appendNotification("5", { label: "Five", priority: nb.PRIORITY_WARNING_LOW });
|
||||||
nb.appendNotification("6", { label: "Six", priority: nb.PRIORITY_WARNING_HIGH });
|
await nb.appendNotification("6", { label: "Six", priority: nb.PRIORITY_WARNING_HIGH });
|
||||||
nb.appendNotification("1", { label: "One", priority: nb.PRIORITY_INFO_LOW });
|
await nb.appendNotification("1", { label: "One", priority: nb.PRIORITY_INFO_LOW });
|
||||||
nb.appendNotification("9", { label: "Nine", priority: nb.PRIORITY_CRITICAL_MEDIUM });
|
await nb.appendNotification("9", { label: "Nine", priority: nb.PRIORITY_CRITICAL_MEDIUM });
|
||||||
let ntf = nb.appendNotification("10", { label: "Ten", priority: nb.PRIORITY_CRITICAL_HIGH });
|
let ntf = await nb.appendNotification("10", { label: "Ten", priority: nb.PRIORITY_CRITICAL_HIGH });
|
||||||
nb.appendNotification("3", { label: "Three", priority: nb.PRIORITY_INFO_MEDIUM });
|
await nb.appendNotification("3", { label: "Three", priority: nb.PRIORITY_INFO_MEDIUM });
|
||||||
return ntf;
|
return ntf;
|
||||||
},
|
},
|
||||||
result(nb, ntf) {
|
result(nb, ntf) {
|
||||||
|
@ -558,16 +556,16 @@ var tests =
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test(nb, ntf) {
|
async test(nb, ntf) {
|
||||||
var exh = false;
|
var exh = false;
|
||||||
try {
|
try {
|
||||||
nb.appendNotification("no", { label: "no", priority: -1 });
|
await nb.appendNotification("no", { label: "no", priority: -1 });
|
||||||
} catch (ex) { exh = true; }
|
} catch (ex) { exh = true; }
|
||||||
SimpleTest.is(exh, true, "appendNotification priority too low");
|
SimpleTest.is(exh, true, "appendNotification priority too low");
|
||||||
|
|
||||||
exh = false;
|
exh = false;
|
||||||
try {
|
try {
|
||||||
nb.appendNotification("no", { label: "no", priority: 11 });
|
await nb.appendNotification("no", { label: "no", priority: 11 });
|
||||||
} catch (ex) { exh = true; }
|
} catch (ex) { exh = true; }
|
||||||
SimpleTest.is(exh, true, "appendNotification priority too high");
|
SimpleTest.is(exh, true, "appendNotification priority too high");
|
||||||
|
|
||||||
|
@ -579,8 +577,8 @@ var tests =
|
||||||
|
|
||||||
var appendPriorityTests = [
|
var appendPriorityTests = [
|
||||||
{
|
{
|
||||||
test(nb, priority) {
|
async test(nb, priority) {
|
||||||
let ntf = nb.appendNotification("note", {
|
let ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority,
|
priority,
|
||||||
|
@ -598,9 +596,9 @@ var appendPriorityTests = [
|
||||||
nb.removeCurrentNotification();
|
nb.removeCurrentNotification();
|
||||||
return priority;
|
return priority;
|
||||||
},
|
},
|
||||||
result(nb, priority) {
|
async result(nb, priority) {
|
||||||
if (priority == nb.PRIORITY_CRITICAL_HIGH) {
|
if (priority == nb.PRIORITY_CRITICAL_HIGH) {
|
||||||
let ntf = nb.appendNotification("note", {
|
let ntf = await nb.appendNotification("note", {
|
||||||
label: "Notification",
|
label: "Notification",
|
||||||
image: "happy.png",
|
image: "happy.png",
|
||||||
priority: nb.PRIORITY_INFO_LOW,
|
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)
|
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.getAttribute("value"), value, testid + " notification value");
|
||||||
is(ntf.priority, priority, testid + " notification priority");
|
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",
|
critical: "chrome://global/skin/icons/error.svg",
|
||||||
};
|
};
|
||||||
let icon = icons[type];
|
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)
|
function checkPopupTest(nb, ntf)
|
||||||
|
@ -697,7 +695,7 @@ function checkPopupClosed()
|
||||||
* function as its arg. The result function may also return a value which
|
* 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.
|
* 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])
|
if (idx >= 0 && "result" in tests[idx])
|
||||||
arg = tests[idx].result(element, arg);
|
arg = tests[idx].result(element, arg);
|
||||||
|
@ -707,7 +705,7 @@ function runTimedTests(tests, idx, element, arg)
|
||||||
idx++;
|
idx++;
|
||||||
|
|
||||||
if (idx < tests.length) {
|
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);
|
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;
|
--close-icon-size: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([message-bar-type=infobar]) {
|
|
||||||
--close-icon-size: 28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
--message-bar-background-color: var(--in-content-box-info-background);
|
--message-bar-background-color: var(--in-content-box-info-background);
|
||||||
--message-bar-text-color: var(--in-content-text-color);
|
--message-bar-text-color: var(--in-content-text-color);
|
||||||
|
@ -28,7 +24,7 @@
|
||||||
--message-bar-icon-url: var(--warn-icon-url);
|
--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);
|
--message-bar-icon-url: var(--success-icon-url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,26 +121,23 @@
|
||||||
min-height: auto;
|
min-height: auto;
|
||||||
width: var(--close-icon-size);
|
width: var(--close-icon-size);
|
||||||
height: var(--close-icon-size);
|
height: var(--close-icon-size);
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
margin: 4px 8px;
|
||||||
|
background-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-contrast) {
|
@media (prefers-contrast) {
|
||||||
:host {
|
:host {
|
||||||
border-color: CanvasText;
|
border-color: CanvasText;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.infobar::before {
|
|
||||||
background-color: CanvasText;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media not (prefers-contrast) {
|
@media not (prefers-contrast) {
|
||||||
/* MessageBar colors by message type */
|
/* MessageBar colors by message type */
|
||||||
/* Colors from: https://design.firefox.com/photon/components/message-bars.html#type-specific-style */
|
/* 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 */
|
/* Ensure colors within the bar are adjusted and controls are readable */
|
||||||
color-scheme: light;
|
color-scheme: light;
|
||||||
|
|
||||||
|
@ -158,7 +151,7 @@
|
||||||
--close-fill-color: var(--message-bar-text-color);
|
--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 */
|
/* Ensure colors within the bar are adjusted and controls are readable */
|
||||||
color-scheme: light;
|
color-scheme: light;
|
||||||
|
|
||||||
|
@ -170,7 +163,7 @@
|
||||||
--in-content-button-background-active: var(--green-80);
|
--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-background-color: var(--red-60);
|
||||||
--message-bar-text-color: #ffffff;
|
--message-bar-text-color: #ffffff;
|
||||||
|
|
||||||
|
@ -191,15 +184,6 @@
|
||||||
color: rgb(226,40,80);
|
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 {
|
.close {
|
||||||
fill: var(--close-fill-color);
|
fill: var(--close-fill-color);
|
||||||
}
|
}
|
||||||
|
@ -207,10 +191,6 @@
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
/* Don't set the background in prefers-contrast mode or macOS can end up
|
/* Don't set the background in prefers-contrast mode or macOS can end up
|
||||||
* with black on black text. */
|
* with black on black text. */
|
||||||
.container.infobar {
|
|
||||||
background: rgb(66,65,77);
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([type=info]) .icon {
|
:host([type=info]) .icon {
|
||||||
color: rgb(128,235,255);
|
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 {
|
strong {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
@ -308,20 +213,6 @@ strong {
|
||||||
cursor: pointer;
|
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 {
|
@keyframes spin {
|
||||||
from { transform: rotate(0); }
|
from { transform: rotate(0); }
|
||||||
to { transform: rotate(360deg); }
|
to { transform: rotate(360deg); }
|
||||||
|
|
|
@ -177,26 +177,27 @@
|
||||||
|
|
||||||
:host([type=warning]) {
|
:host([type=warning]) {
|
||||||
--message-bar-background-color: var(--color-background-warning);
|
--message-bar-background-color: var(--color-background-warning);
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
--message-bar-icon-color: var(--icon-color-warning);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([type=success]) {
|
:host([type=success]) {
|
||||||
--message-bar-background-color: var(--color-background-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);
|
--message-bar-background-color: var(--color-background-critical);
|
||||||
}
|
|
||||||
|
|
||||||
:host([type=success]) .icon {
|
.icon {
|
||||||
--message-bar-icon-color: var(--icon-color-success);
|
--message-bar-icon-color: var(--icon-color-critical);
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([type=warning]) .icon {
|
|
||||||
--message-bar-icon-color: var(--icon-color-warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([type=error]) .icon {
|
|
||||||
--message-bar-icon-color: var(--icon-color-critical);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.close {
|
.close {
|
||||||
|
|
|
@ -22,6 +22,10 @@ const messageTypeToIconData = {
|
||||||
iconSrc: "chrome://global/skin/icons/error.svg",
|
iconSrc: "chrome://global/skin/icons/error.svg",
|
||||||
l10nId: "moz-message-bar-icon-error",
|
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} heading - The heading of the message.
|
||||||
* @property {string} message - The message text.
|
* @property {string} message - The message text.
|
||||||
* @property {boolean} dismissable - Whether or not the element is dismissable.
|
* @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
|
* @fires message-bar:close
|
||||||
* Custom event indicating that message bar was closed.
|
* Custom event indicating that message bar was closed.
|
||||||
* @fires message-bar:user-dismissed
|
* @fires message-bar:user-dismissed
|
||||||
|
@ -44,6 +50,7 @@ export default class MozMessageBar extends MozLitElement {
|
||||||
actionsSlotEl: "slot[name=actions]",
|
actionsSlotEl: "slot[name=actions]",
|
||||||
actionsEl: ".actions",
|
actionsEl: ".actions",
|
||||||
closeButtonEl: "button.close",
|
closeButtonEl: "button.close",
|
||||||
|
supportLinkSlotEl: "slot[name=support-link]",
|
||||||
};
|
};
|
||||||
|
|
||||||
static properties = {
|
static properties = {
|
||||||
|
@ -51,6 +58,8 @@ export default class MozMessageBar extends MozLitElement {
|
||||||
heading: { type: String },
|
heading: { type: String },
|
||||||
message: { type: String },
|
message: { type: String },
|
||||||
dismissable: { type: Boolean },
|
dismissable: { type: Boolean },
|
||||||
|
messageL10nId: { type: String },
|
||||||
|
messageL10nArgs: { type: String },
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -75,6 +84,10 @@ export default class MozMessageBar extends MozLitElement {
|
||||||
this.dispatchEvent(new CustomEvent("message-bar:close"));
|
this.dispatchEvent(new CustomEvent("message-bar:close"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get supportLinkEls() {
|
||||||
|
return this.supportLinkSlotEl.assignedElements();
|
||||||
|
}
|
||||||
|
|
||||||
iconTemplate() {
|
iconTemplate() {
|
||||||
let iconData = messageTypeToIconData[this.type];
|
let iconData = messageTypeToIconData[this.type];
|
||||||
if (iconData) {
|
if (iconData) {
|
||||||
|
@ -126,7 +139,15 @@ export default class MozMessageBar extends MozLitElement {
|
||||||
<div class="text-content">
|
<div class="text-content">
|
||||||
${this.headingTemplate()}
|
${this.headingTemplate()}
|
||||||
<div>
|
<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">
|
<span class="link">
|
||||||
<slot name="support-link"></slot>
|
<slot name="support-link"></slot>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -144,7 +144,7 @@
|
||||||
*
|
*
|
||||||
* @return The <notification> element that is shown.
|
* @return The <notification> element that is shown.
|
||||||
*/
|
*/
|
||||||
appendNotification(aType, aNotification, aButtons) {
|
async appendNotification(aType, aNotification, aButtons) {
|
||||||
if (
|
if (
|
||||||
aNotification.priority < this.PRIORITY_SYSTEM ||
|
aNotification.priority < this.PRIORITY_SYSTEM ||
|
||||||
aNotification.priority > this.PRIORITY_CRITICAL_HIGH
|
aNotification.priority > this.PRIORITY_CRITICAL_HIGH
|
||||||
|
@ -157,12 +157,19 @@
|
||||||
MozXULElement.insertFTLIfNeeded("toolkit/global/notification.ftl");
|
MozXULElement.insertFTLIfNeeded("toolkit/global/notification.ftl");
|
||||||
|
|
||||||
// Create the Custom Element and connect it to the document immediately.
|
// Create the Custom Element and connect it to the document immediately.
|
||||||
var newitem;
|
let newitem;
|
||||||
if (!aNotification.notificationIs) {
|
if (!aNotification.notificationIs) {
|
||||||
if (!customElements.get("notification-message")) {
|
if (!customElements.get("notification-message")) {
|
||||||
// There's some weird timing stuff when this element is created at
|
// 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.
|
// 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 = document.createElement("notification-message");
|
||||||
newitem.setAttribute("message-bar-type", "infobar");
|
newitem.setAttribute("message-bar-type", "infobar");
|
||||||
|
@ -182,8 +189,10 @@
|
||||||
this.stack.append(newitem);
|
this.stack.append(newitem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom notification classes may not have the messageText property.
|
if (newitem.localName === "notification-message" && aNotification.label) {
|
||||||
if (newitem.messageText) {
|
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:
|
// Can't use instanceof in case this was created from a different document:
|
||||||
if (
|
if (
|
||||||
aNotification.label &&
|
aNotification.label &&
|
||||||
|
@ -241,6 +250,10 @@
|
||||||
newitem.style.top = "100%";
|
newitem.style.top = "100%";
|
||||||
newitem.style.marginTop = "-15px";
|
newitem.style.marginTop = "-15px";
|
||||||
newitem.style.opacity = "0";
|
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);
|
this._showNotification(newitem, true);
|
||||||
|
|
||||||
// Fire event for accessibility APIs
|
// Fire event for accessibility APIs
|
||||||
|
@ -607,53 +620,56 @@
|
||||||
|
|
||||||
customElements.define("notification", MozElements.Notification);
|
customElements.define("notification", MozElements.Notification);
|
||||||
|
|
||||||
function createNotificationMessageElement() {
|
async function createNotificationMessageElement() {
|
||||||
// Get a reference to MessageBarElement from a created element so the import
|
await window.ensureCustomElements("moz-message-bar");
|
||||||
// gets handled automatically if needed.
|
let MozMessageBar = customElements.get("moz-message-bar");
|
||||||
class NotificationMessage extends document.createElement("message-bar")
|
class NotificationMessage extends MozMessageBar {
|
||||||
.constructor {
|
static queries = {
|
||||||
|
...MozMessageBar.queries,
|
||||||
|
messageText: ".message",
|
||||||
|
messageImage: ".icon",
|
||||||
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.persistence = 0;
|
this.persistence = 0;
|
||||||
this.priority = 0;
|
this.priority = 0;
|
||||||
this.timeout = 0;
|
this.timeout = 0;
|
||||||
this.telemetry = null;
|
this.telemetry = null;
|
||||||
|
this.dismissable = true;
|
||||||
this._shown = false;
|
this._shown = false;
|
||||||
|
|
||||||
|
this.addEventListener("click", this);
|
||||||
|
this.addEventListener("command", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.toggleAttribute("dismissable", true);
|
super.connectedCallback();
|
||||||
this.closeButton.classList.add("notification-close");
|
this.#setStyles();
|
||||||
|
|
||||||
this.container = this.shadowRoot.querySelector(".container");
|
this.classList.add("infobar");
|
||||||
this.container.classList.add("infobar");
|
|
||||||
this.setAlertRole();
|
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 = document.createElement("span");
|
||||||
this.buttonContainer.classList.add("notification-button-container");
|
this.buttonContainer.classList.add("notification-button-container");
|
||||||
|
this.buttonContainer.setAttribute("slot", "actions");
|
||||||
this.messageImage = this.shadowRoot.querySelector(".icon");
|
this.appendChild(this.buttonContainer);
|
||||||
|
|
||||||
messageContent.append(this.messageText, this.buttonContainer);
|
|
||||||
this.shadowRoot.addEventListener("click", this);
|
|
||||||
this.shadowRoot.addEventListener("command", this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
if (this.eventCallback) {
|
if (this.eventCallback) {
|
||||||
this.eventCallback("disconnected");
|
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) {
|
_doTelemetry(type) {
|
||||||
if (
|
if (
|
||||||
this.telemetry &&
|
this.telemetry &&
|
||||||
|
@ -686,10 +702,10 @@
|
||||||
setAlertRole() {
|
setAlertRole() {
|
||||||
// Wait a little for this to render before setting the role for more
|
// Wait a little for this to render before setting the role for more
|
||||||
// consistent alerts to screen readers.
|
// consistent alerts to screen readers.
|
||||||
this.container.removeAttribute("role");
|
this.removeAttribute("role");
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
this.container.setAttribute("role", "alert");
|
this.setAttribute("role", "alert");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -736,18 +752,10 @@
|
||||||
*/
|
*/
|
||||||
set label(value) {
|
set label(value) {
|
||||||
if (value && typeof value == "object" && "l10n-id" in value) {
|
if (value && typeof value == "object" && "l10n-id" in value) {
|
||||||
const message = document.createElement("span");
|
this.messageL10nId = value["l10n-id"];
|
||||||
document.l10n.setAttributes(
|
this.messageL10nArgs = value["l10n-args"];
|
||||||
message,
|
|
||||||
value["l10n-id"],
|
|
||||||
value["l10n-args"]
|
|
||||||
);
|
|
||||||
while (this.messageText.firstChild) {
|
|
||||||
this.messageText.firstChild.remove();
|
|
||||||
}
|
|
||||||
this.messageText.appendChild(message);
|
|
||||||
} else {
|
} else {
|
||||||
this.messageText.textContent = value;
|
this.message = value;
|
||||||
}
|
}
|
||||||
this.setAlertRole();
|
this.setAlertRole();
|
||||||
}
|
}
|
||||||
|
@ -777,7 +785,11 @@
|
||||||
"button",
|
"button",
|
||||||
button.is ? { is: button.is } : {}
|
button.is ? { is: button.is } : {}
|
||||||
);
|
);
|
||||||
buttonElem.classList.add("notification-button", "small-button");
|
buttonElem.classList.add(
|
||||||
|
"notification-button",
|
||||||
|
"small-button",
|
||||||
|
"footer-button"
|
||||||
|
);
|
||||||
|
|
||||||
if (button.primary) {
|
if (button.primary) {
|
||||||
buttonElem.classList.add("primary");
|
buttonElem.classList.add("primary");
|
||||||
|
@ -794,7 +806,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link) {
|
if (link) {
|
||||||
this.messageText.append(new Text(" "), buttonElem);
|
buttonElem.setAttribute("slot", "support-link");
|
||||||
|
this.appendChild(buttonElem);
|
||||||
} else {
|
} else {
|
||||||
this.buttonContainer.appendChild(buttonElem);
|
this.buttonContainer.appendChild(buttonElem);
|
||||||
}
|
}
|
||||||
|
@ -811,6 +824,8 @@
|
||||||
super.dismiss();
|
super.dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define("notification-message", NotificationMessage);
|
if (!customElements.get("notification-message")) {
|
||||||
|
customElements.define("notification-message", NotificationMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@
|
||||||
|
|
||||||
/** Size **/
|
/** Size **/
|
||||||
--size-item-small: 16px;
|
--size-item-small: 16px;
|
||||||
|
--size-item-medium: 28px;
|
||||||
--size-item-large: 32px;
|
--size-item-large: 32px;
|
||||||
|
|
||||||
/** Spacing **/
|
/** Spacing **/
|
||||||
|
|
|
@ -225,12 +225,19 @@ button.text-link .button-text {
|
||||||
color: var(--button-color, inherit);
|
color: var(--button-color, inherit);
|
||||||
background-color: var(--button-bgcolor, color-mix(in srgb, currentColor 13%, transparent));
|
background-color: var(--button-bgcolor, color-mix(in srgb, currentColor 13%, transparent));
|
||||||
padding: .45em 1em;
|
padding: .45em 1em;
|
||||||
min-height: 32px;
|
min-height: var(--size-item-large);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
margin-inline: 8px 0;
|
margin-inline: 8px 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
&.small-button {
|
||||||
|
margin: 0;
|
||||||
|
min-height: var(--size-item-medium);
|
||||||
|
padding: .6em 1em;
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
}
|
||||||
|
|
||||||
&[disabled] {
|
&[disabled] {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
|
@ -247,7 +254,8 @@ button.text-link .button-text {
|
||||||
&:hover:active {
|
&:hover:active {
|
||||||
background-color: var(--button-active-bgcolor, color-mix(in srgb, currentColor 30%, transparent));
|
background-color: var(--button-active-bgcolor, color-mix(in srgb, currentColor 30%, transparent));
|
||||||
}
|
}
|
||||||
&[default] {
|
&[default],
|
||||||
|
&.primary {
|
||||||
color: var(--button-primary-color);
|
color: var(--button-primary-color);
|
||||||
background-color: var(--button-primary-bgcolor);
|
background-color: var(--button-primary-bgcolor);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче