Bug 581229: Allow popup notifications to persist across page loads. r=gavin

This commit is contained in:
Dave Townsend 2010-07-29 15:59:55 -07:00
parent 6f2ff7bdf9
commit f96454bd40
4 changed files with 174 additions and 8 deletions

View File

@ -645,6 +645,10 @@ const gXPInstallObserver = {
var brandShortName = brandBundle.getString("brandShortName");
var notificationID = aTopic;
// Make notifications persist a minimum of 30 seconds
var options = {
timeout: Date.now() + 30000
};
switch (aTopic) {
case "addon-install-blocked":
@ -693,7 +697,7 @@ const gXPInstallObserver = {
}
PopupNotifications.show(browser, notificationID, messageString, anchorID,
action);
action, null, options);
break;
case "addon-install-failed":
// TODO This isn't terribly ideal for the multiple failure case
@ -720,7 +724,7 @@ const gXPInstallObserver = {
messageString = messageString.replace("#4", Services.appinfo.version);
PopupNotifications.show(browser, notificationID, messageString, anchorID,
action);
action, null, options);
});
break;
case "addon-install-complete":
@ -772,7 +776,7 @@ const gXPInstallObserver = {
messageString = messageString.replace("#3", brandShortName);
PopupNotifications.show(browser, notificationID, messageString, anchorID,
action);
action, null, options);
break;
}
}

View File

