Bug 1209602 - XUL: Implement disabling notifications for a site. r=MattN

This commit is contained in:
Jared Wein 2015-10-15 22:58:56 -04:00
parent b7e57f14bd
commit b55b7bd64f
11 changed files with 152 additions and 89 deletions

View File

@ -3,5 +3,7 @@ support-files =
file_dom_notifications.html
[browser_notification_open_settings.js]
[browser_notification_remove_permission.js]
skip-if = e10s
[browser_notification_tab_switching.js]
skip-if = buildapp == 'mulet' || e10s # Bug 1100662 - content access causing uncaught exception - Error: cannot ipc non-cpow object at chrome://mochitests/content/browser/browser/base/content/test/general/browser_notification_tab_switching.js:32 (or in RemoteAddonsChild.jsm)

View File

@ -0,0 +1,79 @@
"use strict";
var tab;
var notification;
var notificationURL = "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
var alertWindowClosed = false;
var permRemoved = false;
function test () {
waitForExplicitFinish();
let pm = Services.perms;
registerCleanupFunction(function() {
pm.remove(makeURI(notificationURL), "desktop-notification");
gBrowser.removeTab(tab);
window.restore();
});
pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION);
tab = gBrowser.addTab(notificationURL);
gBrowser.selectedTab = tab;
tab.linkedBrowser.addEventListener("load", onLoad, true);
}
function onLoad() {
tab.linkedBrowser.removeEventListener("load", onLoad, true);
let win = tab.linkedBrowser.contentWindow.wrappedJSObject;
notification = win.showNotification2();
notification.addEventListener("show", onAlertShowing);
}
function onAlertShowing() {
info("Notification alert showing");
notification.removeEventListener("show", onAlertShowing);
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
if (!alertWindow) {
ok(true, "Notifications don't use XUL windows on all platforms.");
notification.close();
finish();
return;
}
ok(Services.perms.testExactPermission(makeURI(notificationURL), "desktop-notification"),
"Permission should exist prior to removal");
let disableForOriginMenuItem = alertWindow.document.getElementById("disableForOriginMenuItem");
is(disableForOriginMenuItem.localName, "menuitem", "menuitem found");
Services.obs.addObserver(permObserver, "perm-changed", false);
alertWindow.addEventListener("beforeunload", onAlertClosing);
disableForOriginMenuItem.click();
info("Clicked on disable-for-origin menuitem")
}
function permObserver(subject, topic, data) {
if (topic != "perm-changed") {
return;
}
let permission = subject.QueryInterface(Ci.nsIPermission);
is(permission.type, "desktop-notification", "desktop-notification permission changed");
is(data, "deleted", "desktop-notification permission deleted");
Services.obs.removeObserver(permObserver, "perm-changed");
permRemoved = true;
if (alertWindowClosed) {
finish();
}
}
function onAlertClosing(event) {
event.target.removeEventListener("beforeunload", onAlertClosing);
alertWindowClosed = true;
if (permRemoved) {
finish();
}
}

View File

