--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -1139,19 +1139,17 @@ toolbarpaletteitem[place="palette"][hidd
#customization-palette .toolbarpaletteitem-box {
-moz-box-pack: center;
-moz-box-flex: 1;
width: 10em;
max-width: 10em;
}
-#main-window[customizing=true] #PanelUI-update-available-menu-item,
-#main-window[customizing=true] #PanelUI-download-available-menu-item,
-#main-window[customizing=true] #PanelUI-update-restart-menu-item {
+#main-window[customizing=true] #PanelUI-notification-menu-item {
display: none;
}
/* UI Tour */
@keyframes uitour-wobble {
from {
transform: rotate(0deg) translateX(3px) rotate(0deg);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2659,44 +2659,42 @@ var gMenuButtonUpdateBadge = {
this.reset();
return;
}
if (status == "failed") {
// Background update has failed, let's show the UI responsible for
// prompting the user to update manually.
this.uninit();
- let openManualUpdateUrl = this.openManualUpdateUrl;
let action = {
- callback: () => { openManualUpdateUrl(); }
+ callback: () => { gMenuButtonUpdateBadge.openManualUpdateUrl(); }
};
- PanelUI.showNotification("update-manual", action, [], {});
+ PanelUI.showNotification("update-manual", action);
return;
}
// Give the user badgeWaitTime seconds to react before prompting.
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.timer.initWithCallback(this, this.badgeWaitTime * 1000,
this.timer.TYPE_ONE_SHOT);
// The timer callback will call uninit() when it completes.
},
notify: function() {
// If the update is successfully applied, or if the updater has fallen back
// to non-staged updates, add a badge to the hamburger menu to indicate an
// update will be applied once the browser restarts.
this.uninit();
- let requestRestart = this.requestRestart;
let action = {
- callback: () => { requestRestart(); }
+ callback: () => { gMenuButtonUpdateBadge.requestRestart(); }
};
- PanelUI.showNotification("update-restart", action, [], {});
+ PanelUI.showNotification("update-restart", action);
},
reset: function() {
PanelUI.removeNotification(/^update-/);
this.uninit();
this.init();
}
};
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -354,17 +354,16 @@ support-files =
[browser_popupUI.js]
[browser_popup_blocker.js]
skip-if = (os == 'linux') || (e10s && debug) # Frequent bug 1081925 and bug 1125520 failures
[browser_printpreview.js]
[browser_private_browsing_window.js]
[browser_private_no_prompt.js]
[browser_purgehistory_clears_sh.js]
[browser_PageMetaData_pushstate.js]
-[browser_panelUINotifications.js]
[browser_refreshBlocker.js]
support-files =
refresh_header.sjs
refresh_meta.sjs
[browser_relatedTabs.js]
[browser_remoteTroubleshoot.js]
skip-if = !updater
reason = depends on UpdateUtils .Locale
@@ -481,17 +480,16 @@ tags = mcb
tags = psm
[browser_mcb_redirect.js]
tags = mcb
[browser_windowactivation.js]
[browser_contextmenu_childprocess.js]
[browser_bug963945.js]
[browser_domFullscreen_fullscreenMode.js]
tags = fullscreen
-[browser_menuButtonBadgeManager.js]
[browser_newTabDrop.js]
[browser_newWindowDrop.js]
[browser_csp_block_all_mixedcontent.js]
tags = mcb
[browser_newwindow_focus.js]
skip-if = (os == "linux" && !e10s) # Bug 1263254 - Perma fails on Linux without e10s for some reason.
[browser_bug1299667.js]
[browser_close_dependent_tabs.js]
deleted file mode 100644
--- a/browser/base/content/test/general/browser_menuButtonBadgeManager.js
+++ /dev/null
@@ -1,43 +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/. */
-
-var menuButton = document.getElementById("PanelUI-menu-button");
-
-add_task(function* testButtonActivities() {
- is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
- is(menuButton.hasAttribute("badge"), false, "Should not have the badge attribute set");
-
- PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
- is(menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Should have fxa-needs-authentication badge status");
-
- PanelUI.showBadgeOnlyNotification("update-succeeded");
- is(menuButton.getAttribute("badge-status"), "update-succeeded", "Should have update-succeeded badge status (update > fxa)");
-
- PanelUI.showBadgeOnlyNotification("update-failed");
- is(menuButton.getAttribute("badge-status"), "update-failed", "Should have update-failed badge status");
-
- PanelUI.showBadgeOnlyNotification("download-severe");
- is(menuButton.getAttribute("badge-status"), "download-severe", "Should have download-severe badge status");
-
- PanelUI.showBadgeOnlyNotification("download-warning");
- is(menuButton.getAttribute("badge-status"), "download-warning", "Should have download-warning badge status");
-
- PanelUI.removeNotification(/^download-/);
- is(menuButton.getAttribute("badge-status"), "update-failed", "Should have update-failed badge status");
-
- PanelUI.removeNotification(/^update-/);
- is(menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Should have fxa-needs-authentication badge status");
-
- PanelUI.removeNotification(/^fxa-/);
- is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
-
- yield PanelUI.show();
- is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status (Hamburger menu opened)");
- PanelUI.hide();
-
- PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
- PanelUI.showBadgeOnlyNotification("update-succeeded");
- PanelUI.removeNotification(/.*/);
- is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status (clearBadges called)");
-});
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -431,18 +431,20 @@
closebuttonhidden="true"
secondarybuttonlabel="&updateAvailable.cancelButton.label;"
secondarybuttonaccesskey="&updateAvailable.cancelButton.accesskey;"
dropmarkerhidden="true"
checkboxhidden="true"
hidden="true">
<popupnotificationcontent id="update-available-notification-content" orient="vertical">
<description id="update-available-description">&updateAvailable.message;
+#ifndef NIGHTLY_BUILD
<label class="text-link" value="&updateAvailable.whatsnew.label;"
- href="&updateAvailable.whatsnew.href;"/>
+#expand href="https://www.mozilla.org/firefox/__MOZ_APP_VERSION__/releasenotes/"/>
+#endif
</description>
</popupnotificationcontent>
</popupnotification>
<popupnotification id="PanelUI-update-manual-notification"
popupid="update-manual"
label="&updateManual.header.message;"
buttonlabel="&updateManual.acceptButton.label;"
@@ -450,18 +452,20 @@
closebuttonhidden="true"
secondarybuttonlabel="&updateManual.cancelButton.label;"
secondarybuttonaccesskey="&updateManual.cancelButton.accesskey;"
dropmarkerhidden="true"
checkboxhidden="true"
hidden="true">
<popupnotificationcontent id="update-manual-notification-content" orient="vertical">
<description id="update-manual-description">&updateManual.message;
+#ifndef NIGHTLY_BUILD
<label class="text-link" value="&updateManual.whatsnew.label;"
- href="&updateManual.whatsnew.href;"/>
+#expand href="https://www.mozilla.org/firefox/__MOZ_APP_VERSION__/releasenotes/"/>
+#endif
</description>
</popupnotificationcontent>
</popupnotification>
<popupnotification id="PanelUI-update-restart-notification"
popupid="update-restart"
label="&updateRestart.header.message;"
buttonlabel="&updateRestart.acceptButton.label;"
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -165,35 +165,47 @@ const PanelUI = {
anchor = this._getPanelAnchor(anchor);
this.panel.openPopup(anchor);
}, (reason) => {
console.error("Error showing the PanelUI menu", reason);
});
});
},
- showNotification: function(id, mainAction, secondaryActions, options) {
- let notification = new Notification(id, mainAction, secondaryActions, options);
+ showNotification(id, mainAction, secondaryActions = [], options = {}) {
+ let notification = new PanelUINotification(id, mainAction, secondaryActions, options);
let existingIndex = this.notifications.findIndex(n => n.id == id);
if (existingIndex != -1) {
this.notifications.splice(existingIndex, 1);
}
- this.notifications.forEach(n => { n.dismissed = true; });
+
+ // we don't want to clobber doorhanger notifications just to show a badge,
+ // so don't dismiss any of them and the badge will show once the doorhanger
+ // gets resolved.
+ if (!options.badgeOnly) {
+ this.notifications.forEach(n => { n.dismissed = true; });
+ }
+
+ // since notifications are generally somewhat pressing, the ideal case is that
+ // we never have two notifications at once. However, in the event that we do,
+ // it's more likely that the older notification has been sitting around for a
+ // bit, and so we don't want to hide the new notification behind it. Thus,
+ // we want our notifications to behave like a stack instead of a queue.
this.notifications.unshift(notification);
this._updateNotifications();
return notification;
},
- showBadgeOnlyNotification: function(id) {
+ showBadgeOnlyNotification(id) {
return this.showNotification(id, null, null, { badgeOnly: true });
},
- removeNotification: function(id) {
+ removeNotification(id) {
let notifications;
- if (typeof(id) == "string") {
+ if (typeof id == "string") {
notifications = this.notifications.filter(n => n.id == id);
} else {
// if it's not a string, assume RegExp
notifications = this.notifications.filter(n => id.test(n.id));
}
notifications.forEach(n => {
this._removeNotification(n);
@@ -432,19 +444,19 @@ const PanelUI = {
}
viewShown = true;
CustomizableUI.addPanelCloseListeners(tempPanel);
tempPanel.addEventListener("popuphidden", panelRemover);
let anchor = this._getPanelAnchor(aAnchor);
- if ((aAnchor != anchor) && aAnchor.id) {
+ if ((aAnchor != anchor) && aAnchor.id)
anchor.setAttribute("consumeanchor", aAnchor.id);
- }
+
tempPanel.openPopup(anchor, "bottomcenter topright");
}
}),
/**
* NB: The enable- and disableSingleSubviewPanelAnimations methods only
* affect the hiding/showing animations of single-subview panels (tempPanel
* in the showSubView method).
@@ -574,17 +586,17 @@ const PanelUI = {
},
_overlayScrollListenerBoundFn: null,
_overlayScrollListener: function(aMQL) {
ScrollbarSampler.resetSystemScrollbarWidth();
this._scrollWidth = null;
},
- _updateNotifications: function() {
+ _updateNotifications() {
if (!this.notifications.length) {
this._clearAllNotifications();
this.notificationPanel.hidePopup();
return;
}
let doorhangers =
this.notifications.filter(n => !n.dismissed && !n.options.badgeOnly);
@@ -603,43 +615,43 @@ const PanelUI = {
this._showNotificationPanel(doorhangers[0]);
} else {
this.notificationPanel.hidePopup();
this._showBadge(this.notifications[0]);
this._showMenuItem(this.notifications[0]);
}
},
- _showNotificationPanel: function(notification) {
+ _showNotificationPanel(notification) {
this._refreshNotificationPanel(notification);
if (this.isNotificationPanelOpen) {
return;
}
let anchor = this._getPanelAnchor(this.menuButton);
this.notificationPanel.hidden = false;
this.notificationPanel.openPopup(anchor, "bottomcenter topright");
},
- _clearNotificationPanel: function() {
+ _clearNotificationPanel() {
for (let popupnotification of this.notificationPanel.children) {
popupnotification.hidden = true;
popupnotification.notification = null;
}
},
- _clearAllNotifications: function() {
+ _clearAllNotifications() {
this._clearNotificationPanel();
this._clearBadges();
this._clearMenuItems();
},
- _refreshNotificationPanel: function(notification) {
+ _refreshNotificationPanel(notification) {
this._clearNotificationPanel();
let popupnotificationID = this._getPopupId(notification);
let popupnotification = document.getElementById(popupnotificationID);
popupnotification.setAttribute("id", popupnotificationID);
popupnotification.setAttribute("buttoncommand", "PanelUI._onNotificationButtonEvent(event, 'buttoncommand');");
popupnotification.setAttribute("secondarybuttoncommand", "PanelUI._onNotificationButtonEvent(event, 'secondarybuttoncommand');");
@@ -651,58 +663,59 @@ const PanelUI = {
popupnotification.hidden = false;
},
_showBadge(notification) {
let badgeStatus = this._getBadgeStatus(notification);
this.menuButton.setAttribute("badge-status", badgeStatus);
},
- _showMenuItem: function(notification) {
+ _showMenuItem(notification) {
this._clearMenuItems();
let menuItemId = this._getMenuItemId(notification);
let menuItem = document.getElementById(menuItemId);
if (menuItem) {
menuItem.notification = notification;
menuItem.setAttribute("oncommand", "PanelUI._onNotificationMenuItemSelected(event)");
+ menuItem.className += " PanelUI-notification-menu-item";
menuItem.hidden = false;
menuItem.fromPanelUINotifications = true;
}
},
- _clearBadges: function() {
+ _clearBadges() {
this.menuButton.removeAttribute("badge-status");
},
- _clearMenuItems: function() {
+ _clearMenuItems() {
for (let child of this.footer.children) {
if (child.fromPanelUINotifications) {
child.notification = null;
child.hidden = true;
}
}
},
- _removeNotification: function(notification) {
+ _removeNotification(notification) {
// This notification may already be removed, in which case let's just fail
// silently.
let notifications = this.notifications;
if (!notifications)
return;
var index = notifications.indexOf(notification);
if (index == -1)
return;
// remove the notification
notifications.splice(index, 1);
},
- _onNotificationButtonEvent: function(event, type) {
+ _onNotificationButtonEvent(event, type) {
let notificationEl = getNotificationFromElement(event.originalTarget);
if (!notificationEl)
throw "PanelUI._onNotificationButtonEvent: couldn't find notification element";
if (!notificationEl.notification)
throw "PanelUI._onNotificationButtonEvent: couldn't find notification";
@@ -712,56 +725,56 @@ const PanelUI = {
if (type == "secondarybuttoncommand") {
action = notification.secondaryActions[0];
}
let dismiss = true;
if (action) {
try {
- action.callback.call(undefined);
+ action.callback();
} catch (error) {
Cu.reportError(error);
}
dismiss = action.dismiss;
}
if (dismiss) {
notification.dismissed = true;
} else {
this._removeNotification(notification);
}
this._updateNotifications();
},
- _onNotificationMenuItemSelected: function(event) {
+ _onNotificationMenuItemSelected(event) {
let target = event.originalTarget;
if (!target.notification)
throw "menucommand target has no associated action/notification";
event.stopPropagation();
try {
- target.notification.mainAction.callback.call(undefined);
+ target.notification.mainAction.callback();
} catch (error) {
Cu.reportError(error);
}
this._removeNotification(target.notification);
this._updateNotifications();
},
- _getPopupId: function(notification) { return "PanelUI-" + notification.id + "-notification"; },
+ _getPopupId(notification) { return "PanelUI-" + notification.id + "-notification"; },
- _getBadgeStatus: function(notification) { return notification.id; },
+ _getBadgeStatus(notification) { return notification.id; },
- _getMenuItemId: function(notification) { return "PanelUI-" + notification.id + "-menu-item"; },
+ _getMenuItemId(notification) { return "PanelUI-" + notification.id + "-menu-item"; },
- _getPanelAnchor: function(candidate) {
+ _getPanelAnchor(candidate) {
let iconAnchor =
document.getAnonymousElementByAttribute(candidate, "class",
"toolbarbutton-icon");
return iconAnchor || candidate;
}
};
XPCOMUtils.defineConstant(this, "PanelUI", PanelUI);
@@ -775,38 +788,28 @@ function getLocale() {
let chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIXULChromeRegistry);
return chromeRegistry.getSelectedLocale("browser");
} catch (ex) {
return "en-US";
}
}
-function Notification(id, mainAction, secondaryActions, options) {
+function PanelUINotification(id, mainAction, secondaryActions = [], options = {}) {
this.id = id;
this.mainAction = mainAction;
- this.secondaryActions = secondaryActions || [];
- this.options = options || {};
+ this.secondaryActions = secondaryActions;
+ this.options = options;
this.dismissed = this.options.dismissed || false;
}
-Notification.prototype = {
- id: null,
- mainAction: null,
- secondaryActions: null,
- browser: null,
- owner: null,
- options: null,
- timeShown: null,
- dismissed: null,
-};
-
function getNotificationFromElement(aElement) {
// Need to find the associated notification object, which is a bit tricky
// since it isn't associated with the element directly - this is kind of
// gross and very dependent on the structure of the popupnotification
// binding's content.
let notificationEl;
let parent = aElement;
- while (parent && (parent = aElement.ownerDocument.getBindingParent(parent)))
+ while (parent && (parent = aElement.ownerDocument.getBindingParent(parent))) {
notificationEl = parent;
+ }
return notificationEl;
}
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -145,10 +145,11 @@ tags = fullscreen
skip-if = os == "mac"
[browser_1087303_button_preferences.js]
[browser_1089591_still_customizable_after_reset.js]
[browser_1096763_seen_widgets_post_reset.js]
[browser_1161838_inserted_new_default_buttons.js]
[browser_bootstrapped_custom_toolbar.js]
[browser_customizemode_contextmenu_menubuttonstate.js]
[browser_panel_toggle.js]
+[browser_panelUINotifications.js]
[browser_switch_to_customize_mode.js]
[browser_check_tooltips_in_navbar.js]
rename from browser/base/content/test/general/browser_panelUINotifications.js
rename to browser/components/customizableui/test/browser_panelUINotifications.js
--- a/browser/base/content/test/general/browser_panelUINotifications.js
+++ b/browser/components/customizableui/test/browser_panelUINotifications.js
@@ -1,68 +1,276 @@
-add_task(function*() {
- yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank"},
- function*(browser) {
- let doc = browser.ownerDocument;
-
- let mainActionCalled = false;
- let mainAction = {
- callback: () => { mainActionCalled = true; }
- };
- PanelUI.showNotification("update-manual", mainAction, [], {});
-
- isnot(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is showing.");
- let notifications = PanelUI.notificationPanel.children;
- is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
- let doorhanger = notifications[0];
- is(doorhanger.id, "PanelUI-update-manual-notification","PanelUI is displaying the update-manual notification.")
-
- let mainActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "button");
- mainActionButton.click();
-
- ok(mainActionCalled, "Main action callback was called")
- is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
- });
-});
-
-add_task(function*() {
- yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank"},
- function*(browser) {
- let doc = browser.ownerDocument;
-
- PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
- is(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is shown on PanelUI button.");
-
- let mainActionCalled = false;
- let mainAction = {
- callback: () => { mainActionCalled = true; },
- };
- PanelUI.showNotification("update-manual", mainAction, [], {});
- isnot(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is hidden on PanelUI button.");
-
- isnot(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is showing.");
- let notifications = PanelUI.notificationPanel.children;
- is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
- let doorhanger = notifications[0];
- is(doorhanger.id, "PanelUI-update-manual-notification", "PanelUI is displaying the update-manual notification.")
-
- let secondaryActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "secondarybutton");
- secondaryActionButton.click();
-
- is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
-
- is(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is displaying on PanelUI button.");
-
- yield PanelUI.show();
- isnot(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is hidden on PanelUI button.");
- let menuItem = doc.getElementById("PanelUI-update-manual-menu-item");
- is(menuItem.hidden, false, "update-manual menu item is showing.")
-
- yield PanelUI.hide();
- is(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is shown on PanelUI button.");
-
- yield PanelUI.show();
- menuItem.click();
- ok(mainActionCalled, "Main action callback was called")
-
- is(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is shown on PanelUI button.");
- });
-});
+/* 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";
+
+/**
+ * Tests that when we click on the main call-to-action of the doorhanger, the provided
+ * action is called, and the doorhanger removed.
+ */
+add_task(function* testMainActionCalled() {
+ yield BrowserTestUtils.withNewTab("about:blank", function*(browser) {
+ let doc = browser.ownerDocument;
+
+ is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
+ let mainActionCalled = false;
+ let mainAction = {
+ callback: () => { mainActionCalled = true; }
+ };
+ PanelUI.showNotification("update-manual", mainAction);
+
+ isnot(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is showing.");
+ let notifications = PanelUI.notificationPanel.children;
+ is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
+ let doorhanger = notifications[0];
+ is(doorhanger.id, "PanelUI-update-manual-notification", "PanelUI is displaying the update-manual notification.");
+
+ let mainActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "button");
+ mainActionButton.click();
+
+ ok(mainActionCalled, "Main action callback was called");
+ is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
+ is(PanelUI.menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
+ });
+});
+
+/**
+ * This tests that when we click the secondary action for a notification,
+ * it will display the badge for that notification on the PanelUI menu button.
+ * Once we click on this button, we should see an item in the menu which will
+ * call our main action.
+ */
+add_task(function* testSecondaryActionWorkflow() {
+ yield BrowserTestUtils.withNewTab("about:blank", function*(browser) {
+ let doc = browser.ownerDocument;
+
+ is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
+
+ let mainActionCalled = false;
+ let mainAction = {
+ callback: () => { mainActionCalled = true; },
+ };
+ PanelUI.showNotification("update-manual", mainAction);
+
+ isnot(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is showing.");
+ let notifications = PanelUI.notificationPanel.children;
+ is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
+ let doorhanger = notifications[0];
+ is(doorhanger.id, "PanelUI-update-manual-notification", "PanelUI is displaying the update-manual notification.");
+
+ let secondaryActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "secondarybutton");
+ secondaryActionButton.click();
+
+ is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
+
+ is(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is displaying on PanelUI button.");
+
+ yield PanelUI.show();
+ isnot(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is hidden on PanelUI button.");
+ let menuItem = doc.getElementById("PanelUI-update-manual-menu-item");
+ is(menuItem.hidden, false, "update-manual menu item is showing.");
+
+ yield PanelUI.hide();
+ is(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is shown on PanelUI button.");
+
+ yield PanelUI.show();
+ menuItem.click();
+ ok(mainActionCalled, "Main action callback was called");
+
+ PanelUI.removeNotification(/.*/);
+ });
+});
+
+/**
+ * We want to ensure a few things with this:
+ * - Adding a doorhanger will make a badge disappear
+ * - once the notification for the doorhanger is resolved (removed, not just dismissed),
+ * then we display any other badges that are remaining.
+ */
+add_task(function* testInteractionWithBadges() {
+ yield BrowserTestUtils.withNewTab("about:blank", function*(browser) {
+ let doc = browser.ownerDocument;
+
+ PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
+ is(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is shown on PanelUI button.");
+ is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
+
+ let mainActionCalled = false;
+ let mainAction = {
+ callback: () => { mainActionCalled = true; },
+ };
+ PanelUI.showNotification("update-manual", mainAction);
+
+ isnot(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is hidden on PanelUI button.");
+ isnot(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is showing.");
+ let notifications = PanelUI.notificationPanel.children;
+ is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
+ let doorhanger = notifications[0];
+ is(doorhanger.id, "PanelUI-update-manual-notification", "PanelUI is displaying the update-manual notification.");
+
+ let secondaryActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "secondarybutton");
+ secondaryActionButton.click();
+
+ is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
+
+ is(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is displaying on PanelUI button.");
+
+ yield PanelUI.show();
+ isnot(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is hidden on PanelUI button.");
+ let menuItem = doc.getElementById("PanelUI-update-manual-menu-item");
+ is(menuItem.hidden, false, "update-manual menu item is showing.");
+
+ menuItem.click();
+ ok(mainActionCalled, "Main action callback was called");
+
+ is(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is shown on PanelUI button.");
+ PanelUI.removeNotification(/.*/);
+ is(PanelUI.menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
+ });
+});
+
+/**
+ * This tests that adding a badge will not dismiss any existing doorhangers.
+ */
+add_task(function* testAddingBadgeWhileDoorhangerIsShowing() {
+ yield BrowserTestUtils.withNewTab("about:blank", function*(browser) {
+ let doc = browser.ownerDocument;
+
+ is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
+ let mainActionCalled = false;
+ let mainAction = {
+ callback: () => { mainActionCalled = true; }
+ };
+ PanelUI.showNotification("update-manual", mainAction);
+ PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
+
+ isnot(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is hidden on PanelUI button.");
+ isnot(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is showing.");
+ let notifications = PanelUI.notificationPanel.children;
+ is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
+ let doorhanger = notifications[0];
+ is(doorhanger.id, "PanelUI-update-manual-notification", "PanelUI is displaying the update-manual notification.");
+
+ let mainActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "button");
+ mainActionButton.click();
+
+ ok(mainActionCalled, "Main action callback was called");
+ is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
+ is(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is shown on PanelUI button.");
+ PanelUI.removeNotification(/.*/);
+ is(PanelUI.menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
+ });
+});
+
+/**
+ * Tests that badges operate like a stack.
+ */
+add_task(function* testMultipleBadges() {
+ yield BrowserTestUtils.withNewTab("about:blank", function*(browser) {
+ let doc = browser.ownerDocument;
+ let menuButton = doc.getElementById("PanelUI-menu-button");
+
+ is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
+ is(menuButton.hasAttribute("badge"), false, "Should not have the badge attribute set");
+
+ PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
+ is(menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Should have fxa-needs-authentication badge status");
+
+ PanelUI.showBadgeOnlyNotification("update-succeeded");
+ is(menuButton.getAttribute("badge-status"), "update-succeeded", "Should have update-succeeded badge status (update > fxa)");
+
+ PanelUI.showBadgeOnlyNotification("update-failed");
+ is(menuButton.getAttribute("badge-status"), "update-failed", "Should have update-failed badge status");
+
+ PanelUI.showBadgeOnlyNotification("download-severe");
+ is(menuButton.getAttribute("badge-status"), "download-severe", "Should have download-severe badge status");
+
+ PanelUI.showBadgeOnlyNotification("download-warning");
+ is(menuButton.getAttribute("badge-status"), "download-warning", "Should have download-warning badge status");
+
+ PanelUI.removeNotification(/^download-/);
+ is(menuButton.getAttribute("badge-status"), "update-failed", "Should have update-failed badge status");
+
+ PanelUI.removeNotification(/^update-/);
+ is(menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Should have fxa-needs-authentication badge status");
+
+ PanelUI.removeNotification(/^fxa-/);
+ is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
+
+ yield PanelUI.show();
+ is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status (Hamburger menu opened)");
+ PanelUI.hide();
+
+ PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
+ PanelUI.showBadgeOnlyNotification("update-succeeded");
+ PanelUI.removeNotification(/.*/);
+ is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
+ });
+});
+
+/**
+ * Tests that non-badges also operate like a stack.
+ */
+add_task(function* testMultipleNonBadges() {
+ yield BrowserTestUtils.withNewTab("about:blank", function*(browser) {
+ let doc = browser.ownerDocument;
+
+ is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
+
+ let updateManualAction = {
+ called: false,
+ callback: () => { updateManualAction.called = true; },
+ };
+ let updateRestartAction = {
+ called: false,
+ callback: () => { updateRestartAction.called = true; },
+ };
+
+ PanelUI.showNotification("update-manual", updateManualAction);
+
+ let notifications;
+ let doorhanger;
+
+ isnot(PanelUI.notificationPanel.state, "closed", "Doorhanger is showing.");
+ notifications = [...PanelUI.notificationPanel.children].filter(n => !n.hidden);
+ is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
+ doorhanger = notifications[0];
+ is(doorhanger.id, "PanelUI-update-manual-notification", "PanelUI is displaying the update-manual notification.");
+
+ PanelUI.showNotification("update-restart", updateRestartAction);
+
+ isnot(PanelUI.notificationPanel.state, "closed", "Doorhanger is showing.");
+ notifications = [...PanelUI.notificationPanel.children].filter(n => !n.hidden);
+ is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
+ doorhanger = notifications[0];
+ is(doorhanger.id, "PanelUI-update-restart-notification", "PanelUI is displaying the update-restart notification.");
+
+ let secondaryActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "secondarybutton");
+ secondaryActionButton.click();
+
+ is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
+ is(PanelUI.menuButton.getAttribute("badge-status"), "update-restart", "update-restart badge is displaying on PanelUI button.");
+
+ let menuItem
+
+ yield PanelUI.show();
+ isnot(PanelUI.menuButton.getAttribute("badge-status"), "update-restart", "update-restart badge is hidden on PanelUI button.");
+ menuItem = doc.getElementById("PanelUI-update-restart-menu-item");
+ is(menuItem.hidden, false, "update-restart menu item is showing.");
+
+ menuItem.click();
+ ok(updateRestartAction.called, "update-restart main action callback was called");
+
+ is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
+ is(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "update-manual badge is displaying on PanelUI button.");
+
+ yield PanelUI.show();
+ isnot(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "update-manual badge is hidden on PanelUI button.");
+ menuItem = doc.getElementById("PanelUI-update-manual-menu-item");
+ is(menuItem.hidden, false, "update-manual menu item is showing.");
+
+ menuItem.click();
+ ok(updateManualAction.called, "update-manual main action callback was called");
+ });
+});
+
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -622,25 +622,16 @@ flashHang.helpButton.accesskey = L
# be replaced with a hyperlink containing the text defined in customizeTips.tip0.learnMore.
customizeTips.tip0 = %1$S: You can customize %2$S to work the way you do. Simply drag any of the above to the menu or toolbar. %3$S about customizing %2$S.
customizeTips.tip0.hint = Hint
customizeTips.tip0.learnMore = Learn more
# LOCALIZATION NOTE (customizeMode.tabTitle): %S is brandShortName
customizeMode.tabTitle = Customize %S
-# LOCALIZATION NOTE(appmenu.*.description, appmenu.*.label): these are used for
-# the appmenu labels and buttons that appear when an update is staged for
-# installation or a background update has failed and a manual download is required.
-# %S is brandShortName
-appmenu.restartNeeded.description = Restart %S to apply updates
-appmenu.updateFailed.description = Background update failed, please download update
-appmenu.restartBrowserButton.label = Restart %S
-appmenu.downloadUpdateButton.label = Download %S Update
-
# LOCALIZATION NOTE : FILE Reader View is a feature name and therefore typically used as a proper noun.
readingList.promo.firstUse.readerView.title = Reader View
readingList.promo.firstUse.readerView.body = Remove clutter so you can focus exactly on what you want to read.
# LOCALIZATION NOTE (appMenuRemoteTabs.mobilePromo.text2):
# %1$S will be replaced with a link, the text of which is
# appMenuRemoteTabs.mobilePromo.android and the link will be to
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -103,47 +103,41 @@
height: 10px;
width: 10px;
background-size: contain;
}
#PanelUI-menu-button[badge-status="download-success"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
display: none;
}
-#PanelUI-menu-button[badge-status="update-succeeded"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
- background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center;
- height: 13px;
-}
#PanelUI-menu-button[badge-status="update-available"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
#PanelUI-menu-button[badge-status="update-manual"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
#PanelUI-menu-button[badge-status="update-restart"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center;
- height: 13px;
-}
-
-#PanelUI-menu-button[badge-status="update-failed"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
- background: #D90000 url(chrome://browser/skin/update-badge-failed.svg) no-repeat center;
- height: 13px;
+ border-radius: 50%;
+ box-shadow: none;
+ border: 1px solid -moz-dialog;
+ margin: -9px 0 0 !important;
+ margin-inline-end: -6px !important;
+ min-width: 16px;
+ min-height: 16px;
}
#PanelUI-menu-button[badge-status="download-warning"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
#PanelUI-menu-button[badge-status="fxa-needs-authentication"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
box-shadow: none;
filter: drop-shadow(0 1px 0 hsla(206, 50%, 10%, .15));
- border-radius: 2px;
- border: none;
}
#PanelUI-menu-button[badge-status="download-warning"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
#PanelUI-menu-button[badge-status="download-severe"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
width: 7px;
height: 7px;
min-width: 0;
- min-height: 0;
/* "!important" is necessary to override the rule in toolbarbutton.css */
margin-top: -1px !important;
margin-right: -2px !important;
}
#PanelUI-menu-button[badge-status="download-warning"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
background: #FFBF00;
}
@@ -439,27 +433,25 @@ toolbaritem[cui-areatype="menu-panel"][s
toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"] > iframe {
margin: 4px auto;
}
#PanelUI-multiView[viewtype="subview"] > .panel-viewcontainer > .panel-viewstack > .panel-mainview > #PanelUI-mainView {
background-color: var(--arrowpanel-dimmed);
}
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-contents-scroller > #PanelUI-contents > .panel-wide-item,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-contents-scroller > #PanelUI-contents > .toolbarbutton-1:not([panel-multiview-anchor="true"]),
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-update-available-menu-item,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-update-manual-menu-item,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-update-restart-menu-item,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-fxa > #PanelUI-fxa-status > #PanelUI-fxa-avatar,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-fxa > #PanelUI-fxa-status > #PanelUI-fxa-label,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-fxa > #PanelUI-fxa-icon,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > toolbarseparator,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > #PanelUI-customize,
-#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > #PanelUI-help:not([panel-multiview-anchor="true"]) {
+#PanelUI-multiView[viewtype="subview"] #PanelUI-contents > .panel-wide-item,
+#PanelUI-multiView[viewtype="subview"] #PanelUI-contents > .toolbarbutton-1:not([panel-multiview-anchor="true"]),
+#PanelUI-multiView[viewtype="subview"] .PanelUI-notification-menu-item,
+#PanelUI-multiView[viewtype="subview"] #PanelUI-fxa-avatar,
+#PanelUI-multiView[viewtype="subview"] #PanelUI-fxa-label,
+#PanelUI-multiView[viewtype="subview"] #PanelUI-fxa-icon,
+#PanelUI-multiView[viewtype="subview"] #PanelUI-footer-inner > toolbarseparator,
+#PanelUI-multiView[viewtype="subview"] #PanelUI-customize,
+#PanelUI-multiView[viewtype="subview"] #PanelUI-help:not([panel-multiview-anchor="true"]) {
opacity: .5;
}
/*
* XXXgijs: this is a workaround for a layout issue that was caused by these iframes,
* which was affecting subview display. Because of this, we're hiding the iframe *only*
* when displaying a subview. The discerning user might notice this, but it's not nearly
* as bad as the brokenness.
@@ -565,19 +557,17 @@ toolbarpaletteitem[place="palette"] > to
width: 47px;
padding-top: 1px;
display: block;
text-align: center;
position: relative;
top: 25%;
}
-#PanelUI-update-available-menu-item::after,
-#PanelUI-update-manual-menu-item::after,
-#PanelUI-update-restart-menu-item::after {
+.PanelUI-notification-menu-item::after {
content: "";
width: 16px;
height: 16px;
margin-inline-end: 16.5px;
border-radius: 50%;
display: -moz-box;
background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center;
}
@@ -607,19 +597,17 @@ toolbarpaletteitem[place="palette"] > to
-moz-appearance: none;
}
#PanelUI-footer-inner:hover > toolbarseparator,
#PanelUI-footer-fxa:hover > toolbarseparator {
margin: 0;
}
-#PanelUI-update-available-menu-item,
-#PanelUI-update-manual-menu-item,
-#PanelUI-update-restart-menu-item,
+.PanelUI-notification-menu-item,
#PanelUI-help,
#PanelUI-fxa-label,
#PanelUI-fxa-icon,
#PanelUI-customize,
#PanelUI-quit {
margin: 0;
padding: 11px 0;
box-sizing: border-box;
@@ -627,54 +615,46 @@ toolbarpaletteitem[place="palette"] > to
-moz-appearance: none;
box-shadow: none;
border: none;
border-radius: 0;
transition: background-color;
-moz-box-orient: horizontal;
}
-#PanelUI-update-available-menu-item,
-#PanelUI-update-manual-menu-item,
-#PanelUI-update-restart-menu-item {
+.PanelUI-notification-menu-item {
border-top: 1px solid var(--panel-separator-color);
border-bottom: 1px solid transparent;
margin-bottom: -1px;
}
-#PanelUI-update-available-menu-item > .toolbarbutton-text,
-#PanelUI-update-manual-menu-item > .toolbarbutton-text,
-#PanelUI-update-restart-menu-item > .toolbarbutton-text {
+.PanelUI-notification-menu-item > .toolbarbutton-text {
width: 0; /* Fancy cropping solution for flexbox. */
}
#PanelUI-help,
#PanelUI-quit {
min-width: 46px;
}
-#PanelUI-update-available-menu-item > .toolbarbutton-text,
-#PanelUI-update-manual-menu-item > .toolbarbutton-text,
-#PanelUI-update-restart-menu-item > .toolbarbutton-text,
+.PanelUI-notification-menu-item > .toolbarbutton-text,
#PanelUI-fxa-label > .toolbarbutton-text,
#PanelUI-customize > .toolbarbutton-text {
margin: 0;
padding: 0 6px;
text-align: start;
}
#PanelUI-help > .toolbarbutton-text,
#PanelUI-quit > .toolbarbutton-text,
#PanelUI-fxa-avatar > .toolbarbutton-text {
display: none;
}
-#PanelUI-update-available-menu-item > .toolbarbutton-icon,
-#PanelUI-update-manual-menu-item > .toolbarbutton-icon,
-#PanelUI-update-restart-menu-item > .toolbarbutton-icon,
+.PanelUI-notification-menu-item > .toolbarbutton-icon,
#PanelUI-fxa-label > .toolbarbutton-icon,
#PanelUI-fxa-icon > .toolbarbutton-icon,
#PanelUI-customize > .toolbarbutton-icon,
#PanelUI-help > .toolbarbutton-icon,
#PanelUI-quit > .toolbarbutton-icon {
margin-inline-end: 0;
}
@@ -690,19 +670,19 @@ toolbarpaletteitem[place="palette"] > to
border-inline-start-style: none;
}
#PanelUI-footer-fxa[fxaprofileimage="set"] > #PanelUI-fxa-status > #PanelUI-fxa-label,
#PanelUI-footer-fxa[fxaprofileimage="enabled"]:not([fxastatus="error"]) > #PanelUI-fxa-status > #PanelUI-fxa-label {
padding-inline-start: 0px;
}
-#PanelUI-update-available-menu-item,
-#PanelUI-update-manual-menu-item,
-#PanelUI-update-restart-menu-item {
+/* descend from #PanelUI-footer to add specificity, or else the
+ padding-inline-start will be overridden */
+#PanelUI-footer > .PanelUI-notification-menu-item {
width: calc(@menuPanelWidth@ + 30px);
padding-inline-start: 15px;
border-inline-start-style: none;
list-style-image: url(chrome://branding/content/icon16.png);
}
#PanelUI-fxa-label,
#PanelUI-fxa-icon {
@@ -945,32 +925,26 @@ toolbarpaletteitem[place="palette"] > to
background-color: hsl(42,94%,85%);
}
#PanelUI-footer-fxa[fxastatus="error"] > #PanelUI-fxa-status:hover:active {
background-color: hsl(42,94%,82%);
box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
}
-#PanelUI-update-available-menu-item,
-#PanelUI-update-manual-menu-item,
-#PanelUI-update-restart-menu-item {
+.PanelUI-notification-menu-item {
color: black;
background-color: hsla(96,65%,75%,.5);
}
-#PanelUI-update-available-menu-item:not([disabled]):hover,
-#PanelUI-update-manual-menu-item:not([disabled]):hover,
-#PanelUI-update-restart-menu-item:not([disabled]):hover {
+.PanelUI-notification-menu-item:not([disabled]):hover {
background-color: hsla(96,65%,75%,.8);
}
-#PanelUI-update-available-menu-item:not([disabled]):hover:active,
-#PanelUI-update-manual-menu-item:not([disabled]):hover:active,
-#PanelUI-update-restart-menu-item:not([disabled]):hover:active {
+.PanelUI-notification-menu-item:not([disabled]):hover:active {
background-color: hsl(96,65%,75%);
}
#PanelUI-quit:not([disabled]):hover {
background-color: #d94141;
outline-color: #c23a3a;
}
@@ -1667,19 +1641,17 @@ menuitem[checked="true"].subviewbutton >
}
#PanelUI-help[panel-multiview-anchor="true"]:-moz-locale-dir(rtl)::after,
toolbarbutton[panel-multiview-anchor="true"]:-moz-locale-dir(rtl) {
background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted-rtl@2x.png),
linear-gradient(rgba(255,255,255,0.3), transparent);
}
- #PanelUI-update-available-menu-item,
- #PanelUI-update-manual-menu-item,
- #PanelUI-update-restart-menu-item {
+ .PanelUI-notification-menu-item {
list-style-image: url(chrome://branding/content/icon32.png);
}
#PanelUI-fxa-label,
#PanelUI-fxa-icon {
list-style-image: url(chrome://browser/skin/sync-horizontalbar@2x.png);
}
@@ -1706,19 +1678,17 @@ menuitem[checked="true"].subviewbutton >
#PanelUI-fxa-label,
#PanelUI-fxa-icon,
#PanelUI-customize,
#PanelUI-help,
#PanelUI-quit {
-moz-image-region: rect(0, 32px, 32px, 0);
}
- #PanelUI-update-available-menu-item > .toolbarbutton-icon,
- #PanelUI-update-manual-menu-item > .toolbarbutton-icon,
- #PanelUI-update-restart-menu-item > .toolbarbutton-icon,
+ .PanelUI-notification-menu-item > .toolbarbutton-icon,
#PanelUI-fxa-label > .toolbarbutton-icon,
#PanelUI-fxa-icon > .toolbarbutton-icon,
#PanelUI-customize > .toolbarbutton-icon,
#PanelUI-help > .toolbarbutton-icon,
#PanelUI-quit > .toolbarbutton-icon {
width: 16px;
}
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -341,14 +341,18 @@ html|*#webRTC-previewVideo {
/* UPDATE */
#update-available-description,
#update-manual-description,
#update-restart-description {
margin: 0;
}
+
+/* the popup-notification-icon class is added to an element in the
+ popup-notification binding (see notification.xml), and that element
+ inherits the popupid that we pass into the <popupnotification> el */
.popup-notification-icon[popupid="update-available"],
.popup-notification-icon[popupid="update-manual"],
.popup-notification-icon[popupid="update-restart"] {
background: #74BF43 url(chrome://browser/skin/notification-icons.svg#update) no-repeat center;
border-radius: 50%;
}
\ No newline at end of file
--- a/toolkit/themes/osx/global/toolbarbutton.css
+++ b/toolkit/themes/osx/global/toolbarbutton.css
@@ -76,24 +76,24 @@ toolbarbutton[type="menu-button"][disabl
/* ::::: toolbarbutton badged ::::: */
.toolbarbutton-badge {
background-color: #d90000;
font-size: 9px;
padding: 1px 2px;
color: #fff;
- border-radius: 50%;
- border: 1px solid hsl(0,0%,95%);
- margin: -9px 0 0 !important;
+ border-radius: 2px;
+ box-shadow: 0 1px 0 hsla(0, 100%, 100%, .2) inset,
+ 0 -1px 0 hsla(0, 0%, 0%, .1) inset,
+ 0 1px 0 hsla(206, 50%, 10%, .2);
+ margin: -6px 0 0 !important;
margin-inline-end: -6px !important;
- min-width: 15px;
+ min-width: 14px;
max-width: 28px;
- min-height: 15px;
- max-height: 28px;
line-height: 10px;
text-align: center;
-moz-stack-sizing: ignore;
}
.toolbarbutton-badge:-moz-window-inactive {
background-color: rgb(230,230,230);
box-shadow: none;
--- a/toolkit/themes/windows/global/toolbarbutton.css
+++ b/toolkit/themes/windows/global/toolbarbutton.css
@@ -144,24 +144,24 @@ toolbarbutton[type="menu-button"][disabl
}
.toolbarbutton-badge {
background-color: #d90000;
font-size: 10px;
font-weight: bold;
padding: 0 2px 1px;
color: #fff;
- border-radius: 50%;
- border: 1px solid hsl(0,0%,96%);
- margin: -9px 0 0 !important;
+ border-radius: 2px;
+ box-shadow: 0 1px 0 hsla(0, 100%, 100%, .2) inset,
+ 0 -1px 0 hsla(0, 0%, 0%, .1) inset,
+ 0 1px 0 hsla(206, 50%, 10%, .2);
+ margin: -6px 0 0 !important;
margin-inline-end: -8px !important;
- min-width: 16px;
+ min-width: 14px;
max-width: 28px;
- min-height: 16px;
- max-height: 28px;
line-height: 10px;
text-align: center;
-moz-stack-sizing: ignore;
}
/* .......... dropmarker .......... */
.toolbarbutton-menubutton-dropmarker {