@ -372,6 +372,57 @@ function runNextTest() {
info("Running " + TESTS[0].name);
TESTS.shift()();
});
},
function test_reload() {
var pm = Services.perms;
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
var triggers = encodeURIComponent(JSON.stringify({
"Unsigned XPI": "unsigned.xpi"
}));
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
// Wait for the install confirmation dialog
wait_for_install_dialog(function(aWindow) {
aWindow.document.documentElement.acceptDialog();
// Wait for the complete notification
wait_for_notification(function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.id, "addon-install-complete", "Should have seen the install complete");
is(notification.button.label, "Restart Now", "Should have seen the right button");
is(notification.getAttribute("label"),
"XPI Test will be installed after you restart " + gApp + ".",
"Should have seen the right message");
function test_fail() {
ok(false, "Reloading should not have hidden the notification");
}
PopupNotifications.panel.addEventListener("popuphiding", test_fail, false);
gBrowser.addEventListener("load", function() {
if (gBrowser.currentURI.spec != TESTROOT2 + "enabled.html")
return;
gBrowser.removeEventListener("load", arguments.callee, true);
PopupNotifications.panel.removeEventListener("popuphiding", test_fail, false);
AddonManager.getAllInstalls(function(aInstalls) {
is(aInstalls.length, 1, "Should be one pending install");
aInstalls[0].cancel();
gBrowser.removeTab(gBrowser.selectedTab);
Services.perms.remove("example.com", "install");
runNextTest();
});
}, true);
gBrowser.loadURI(TESTROOT2 + "enabled.html");
});
});
}
function test() {

View File

@ -344,6 +344,80 @@ var tests = [
this.notification.remove();
}
},
// Test that persistence allows the notification to persist across reloads
{ // Test #12
run: function () {
this.oldSelectedTab = gBrowser.selectedTab;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
let self = this;
loadURI("http://example.com/", function() {
self.notifyObj = new basicNotification();
self.notifyObj.options = {
persistence: 2
};
self.notification = showNotification(self.notifyObj);
});
},
onShown: function (popup) {
this.complete = false;
let self = this;
loadURI("http://example.org/", function() {
loadURI("http://example.com/", function() {
// Next load will hide the notification
self.complete = true;
loadURI("http://example.org/");
});
});
},
onHidden: function (popup) {
ok(this.complete, "Should only have hidden the notification after 3 page loads");
this.notification.remove();
gBrowser.removeTab(gBrowser.selectedTab);
gBrowser.selectedTab = this.oldSelectedTab;
}
},
// Test that a timeout allows the notification to persist across reloads
{ // Test #13
run: function () {
this.oldSelectedTab = gBrowser.selectedTab;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
let self = this;
loadURI("http://example.com/", function() {
self.notifyObj = new basicNotification();
// Set a timeout of 10 minutes that should never be hit
self.notifyObj.options = {
timeout: Date.now() + 600000
};
self.notification = showNotification(self.notifyObj);
});
},
onShown: function (popup) {
this.complete = false;
let self = this;
loadURI("http://example.org/", function() {
loadURI("http://example.com/", function() {
// Next load will hide the notification
self.notification.options.timeout = Date.now() - 1;
self.complete = true;
loadURI("http://example.org/");
});
});
},
onHidden: function (popup) {
ok(this.complete, "Should only have hidden the notification after the timeout was passed");
this.notification.remove();
gBrowser.removeTab(gBrowser.selectedTab);
gBrowser.selectedTab = this.oldSelectedTab;
}
},
];
function showNotification(notifyObj) {
@ -352,7 +426,8 @@ function showNotification(notifyObj) {
notifyObj.message,
notifyObj.anchorID,
notifyObj.mainAction,
notifyObj.secondaryActions);
notifyObj.secondaryActions,
notifyObj.options);
}
function checkPopup(popup, notificationObj) {
@ -409,6 +484,19 @@ function triggerSecondaryCommand(popup, index) {
EventUtils.synthesizeKey("VK_DOWN", { altKey: (navigator.platform.indexOf("Mac") == -1) });
}
function loadURI(uri, callback) {
gBrowser.addEventListener("load", function() {
// Ignore the about:blank load
if (gBrowser.currentURI.spec != uri)
return;
gBrowser.removeEventListener("load", arguments.callee, true);
callback();
}, true);
gBrowser.loadURI(uri);
}
function dismissNotification(popup) {
info("[Test #" + gTestIndex + "] dismissing notification");
executeSoon(function () {

View File

@ -47,7 +47,7 @@ Components.utils.import("resource://gre/modules/Services.jsm");
* @see PopupNotifications.show()
*/
function Notification(id, message, anchorID, mainAction, secondaryActions,
browser, owner) {
browser, owner, options) {
this.id = id;
this.message = message;
this.anchorID = anchorID;
@ -55,6 +55,7 @@ function Notification(id, message, anchorID, mainAction, secondaryActions,
this.secondaryActions = secondaryActions || [];
this.browser = browser;
this.owner = owner;
this.options = options || {};
}
Notification.prototype = {
@ -163,6 +164,13 @@ PopupNotifications.prototype = {
* actions. The array should contain objects with the same properties
* as mainAction. These are used to populate the notification button's
* dropdown menu.
* @param options
* An options JavaScript object holding additional properties for the
* notification. The following properties are currently supported:
* persistence: An integer. The notification will not automatically
* dismiss for this many page loads.
* timeout: A time in milliseconds. The notification will not
* automatically dismiss before this time.
* @returns the Notification object corresponding to the added notification.
*/
show: function PopupNotifications_show(browser, id, message, anchorID,
@ -183,7 +191,7 @@ PopupNotifications.prototype = {
throw "PopupNotifications_show: invalid secondaryActions";
let notification = new Notification(id, message, anchorID, mainAction,
secondaryActions, browser, this);
secondaryActions, browser, this, options);
let existingNotification = this.getNotification(id, browser);
@ -222,8 +230,23 @@ PopupNotifications.prototype = {
* changed, so that we can update the active notifications accordingly.
*/
locationChange: function PopupNotifications_locationChange() {
// For now, just clear all notifications...
this._currentNotifications = [];
this._currentNotifications = this._currentNotifications.filter(function(notification) {
// The persistence option allows a notification to persist across multiple
// page loads
if ("persistence" in notification.options &&
notification.options.persistence) {
notification.options.persistence--;
return true;
}
// The timeout option allows a notification to persist until a certain time
if ("timeout" in notification.options &&
Date.now() <= notification.options.timeout) {
return true;
}
return false;
});
this._update();
},