@ -60,7 +60,7 @@ function onAlertShowing() {
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
if (!alertWindow) {
todo(false, "Notifications don't use XUL windows on all platforms.");
ok(true, "Notifications don't use XUL windows on all platforms.");
notification.close();
newWindowOpenedFromTab.close();
finish();

View File

@ -20,55 +20,3 @@ nsAlertsUtils::IsActionablePrincipal(nsIPrincipal* aPrincipal)
!nsContentUtils::IsSystemOrExpandedPrincipal(aPrincipal) &&
!aPrincipal->GetIsNullPrincipal();
}
/* static */
void
nsAlertsUtils::GetSource(nsIPrincipal* aPrincipal, nsAString& aSource)
{
nsAutoString hostPort;
GetSourceHostPort(aPrincipal, hostPort);
if (hostPort.IsEmpty()) {
return;
}
nsCOMPtr<nsIStringBundleService> stringService(
mozilla::services::GetStringBundleService());
if (!stringService) {
return;
}
nsCOMPtr<nsIStringBundle> alertsBundle;
if (NS_WARN_IF(NS_FAILED(stringService->CreateBundle(ALERTS_BUNDLE,
getter_AddRefs(alertsBundle))))) {
return;
}
const char16_t* params[1] = { hostPort.get() };
nsXPIDLString result;
if (NS_WARN_IF(NS_FAILED(
alertsBundle->FormatStringFromName(MOZ_UTF16("source.label"), params, 1,
getter_Copies(result))))) {
return;
}
aSource = result;
}
/* static */
void
nsAlertsUtils::GetSourceHostPort(nsIPrincipal* aPrincipal,
nsAString& aHostPort)
{
if (!IsActionablePrincipal(aPrincipal)) {
return;
}
nsCOMPtr<nsIURI> principalURI;
if (NS_WARN_IF(NS_FAILED(
aPrincipal->GetURI(getter_AddRefs(principalURI))))) {
return;
}
if (!principalURI) {
return;
}
nsAutoCString hostPort;
if (NS_WARN_IF(NS_FAILED(principalURI->GetHostPort(hostPort)))) {
return;
}
CopyUTF8toUTF16(hostPort, aHostPort);
}

View File

@ -21,19 +21,5 @@ public:
*/
static bool
IsActionablePrincipal(nsIPrincipal* aPrincipal);
/**
* Sets |aSource| to the localized notification source string, or an empty
* string if |aPrincipal| is not actionable.
*/
static void
GetSource(nsIPrincipal* aPrincipal, nsAString& aSource);
/**
* Sets |aHostPort| to the host and port from |aPrincipal|'s URI, or an
* empty string if |aPrincipal| is not actionable.
*/
static void
GetSourceHostPort(nsIPrincipal* aPrincipal, nsAString& aHostPort);
};
#endif /* nsAlertsUtils_h */

View File

