--- a/browser/base/content/test/general/browser_bug553455.js
+++ b/browser/base/content/test/general/browser_bug553455.js
@@ -239,17 +239,17 @@ async function test_disabledInstall() {
let triggers = encodeURIComponent(JSON.stringify({
"XPI": "amosigned.xpi"
}));
BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
let panel = await notificationPromise;
let notification = panel.childNodes[0];
is(notification.button.label, "Enable", "Should have seen the right button");
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"Software installation is currently disabled. Click Enable and try again.");
let closePromise = waitForNotificationClose();
// Click on Enable
EventUtils.synthesizeMouseAtCenter(notification.button, {});
await closePromise;
try {
@@ -270,17 +270,17 @@ async function test_blockedInstall() {
}));
BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
let panel = await notificationPromise;
let notification = panel.childNodes[0];
is(notification.button.label, "Allow", "Should have seen the right button");
is(notification.getAttribute("origin"), "example.com",
"Should have seen the right origin host");
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
gApp + " prevented this site from asking you to install software on your computer.",
"Should have seen the right message");
let dialogPromise = waitForInstallDialog();
// Click on Allow
EventUtils.synthesizeMouse(notification.button, 20, 10, {});
// Notification should have changed to progress notification
ok(PopupNotifications.isPanelOpen, "Notification should still be open");
@@ -289,17 +289,17 @@ async function test_blockedInstall() {
let installDialog = await dialogPromise;
notificationPromise = waitForNotification("addon-install-restart");
acceptInstallDialog(installDialog);
panel = await notificationPromise;
notification = panel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"XPI Test will be installed after you restart " + gApp + ".",
"Should have seen the right message");
let installs = await getInstalls();
is(installs.length, 1, "Should be one pending install");
installs[0].cancel();
await removeTab();
},
@@ -326,17 +326,17 @@ async function test_whitelistedInstall()
"tab selected in response to the addon-install-confirmation notification");
let notificationPromise = waitForNotification("addon-install-restart");
acceptInstallDialog(installDialog);
let panel = await notificationPromise;
let notification = panel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"XPI Test will be installed after you restart " + gApp + ".",
"Should have seen the right message");
let installs = await getInstalls();
is(installs.length, 1, "Should be one pending install");
installs[0].cancel();
Services.perms.remove(makeURI("http://example.com/"), "install");
@@ -352,17 +352,17 @@ async function test_failedDownload() {
let triggers = encodeURIComponent(JSON.stringify({
"XPI": "missing.xpi"
}));
BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
await progressPromise;
let panel = await failPromise;
let notification = panel.childNodes[0];
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"The add-on could not be downloaded because of a connection failure.",
"Should have seen the right message");
Services.perms.remove(makeURI("http://example.com/"), "install");
await removeTab();
},
async function test_corruptFile() {
@@ -374,17 +374,17 @@ async function test_corruptFile() {
let triggers = encodeURIComponent(JSON.stringify({
"XPI": "corrupt.xpi"
}));
BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
await progressPromise;
let panel = await failPromise;
let notification = panel.childNodes[0];
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"The add-on downloaded from this site could not be installed " +
"because it appears to be corrupt.",
"Should have seen the right message");
Services.perms.remove(makeURI("http://example.com/"), "install");
await removeTab();
},
@@ -397,17 +397,17 @@ async function test_incompatible() {
let triggers = encodeURIComponent(JSON.stringify({
"XPI": "incompatible.xpi"
}));
BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
await progressPromise;
let panel = await failPromise;
let notification = panel.childNodes[0];
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"XPI Test could not be installed because it is not compatible with " +
gApp + " " + gVersion + ".",
"Should have seen the right message");
Services.perms.remove(makeURI("http://example.com/"), "install");
await removeTab();
},
@@ -536,17 +536,17 @@ async function test_allUnverified() {
let triggers = encodeURIComponent(JSON.stringify({
"Extension XPI": "restartless-unsigned.xpi"
}));
BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
await progressPromise;
let installDialog = await dialogPromise;
let notification = document.getElementById("addon-install-confirmation-notification");
- let message = notification.getAttribute("label");
+ let message = notification.getAttribute("startlabel");
is(message, "Caution: This site would like to install an unverified add-on in " + gApp + ". Proceed at your own risk.");
let container = document.getElementById("addon-install-confirmation-content");
is(container.childNodes.length, 1, "Should be one item listed");
is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
is(container.childNodes[0].childNodes.length, 1, "Shouldn't have the unverified marker");
let notificationPromise = waitForNotification("addon-installed");
@@ -574,17 +574,17 @@ async function test_url() {
let installDialog = await dialogPromise;
let notificationPromise = waitForNotification("addon-install-restart");
acceptInstallDialog(installDialog);
let panel = await notificationPromise;
let notification = panel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"XPI Test will be installed after you restart " + gApp + ".",
"Should have seen the right message");
let installs = await getInstalls();
is(installs.length, 1, "Should be one pending install");
installs[0].cancel();
await removeTab();
@@ -611,17 +611,17 @@ async function test_localFile() {
gBrowser.loadURI(path);
await failPromise;
// Wait for the browser code to add the failure notification
await waitForSingleNotification();
let notification = PopupNotifications.panel.childNodes[0];
is(notification.id, "addon-install-failed-notification", "Should have seen the install fail");
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"This add-on could not be installed because it appears to be corrupt.",
"Should have seen the right message");
await removeTab();
},
async function test_tabClose() {
if (!Services.prefs.getBoolPref("xpinstall.customConfirmationUI", false)) {
@@ -700,17 +700,17 @@ async function test_urlBar() {
let installDialog = await dialogPromise;
let notificationPromise = waitForNotification("addon-install-restart");
acceptInstallDialog(installDialog);
let panel = await notificationPromise;
let notification = panel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"XPI Test will be installed after you restart " + gApp + ".",
"Should have seen the right message");
let installs = await getInstalls();
is(installs.length, 1, "Should be one pending install");
installs[0].cancel();
await removeTab();
@@ -726,17 +726,17 @@ async function test_wrongHost() {
let progressPromise = waitForProgressNotification();
let notificationPromise = waitForNotification("addon-install-failed");
gBrowser.loadURI(TESTROOT + "corrupt.xpi");
await progressPromise;
let panel = await notificationPromise;
let notification = panel.childNodes[0];
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"The add-on downloaded from this site could not be installed " +
"because it appears to be corrupt.",
"Should have seen the right message");
await removeTab();
},
async function test_reload() {
@@ -753,17 +753,17 @@ async function test_reload() {
let installDialog = await dialogPromise;
let notificationPromise = waitForNotification("addon-install-restart");
acceptInstallDialog(installDialog);
let panel = await notificationPromise;
let notification = panel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"XPI Test will be installed after you restart " + gApp + ".",
"Should have seen the right message");
function testFail() {
ok(false, "Reloading should not have hidden the notification");
}
PopupNotifications.panel.addEventListener("popuphiding", testFail);
let requestedUrl = TESTROOT2 + "enabled.html";
@@ -794,17 +794,17 @@ async function test_theme() {
let installDialog = await dialogPromise;
let notificationPromise = waitForNotification("addon-install-restart");
acceptInstallDialog(installDialog);
let panel = await notificationPromise;
let notification = panel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
- is(notification.getAttribute("label"),
+ is(notification.getAttribute("startlabel"),
"Theme Test will be installed after you restart " + gApp + ".",
"Should have seen the right message");
let addon = await new Promise(resolve => {
AddonManager.getAddonByID("{972ce4c6-7e08-4474-a285-3208198ce6fd}", function(result) {
resolve(result);
});
});
--- a/browser/base/content/test/popupNotifications/head.js
+++ b/browser/base/content/test/popupNotifications/head.js
@@ -198,17 +198,25 @@ function checkPopup(popup, notifyObj) {
return;
let icon = document.getAnonymousElementByAttribute(notification, "class",
"popup-notification-icon");
if (notifyObj.id == "geolocation") {
isnot(icon.boxObject.width, 0, "icon for geo displayed");
ok(popup.anchorNode.classList.contains("notification-anchor-icon"),
"notification anchored to icon");
}
- is(notification.getAttribute("label"), notifyObj.message, "message matches");
+
+ if (typeof notifyObj.message == "string") {
+ is(notification.getAttribute("startlabel"), notifyObj.message, "message matches");
+ } else {
+ is(notification.getAttribute("startlabel"), notifyObj.message.start, "message matches");
+ is(notification.getAttribute("hostname"), notifyObj.message.host, "message matches");
+ is(notification.getAttribute("endlabel"), notifyObj.message.end, "message matches");
+ }
+
is(notification.id, notifyObj.id + "-notification", "id matches");
if (notifyObj.mainAction) {
is(notification.getAttribute("buttonlabel"), notifyObj.mainAction.label,
"main action label matches");
is(notification.getAttribute("buttonaccesskey"),
notifyObj.mainAction.accessKey, "main action accesskey matches");
is(notification.getAttribute("buttonhighlight"),
(!notifyObj.mainAction.disableHighlight).toString(),
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -456,26 +456,30 @@ GeolocationPermissionPrompt.prototype =
return "geolocation";
},
get anchorID() {
return "geo-notification-icon";
},
get message() {
- let message;
+ let message = {};
if (this.principal.URI.schemeIs("file")) {
- message = gBrowserBundle.GetStringFromName("geolocation.shareWithFile3");
+ message.start = gBrowserBundle.GetStringFromName("geolocation.shareWithFile3");
} else {
- let hostPort = "<>";
+ let header = gBrowserBundle.formatStringFromName("geolocation.shareWithSite3",
+ ["<>"], 1);
+ header = header.split("<>");
+ message.end = header[1];
+ message.start = header[0];
+
+ message.host = "<>";
try {
- hostPort = this.principal.URI.hostPort;
+ message.host = this.principal.URI.hostPort;
} catch (ex) { }
- message = gBrowserBundle.formatStringFromName("geolocation.shareWithSite3",
- [hostPort], 1);
}
return message;
},
get promptActions() {
// We collect Telemetry data on Geolocation prompts and how users
// respond to them. The probe keys are a bit verbose, so let's alias them.
const SHARE_LOCATION =
@@ -554,22 +558,30 @@ DesktopNotificationPermissionPrompt.prot
return "web-notifications";
},
get anchorID() {
return "web-notifications-notification-icon";
},
get message() {
- let hostPort = "<>";
+ let message = {};
+
+ message.host = "<>";
try {
- hostPort = this.principal.URI.hostPort;
+ message.host = this.principal.URI.hostPort;
} catch (ex) { }
- return gBrowserBundle.formatStringFromName("webNotifications.receiveFromSite2",
- [hostPort], 1);
+
+ let header = gBrowserBundle.formatStringFromName("webNotifications.receiveFromSite2",
+ ["<>"], 1);
+ header = header.split("<>");
+ message.end = header[1];
+ message.start = header[0];
+
+ return message;
},
get promptActions() {
let actions = [
{
label: gBrowserBundle.GetStringFromName("webNotifications.allow"),
accessKey:
gBrowserBundle.GetStringFromName("webNotifications.allow.accesskey"),
@@ -625,35 +637,44 @@ PersistentStoragePermissionPrompt.protot
if (checkbox.show) {
checkbox.checked = true;
checkbox.label = gBrowserBundle.GetStringFromName("persistentStorage.remember");
}
let learnMoreURL =
Services.urlFormatter.formatURLPref("app.support.baseURL") + "storage-permissions";
return {
checkbox,
- learnMoreURL
+ learnMoreURL,
+ displayURI: false
};
},
get notificationID() {
return "persistent-storage";
},
get anchorID() {
return "persistent-storage-notification-icon";
},
get message() {
- let hostPort = "<>";
+ let message = {};
+
+ message.host = "<>";
try {
- hostPort = this.principal.URI.hostPort;
+ message.host = this.principal.URI.hostPort;
} catch (ex) {}
- return gBrowserBundle.formatStringFromName(
- "persistentStorage.allowWithSite", [hostPort], 1);
+
+ let header = gBrowserBundle.formatStringFromName("persistentStorage.allowWithSite",
+ ["<>"], 1);
+ header = header.split("<>");
+ message.end = header[1];
+ message.start = header[0];
+
+ return message;
},
get promptActions() {
return [
{
label: gBrowserBundle.GetStringFromName("persistentStorage.allow"),
accessKey:
gBrowserBundle.GetStringFromName("persistentStorage.allow.accesskey"),
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -370,17 +370,18 @@ function prompt(aBrowser, aRequest) {
let uri;
try {
// This fails for principals that serialize to "null", e.g. file URIs.
uri = Services.io.newURI(aRequest.origin);
} catch (e) {
uri = Services.io.newURI(aRequest.documentURI);
}
- let host = getHost(uri);
+ let message = {};
+ message.host = getHost(uri);
let chromeDoc = aBrowser.ownerDocument;
let stringBundle = chromeDoc.defaultView.gNavigatorBundle;
// Mind the order, because for simplicity we're iterating over the list using
// "includes()". This allows the rotation of string identifiers. We list the
// full identifiers here so they can be cross-referenced more easily.
let joinedRequestTypes = requestTypes.join("And");
let stringId = [
@@ -391,17 +392,20 @@ function prompt(aBrowser, aRequest) {
"getUserMedia.shareAudioCapture2.message",
// Combinations of the above request types last.
"getUserMedia.shareCameraAndMicrophone2.message",
"getUserMedia.shareCameraAndAudioCapture2.message",
"getUserMedia.shareScreenAndMicrophone3.message",
"getUserMedia.shareScreenAndAudioCapture3.message",
].find(id => id.includes(joinedRequestTypes));
- let message = stringBundle.getFormattedString(stringId, [host]);
+ let header = stringBundle.getFormattedString(stringId, ["<>"], 1);
+ header = header.split("<>");
+ message.end = header[1];
+ message.start = header[0];
let notification; // Used by action callbacks.
let mainAction = {
label: stringBundle.getString("getUserMedia.allow.label"),
accessKey: stringBundle.getString("getUserMedia.allow.accesskey"),
// The real callback will be set during the "showing" event. The
// empty function here is so that PopupNotifications.show doesn't
// reject the action.
--- a/toolkit/content/widgets/notification.xml
+++ b/toolkit/content/widgets/notification.xml
@@ -7,17 +7,18 @@
<!DOCTYPE bindings [
<!ENTITY % notificationDTD SYSTEM "chrome://global/locale/notification.dtd">
%notificationDTD;
]>
<bindings id="notificationBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:xbl="http://www.mozilla.org/xbl"
- xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html = "http://www.w3.org/1999/xhtml">
<binding id="notificationbox">
<content>
<xul:stack xbl:inherits="hidden=notificationshidden"
class="notificationbox-stack">
<xul:spacer/>
<children includes="notification"/>
</xul:stack>
@@ -506,18 +507,21 @@
xbl:inherits="popupid,src=icon,class=iconclass"/>
<xul:vbox flex="1" pack="start"
class="popup-notification-body" xbl:inherits="popupid">
<xul:hbox align="start">
<xul:vbox flex="1">
<xul:label class="popup-notification-origin header"
xbl:inherits="value=origin,tooltiptext=origin"
crop="center"/>
- <xul:description class="popup-notification-description"
- xbl:inherits="xbl:text=label,popupid"/>
+ <xul:description>
+ <html:span xbl:inherits="xbl:text=startlabel,popupid"/>
+ <html:b xbl:inherits="xbl:text=hostname,popupid"/>
+ <html:span xbl:inherits="xbl:text=endlabel,popupid"/>
+ </xul:description>
</xul:vbox>
<xul:toolbarbutton anonid="closebutton"
class="messageCloseButton close-icon popup-notification-closebutton tabbable"
xbl:inherits="oncommand=closebuttoncommand,hidden=closebuttonhidden"
tooltiptext="&closeNotification.tooltip;"/>
</xul:hbox>
<children includes="popupnotificationcontent"/>
<xul:label class="text-link popup-notification-learnmore-link"
--- a/toolkit/modules/PopupNotifications.jsm
+++ b/toolkit/modules/PopupNotifications.jsm
@@ -326,17 +326,23 @@ PopupNotifications.prototype = {
* The <xul:browser> element associated with the notification. Must not
* be null.
* @param id
* A unique ID that identifies the type of notification (e.g.
* "geolocation"). Only one notification with a given ID can be visible
* at a time. If a notification already exists with the given ID, it
* will be replaced.
* @param message
- * The text to be displayed in the notification.
+ * A JavaScript object or a string containing the text to be displayed in the
+ * notification header. It must have the following properties:
+ * - start(string): First part of the notification header text. Optionally,
+ * it is also the entire header text when the notification header does not
+ * contain a host name. eg. file URIs.
+ * - host(string): Hostname of the site displaying the notifiation.
+ * - end(string): An optional end label to the notification header text.
* @param anchorID
* The ID of the element that should be used as this notification
* popup's anchor. May be null, in which case the notification will be
* anchored to the iconBox.
* @param mainAction
* A JavaScript object literal describing the notification button's
* action. If present, it must have the following properties:
* - label (string): the button's label.
@@ -762,17 +768,33 @@ PopupNotifications.prototype = {
// If the chrome document provides a popupnotification with this id, use
// that. Otherwise create it ad-hoc.
let popupnotification = doc.getElementById(popupnotificationID);
if (popupnotification)
gNotificationParents.set(popupnotification, popupnotification.parentNode);
else
popupnotification = doc.createElementNS(XUL_NS, "popupnotification");
- popupnotification.setAttribute("label", n.message);
+ // Create the notification description element.
+
+ // Adding an if condition to check if n.message(i.e. the notification-description-text) is a string or an object.
+ if (typeof n.message == "string") {
+ popupnotification.setAttribute("startlabel", n.message);
+ } else {
+ if (n.message.start) {
+ popupnotification.setAttribute("startlabel", n.message.start);
+ }
+ if (n.message.host) {
+ popupnotification.setAttribute("hostname", n.message.host);
+ }
+ if (n.message.end) {
+ popupnotification.setAttribute("endlabel", n.message.end);
+ }
+ }
+
popupnotification.setAttribute("id", popupnotificationID);
popupnotification.setAttribute("popupid", n.id);
popupnotification.setAttribute("oncommand", "PopupNotifications._onCommand(event);");
if (Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton")) {
popupnotification.setAttribute("closebuttoncommand", "PopupNotifications._onButtonEvent(event, 'secondarybuttoncommand');");
} else {
popupnotification.setAttribute("closebuttoncommand", `PopupNotifications._dismiss(event, ${TELEMETRY_STAT_DISMISSAL_CLOSE_BUTTON});`);
}