Bug 572967: don't remove notifications once dismissed, and instead allow them to be re-opened from the anchor icon, r=dolske

This commit is contained in:
Gavin Sharp 2010-06-23 12:53:09 -04:00
Родитель 16f0a7a2da
Коммит 28d45e6b89
8 изменённых файлов: 96 добавлений и 27 удалений

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

@ -326,6 +326,7 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
notifications are */
.notification-anchor-icon {
display: none;
-moz-user-focus: normal;
}
#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,

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

@ -159,9 +159,13 @@ XPCOMUtils.defineLazyGetter(this, "Weave", function() {
XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () {
let tmp = {};
Cu.import("resource://gre/modules/PopupNotifications.jsm", tmp);
return new tmp.PopupNotifications(gBrowser,
document.getElementById("notification-popup"),
document.getElementById("notification-popup-box"));
try {
return new tmp.PopupNotifications(gBrowser,
document.getElementById("notification-popup"),
document.getElementById("notification-popup-box"));
} catch (ex) {
Cu.reportError(ex);
}
});
let gInitialPages = [

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

@ -705,8 +705,8 @@
onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
<box id="notification-popup-box" hidden="true" align="center">
<image id="geo-notification-icon" class="notification-anchor-icon"/>
<image id="addons-notification-icon" class="notification-anchor-icon"/>
<image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
</box>
<!-- Use onclick instead of normal popup= syntax since the popup
code fires onmousedown, and hence eats our favicon drag events.

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

@ -296,7 +296,7 @@ var tests = [
this.firstNotification = showNotification(this.notifyObj);
this.notifyObj2 = new basicNotification();
this.notifyObj2.id += "-2";
this.notifyObj2.anchorID = "urlbar";
this.notifyObj2.anchorID = "addons-notification-icon";
// Second showNotification() overrides the first
this.secondNotification = showNotification(this.notifyObj2);
},
@ -485,15 +485,17 @@ function triggerSecondaryCommand(popup, index) {
}
function loadURI(uri, callback) {
gBrowser.addEventListener("load", function() {
// Ignore the about:blank load
if (gBrowser.currentURI.spec != uri)
return;
if (callback) {
gBrowser.addEventListener("load", function() {
// Ignore the about:blank load
if (gBrowser.currentURI.spec != uri)
return;
gBrowser.removeEventListener("load", arguments.callee, true);
gBrowser.removeEventListener("load", arguments.callee, true);
callback();
}, true);
callback();
}, true);
}
gBrowser.loadURI(uri);
}
@ -502,4 +504,4 @@ function dismissNotification(popup) {
executeSoon(function () {
EventUtils.synthesizeKey("VK_ESCAPE", {});
});
}
}

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

@ -1007,6 +1007,10 @@ toolbar[iconsize="small"] #fullscreen-button {
height: 16px;
}
.notification-anchor-icon:-moz-focusring {
outline: 1px dotted -moz-DialogText;
}
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
}

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

@ -1868,6 +1868,11 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
margin: 0 2px;
}
.notification-anchor-icon:-moz-focusring {
-moz-box-shadow: 0 0 3px 1px -moz-mac-focusring inset,
0 0 3px 2px -moz-mac-focusring;
}
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
}

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

@ -1665,6 +1665,11 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
height: 16px;
}
.notification-anchor-icon:-moz-focusring {
outline: 1px dotted -moz-DialogText;
outline-offset: -3px;
}
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
}

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

