Bug 1690333 - Proton infobar styles r=jaws

Differential Revision: https://phabricator.services.mozilla.com/D104585
This commit is contained in:
Mark Striemer 2021-03-28 19:04:34 +00:00
Родитель 81479b1262
Коммит bc875387b4
19 изменённых файлов: 666 добавлений и 270 удалений

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

@ -32,6 +32,13 @@ XPCOMUtils.defineLazyPreferenceGetter(
false
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"PROTON_INFOBARS_ENABLED",
"browser.proton.infobars.enabled",
false
);
class AboutNewTabParent extends JSWindowActorParent {
async receiveMessage(message) {
switch (message.name) {
@ -155,7 +162,9 @@ var DefaultBrowserNotification = {
let iconPixels = win.devicePixelRatio > 1 ? "64" : "32";
let iconURL = "chrome://branding/content/icon" + iconPixels + ".png";
const priority = win.gNotificationBox.PRIORITY_INFO_MEDIUM;
const priority = PROTON_INFOBARS_ENABLED
? win.gNotificationBox.PRIORITY_SYSTEM
: win.gNotificationBox.PRIORITY_INFO_MEDIUM;
let callback = this._onNotificationEvent.bind(this);
this._notification = gBrowser
.getNotificationBox(browser)
@ -165,7 +174,9 @@ var DefaultBrowserNotification = {
iconURL,
priority,
buttons,
callback
callback,
null,
["browser/defaultBrowserNotification.ftl"]
);
},

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

@ -396,7 +396,7 @@ XPCOMUtils.defineLazyGetter(this, "gHighPriorityNotificationBox", () => {
return new MozElements.NotificationBox(element => {
element.classList.add("global-notificationbox");
element.setAttribute("notificationside", "top");
if (Services.prefs.getBoolPref("browser.proton.infobars.enabled", false)) {
if (gProtonInfobarsEnabled) {
// With Proton enabled all notification boxes are at the top, built into the browser chrome.
let tabNotifications = document.getElementById("tab-notification-deck");
gNavToolbox.insertBefore(element, tabNotifications);
@ -408,7 +408,7 @@ XPCOMUtils.defineLazyGetter(this, "gHighPriorityNotificationBox", () => {
// Regular notification bars shown at the bottom of the window.
XPCOMUtils.defineLazyGetter(this, "gNotificationBox", () => {
return Services.prefs.getBoolPref("browser.proton.infobars.enabled", false)
return gProtonInfobarsEnabled
? gHighPriorityNotificationBox
: new MozElements.NotificationBox(element => {
element.classList.add("global-notificationbox");
@ -587,6 +587,14 @@ XPCOMUtils.defineLazyPreferenceGetter(
}
);
/* Temporary pref while the Proton infobars work stabilizes. */
XPCOMUtils.defineLazyPreferenceGetter(
this,
"gProtonInfobarsEnabled",
"browser.proton.infobars.enabled",
false
);
/* Temporary pref while the dust settles around the updated tooltip design
for tabs and bookmarks toolbar. This will eventually be removed and
browser.proton.enabled will be used instead. */
@ -1047,7 +1055,9 @@ const gStoragePressureObserver = {
null,
gHighPriorityNotificationBox.PRIORITY_WARNING_HIGH,
buttons,
null
null,
null,
["branding/brand.ftl", "browser/preferences/preferences.ftl"]
);
// This seems to be necessary to get the buttons to display correctly

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

@ -826,9 +826,7 @@
if (!browser._notificationBox) {
browser._notificationBox = new MozElements.NotificationBox(element => {
element.setAttribute("notificationside", "top");
if (
Services.prefs.getBoolPref("browser.proton.infobars.enabled", false)
) {
if (gProtonInfobarsEnabled) {
element.setAttribute(
"name",
`tab-notification-box-${this._nextNotificationBoxId++}`
@ -1114,9 +1112,7 @@
this._appendStatusPanel();
if (
Services.prefs.getBoolPref("browser.proton.infobars.enabled", false)
) {
if (gProtonInfobarsEnabled) {
this._updateVisibleNotificationBox(newBrowser);
}

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

@ -733,7 +733,10 @@ var AboutLogins = {
id,
iconURL,
notificationBox[priority],
buttons
buttons,
null,
null,
["browser/aboutLogins.ftl"]
);
}
},

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

@ -13,6 +13,11 @@ XPCOMUtils.defineLazyModuleGetters(this, {
Services: "resource://gre/modules/Services.jsm",
});
const FTL_PATHS = [
"browser/newtab/asrouter.ftl",
"browser/defaultBrowserNotification.ftl",
];
class InfoBarNotification {
constructor(message, dispatch) {
this._dispatch = dispatch;
@ -45,7 +50,9 @@ class InfoBarNotification {
content.icon || "chrome://branding/content/icon64.png",
notificationContainer.PRIORITY_INFO_MEDIUM,
content.buttons.map(b => this.formatButtonConfig(b)),
this.infobarCallback
this.infobarCallback,
null,
FTL_PATHS
);
this.addImpression();
@ -131,10 +138,9 @@ const InfoBar = {
},
maybeInsertFTL(win) {
win.MozXULElement.insertFTLIfNeeded("browser/newtab/asrouter.ftl");
win.MozXULElement.insertFTLIfNeeded(
"browser/defaultBrowserNotification.ftl"
);
for (let filepath of FTL_PATHS) {
win.MozXULElement.insertFTLIfNeeded(filepath);
}
},
showInfoBarMessage(browser, message, dispatch) {

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

@ -461,7 +461,9 @@ var TabCrashHandler = {
closeAllNotifications();
}
}
},
null,
"browser/browser.ftl"
);
let existingItem = this.notificationsMap.get(childID);

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

@ -944,5 +944,5 @@ popupnotificationcontent {
} /** END Proton **/
#tab-notification-deck {
display: flex;
display: block;
}

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

@ -838,6 +838,7 @@
["button-group", "chrome://global/content/elements/named-deck.js"],
["findbar", "chrome://global/content/elements/findbar.js"],
["menulist", "chrome://global/content/elements/menulist.js"],
["message-bar", "chrome://global/content/elements/message-bar.js"],
["named-deck", "chrome://global/content/elements/named-deck.js"],
["named-deck-button", "chrome://global/content/elements/named-deck.js"],
["search-textbox", "chrome://global/content/elements/search-textbox.js"],

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

@ -83,6 +83,8 @@ toolkit.jar:
content/global/elements/findbar.js (widgets/findbar.js)
content/global/elements/editor.js (widgets/editor.js)
content/global/elements/general.js (widgets/general.js)
content/global/elements/message-bar.css (widgets/message-bar.css)
content/global/elements/message-bar.js (widgets/message-bar.js)
content/global/elements/menu.js (widgets/menu.js)
content/global/elements/menupopup.js (widgets/menupopup.js)
content/global/elements/moz-input-box.js (widgets/moz-input-box.js)

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

@ -411,7 +411,7 @@ var tests =
test(nb, ntf) {
var exh = false;
try {
nb.appendNotification("no", "no", "no", 0, null);
nb.appendNotification("no", "no", "no", -1, null);
} catch (ex) { exh = true; }
SimpleTest.is(exh, true, "appendNotification priority too low");

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

@ -12,38 +12,35 @@
--close-icon-size: 32px;
}
:host([message-bar-type=infobar]) {
--close-icon-size: 24px;
}
/* MessageBar colors by message type */
/* Colors from: https://design.firefox.com/photon/components/message-bars.html#type-specific-style */
:host {
/* Colors used by default, and for [type=generic] message bars.*/
background-color: var(--in-content-box-info-background);
color: var(--in-content-text-color);
--message-bar-background-color: var(--in-content-box-info-background);
--message-bar-text-color: var(--in-content-text-color);
--message-bar-icon-url: var(--info-icon-url);
/* The default values of --in-content-button* are sufficient, even for dark themes */
}
:host([type=warning]) {
background-color: var(--yellow-50);
color: var(--yellow-90);
:host([type=warning]:not([message-bar-type=infobar])) {
--message-bar-background-color: var(--yellow-50);
--message-bar-text-color: var(--yellow-90);
--message-bar-icon-url: var(--warn-icon-url);
--in-content-button-background: var(--yellow-60);
--in-content-button-background-hover: var(--yellow-70);
--in-content-button-background-active: var(--yellow-80);
}
:host([type=warning]) ::slotted(button:enabled:hover),
:host([type=warning]) ::slotted(button:enabled:hover),
:host([type=warning]) .close:enabled:hover,
:host([type=warning]) .close:enabled:hover:active {
/* common.css sets color: inherit !important... */
color: white !important;
:host([type=warning]) {
--message-bar-icon-url: var(--warn-icon-url);
}
:host([type=success]) {
background-color: var(--green-50);
color: var(--green-90);
:host([type=success]:not([message-bar-type=infobar])) {
--message-bar-background-color: var(--green-50);
--message-bar-text-color: var(--green-90);
--message-bar-icon-url: var(--success-icon-url);
--in-content-button-background: var(--green-60);
@ -51,15 +48,18 @@
--in-content-button-background-active: var(--green-80);
}
:host([type=error]) {
background-color: var(--red-60);
color: #ffffff;
:host([type=error]:not([message-bar-type=infobar])) {
--message-bar-background-color: var(--red-60);
--message-bar-text-color: #ffffff;
--message-bar-icon-url: var(--error-icon-url);
--in-content-button-background: var(--red-70);
--in-content-button-background-hover: var(--red-80);
--in-content-button-background-active: var(--red-90);
}
:host([type=error]),
:host([type=critical]) {
--message-bar-icon-url: var(--error-icon-url);
}
:host {
border-radius: 4px;
@ -78,12 +78,12 @@
/* MessageBar Grid Layout */
.container {
background: inherit;
color: inherit;
background: var(--message-bar-background-color);
color: var(--message-bar-text-color);
padding: 8px;
padding: 4px 8px;
position: relative;
min-height: 32px;
border-radius: 4px;
display: flex;
@ -97,7 +97,7 @@
.content {
margin: 0 4px;
display: flex;
display: inline-block;
/* Ensure that the message bar content is vertically aligned. */
align-items: center;
/* Ensure that the message bar content is wrapped. */
@ -144,7 +144,150 @@
width: var(--close-icon-size);
height: var(--close-icon-size);
margin: 0;
margin-inline-end: 4px;
padding: 0;
flex-shrink: 0;
}
@supports -moz-bool-pref("browser.proton.infobars.enabled") {
@media not (prefers-contrast) {
.container.infobar {
box-shadow: 0 1px 2px rgba(58, 57, 68, 0.1);
background: var(--in-content-page-background);
}
}
.close {
fill: var(--in-content-icon-color);
}
@media (prefers-color-scheme: dark) {
.container.infobar {
background: rgb(66,65,77);
}
}
: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;
background-image: linear-gradient(0, #9059ff 0%, #ff4aa2 52.08%, #ffbd4f 100%);
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;
}
.notification-message {
min-height: 16px; /* min-height: 32px with block padding */
padding-block: 8px;
margin-inline-end: 20px;
}
.notification-button-container,
.notification-message {
display: inline-block;
vertical-align: middle;
}
.close {
margin: 4px 8px;
background-size: 16px;
}
.notification-button {
margin: 4px;
/* This is supposed to be 6px but then the buttons are 26px tall by default
* on Windows. Drop it down to 4px (with the 1px border) */
padding-block: 3px;
}
.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;
}
.text-link:hover {
cursor: pointer;
}
.infobar > .icon {
padding: 0;
margin: 8px 0;
}
.infobar > .icon,
:host([type=system]) .notification-content {
margin-inline-start: 16px;
}
:host([type=system]) .icon {
display: none;
}
:host([type=info]) .icon {
color: rgb(128,235,255);
}
:host([type=warning]) .icon {
color: rgb(255,164,54);
}
:host([type=critical]) .icon {
color: rgb(226,40,80);
}
@media (prefers-color-scheme: dark) {
:host([type=info]) .icon {
color: rgb(0,221,255);
}
:host([type=warning]) .icon {
color: rgb(255,189,79);
}
:host([type=critical]) .icon {
color: rgb(255,154,162);
}
}
}
@supports not -moz-bool-pref("browser.proton.infobars.enabled") {
:host {
/* Colors used by default, and for [type=generic] message bars.*/
background-color: var(--in-content-box-info-background);
color: var(--in-content-text-color);
}
.container {
padding: 8px;
min-height: 32px;
}
.close {
margin-inline-end: 4px;
}
}

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

@ -0,0 +1,84 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// This is loaded into chrome windows with the subscript loader. Wrap in
// a block to prevent accidentally leaking globals onto `window`.
{
class MessageBarElement extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: "open" });
const content = this.constructor.template.content.cloneNode(true);
shadowRoot.append(content);
this.closeButton.addEventListener("click", () => this.dismiss(), {
once: true,
});
}
disconnectedCallback() {
this.dispatchEvent(new CustomEvent("message-bar:close"));
}
get closeButton() {
return this.shadowRoot.querySelector("button.close");
}
static get template() {
const template = document.createElement("template");
const commonStyles = document.createElement("link");
commonStyles.rel = "stylesheet";
commonStyles.href = "chrome://global/skin/in-content/common.css";
const messageBarStyles = document.createElement("link");
messageBarStyles.rel = "stylesheet";
messageBarStyles.href =
"chrome://global/content/elements/message-bar.css";
template.content.append(commonStyles, messageBarStyles);
// A container for the entire message bar content,
// most of the css rules needed to provide the
// expected message bar layout is applied on this
// element.
const container = document.createElement("div");
container.classList.add("container");
template.content.append(container);
const icon = document.createElement("span");
icon.classList.add("icon");
container.append(icon);
const barcontent = document.createElement("span");
barcontent.classList.add("content");
barcontent.append(document.createElement("slot"));
container.append(barcontent);
const spacer = document.createElement("span");
spacer.classList.add("spacer");
container.append(spacer);
const closeIcon = document.createElement("button");
closeIcon.classList.add("close", "ghost-button");
container.append(closeIcon);
Object.defineProperty(this, "template", {
value: template,
});
return template;
}
dismiss() {
this.dispatchEvent(new CustomEvent("message-bar:user-dismissed"));
this.close();
}
close() {
this.remove();
}
}
customElements.define("message-bar", MessageBarElement);
}

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

@ -28,13 +28,19 @@
get stack() {
if (!this._stack) {
let stack = document.createXULElement("legacy-stack");
let stack;
stack = document.createXULElement(
this.protonInfobarsEnabled ? "vbox" : "legacy-stack"
);
stack._notificationBox = this;
stack.className = "notificationbox-stack";
stack.appendChild(document.createXULElement("spacer"));
if (!this.protonInfobarsEnabled) {
stack.appendChild(document.createXULElement("spacer"));
}
stack.addEventListener("transitionend", event => {
if (
event.target.localName == "notification" &&
(event.target.localName == "notification" ||
event.target.localName == "notification-message") &&
event.propertyName == "margin-top"
) {
this._finishAnimation();
@ -58,7 +64,9 @@
}
var closedNotification = this._closedNotification;
var notifications = this.stack.getElementsByTagName("notification");
var notifications = this.stack.getElementsByTagName(
this.protonInfobarsEnabled ? "notification-message" : "notification"
);
return Array.prototype.filter.call(
notifications,
n => n != closedNotification
@ -140,10 +148,11 @@
aPriority,
aButtons,
aEventCallback,
aNotificationIs
aNotificationIs,
aFtlFilePaths
) {
if (
aPriority < this.PRIORITY_INFO_LOW ||
aPriority < this.PRIORITY_SYSTEM ||
aPriority > this.PRIORITY_CRITICAL_HIGH
) {
throw new Error("Invalid notification priority " + aPriority);
@ -163,10 +172,24 @@
MozXULElement.insertFTLIfNeeded("toolkit/global/notification.ftl");
// Create the Custom Element and connect it to the document immediately.
var newitem = document.createXULElement(
"notification",
aNotificationIs ? { is: aNotificationIs } : {}
);
var newitem;
if (this.protonInfobarsEnabled) {
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();
}
newitem = document.createElement("notification-message");
newitem.setAttribute("message-bar-type", "infobar");
if (aFtlFilePaths) {
newitem.addFtl(aFtlFilePaths);
}
} else {
newitem = document.createXULElement(
"notification",
aNotificationIs ? { is: aNotificationIs } : {}
);
}
this.stack.insertBefore(newitem, insertPos);
// Custom notification classes may not have the messageText property.
@ -184,65 +207,20 @@
}
}
newitem.setAttribute("value", aValue);
if (aImage) {
if (aImage && !this.protonInfobarsEnabled) {
newitem.messageImage.setAttribute("src", aImage);
}
newitem.eventCallback = aEventCallback;
if (aButtons) {
for (var b = 0; b < aButtons.length; b++) {
let button = aButtons[b];
let buttonElem;
let link = button.link;
let localeId = button["l10n-id"];
if (!link && button.supportPage) {
link =
Services.urlFormatter.formatURLPref("app.support.baseURL") +
button.supportPage;
if (!button.label && !localeId) {
localeId = "notification-learnmore-default-label";
}
}
if (link) {
buttonElem = document.createXULElement("label", {
is: "text-link",
});
buttonElem.setAttribute("href", link);
buttonElem.classList.add("notification-link");
} else {
buttonElem = document.createXULElement(
"button",
button.is ? { is: button.is } : {}
);
buttonElem.classList.add("notification-button");
if (button.primary) {
buttonElem.classList.add("primary");
}
}
if (localeId) {
buttonElem.setAttribute("data-l10n-id", localeId);
} else {
buttonElem.setAttribute(link ? "value" : "label", button.label);
if (typeof button.accessKey == "string") {
buttonElem.setAttribute("accesskey", button.accessKey);
}
}
if (link) {
newitem.messageText.appendChild(buttonElem);
} else {
newitem.messageDetails.appendChild(buttonElem);
}
buttonElem.buttonInfo = button;
}
newitem.setButtons(aButtons);
}
newitem.priority = aPriority;
if (aPriority >= this.PRIORITY_CRITICAL_LOW) {
if (aPriority == this.PRIORITY_SYSTEM) {
newitem.setAttribute("type", "system");
} else if (aPriority >= this.PRIORITY_CRITICAL_LOW) {
newitem.setAttribute("type", "critical");
} else if (aPriority <= this.PRIORITY_INFO_HIGH) {
newitem.setAttribute("type", "info");
@ -271,7 +249,10 @@
if (!aItem.parentNode) {
return;
}
if (aItem == this.currentNotification) {
if (this.protonInfobarsEnabled) {
this.currentNotification = aItem;
this.removeCurrentNotification(aSkipAnimation);
} else if (aItem == this.currentNotification) {
this.removeCurrentNotification(aSkipAnimation);
} else if (aItem != this._closedNotification) {
this._removeNotificationElement(aItem);
@ -336,7 +317,11 @@
_showNotification(aNotification, aSlideIn, aSkipAnimation) {
this._finishAnimation();
var height = aNotification.getBoundingClientRect().height;
let { marginTop, marginBottom } = getComputedStyle(aNotification);
var height =
aNotification.getBoundingClientRect().height +
parseInt(marginTop, 10) +
parseInt(marginBottom, 10);
var skipAnimation =
aSkipAnimation || height == 0 || !this._allowAnimation;
aNotification.classList.toggle("animated", !skipAnimation);
@ -380,10 +365,18 @@
}
}
}
get protonInfobarsEnabled() {
return Services.prefs.getBoolPref(
"browser.proton.infobars.enabled",
false
);
}
};
// These are defined on the instance prototype for backwards compatibility.
Object.assign(MozElements.NotificationBox.prototype, {
PRIORITY_SYSTEM: 0,
PRIORITY_INFO_LOW: 1,
PRIORITY_INFO_MEDIUM: 2,
PRIORITY_INFO_HIGH: 3,
@ -441,6 +434,57 @@
}
}
setButtons(aButtons) {
for (let button of aButtons) {
let buttonElem;
let link = button.link;
let localeId = button["l10n-id"];
if (!link && button.supportPage) {
link =
Services.urlFormatter.formatURLPref("app.support.baseURL") +
button.supportPage;
if (!button.label && !localeId) {
localeId = "notification-learnmore-default-label";
}
}
if (link) {
buttonElem = document.createXULElement("label", {
is: "text-link",
});
buttonElem.setAttribute("href", link);
buttonElem.classList.add("notification-link");
} else {
buttonElem = document.createXULElement(
"button",
button.is ? { is: button.is } : {}
);
buttonElem.classList.add("notification-button");
if (button.primary) {
buttonElem.classList.add("primary");
}
}
if (localeId) {
buttonElem.setAttribute("data-l10n-id", localeId);
} else {
buttonElem.setAttribute(link ? "value" : "label", button.label);
if (typeof button.accessKey == "string") {
buttonElem.setAttribute("accesskey", button.accessKey);
}
}
if (link) {
this.messageText.appendChild(buttonElem);
} else {
this.messageDetails.appendChild(buttonElem);
}
buttonElem.buttonInfo = button;
}
}
get control() {
return this.closest(".notificationbox-stack")._notificationBox;
}
@ -502,7 +546,159 @@
}
}
}
get protonInfobarsEnabled() {
return Services.prefs.getBoolPref(
"browser.proton.infobars.enabled",
false
);
}
};
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 {
connectedCallback() {
this.toggleAttribute("dismissable", true);
this.closeButton.classList.add("notification-close");
this.shadowRoot.querySelector(".container").classList.add("infobar");
let messageContent = this.shadowRoot.querySelector(".content");
messageContent.classList.add("notification-content");
// Remove the <slot>, API surface is `set label()` and `setButtons()`.
messageContent.textContent = "";
this.messageText = document.createElement("span");
this.messageText.classList.add("notification-message");
this.buttonContainer = document.createElement("span");
this.buttonContainer.classList.add("notification-button-container");
messageContent.append(this.messageText, this.buttonContainer);
this.shadowRoot.addEventListener("click", this);
}
disconnectedCallback() {
if (this.eventCallback) {
this.eventCallback("disconnected");
}
}
close() {
this.closest(
".notificationbox-stack"
)._notificationBox.removeNotification(this);
}
addFtl(filepaths) {
for (let filepath of filepaths) {
let link = document.createElement("link");
link.setAttribute("rel", "localization");
link.href = filepath;
this.shadowRoot.append(link);
}
document.l10n.connectRoot(this.shadowRoot);
}
_insertNotificationFtl() {
if (!this._insertedNotificationFtl) {
this._insertedNotificationFtl = true;
this.addFtl(["toolkit/global/notification.ftl"]);
}
}
handleEvent(e) {
if (e.type == "click" && "buttonInfo" in e.target) {
let { buttonInfo } = e.target;
let { callback, popup } = buttonInfo;
if (callback) {
if (!callback(this, buttonInfo, e.target, e)) {
this.close();
}
e.stopPropagation();
} else if (popup) {
document
.getElementById(popup)
.openPopup(
e.originalTarget,
"after_start",
0,
0,
false,
false,
e
);
e.stopPropagation();
}
}
}
set label(value) {
this.messageText.textContent = value;
}
setButtons(buttons) {
this._buttons = buttons;
for (let button of buttons) {
let link = button.link;
let localeId = button["l10n-id"];
if (!link && button.supportPage) {
link =
Services.urlFormatter.formatURLPref("app.support.baseURL") +
button.supportPage;
if (!button.label && !localeId) {
localeId = "notification-learnmore-default-label";
}
this._insertNotificationFtl();
}
let buttonElem;
if (link) {
buttonElem = document.createXULElement("label", {
is: "text-link",
});
buttonElem.setAttribute("href", link);
buttonElem.classList.add("notification-link");
} else {
buttonElem = document.createXULElement(
"button",
button.is ? { is: button.is } : {}
);
buttonElem.classList.add("notification-button", "small");
if (button.primary) {
buttonElem.classList.add("primary");
}
}
if (localeId) {
document.l10n.setAttributes(buttonElem, localeId);
} else {
buttonElem.textContent = button.label;
if (typeof button.accessKey == "string") {
buttonElem.setAttribute("accesskey", button.accessKey);
}
}
if (link) {
this.messageText.append(new Text(" "), buttonElem);
} else {
this.buttonContainer.appendChild(buttonElem);
}
buttonElem.buttonInfo = button;
}
}
dismiss() {
if (this.eventCallback) {
this.eventCallback("dismissed");
}
super.dismiss();
}
}
customElements.define("notification-message", NotificationMessage);
}
}

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

@ -25,7 +25,6 @@
<!-- Defer scripts so all the templates are loaded by the time they run. -->
<script defer src="chrome://mozapps/content/extensions/aboutaddonsCommon.js"></script>
<script defer src="chrome://mozapps/content/extensions/message-bar.js"></script>
<script defer src="chrome://mozapps/content/extensions/abuse-reports.js"></script>
<script defer src="chrome://mozapps/content/extensions/shortcuts.js"></script>
<script defer src="chrome://mozapps/content/extensions/drag-drop-addon-installer.js"></script>
@ -331,7 +330,10 @@
<message-bar class="discopane-notice" dismissable>
<div class="discopane-notice-content">
<span data-l10n-id="discopane-notice-recommendations"></span>
<button data-l10n-id="discopane-notice-learn-more" action="notice-learn-more"></button>
<a is="support-link"
support-page="personalized-addons"
data-l10n-id="discopane-notice-learn-more"
action="notice-learn-more"></a>
</div>
</message-bar>
</template>

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

@ -5,7 +5,7 @@
/* import-globals-from aboutaddonsCommon.js */
/* import-globals-from abuse-reports.js */
/* import-globals-from view-controller.js */
/* global MozXULElement, MessageBarStackElement, windowRoot */
/* global MozXULElement, windowRoot */
"use strict";
@ -1239,6 +1239,77 @@ class SearchAddons extends HTMLElement {
}
customElements.define("search-addons", SearchAddons);
class MessageBarStackElement extends HTMLElement {
constructor() {
super();
this._observer = null;
const shadowRoot = this.attachShadow({ mode: "open" });
shadowRoot.append(this.constructor.template.content.cloneNode(true));
}
connectedCallback() {
// Close any message bar that should be allowed based on the
// maximum number of message bars.
this.closeMessageBars();
// Observe mutations to close older bars when new ones have been
// added.
this._observer = new MutationObserver(() => {
this._observer.disconnect();
this.closeMessageBars();
this._observer.observe(this, { childList: true });
});
this._observer.observe(this, { childList: true });
}
disconnectedCallback() {
this._observer.disconnect();
this._observer = null;
}
closeMessageBars() {
const { maxMessageBarCount } = this;
if (maxMessageBarCount > 1) {
// Remove the older message bars if the stack reached the
// maximum number of message bars allowed.
while (this.childElementCount > maxMessageBarCount) {
this.firstElementChild.remove();
}
}
}
get maxMessageBarCount() {
return parseInt(this.getAttribute("max-message-bar-count"), 10);
}
static get template() {
const template = document.createElement("template");
const style = document.createElement("style");
// Render the stack in the reverse order if the stack has the
// reverse attribute set.
style.textContent = `
:host {
display: block;
}
:host([reverse]) > slot {
display: flex;
flex-direction: column-reverse;
}
`;
template.content.append(style);
template.content.append(document.createElement("slot"));
Object.defineProperty(this, "template", {
value: template,
});
return template;
}
}
customElements.define("message-bar-stack", MessageBarStackElement);
class GlobalWarnings extends MessageBarStackElement {
constructor() {
super();
@ -4381,7 +4452,6 @@ class TaarMessageBar extends HTMLElement {
e.type == "click" &&
e.target.getAttribute("action") == "notice-learn-more"
) {
// The element is a button but opens a URL, so record as link.
AMTelemetry.recordLinkEvent({
object: "aboutAddons",
value: "disconotice",
@ -4389,10 +4459,6 @@ class TaarMessageBar extends HTMLElement {
view: getTelemetryViewName(this),
},
});
windowRoot.ownerGlobal.openTrustedLinkIn(
SUPPORT_URL + "personalized-addons",
"tab"
);
} else if (e.type == "message-bar:user-dismissed") {
Services.prefs.setBoolPref(PREF_RECOMMENDATION_HIDE_NOTICE, true);
}

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

@ -1,148 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint max-len: ["error", 80] */
"use strict";
class MessageBarStackElement extends HTMLElement {
constructor() {
super();
this._observer = null;
const shadowRoot = this.attachShadow({ mode: "open" });
shadowRoot.append(this.constructor.template.content.cloneNode(true));
}
connectedCallback() {
// Close any message bar that should be allowed based on the
// maximum number of message bars.
this.closeMessageBars();
// Observe mutations to close older bars when new ones have been
// added.
this._observer = new MutationObserver(() => {
this._observer.disconnect();
this.closeMessageBars();
this._observer.observe(this, { childList: true });
});
this._observer.observe(this, { childList: true });
}
disconnectedCallback() {
this._observer.disconnect();
this._observer = null;
}
closeMessageBars() {
const { maxMessageBarCount } = this;
if (maxMessageBarCount > 1) {
// Remove the older message bars if the stack reached the
// maximum number of message bars allowed.
while (this.childElementCount > maxMessageBarCount) {
this.firstElementChild.remove();
}
}
}
get maxMessageBarCount() {
return parseInt(this.getAttribute("max-message-bar-count"), 10);
}
static get template() {
const template = document.createElement("template");
const style = document.createElement("style");
// Render the stack in the reverse order if the stack has the
// reverse attribute set.
style.textContent = `
:host {
display: block;
}
:host([reverse]) > slot {
display: flex;
flex-direction: column-reverse;
}
`;
template.content.append(style);
template.content.append(document.createElement("slot"));
Object.defineProperty(this, "template", {
value: template,
});
return template;
}
}
class MessageBarElement extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: "open" });
const content = this.constructor.template.content.cloneNode(true);
shadowRoot.append(content);
this.closeButton.addEventListener(
"click",
() => {
this.dispatchEvent(new CustomEvent("message-bar:user-dismissed"));
this.remove();
},
{
once: true,
}
);
}
disconnectedCallback() {
this.dispatchEvent(new CustomEvent("message-bar:close"));
}
get closeButton() {
return this.shadowRoot.querySelector("button.close");
}
static get template() {
const template = document.createElement("template");
const style = document.createElement("style");
style.textContent = `
@import "chrome://global/skin/in-content/common.css";
@import "chrome://mozapps/content/extensions/message-bar.css";
`;
template.content.append(style);
// A container for the entire message bar content,
// most of the css rules needed to provide the
// expected message bar layout is applied on this
// element.
const container = document.createElement("div");
container.setAttribute("class", "container");
template.content.append(container);
const icon = document.createElement("span");
icon.setAttribute("class", "icon");
container.append(icon);
const barcontent = document.createElement("span");
barcontent.setAttribute("class", "content");
barcontent.append(document.createElement("slot"));
container.append(barcontent);
const spacer = document.createElement("span");
spacer.classList.add("spacer");
container.append(spacer);
const closeIcon = document.createElement("button");
closeIcon.setAttribute("class", "close");
container.append(closeIcon);
Object.defineProperty(this, "template", {
value: template,
});
return template;
}
}
customElements.define("message-bar", MessageBarElement);
customElements.define("message-bar-stack", MessageBarStackElement);

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

@ -21,8 +21,6 @@ toolkit.jar:
content/mozapps/extensions/firefox-compact-dark.svg (content/firefox-compact-dark.svg)
content/mozapps/extensions/firefox-compact-light.svg (content/firefox-compact-light.svg)
content/mozapps/extensions/firefox-alpenglow.svg (content/firefox-alpenglow.svg)
content/mozapps/extensions/message-bar.css (content/message-bar.css)
content/mozapps/extensions/message-bar.js (content/message-bar.js)
content/mozapps/extensions/panel-list.css (content/panel-list.css)
content/mozapps/extensions/panel-item.css (content/panel-item.css)
content/mozapps/extensions/rating-star.css (content/rating-star.css)

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

@ -6,6 +6,7 @@
@namespace html "http://www.w3.org/1999/xhtml";
@namespace xul "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
:host,
:root {
--in-content-page-color: #0c0c0d;
--in-content-page-background: #fff;
@ -18,6 +19,7 @@
--in-content-item-hover: rgba(69, 161, 255, 0.2); /* blue 40 a20 */
--in-content-item-selected: #0a84ff;
--in-content-item-selected-text: #fff;
--in-content-icon-color: rgb(91,91,102);
--in-content-accent-color: #0a84ff;
--in-content-accent-color-active: #0060df;
--in-content-border-hover: var(--grey-90-a50);
@ -103,6 +105,7 @@
}
@supports not -moz-bool-pref("browser.proton.enabled") {
:host,
:root {
--in-content-page-background: #f9f9fa;
--in-content-box-info-background: var(--grey-20);
@ -123,6 +126,7 @@
}
@media (prefers-color-scheme: dark) {
:host,
:root {
/* Keep these in sync with layout/base/PresShell.cpp, and plaintext.css */
--in-content-page-background: rgb(28,27,34);
@ -142,6 +146,7 @@
--in-content-button-background: rgb(43,42,51);
--in-content-button-background-hover: rgb(82,82,94);
--in-content-button-background-active: rgb(91,91,102);
--in-content-icon-color: rgb(251,251,254);
--in-content-primary-button-text-color: rgb(21,20,26);
--in-content-primary-button-background: rgb(0,221,255);
@ -174,6 +179,7 @@
@supports not -moz-bool-pref("browser.proton.enabled") {
@media (prefers-color-scheme: dark) {
:host,
:root {
--in-content-page-background: #2A2A2E;
--in-content-page-color: rgb(249, 249, 250);
@ -197,6 +203,7 @@
}
}
}
:root {
font: message-box;
appearance: none;
@ -446,6 +453,16 @@ html|button.ghost-button:enabled:hover:active {
background-color: var(--in-content-button-background-hover);
}
@supports -moz-bool-pref("browser.proton.enabled") {
html|button.ghost-button:enabled:hover {
background-color: var(--in-content-button-background-hover);
}
html|button.ghost-button:enabled:hover:active {
background-color: var(--in-content-button-background-active);
}
}
html|input[type="color"] {
padding: 6px;
width: 50px;

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

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html "http://www.w3.org/1999/xhtml";
.notificationbox-stack {
/* Prevent the animation from overlapping the navigation toolbar */
@ -13,8 +14,13 @@
/* Create a stacking context for the box-shadow */
position: relative;
z-index: 1;
}
@supports not -moz-bool-pref("browser.proton.enabled") {
.notificationbox-stack[notificationside="top"] {
box-shadow: 0 3px 10px -7px #00000080;
}
}
notification {
min-height: 40px;
@ -48,6 +54,7 @@ notification[type="info"]:-moz-lwtheme-brighttext {
--notification-button-background-active: rgba(249,249,250,.3);
}
html|notification-message.animated,
notification.animated {
transition: margin-top 300ms var(--animation-easing-function), opacity 300ms var(--animation-easing-function);
}
@ -185,8 +192,8 @@ notification[type="critical"] > hbox > .messageImage {
}
@supports -moz-bool-pref("browser.proton.infobars.enabled") {
.notificationbox-stack,
notification {
.notificationbox-stack {
background-color: var(--toolbar-bgcolor);
width: 100%;
}
}