@ -136,15 +136,12 @@ nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString&
rv = argsArray->AppendElement(ifptr);
NS_ENSURE_SUCCESS(rv, rv);
// The source contains the host and port of the site that sent the
// notification. It is empty for system alerts.
nsCOMPtr<nsISupportsString> scriptableAlertSource (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
NS_ENSURE_TRUE(scriptableAlertSource, NS_ERROR_FAILURE);
nsAutoString source;
nsAlertsUtils::GetSource(aPrincipal, source);
scriptableAlertSource->SetData(source);
rv = argsArray->AppendElement(scriptableAlertSource);
NS_ENSURE_SUCCESS(rv, rv);
// aPrincipal contains the scheme and hostPort of the
// website that requested the notification. Optional.
if (nsAlertsUtils::IsActionablePrincipal(aPrincipal)) {
rv = argsArray->AppendElement(aPrincipal);
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIDOMWindow> newWindow;
nsAutoCString features("chrome,dialog=yes,titlebar=no,popup=yes");

View File

@ -19,6 +19,7 @@ var gAlertListener = null;
var gAlertTextClickable = false;
var gAlertCookie = "";
var gIsReplaced = false;
var gPrincipal = null;
function prefillAlertInfo() {
// unwrap all the args....
@ -32,14 +33,39 @@ function prefillAlertInfo() {
// arguments[7] --> lang
// arguments[8] --> replaced alert window (nsIDOMWindow)
// arguments[9] --> an optional callback listener (nsIObserver)
// arguments[10] -> the localized alert source string
// arguments[10] -> the nsIPrincipal of the site that requested the notification, optional
switch (window.arguments.length) {
default:
case 11: {
if (window.arguments[10]) {
document.getElementById('alertBox').setAttribute('hasOrigin', true);
document.getElementById('alertSourceLabel').setAttribute('value', window.arguments[10]);
let principal = window.arguments[10] &&
window.arguments[10].QueryInterface(Ci.nsIPrincipal);
let uri = principal.URI;
let scheme;
let hostPort;
try {
scheme = uri.scheme;
hostPort = uri.hostPort;
} catch (ex) {}
// `scheme` is checked here to require a valid scheme (ftp, http,
// https, for example) to be present on the nsIURI.
if (scheme && hostPort) {
const ALERT_BUNDLE = Services.strings.createBundle(
"chrome://alerts/locale/alert.properties");
let label = document.getElementById("alertSourceLabel");
let alertBox = document.getElementById("alertBox");
alertBox.setAttribute("hasOrigin", true);
label.setAttribute("value",
ALERT_BUNDLE.formatStringFromName("source.label",
[hostPort],
1));
let disableForOrigin = document.getElementById("disableForOriginMenuItem");
disableForOrigin.setAttribute("label",
ALERT_BUNDLE.formatStringFromName("webActions.disableForOrigin.label",
[hostPort],
1));
gPrincipal = principal;
}
}
case 10:
@ -217,6 +243,12 @@ function onAlertClick() {
}
}
function disableForOrigin() {
Services.perms.removeFromPrincipal(gPrincipal,
"desktop-notification");
onAlertClose();
}
function onAlertClose() {
let alertBox = document.getElementById("alertBox");
if (alertBox.getAttribute("animate") == "true") {

View File

@ -43,7 +43,13 @@
<spacer flex="1"/>
<box id="alertFooter">
<label id="alertSourceLabel" class="alertSource plain"/>
<button type="menu" id="alertSettings" tooltiptext="&settings.label;"/>
<button type="menu" id="alertSettings" tooltiptext="&settings.label;"
onclick="event.stopPropagation();">
<menupopup position="after_end">
<menuitem id="disableForOriginMenuItem"
oncommand="disableForOrigin();"/>
</menupopup>
</button>
</box>
</vbox>
</box>

View File

@ -8,7 +8,9 @@
closeButton.title = Close
# LOCALIZATION NOTE(actionButton.label): Used as the button label to provide more actions on OS X notifications. OS X will truncate this if it's too long.
actionButton.label =
webActions.disable.label = Disable notifications from this site
# LOCALIZATION NOTE(webActions.disableForOrigin.label): %S is replaced
# with the hostname origin of the notification.
webActions.disableForOrigin.label = Disable notifications from %S
# LOCALIZATION NOTE(source.label): Used to show the URL of the site that
# sent the notification (e.g., "via mozilla.org"). "%1$S" is the source host

View File

@ -65,7 +65,6 @@ label {
border-width: 0;
min-width: 0;
list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities");
visibility: hidden; /* Temporary until bug 1209602 or bug 1205172 is fixed. */
}
#alertSettings:hover {
@ -73,7 +72,7 @@ label {
border-radius: 20px;
}
#alertSettings["open"],
#alertSettings[open],
#alertSettings:hover:active {
background-color: rgba(107,107,107,.4);
}

View File

@ -243,10 +243,17 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
id<FakeNSUserNotification> notification = [[unClass alloc] init];
notification.title = nsCocoaUtils::ToNSString(aAlertTitle);
nsCOMPtr<nsIURI> principalURI;
nsAutoString hostPort;
nsAlertsUtils::GetSourceHostPort(aPrincipal, hostPort);
if (!hostPort.IsEmpty()) {
notification.subtitle = nsCocoaUtils::ToNSString(hostPort);
if (NS_SUCCEEDED(aPrincipal->GetURI(getter_AddRefs(principalURI)))) {
if (principalURI) {
nsAutoCString hostPortTemp;
if (NS_SUCCEEDED(principalURI->GetHostPort(hostPortTemp))) {
if (!hostPortTemp.IsEmpty()) {
CopyUTF8toUTF16(hostPortTemp, hostPort);
notification.subtitle = nsCocoaUtils::ToNSString(hostPort);
}
}
}
notification.informativeText = nsCocoaUtils::ToNSString(aAlertText);
@ -264,8 +271,13 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
getter_Copies(closeButtonTitle));
bundle->GetStringFromName(NS_LITERAL_STRING("actionButton.label").get(),
getter_Copies(actionButtonTitle));
bundle->GetStringFromName(NS_LITERAL_STRING("webActions.disable.label").get(),
getter_Copies(disableButtonTitle));
if (!hostPort.IsEmpty()) {
const char16_t* formatStrings[] = { hostPort.get() };
bundle->FormatStringFromName(NS_LITERAL_STRING("webActions.disableForOrigin.label").get(),
formatStrings,
ArrayLength(formatStrings),
getter_Copies(disableButtonTitle));
}
bundle->GetStringFromName(NS_LITERAL_STRING("webActions.settings.label").get(),
getter_Copies(settingsButtonTitle));