@ -69,7 +69,7 @@ Notification.prototype = {
get anchorElement() {
let anchorElement = null;
if (this.anchorID)
anchorElement = this.owner.window.document.getElementById(this.anchorID);
anchorElement = this.owner.iconBox.querySelector("#"+this.anchorID);
if (!anchorElement)
anchorElement = this.owner.iconBox;
@ -89,17 +89,32 @@ Notification.prototype = {
* populated with <popupnotification> children and displayed it as
* needed.
* @param iconBox
* Optional reference to a container element that should be hidden or
* unhidden when notifications are hidden or shown. Used as a fallback
* popup anchor if notifications do not specify anchor IDs.
* Reference to a container element that should be hidden or
* unhidden when notifications are hidden or shown. It should be the
* parent of anchor elements whose IDs are passed to show().
* It is used as a fallback popup anchor if notifications specify
* invalid or non-existent anchor IDs.
*/
function PopupNotifications(tabbrowser, panel, iconBox) {
if (!(tabbrowser instanceof Ci.nsIDOMXULElement))
throw "Invalid tabbrowser";
if (!(iconBox instanceof Ci.nsIDOMXULElement))
throw "Invalid iconBox";
if (!(panel instanceof Ci.nsIDOMXULElement))
throw "Invalid panel";
this.window = tabbrowser.ownerDocument.defaultView;
this.panel = panel;
this.iconBox = iconBox;
this.tabbrowser = tabbrowser;
let self = this;
this.iconBox.addEventListener("click", function (event) {
self._onIconBoxCommand(event);
}, false);
this.iconBox.addEventListener("keypress", function (event) {
self._onIconBoxCommand(event);
}, false);
this.panel.addEventListener("popuphidden", function (event) {
self._onPopupHidden(event);
}, true);
@ -171,6 +186,9 @@ PopupNotifications.prototype = {
* dismiss for this many page loads.
* timeout: A time in milliseconds. The notification will not
* automatically dismiss before this time.
* dismissed: Whether the notification should be added as a dismissed
* notification. Dismissed notifications can be activated
* by clicking on their anchorElement.
* @returns the Notification object corresponding to the added notification.
*/
show: function PopupNotifications_show(browser, id, message, anchorID,
@ -193,6 +211,8 @@ PopupNotifications.prototype = {
let notification = new Notification(id, message, anchorID, mainAction,
secondaryActions, browser, this, options);
if (options && options.dismissed)
notification.dismissed = true;
let existingNotification = this.getNotification(id, browser);
if (existingNotification)
@ -366,19 +386,19 @@ PopupNotifications.prototype = {
*/
_update: function PopupNotifications_update(anchor) {
let anchorElement, notificationsToShow = [];
if (this._currentNotifications.length > 0) {
let haveNotifications = this._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;
if (this.iconBox) {
this.iconBox.hidden = false;
this.iconBox.setAttribute("anchorid", anchorElement.id);
}
this.iconBox.hidden = false;
this.iconBox.setAttribute("anchorid", anchorElement.id);
// Also filter out notifications that have been dismissed.
notificationsToShow = this._currentNotifications.filter(function (n) {
return n.anchorElement == anchorElement;
return !n.dismissed && n.anchorElement == anchorElement;
});
}
@ -390,7 +410,9 @@ PopupNotifications.prototype = {
this._hidePanel();
if (this.iconBox)
// Only hide the iconBox if we actually have no notifications (as opposed
// to not having any showable notifications)
if (this.iconBox && !haveNotifications)
this.iconBox.hidden = true;
}
},
@ -402,14 +424,40 @@ PopupNotifications.prototype = {
return browser.popupNotifications = [];
},
_onIconBoxCommand: function PopupNotifications_onIconBoxCommand(event) {
// Left click, space or enter only
let type = event.type;
if (type == "click" && event.button != 0)
return;
if (type == "keypress" &&
!(event.charCode == Ci.nsIDOMKeyEvent.DOM_VK_SPACE ||
event.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_RETURN))
return;
if (this._currentNotifications.length == 0)
return;
let anchor = event.originalTarget;
// Mark notifications anchored to this anchor as un-dismissed
this._currentNotifications.forEach(function (n) {
if (n.anchorElement == anchor)
n.dismissed = false;
});
// ...and then show them.
this._update(anchor);
},
_onPopupHidden: function PopupNotifications_onPopupHidden(event) {
if (event.target != this.panel || this._ignoreDismissal)
return;
// Remove notifications being dismissed
// Mark notifications as dismissed
Array.forEach(this.panel.childNodes, function (nEl) {
let notificationObj = nEl.notification;
this._remove(notificationObj);
notificationObj.dismissed = true;
}, this);
this._update();