diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index 9fd10506a320..5db3987aa8b5 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -430,20 +430,11 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m /* notification anchors should only be visible when their associated notifications are */ .notification-anchor-icon { - display: none; -moz-user-focus: normal; } -/* We use the iconBox as the notification anchor when a popup notification is - created with a null anchorID, so in that case use a default anchor icon. */ -#notification-popup-box[anchorid="notification-popup-box"] > #default-notification-icon, -#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon, -#notification-popup-box[anchorid="indexedDB-notification-icon"] > #indexedDB-notification-icon, -#notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon, -#notification-popup-box[anchorid="password-notification-icon"] > #password-notification-icon, -#notification-popup-box[anchorid="webapps-notification-icon"] > #webapps-notification-icon, -#notification-popup-box[anchorid="plugins-notification-icon"] > #plugins-notification-icon { - display: -moz-box; +.notification-anchor-icon:not([showing]) { + display: none; } #invalid-form-popup > description { diff --git a/browser/base/content/test/browser_popupNotification.js b/browser/base/content/test/browser_popupNotification.js index 9b1a364f4eb4..37afe77b2156 100644 --- a/browser/base/content/test/browser_popupNotification.js +++ b/browser/base/content/test/browser_popupNotification.js @@ -642,6 +642,84 @@ var tests = [ ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); } }, + // Test multiple notification icons are shown + { // Test #21 + run: function () { + this.notifyObj1 = new basicNotification(); + this.notifyObj1.id += "_1"; + this.notifyObj1.anchorID = "default-notification-icon"; + this.notification1 = showNotification(this.notifyObj1); + + this.notifyObj2 = new basicNotification(); + this.notifyObj2.id += "_2"; + this.notifyObj2.anchorID = "geo-notification-icon"; + this.notification2 = showNotification(this.notifyObj2); + }, + onShown: function (popup) { + checkPopup(popup, this.notifyObj2); + + // check notifyObj1 anchor icon is showing + isnot(document.getElementById("default-notification-icon").boxObject.width, 0, + "default anchor should be visible"); + // check notifyObj2 anchor icon is showing + isnot(document.getElementById("geo-notification-icon").boxObject.width, 0, + "geo anchor should be visible"); + + dismissNotification(popup); + }, + onHidden: [ + function (popup) { + }, + function (popup) { + this.notification1.remove(); + ok(this.notifyObj1.removedCallbackTriggered, "removed callback triggered"); + + this.notification2.remove(); + ok(this.notifyObj2.removedCallbackTriggered, "removed callback triggered"); + } + ], + }, + // Test that multiple notification icons are removed when switching tabs + { // Test #22 + run: function () { + // show the notification on old tab. + this.notifyObjOld = new basicNotification(); + this.notifyObjOld.anchorID = "default-notification-icon"; + this.notificationOld = showNotification(this.notifyObjOld); + + // switch tab + this.oldSelectedTab = gBrowser.selectedTab; + gBrowser.selectedTab = gBrowser.addTab("about:blank"); + + // show the notification on new tab. + this.notifyObjNew = new basicNotification(); + this.notifyObjNew.anchorID = "geo-notification-icon"; + this.notificationNew = showNotification(this.notifyObjNew); + }, + onShown: function (popup) { + checkPopup(popup, this.notifyObjNew); + + // check notifyObjOld anchor icon is removed + is(document.getElementById("default-notification-icon").boxObject.width, 0, + "default anchor shouldn't be visible"); + // check notifyObjNew anchor icon is showing + isnot(document.getElementById("geo-notification-icon").boxObject.width, 0, + "geo anchor should be visible"); + + dismissNotification(popup); + }, + onHidden: [ + function (popup) { + }, + function (popup) { + this.notificationNew.remove(); + gBrowser.removeTab(gBrowser.selectedTab); + + gBrowser.selectedTab = this.oldSelectedTab; + this.notificationOld.remove(); + } + ], + } ]; function showNotification(notifyObj) { diff --git a/browser/themes/gnomestripe/browser.css b/browser/themes/gnomestripe/browser.css index 4d23d73fcdbc..feee0a714e8e 100644 --- a/browser/themes/gnomestripe/browser.css +++ b/browser/themes/gnomestripe/browser.css @@ -1260,6 +1260,7 @@ toolbar[iconsize="small"] #feed-button { .notification-anchor-icon { width: 16px; height: 16px; + margin: 0 2px; } .notification-anchor-icon:-moz-focusring { diff --git a/browser/themes/winstripe/browser.css b/browser/themes/winstripe/browser.css index f4c87ca88958..bf94e0c3639a 100644 --- a/browser/themes/winstripe/browser.css +++ b/browser/themes/winstripe/browser.css @@ -2321,6 +2321,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { .notification-anchor-icon { width: 16px; height: 16px; + margin: 0 2px; } .notification-anchor-icon:-moz-focusring { diff --git a/toolkit/content/PopupNotifications.jsm b/toolkit/content/PopupNotifications.jsm index 9037647a46cd..4c9fcdce6362 100644 --- a/toolkit/content/PopupNotifications.jsm +++ b/toolkit/content/PopupNotifications.jsm @@ -46,6 +46,9 @@ const NOTIFICATION_EVENT_DISMISSED = "dismissed"; const NOTIFICATION_EVENT_REMOVED = "removed"; const NOTIFICATION_EVENT_SHOWN = "shown"; +const ICON_SELECTOR = ".notification-anchor-icon"; +const ICON_ATTRIBUTE_SHOWING = "showing"; + /** * Notification object describes a single popup notification. * @@ -82,15 +85,18 @@ Notification.prototype = { }, get anchorElement() { - if (!this.owner.iconBox) + let iconBox = this.owner.iconBox; + if (!iconBox) return null; let anchorElement = null; if (this.anchorID) - anchorElement = this.owner.iconBox.querySelector("#"+this.anchorID); + anchorElement = iconBox.querySelector("#"+this.anchorID); + // Use a default anchor icon if it's available if (!anchorElement) - anchorElement = this.owner.iconBox; + anchorElement = iconBox.querySelector("#default-notification-icon") || + iconBox; return anchorElement; } @@ -393,6 +399,8 @@ PopupNotifications.prototype = { if (index == -1) return; + notification.anchorElement.removeAttribute(ICON_ATTRIBUTE_SHOWING); + // remove the notification notifications.splice(index, 1); this._fireCallback(notification, NOTIFICATION_EVENT_REMOVED); @@ -502,21 +510,27 @@ PopupNotifications.prototype = { * selection changes. */ _update: function PopupNotifications_update(anchor) { + if (this.iconBox) { + // hide icons of the previous tab. + this._hideIcons(); + } + let anchorElement, notificationsToShow = []; - let haveNotifications = this._currentNotifications.length > 0; + let currentNotifications = this._currentNotifications; + let haveNotifications = currentNotifications.length > 0; if (haveNotifications) { // Only show the notifications that have the passed-in anchor (or the // first notification's anchor, if none was passed in). Other // notifications will be shown once these are dismissed. - anchorElement = anchor || this._currentNotifications[0].anchorElement; + anchorElement = anchor || currentNotifications[0].anchorElement; if (this.iconBox) { + this._showIcons(currentNotifications); this.iconBox.hidden = false; - this.iconBox.setAttribute("anchorid", anchorElement.id); } // Also filter out notifications that have been dismissed. - notificationsToShow = this._currentNotifications.filter(function (n) { + notificationsToShow = currentNotifications.filter(function (n) { return !n.dismissed && n.anchorElement == anchorElement && !n.options.neverShow; }); @@ -539,6 +553,22 @@ PopupNotifications.prototype = { } }, + _showIcons: function PopupNotifications_showIcons(aCurrentNotifications) { + for (let notification of aCurrentNotifications) { + let anchorElm = notification.anchorElement; + if (anchorElm) { + anchorElm.setAttribute(ICON_ATTRIBUTE_SHOWING, "true"); + } + } + }, + + _hideIcons: function PopupNotifications_hideIcons() { + let icons = this.iconBox.querySelectorAll(ICON_SELECTOR); + for (let icon of icons) { + icon.removeAttribute(ICON_ATTRIBUTE_SHOWING); + } + }, + _getNotificationsForBrowser: function PopupNotifications_getNotifications(browser) { if (browser.popupNotifications) return browser.popupNotifications;