--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -5965,18 +5965,22 @@ var OfflineApps = {
let warnQuotaKB = Services.prefs.getIntPref("offline-apps.quota.warn");
// This message shows the quota in MB, and so we divide the quota (in kb) by 1024.
let message = gNavigatorBundle.getFormattedString("offlineApps.usage",
[ uri.host,
warnQuotaKB / 1024 ]);
let anchorID = "indexedDB-notification-icon";
+ let options = {
+ persistent: true,
+ hideClose: true,
+ };
PopupNotifications.show(browser, "offline-app-usage", message,
- anchorID, mainAction, null, { persistent: true });
+ anchorID, mainAction, null, options);
// Now that we've warned once, prevent the warning from showing up
// again.
Services.perms.add(uri, "offline-app",
Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
},
// XXX: duplicated in preferences/advanced.js
@@ -6025,38 +6029,39 @@ var OfflineApps = {
let notification = PopupNotifications.getNotification(notificationID, browser);
if (notification) {
notification.options.controlledItems.push([
Cu.getWeakReference(browser), docId, uri
]);
} else {
let mainAction = {
- label: gNavigatorBundle.getString("offlineApps.allow"),
- accessKey: gNavigatorBundle.getString("offlineApps.allowAccessKey"),
+ label: gNavigatorBundle.getString("offlineApps.allowStoring.label"),
+ accessKey: gNavigatorBundle.getString("offlineApps.allowStoring.accesskey"),
callback: function() {
for (let [ciBrowser, ciDocId, ciUri] of notification.options.controlledItems) {
OfflineApps.allowSite(ciBrowser, ciDocId, ciUri);
}
}
};
let secondaryActions = [{
- label: gNavigatorBundle.getString("offlineApps.never"),
- accessKey: gNavigatorBundle.getString("offlineApps.neverAccessKey"),
+ label: gNavigatorBundle.getString("offlineApps.dontAllow.label"),
+ accessKey: gNavigatorBundle.getString("offlineApps.dontAllow.accesskey"),
callback: function() {
for (let [, , ciUri] of notification.options.controlledItems) {
OfflineApps.disallowSite(ciUri);
}
}
}];
- let message = gNavigatorBundle.getFormattedString("offlineApps.available",
+ let message = gNavigatorBundle.getFormattedString("offlineApps.available2",
[host]);
let anchorID = "indexedDB-notification-icon";
let options = {
persistent: true,
+ hideClose: true,
controlledItems : [[Cu.getWeakReference(browser), docId, uri]]
};
notification = PopupNotifications.show(browser, notificationID, message,
anchorID, mainAction,
secondaryActions, options);
}
},
@@ -6128,51 +6133,55 @@ var IndexedDBPromptHelper = {
var requestor = subject.QueryInterface(Ci.nsIInterfaceRequestor);
var browser = requestor.getInterface(Ci.nsIDOMNode);
if (browser.ownerGlobal != window) {
// Only listen for notifications for browsers in our chrome window.
return;
}
- var host = browser.currentURI.asciiHost;
+ // Get the host name if available or the file path otherwise.
+ var host = browser.currentURI.asciiHost || browser.currentURI.path;
var message;
var responseTopic;
if (topic == this._permissionsPrompt) {
- message = gNavigatorBundle.getFormattedString("offlineApps.available",
+ message = gNavigatorBundle.getFormattedString("offlineApps.available2",
[ host ]);
responseTopic = this._permissionsResponse;
}
var observer = requestor.getInterface(Ci.nsIObserver);
var mainAction = {
- label: gNavigatorBundle.getString("offlineApps.allow"),
- accessKey: gNavigatorBundle.getString("offlineApps.allowAccessKey"),
+ label: gNavigatorBundle.getString("offlineApps.allowStoring.label"),
+ accessKey: gNavigatorBundle.getString("offlineApps.allowStoring.accesskey"),
callback: function() {
observer.observe(null, responseTopic,
Ci.nsIPermissionManager.ALLOW_ACTION);
}
};
var secondaryActions = [
{
- label: gNavigatorBundle.getString("offlineApps.never"),
- accessKey: gNavigatorBundle.getString("offlineApps.neverAccessKey"),
+ label: gNavigatorBundle.getString("offlineApps.dontAllow.label"),
+ accessKey: gNavigatorBundle.getString("offlineApps.dontAllow.accesskey"),
callback: function() {
observer.observe(null, responseTopic,
Ci.nsIPermissionManager.DENY_ACTION);
}
}
];
PopupNotifications.show(browser, topic, message,
this._notificationIcon, mainAction,
- secondaryActions, { persistent: true });
+ secondaryActions, {
+ persistent: true,
+ hideClose: true,
+ });
}
};
function CanCloseWindow()
{
// Avoid redundant calls to canClose from showing multiple
// PermitUnload dialogs.
if (Services.startup.shuttingDown || window.skipNextCanClose) {
--- a/browser/base/content/popup-notifications.inc
+++ b/browser/base/content/popup-notifications.inc
@@ -17,17 +17,17 @@
<menupopup id="webRTC-selectCamera-menupopup"/>
</menulist>
</popupnotificationcontent>
<popupnotificationcontent id="webRTC-selectWindowOrScreen" orient="vertical">
<label id="webRTC-selectWindow-label"
control="webRTC-selectWindow-menulist"/>
<menulist id="webRTC-selectWindow-menulist"
- oncommand="webrtcUI.updateMainActionLabel(this);">
+ oncommand="webrtcUI.updateWarningLabel(this);">
<menupopup id="webRTC-selectWindow-menupopup"/>
</menulist>
<description id="webRTC-all-windows-shared" hidden="true">&getUserMedia.allWindowsShared.message;</description>
</popupnotificationcontent>
<popupnotificationcontent id="webRTC-preview" hidden="true">
<html:video id="webRTC-previewVideo"/>
<vbox id="webRTC-previewWarningBox">
--- a/browser/base/content/test/popupNotifications/browser_popupNotification.js
+++ b/browser/base/content/test/popupNotifications/browser_popupNotification.js
@@ -43,54 +43,54 @@ var tests = [
},
onHidden: function(popup) {
ok(this.notifyObj.secondaryActionClicked, "secondaryAction was clicked");
ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
}
},
{ id: "Test#2b",
- run: function () {
+ run: function() {
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.secondaryActions.push({
label: "Extra Secondary Action",
accessKey: "E",
callback: () => this.extraSecondaryActionClicked = true,
});
showNotification(this.notifyObj);
},
- onShown: function (popup) {
+ onShown: function(popup) {
checkPopup(popup, this.notifyObj);
triggerSecondaryCommand(popup, 1);
},
- onHidden: function (popup) {
+ onHidden: function(popup) {
ok(this.extraSecondaryActionClicked, "extra secondary action was clicked");
ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
}
},
{ id: "Test#2c",
- run: function () {
+ run: function() {
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.secondaryActions.push({
label: "Extra Secondary Action",
accessKey: "E",
callback: () => ok(false, "unexpected callback invocation"),
}, {
label: "Other Extra Secondary Action",
accessKey: "O",
callback: () => this.extraSecondaryActionClicked = true,
});
showNotification(this.notifyObj);
},
- onShown: function (popup) {
+ onShown: function(popup) {
checkPopup(popup, this.notifyObj);
triggerSecondaryCommand(popup, 2);
},
- onHidden: function (popup) {
+ onHidden: function(popup) {
ok(this.extraSecondaryActionClicked, "extra secondary action was clicked");
ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
}
},
{ id: "Test#3",
run: function() {
this.notifyObj = new BasicNotification(this.id);
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media.js
@@ -469,17 +469,17 @@ var gTests = [
gIdentityHandler._identityPopup.hidden = true;
yield expectNoObserverCalled();
yield closeStream();
}
},
{
- desc: "'Always Allow' ignored and not shown on http pages",
+ desc: "'Always Allow' disabled on http pages",
run: function* checkNoAlwaysOnHttp() {
// Load an http page instead of the https version.
let browser = gBrowser.selectedBrowser;
browser.loadURI(browser.documentURI.spec.replace("https://", "http://"));
yield BrowserTestUtils.browserLoaded(browser);
// Initially set both permissions to 'allow'.
let Perms = Services.perms;
@@ -489,26 +489,26 @@ var gTests = [
// Request devices and expect a prompt despite the saved 'Allow' permission,
// because the connection isn't secure.
let promise = promisePopupNotificationShown("webRTC-shareDevices");
yield promiseRequestDevice(true, true);
yield promise;
yield expectObserverCalled("getUserMedia:request");
- // Ensure that the 'Always Allow' action isn't shown.
- let alwaysLabel = gNavigatorBundle.getString("getUserMedia.always.label");
- ok(!!alwaysLabel, "found the 'Always Allow' localized label");
- let labels = [];
+ // Ensure that checking the 'Remember this decision' checkbox disables
+ // 'Allow'.
let notification = PopupNotifications.panel.firstChild;
- for (let node of notification.childNodes) {
- if (node.localName == "menuitem")
- labels.push(node.getAttribute("label"));
- }
- is(labels.indexOf(alwaysLabel), -1, "The 'Always Allow' item isn't shown");
+ let checkbox = notification.checkbox;
+ ok(!!checkbox, "checkbox is present");
+ ok(!checkbox.checked, "checkbox is not checked");
+ checkbox.click();
+ ok(checkbox.checked, "checkbox now checked");
+ ok(notification.button.disabled, "Allow button is disabled");
+ ok(!notification.hasAttribute("warninghidden"), "warning message is shown");
// Cleanup.
yield closeStream(true);
Perms.remove(uri, "camera");
Perms.remove(uri, "microphone");
}
}
--- a/browser/base/content/test/webrtc/head.js
+++ b/browser/base/content/test/webrtc/head.js
@@ -300,38 +300,27 @@ function promiseNoPopupNotification(aNam
}
const kActionAlways = 1;
const kActionDeny = 2;
const kActionNever = 3;
function activateSecondaryAction(aAction) {
let notification = PopupNotifications.panel.firstChild;
-
- if (aAction == kActionAlways) {
- notification.secondaryButton.click();
- return;
+ switch (aAction) {
+ case kActionNever:
+ notification.checkbox.setAttribute("checked", true); // fallthrough
+ case kActionDeny:
+ notification.secondaryButton.click();
+ break;
+ case kActionAlways:
+ notification.checkbox.setAttribute("checked", true);
+ notification.button.click();
+ break;
}
-
- notification.secondaryButton.nextSibling.nextSibling.focus();
- let popup = notification.menupopup;
- popup.addEventListener("popupshown", function() {
- popup.removeEventListener("popupshown", arguments.callee, false);
-
- // Press 'down' as many time as needed to select the requested action.
- while (--aAction)
- EventUtils.synthesizeKey("VK_DOWN", {});
-
- // Activate
- EventUtils.synthesizeKey("VK_RETURN", {});
- }, false);
-
- // One down event to open the popup
- EventUtils.synthesizeKey("VK_DOWN",
- { altKey: !navigator.platform.includes("Mac") });
}
function getMediaCaptureState() {
return new Promise(resolve => {
let mm = _mm();
mm.addMessageListener("Test:MediaCaptureState", ({data}) => {
resolve(data);
});
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt.js
@@ -19,19 +19,19 @@ add_task(function* test() {
// Wait until the notification is available.
while (!notification){
yield new Promise(resolve => { executeSoon(resolve); });
let notification = aWindow.PopupNotifications.getNotification("geolocation");
}
if (aPrivateMode) {
// Make sure the notification is correctly displayed without a remember control
- is(notification.secondaryActions.length, 0, "Secondary actions shouldn't exist (always/never remember)");
+ ok(!notification.options.checkbox.show, "Secondary actions should exist (always/never remember)");
} else {
- ok(notification.secondaryActions.length > 1, "Secondary actions should exist (always/never remember)");
+ ok(notification.options.checkbox.show, "Secondary actions should exist (always/never remember)");
}
notification.remove();
aWindow.gBrowser.removeCurrentTab();
});
};
let win = yield BrowserTestUtils.openNewBrowserWindow();
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -310,23 +310,21 @@ printButton.tooltip=Print this page… (%S)
newWindowButton.tooltip=Open a new window (%S)
# New Tab button tooltip
# LOCALIZATION NOTE (newTabButton.tooltip):
# %S is the keyboard shortcut for "New Tab"
newTabButton.tooltip=Open a new tab (%S)
# Offline web applications
-offlineApps.available=This website (%S) is asking to store data on your computer for offline use.
-offlineApps.allow=Allow
-offlineApps.allowAccessKey=A
-offlineApps.never=Never for This Site
-offlineApps.neverAccessKey=e
-offlineApps.notNow=Not Now
-offlineApps.notNowAccessKey=N
+offlineApps.available2=Will you allow %S to store data on your computer?
+offlineApps.allowStoring.label=Allow Storing Data
+offlineApps.allowStoring.accesskey=A
+offlineApps.dontAllow.label=Don’t Allow
+offlineApps.dontAllow.accesskey=n
offlineApps.usage=This website (%S) is now storing more than %SMB of data on your computer for offline use.
offlineApps.manageUsage=Show settings
offlineApps.manageUsageAccessKey=S
identity.identified.verifier=Verified by: %S
identity.identified.verified_by_you=You have added a security exception for this site.
identity.identified.state_and_country=%S, %S
@@ -363,34 +361,31 @@ pu.notifyButton.label=Details…
pu.notifyButton.accesskey=D
# LOCALIZATION NOTE %S will be replaced by the short name of the application.
puNotifyText=%S has been updated
puAlertTitle=%S Updated
puAlertText=Click here for details
# Geolocation UI
-# LOCALIZATION NOTE (geolocation.shareLocation geolocation.alwaysShareLocation geolocation.neverShareLocation):
-# If you're having trouble with the word Share, please use Allow and Block in your language.
-geolocation.shareLocation=Share Location
-geolocation.shareLocation.accesskey=a
-geolocation.alwaysShareLocation=Always Share Location
-geolocation.alwaysShareLocation.accesskey=A
-geolocation.neverShareLocation=Never Share Location
-geolocation.neverShareLocation.accesskey=N
-geolocation.shareWithSite2=Would you like to share your location with this site?
-geolocation.shareWithFile2=Would you like to share your location with this file?
+geolocation.allowLocation=Allow Location Access
+geolocation.allowLocation.accesskey=A
+geolocation.dontAllowLocation=Don’t Allow
+geolocation.dontAllowLocation.accesskey=n
+geolocation.shareWithSite3=Will you allow %S to access your location?
+geolocation.shareWithFile3=Will you allow this local file to access your location?
+geolocation.remember=Remember this decision
-webNotifications.receiveForSession=Receive for this session
-webNotifications.receiveForSession.accesskey=s
-webNotifications.alwaysReceive=Always Receive Notifications
-webNotifications.alwaysReceive.accesskey=A
-webNotifications.neverShow=Always Block Notifications
-webNotifications.neverShow.accesskey=N
-webNotifications.receiveFromSite=Would you like to receive notifications from this site?
+webNotifications.remember=Remember this decision
+webNotifications.rememberForSession=Remember decision for this session
+webNotifications.allow=Allow Notifications
+webNotifications.allow.accesskey=A
+webNotifications.dontAllow=Don’t Allow
+webNotifications.dontAllow.accesskey=n
+webNotifications.receiveFromSite2=Will you allow %S to send notifications?
# LOCALIZATION NOTE (webNotifications.upgradeTitle): When using native notifications on OS X, the title may be truncated around 32 characters.
webNotifications.upgradeTitle=Upgraded notifications
# LOCALIZATION NOTE (webNotifications.upgradeBody): When using native notifications on OS X, the body may be truncated around 100 characters in some views.
webNotifications.upgradeBody=You can now receive notifications from sites that are not currently loaded. Click to learn more.
# Phishing/Malware Notification Bar.
# LOCALIZATION NOTE (notADeceptiveSite, notAnAttack)
# The two button strings will never be shown at the same time, so
@@ -468,29 +463,29 @@ social.error.message=%1$S is unable to c
social.error.tryAgain.label=Try Again
social.error.tryAgain.accesskey=T
social.error.closeSidebar.label=Close This Sidebar
social.error.closeSidebar.accesskey=C
# LOCALIZATION NOTE: %1$S is the label for the toolbar button, %2$S is the associated badge numbering that the social provider may provide.
social.aria.toolbarButtonBadgeText=%1$S (%2$S)
-# LOCALIZATION NOTE (getUserMedia.shareCamera.message, getUserMedia.shareMicrophone.message,
-# getUserMedia.shareScreen.message, getUserMedia.shareCameraAndMicrophone.message,
-# getUserMedia.shareScreenAndMicrophone.message, getUserMedia.shareCameraAndAudioCapture.message,
-# getUserMedia.shareAudioCapture.message, getUserMedia.shareScreenAndAudioCapture.message):
+# LOCALIZATION NOTE (getUserMedia.shareCamera2.message, getUserMedia.shareMicrophone2.message,
+# getUserMedia.shareScreen2.message, getUserMedia.shareCameraAndMicrophone2.message,
+# getUserMedia.shareScreenAndMicrophone2.message, getUserMedia.shareCameraAndAudioCapture2.message,
+# getUserMedia.shareAudioCapture2.message, getUserMedia.shareScreenAndAudioCapture2.message):
# %S is the website origin (e.g. www.mozilla.org)
-getUserMedia.shareCamera.message = Would you like to share your camera with %S?
-getUserMedia.shareMicrophone.message = Would you like to share your microphone with %S?
-getUserMedia.shareScreen.message = Would you like to share your screen with %S?
-getUserMedia.shareCameraAndMicrophone.message = Would you like to share your camera and microphone with %S?
-getUserMedia.shareCameraAndAudioCapture.message = Would you like to share your camera and this tab’s audio with %S?
-getUserMedia.shareScreenAndMicrophone.message = Would you like to share your microphone and screen with %S?
-getUserMedia.shareScreenAndAudioCapture.message = Would you like to share this tab’s audio and your screen with %S?
-getUserMedia.shareAudioCapture.message = Would you like to share this tab’s audio with %S?
+getUserMedia.shareCamera2.message = Will you allow %S to use your camera?
+getUserMedia.shareMicrophone2.message = Will you allow %S to use your microphone?
+getUserMedia.shareScreen2.message = Will you allow %S to see your screen or application window?
+getUserMedia.shareCameraAndMicrophone2.message = Will you allow %S to use your camera and microphone?
+getUserMedia.shareCameraAndAudioCapture2.message = Will you allow %S to use your camera and listen to this tab’s audio?
+getUserMedia.shareScreenAndMicrophone2.message = Will you allow %S to use your microphone and see your screen or application window?
+getUserMedia.shareScreenAndAudioCapture2.message = Will you allow %S to listen to this tab’s audio and see your screen or application window?
+getUserMedia.shareAudioCapture2.message = Will you allow %S to listen to this tab’s audio?
# LOCALIZATION NOTE (getUserMedia.shareScreenWarning.message): NB: inserted via innerHTML, so please don't use <, > or & in this string.
# %S will be the 'learn more' link
getUserMedia.shareScreenWarning.message = Only share screens with sites you trust. Sharing can allow deceptive sites to browse as you and steal your private data. %S
# LOCALIZATION NOTE (getUserMedia.shareFirefoxWarning.message): NB: inserted via innerHTML, so please don't use <, > or & in this string.
# %1$S is brandShortName (eg. Firefox)
# %2$S will be the 'learn more' link
getUserMedia.shareFirefoxWarning.message = Only share %1$S with sites you trust. Sharing can allow deceptive sites to browse as you and steal your private data. %2$S
# LOCALIZATION NOTE(getUserMedia.shareScreen.learnMoreLabel): NB: inserted via innerHTML, so please don't use <, > or & in this string.
@@ -510,32 +505,28 @@ getUserMedia.shareEntireScreen.label = E
# Example: Screen 1, Screen 2,..
getUserMedia.shareMonitor.label = Screen %S
# LOCALIZATION NOTE (getUserMedia.shareApplicationWindowCount.label):
# Semicolon-separated list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# Replacement for #1 is the name of the application.
# Replacement for #2 is the number of windows currently displayed by the application.
getUserMedia.shareApplicationWindowCount.label=#1 (#2 window);#1 (#2 windows)
-# LOCALIZATION NOTE (getUserMedia.shareSelectedDevices.label):
-# Semicolon-separated list of plural forms. See:
-# http://developer.mozilla.org/en/docs/Localization_and_Plurals
-# The number of devices can be either one or two.
-getUserMedia.shareSelectedDevices.label = Share Selected Device;Share Selected Devices
-getUserMedia.shareSelectedDevices.accesskey = S
-getUserMedia.shareScreen.label = Share Screen
-getUserMedia.shareApplication.label = Share Selected Application
-getUserMedia.shareWindow.label = Share Selected Window
-getUserMedia.shareSelectedItems.label = Share Selected Items
-getUserMedia.always.label = Always Share
-getUserMedia.always.accesskey = A
-getUserMedia.denyRequest.label = Don’t Share
-getUserMedia.denyRequest.accesskey = D
-getUserMedia.never.label = Never Share
-getUserMedia.never.accesskey = N
+getUserMedia.allow.label = Allow
+getUserMedia.allow.accesskey = A
+getUserMedia.dontAllow.label = Don’t Allow
+getUserMedia.dontAllow.accesskey = D
+getUserMedia.remember=Remember this decision
+# LOCALIZATION NOTE (ggetUserMedia.reasonForNoPermanentAllow.screen,
+# getUserMedia.reasonForNoPermanentAllow.audio,
+# getUserMedia.reasonForNoPermanentAllow.insecure):
+# %S is brandShortName
+getUserMedia.reasonForNoPermanentAllow.screen=%S can not allow permanent access to your screen or application without asking which one to share.
+getUserMedia.reasonForNoPermanentAllow.audio=%S can not allow permanent access to your tab’s audio without asking which tab to share.
+getUserMedia.reasonForNoPermanentAllow.insecure=Your connection to this site is not secure. To protect you, %S will only allow access for this session.
getUserMedia.sharingMenu.label = Tabs sharing devices
getUserMedia.sharingMenu.accesskey = d
# LOCALIZATION NOTE (getUserMedia.sharingMenuCamera
# getUserMedia.sharingMenuMicrophone,
# getUserMedia.sharingMenuAudioCapture,
# getUserMedia.sharingMenuApplication,
# getUserMedia.sharingMenuScreen,
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -221,17 +221,20 @@ this.PermissionPromptPrototype = {
* If omitted, the nsIPermissionManager will not be written to
* when this choice is chosen.
* expireType (Ci.nsIPermissionManager expiration policy, optional)
* The nsIPermissionManager expiration policy that will be associated
* with this choice. For example, Ci.nsIPermissionManager.EXPIRE_SESSION.
*
* If action is not set, expireType will be ignored.
* callback (function, optional)
- * A callback function that will fire if the user makes this choice.
+ * A callback function that will fire if the user makes this choice, with
+ * a single parameter, state. State is an Object that contains the property
+ * checkboxChecked, which identifies whether the checkbox to remember this
+ * decision was checked.
*/
get promptActions() {
return [];
},
/**
* If the prompt will be shown to the user, this callback will
* be called just before. Subclasses may want to override this
@@ -292,24 +295,24 @@ this.PermissionPromptPrototype = {
promptAction.expireType != Ci.nsIPermissionManager.EXPIRE_SESSION &&
promptAction.action) {
continue;
}
let action = {
label: promptAction.label,
accessKey: promptAction.accessKey,
- callback: () => {
+ callback: state => {
if (promptAction.callback) {
promptAction.callback();
}
if (this.permissionKey) {
// Remember permissions.
- if (promptAction.action) {
+ if (state && state.checkboxChecked && promptAction.action) {
Services.perms.addFromPrincipal(this.principal,
this.permissionKey,
promptAction.action,
promptAction.expireType);
}
// Grant permission if action is null or ALLOW_ACTION.
if (!promptAction.action ||
@@ -332,17 +335,19 @@ this.PermissionPromptPrototype = {
popupNotificationActions[0] : null;
let secondaryActions = popupNotificationActions.splice(1);
let options = this.popupOptions;
if (!options.hasOwnProperty('displayURI') || options.displayURI) {
options.displayURI = this.principal.URI;
}
+ // Permission prompts are always persistent and don't have a close button.
options.persistent = true;
+ options.hideClose = true;
this.onBeforeShow();
chromeWin.PopupNotifications.show(this.browser,
this.notificationID,
this.message,
this.anchorID,
mainAction,
secondaryActions,
@@ -409,89 +414,99 @@ GeolocationPermissionPrompt.prototype =
__proto__: PermissionPromptForRequestPrototype,
get permissionKey() {
return "geo";
},
get popupOptions() {
let pref = "browser.geolocation.warning.infoURL";
- return {
+ let options = {
learnMoreURL: Services.urlFormatter.formatURLPref(pref),
+ displayURI: false
};
+
+ if (this.principal.URI.schemeIs("file")) {
+ options.checkbox = { show: false };
+ } else {
+ // Don't offer "always remember" action in PB mode
+ options.checkbox = {
+ show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal)
+ };
+ }
+
+ if (options.checkbox.show) {
+ options.checkbox.label = gBrowserBundle.GetStringFromName("geolocation.remember");
+ }
+
+ return options;
},
get notificationID() {
return "geolocation";
},
get anchorID() {
return "geo-notification-icon";
},
get message() {
let message;
if (this.principal.URI.schemeIs("file")) {
- message = gBrowserBundle.GetStringFromName("geolocation.shareWithFile2");
+ message = gBrowserBundle.GetStringFromName("geolocation.shareWithFile3");
} else {
- message = gBrowserBundle.GetStringFromName("geolocation.shareWithSite2");
+ let hostPort = "<>";
+ try {
+ hostPort = 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 =
Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_SHARE_LOCATION;
const ALWAYS_SHARE =
Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_ALWAYS_SHARE;
const NEVER_SHARE =
Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_NEVER_SHARE;
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
- let actions = [{
- label: gBrowserBundle.GetStringFromName("geolocation.shareLocation"),
+ return [{
+ label: gBrowserBundle.GetStringFromName("geolocation.allowLocation"),
accessKey:
- gBrowserBundle.GetStringFromName("geolocation.shareLocation.accesskey"),
+ gBrowserBundle.GetStringFromName("geolocation.allowLocation.accesskey"),
action: null,
expireType: null,
- callback: function() {
- secHistogram.add(SHARE_LOCATION);
+ callback: function(state) {
+ if (state && state.checkboxChecked) {
+ secHistogram.add(ALWAYS_SHARE);
+ } else {
+ secHistogram.add(SHARE_LOCATION);
+ }
+ },
+ }, {
+ label: gBrowserBundle.GetStringFromName("geolocation.dontAllowLocation"),
+ accessKey:
+ gBrowserBundle.GetStringFromName("geolocation.dontAllowLocation.accesskey"),
+ action: Ci.nsIPermissionManager.DENY_ACTION,
+ expireType: PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal) ?
+ Ci.nsIPermissionManager.EXPIRE_SESSION :
+ null,
+ callback: function(state) {
+ if (state && state.checkboxChecked) {
+ secHistogram.add(NEVER_SHARE);
+ }
},
}];
-
- if (!this.principal.URI.schemeIs("file")) {
- // Always share location action.
- actions.push({
- label: gBrowserBundle.GetStringFromName("geolocation.alwaysShareLocation"),
- accessKey:
- gBrowserBundle.GetStringFromName("geolocation.alwaysShareLocation.accesskey"),
- action: Ci.nsIPermissionManager.ALLOW_ACTION,
- expireType: null,
- callback: function() {
- secHistogram.add(ALWAYS_SHARE);
- },
- });
-
- // Never share location action.
- actions.push({
- label: gBrowserBundle.GetStringFromName("geolocation.neverShareLocation"),
- accessKey:
- gBrowserBundle.GetStringFromName("geolocation.neverShareLocation.accesskey"),
- action: Ci.nsIPermissionManager.DENY_ACTION,
- expireType: null,
- callback: function() {
- secHistogram.add(NEVER_SHARE);
- },
- });
- }
-
- return actions;
},
onBeforeShow() {
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
const SHOW_REQUEST = Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST;
secHistogram.add(SHOW_REQUEST);
},
};
@@ -516,81 +531,71 @@ DesktopNotificationPermissionPrompt.prot
get permissionKey() {
return "desktop-notification";
},
get popupOptions() {
let learnMoreURL =
Services.urlFormatter.formatURLPref("app.support.baseURL") + "push";
- // The eventCallback is bound to the Notification that's being
- // shown. We'll stash a reference to this in the closure so that
- // the request can be cancelled.
- let prompt = this;
+ let checkbox = {
+ show: true,
+ checked: true,
+ label: gBrowserBundle.GetStringFromName("webNotifications.remember")
+ };
- let eventCallback = function(type) {
- if (type == "dismissed") {
- // Bug 1259148: Hide the doorhanger icon. Unlike other permission
- // doorhangers, the user can't restore the doorhanger using the icon
- // in the location bar. Instead, the site will be notified that the
- // doorhanger was dismissed.
- this.remove();
- prompt.request.cancel();
- }
- };
+ // In PB mode, the "always remember" checkbox should only remember for the
+ // session.
+ if (PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal)) {
+ checkbox.label =
+ gBrowserBundle.GetStringFromName("webNotifications.rememberForSession");
+ }
return {
learnMoreURL,
- eventCallback,
+ checkbox,
+ displayURI: false
};
},
get notificationID() {
return "web-notifications";
},
get anchorID() {
return "web-notifications-notification-icon";
},
get message() {
- return gBrowserBundle.GetStringFromName("webNotifications.receiveFromSite");
+ let hostPort = "<>";
+ try {
+ hostPort = this.principal.URI.hostPort;
+ } catch (ex) { }
+ return gBrowserBundle.formatStringFromName("webNotifications.receiveFromSite2",
+ [hostPort], 1);
},
get promptActions() {
- let promptActions;
- // Only show "allow for session" in PB mode, we don't
- // support "allow for session" in non-PB mode.
- if (PrivateBrowsingUtils.isBrowserPrivate(this.browser)) {
- promptActions = [
- {
- label: gBrowserBundle.GetStringFromName("webNotifications.receiveForSession"),
- accessKey:
- gBrowserBundle.GetStringFromName("webNotifications.receiveForSession.accesskey"),
- action: Ci.nsIPermissionManager.ALLOW_ACTION,
- expireType: Ci.nsIPermissionManager.EXPIRE_SESSION,
- }
- ];
- } else {
- promptActions = [
- {
- label: gBrowserBundle.GetStringFromName("webNotifications.alwaysReceive"),
- accessKey:
- gBrowserBundle.GetStringFromName("webNotifications.alwaysReceive.accesskey"),
- action: Ci.nsIPermissionManager.ALLOW_ACTION,
- expireType: null,
- },
- {
- label: gBrowserBundle.GetStringFromName("webNotifications.neverShow"),
- accessKey:
- gBrowserBundle.GetStringFromName("webNotifications.neverShow.accesskey"),
- action: Ci.nsIPermissionManager.DENY_ACTION,
- expireType: null,
- },
- ];
- }
-
- return promptActions;
+ return [
+ {
+ label: gBrowserBundle.GetStringFromName("webNotifications.allow"),
+ accessKey:
+ gBrowserBundle.GetStringFromName("webNotifications.allow.accesskey"),
+ action: Ci.nsIPermissionManager.ALLOW_ACTION,
+ expireType: PrivateBrowsingUtils.isBrowserPrivate(this.browser) ?
+ Ci.nsIPermissionManager.EXPIRE_SESSION :
+ null,
+ },
+ {
+ label: gBrowserBundle.GetStringFromName("webNotifications.dontAllow"),
+ accessKey:
+ gBrowserBundle.GetStringFromName("webNotifications.dontAllow.accesskey"),
+ action: Ci.nsIPermissionManager.DENY_ACTION,
+ expireType: PrivateBrowsingUtils.isBrowserPrivate(this.browser) ?
+ Ci.nsIPermissionManager.EXPIRE_SESSION :
+ null,
+ },
+ ];
},
};
PermissionUI.DesktopNotificationPermissionPrompt =
DesktopNotificationPermissionPrompt;
--- a/browser/modules/test/browser_PermissionUI.js
+++ b/browser/modules/test/browser_PermissionUI.js
@@ -247,16 +247,23 @@ add_task(function* test_with_permission_
let TestPrompt = {
__proto__: PermissionUI.PermissionPromptForRequestPrototype,
request: mockRequest,
notificationID: kTestNotificationID,
permissionKey: kTestPermissionKey,
message: kTestMessage,
promptActions: [mainAction, secondaryAction],
+ popupOptions: {
+ checkbox: {
+ label: "Remember this decision",
+ show: true,
+ checked: true
+ }
+ }
};
let shownPromise =
BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
TestPrompt.prompt();
yield shownPromise;
let notification =
PopupNotifications.getNotification(kTestNotificationID, browser);
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -13,16 +13,20 @@ const Ci = Components.interfaces;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
+XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
+ return Services.strings.createBundle("chrome://branding/locale/brand.properties");
+});
+
this.webrtcUI = {
init: function() {
Services.obs.addObserver(maybeAddMenuIndicator, "browser-delayed-startup-finished", false);
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
.getService(Ci.nsIMessageBroadcaster);
ppmm.addMessageListener("webrtc:UpdatingIndicators", this);
ppmm.addMessageListener("webrtc:UpdateGlobalIndicators", this);
@@ -150,30 +154,20 @@ this.webrtcUI = {
});
Cc["@mozilla.org/widget/macdocksupport;1"].getService(Ci.nsIMacDockSupport)
.activateApplication(true);
return;
}
identityBox.click();
},
- updateMainActionLabel: function(aMenuList) {
+ updateWarningLabel: function(aMenuList) {
let type = aMenuList.selectedItem.getAttribute("devicetype");
let document = aMenuList.ownerDocument;
document.getElementById("webRTC-all-windows-shared").hidden = type != "Screen";
-
- // If we are also requesting audio in addition to screen sharing,
- // always use a generic label.
- if (!document.getElementById("webRTC-selectMicrophone").hidden)
- type = "";
-
- let bundle = document.defaultView.gNavigatorBundle;
- let stringId = "getUserMedia.share" + (type || "SelectedItems") + ".label";
- let popupnotification = aMenuList.parentNode.parentNode;
- popupnotification.setAttribute("buttonlabel", bundle.getString(stringId));
},
receiveMessage: function(aMessage) {
switch (aMessage.name) {
// Add-ons can override stock permission behavior by doing:
//
// var stockReceiveMessage = webrtcUI.receiveMessage;
@@ -289,79 +283,71 @@ function getHost(uri, href) {
function prompt(aBrowser, aRequest) {
let {audioDevices: audioDevices, videoDevices: videoDevices,
sharingScreen: sharingScreen, sharingAudio: sharingAudio,
requestTypes: requestTypes} = aRequest;
let uri = Services.io.newURI(aRequest.documentURI, null, null);
let host = getHost(uri);
let chromeDoc = aBrowser.ownerDocument;
let stringBundle = chromeDoc.defaultView.gNavigatorBundle;
- let stringId = "getUserMedia.share" + requestTypes.join("And") + ".message";
+ let stringId = "getUserMedia.share" + requestTypes.join("And") + "2.message";
let message = stringBundle.getFormattedString(stringId, [host]);
- let mainLabel;
- if (sharingScreen || sharingAudio) {
- mainLabel = stringBundle.getString("getUserMedia.shareSelectedItems.label");
- } else {
- let string = stringBundle.getString("getUserMedia.shareSelectedDevices.label");
- mainLabel = PluralForm.get(requestTypes.length, string);
- }
-
let notification; // Used by action callbacks.
let mainAction = {
- label: mainLabel,
- accessKey: stringBundle.getString("getUserMedia.shareSelectedDevices.accesskey"),
+ 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.
callback: function() {}
};
let secondaryActions = [
{
- label: stringBundle.getString("getUserMedia.denyRequest.label"),
- accessKey: stringBundle.getString("getUserMedia.denyRequest.accesskey"),
- callback: function() {
+ label: stringBundle.getString("getUserMedia.dontAllow.label"),
+ accessKey: stringBundle.getString("getUserMedia.dontAllow.accesskey"),
+ callback: function(aState) {
denyRequest(notification.browser, aRequest);
+ if (aState && aState.checkboxChecked) {
+ let perms = Services.perms;
+ if (audioDevices.length)
+ perms.add(uri, "microphone", perms.DENY_ACTION);
+ if (videoDevices.length)
+ perms.add(uri, "camera", perms.DENY_ACTION);
+ }
}
}
];
- // Bug 1037438: implement 'never' for screen sharing.
- if (!sharingScreen && !sharingAudio) {
- secondaryActions.push({
- label: stringBundle.getString("getUserMedia.never.label"),
- accessKey: stringBundle.getString("getUserMedia.never.accesskey"),
- callback: function() {
- denyRequest(notification.browser, aRequest);
- // Let someone save "Never" for http sites so that they can be stopped from
- // bothering you with doorhangers.
- let perms = Services.perms;
- if (audioDevices.length)
- perms.add(uri, "microphone", perms.DENY_ACTION);
- if (videoDevices.length)
- perms.add(uri, "camera", perms.DENY_ACTION);
- }
- });
- }
+
+ let productName = gBrandBundle.GetStringFromName("brandShortName");
- if (aRequest.secure && !sharingScreen && !sharingAudio) {
- // Don't show the 'Always' action if the connection isn't secure, or for
- // screen/audio sharing (because we can't guess which window the user wants
- // to share without prompting).
- secondaryActions.unshift({
- label: stringBundle.getString("getUserMedia.always.label"),
- accessKey: stringBundle.getString("getUserMedia.always.accesskey"),
- callback: function(aState) {
- mainAction.callback(aState, true);
- }
- });
+ // Disable the permanent 'Allow' action if the connection isn't secure, or for
+ // screen/audio sharing (because we can't guess which window the user wants to
+ // share without prompting).
+ let reasonForNoPermanentAllow = "";
+ if (sharingScreen) {
+ reasonForNoPermanentAllow = "getUserMedia.reasonForNoPermanentAllow.screen";
+ } else if (sharingAudio) {
+ reasonForNoPermanentAllow = "getUserMedia.reasonForNoPermanentAllow.audio";
+ } else if (!aRequest.secure) {
+ reasonForNoPermanentAllow = "getUserMedia.reasonForNoPermanentAllow.insecure";
}
let options = {
persistent: true,
+ hideClose: true,
+ checkbox: {
+ label: stringBundle.getString("getUserMedia.remember"),
+ checkedState: reasonForNoPermanentAllow ? {
+ disableMainAction: true,
+ warningLabel: stringBundle.getFormattedString(reasonForNoPermanentAllow,
+ [productName])
+ } : undefined,
+ },
eventCallback: function(aTopic, aNewBrowser) {
if (aTopic == "swapping")
return true;
let doc = this.browser.ownerDocument;
// Clean-up video streams of screensharing previews.
if ((aTopic == "dismissed" || aTopic == "removed") &&
@@ -599,57 +585,58 @@ function prompt(aBrowser, aRequest) {
if (sharingScreen)
listScreenShareDevices(windowMenupopup, videoDevices);
else
listDevices(camMenupopup, videoDevices);
if (!sharingAudio)
listDevices(micMenupopup, audioDevices);
- this.mainAction.callback = function(aState, aRemember) {
+ this.mainAction.callback = function(aState) {
+ let remember = aState && aState.checkboxChecked;
let allowedDevices = [];
let perms = Services.perms;
if (videoDevices.length) {
let listId = "webRTC-select" + (sharingScreen ? "Window" : "Camera") + "-menulist";
let videoDeviceIndex = doc.getElementById(listId).value;
let allowCamera = videoDeviceIndex != "-1";
if (allowCamera) {
allowedDevices.push(videoDeviceIndex);
// Session permission will be removed after use
// (it's really one-shot, not for the entire session)
perms.add(uri, "MediaManagerVideo", perms.ALLOW_ACTION,
perms.EXPIRE_SESSION);
}
- if (aRemember) {
+ if (remember) {
perms.add(uri, "camera",
allowCamera ? perms.ALLOW_ACTION : perms.DENY_ACTION);
}
}
if (audioDevices.length) {
if (!sharingAudio) {
let audioDeviceIndex = doc.getElementById("webRTC-selectMicrophone-menulist").value;
let allowMic = audioDeviceIndex != "-1";
if (allowMic)
allowedDevices.push(audioDeviceIndex);
- if (aRemember) {
+ if (remember) {
perms.add(uri, "microphone",
allowMic ? perms.ALLOW_ACTION : perms.DENY_ACTION);
}
} else {
// Only one device possible for audio capture.
allowedDevices.push(0);
}
}
if (!allowedDevices.length) {
denyRequest(notification.browser, aRequest);
return;
}
- if (aRemember) {
+ if (remember) {
// Remember on which URIs we set persistent permissions so that we
// can remove them if the user clicks 'Stop Sharing'.
aBrowser._devicePermissionURIs = aBrowser._devicePermissionURIs || [];
aBrowser._devicePermissionURIs.push(uri);
}
let mm = notification.browser.messageManager;
mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
--- a/dom/notification/test/browser/browser_permission_dismiss.js
+++ b/dom/notification/test/browser/browser_permission_dismiss.js
@@ -91,21 +91,8 @@ add_task(function* test_requestPermissio
ok(!PopupNotifications.getNotification("web-notifications"),
"Should remove the doorhanger notification icon if denied");
is(Services.perms.testPermission(ORIGIN_URI, PERMISSION_NAME),
Services.perms.DENY_ACTION,
"Check permission in perm. manager");
});
-
-add_task(function* test_requestPermission_dismissed() {
- yield tabWithRequest(function() {
- PopupNotifications.panel.hidePopup();
- }, "default");
-
- ok(!PopupNotifications.getNotification("web-notifications"),
- "Should remove the doorhanger notification icon if dismissed");
-
- is(Services.perms.testPermission(ORIGIN_URI, PERMISSION_NAME),
- Services.perms.UNKNOWN_ACTION,
- "Check permission in perm. manager");
-});
--- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
+++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
@@ -767,35 +767,40 @@ LoginManagerPrompter.prototype = {
* @param {string} type
* This is "password-save" or "password-change" depending on the
* original notification type. This is used for telemetry and tests.
*/
_showLoginCaptureDoorhanger(login, type) {
let { browser } = this._getNotifyWindow();
let saveMsgNames = {
- prompt: login.username === "" ? "rememberLoginMsgNoUser"
- : "rememberLoginMsg",
- buttonLabel: "rememberLoginButtonText",
- buttonAccessKey: "rememberLoginButtonAccessKey",
+ prompt: login.username === "" ? "saveLoginMsgNoUser"
+ : "saveLoginMsg",
+ buttonLabel: "saveLoginButtonAllow.label",
+ buttonAccessKey: "saveLoginButtonAllow.accesskey",
+ secondaryButtonLabel: "saveLoginButtonDeny.label",
+ secondaryButtonAccessKey: "saveLoginButtonDeny.accesskey",
};
let changeMsgNames = {
prompt: login.username === "" ? "updateLoginMsgNoUser"
: "updateLoginMsg",
buttonLabel: "updateLoginButtonText",
buttonAccessKey: "updateLoginButtonAccessKey",
+ secondaryButtonLabel: "updateLoginButtonDeny.label",
+ secondaryButtonAccessKey: "updateLoginButtonDeny.accesskey",
};
let initialMsgNames = type == "password-save" ? saveMsgNames
: changeMsgNames;
let brandBundle = Services.strings.createBundle(BRAND_BUNDLE);
let brandShortName = brandBundle.GetStringFromName("brandShortName");
- let promptMsg = type == "password-save" ? this._getLocalizedString(saveMsgNames.prompt, [brandShortName])
+ let host = this._getShortDisplayHost(login.hostname);
+ let promptMsg = type == "password-save" ? this._getLocalizedString(saveMsgNames.prompt, [brandShortName, host])
: this._getLocalizedString(changeMsgNames.prompt);
let histogramName = type == "password-save" ? "PWMGR_PROMPT_REMEMBER_ACTION"
: "PWMGR_PROMPT_UPDATE_ACTION";
let histogram = Services.telemetry.getHistogramById(histogramName);
histogram.add(PROMPT_DISPLAYED);
let chromeDoc = browser.ownerDocument;
@@ -914,58 +919,68 @@ LoginManagerPrompter.prototype = {
} else {
this._updateLogin(logins[0], login);
}
} else {
Cu.reportError("Unexpected match of multiple logins.");
}
};
- // The main action is the "Remember" or "Update" button.
+ // The main action is the "Save" or "Update" button.
let mainAction = {
label: this._getLocalizedString(initialMsgNames.buttonLabel),
accessKey: this._getLocalizedString(initialMsgNames.buttonAccessKey),
callback: () => {
histogram.add(PROMPT_ADD_OR_UPDATE);
if (histogramName == "PWMGR_PROMPT_REMEMBER_ACTION") {
Services.obs.notifyObservers(null, 'LoginStats:NewSavedPassword', null);
}
readDataFromUI();
persistData();
browser.focus();
}
};
- // Include a "Never for this site" button when saving a new password.
- let secondaryActions = type == "password-save" ? [{
- label: this._getLocalizedString("notifyBarNeverRememberButtonText"),
- accessKey: this._getLocalizedString("notifyBarNeverRememberButtonAccessKey"),
+ let secondaryActions = [{
+ label: this._getLocalizedString(initialMsgNames.secondaryButtonLabel),
+ accessKey: this._getLocalizedString(initialMsgNames.secondaryButtonAccessKey),
callback: () => {
- histogram.add(PROMPT_NEVER);
- Services.logins.setLoginSavingEnabled(login.hostname, false);
+ histogram.add(PROMPT_NOTNOW);
browser.focus();
}
- }] : null;
+ }];
+ // Include a "Never for this site" button when saving a new password.
+ if (type == "password-save") {
+ secondaryActions.push({
+ label: this._getLocalizedString("notifyBarNeverRememberButtonText2"),
+ accessKey: this._getLocalizedString("notifyBarNeverRememberButtonAccessKey2"),
+ callback: () => {
+ histogram.add(PROMPT_NEVER);
+ Services.logins.setLoginSavingEnabled(login.hostname, false);
+ browser.focus();
+ }
+ });
+ }
let usernamePlaceholder = this._getLocalizedString("noUsernamePlaceholder");
let togglePasswordLabel = this._getLocalizedString("togglePasswordLabel");
let togglePasswordAccessKey = this._getLocalizedString("togglePasswordAccessKey");
this._getPopupNote().show(
browser,
"password",
promptMsg,
"password-notification-icon",
mainAction,
secondaryActions,
{
- displayURI: Services.io.newURI(login.hostname, null, null),
persistWhileVisible: true,
persistent: true,
passwordNotificationType: type,
+ hideClose: true,
eventCallback: function(topic) {
switch (topic) {
case "showing":
currentNotification = this;
chromeDoc.getElementById("password-notification-password")
.removeAttribute("focused");
chromeDoc.getElementById("password-notification-username")
.removeAttribute("focused");
@@ -1020,19 +1035,19 @@ LoginManagerPrompter.prototype = {
* The login captured from the form.
*/
_showSaveLoginNotification : function(aNotifyObj, aLogin) {
// Ugh. We can't use the strings from the popup window, because they
// have the access key marked in the string (eg "Mo&zilla"), along
// with some weird rules for handling access keys that do not occur
// in the string, for L10N. See commonDialog.js's setLabelForNode().
var neverButtonText =
- this._getLocalizedString("notifyBarNeverRememberButtonText");
+ this._getLocalizedString("notifyBarNeverRememberButtonText2");
var neverButtonAccessKey =
- this._getLocalizedString("notifyBarNeverRememberButtonAccessKey");
+ this._getLocalizedString("notifyBarNeverRememberButtonAccessKey2");
var rememberButtonText =
this._getLocalizedString("notifyBarRememberPasswordButtonText");
var rememberButtonAccessKey =
this._getLocalizedString("notifyBarRememberPasswordButtonAccessKey");
var displayHost = this._getShortDisplayHost(aLogin.hostname);
var notificationText = this._getLocalizedString(
"rememberPasswordMsgNoUsername",
--- a/toolkit/components/passwordmgr/test/browser/browser_capture_doorhanger.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_capture_doorhanger.js
@@ -375,37 +375,37 @@ add_task(function* test_changePLoginOnPF
add_task(function* test_checkUPSaveText() {
info("Check text on a user+pass notification popup");
yield testSubmittingLoginForm("subtst_notifications_1.html", function*(fieldValues) {
is(fieldValues.username, "notifyu1", "Checking submitted username");
is(fieldValues.password, "notifyp1", "Checking submitted password");
let notif = getCaptureDoorhanger("password-save");
ok(notif, "got notification popup");
- // Check the text, which comes from the localized saveLoginText string.
+ // Check the text, which comes from the localized saveLoginMsg string.
let notificationText = notif.message;
- let expectedText = "Would you like " + BRAND_SHORT_NAME + " to remember this login?";
+ let expectedText = "Would you like " + BRAND_SHORT_NAME + " to save this login for example.com?";
is(expectedText, notificationText, "Checking text: " + notificationText);
notif.remove();
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
add_task(function* test_checkPSaveText() {
info("Check text on a pass-only notification popup");
yield testSubmittingLoginForm("subtst_notifications_6.html", function*(fieldValues) {
is(fieldValues.username, "null", "Checking submitted username");
is(fieldValues.password, "notifyp1", "Checking submitted password");
let notif = getCaptureDoorhanger("password-save");
ok(notif, "got notification popup");
- // Check the text, which comes from the localized saveLoginTextNoUser string.
+ // Check the text, which comes from the localized saveLoginMsgNoUser string.
let notificationText = notif.message;
- let expectedText = "Would you like " + BRAND_SHORT_NAME + " to remember this password?";
+ let expectedText = "Would you like " + BRAND_SHORT_NAME + " to save this password for example.com?";
is(expectedText, notificationText, "Checking text: " + notificationText);
notif.remove();
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
add_task(function* test_capture2pw0un() {
--- a/toolkit/components/passwordmgr/test/browser/head.js
+++ b/toolkit/components/passwordmgr/test/browser/head.js
@@ -68,17 +68,17 @@ function checkOnlyLoginWasUsedTwice({ ju
} else {
is(logins[0].timeCreated, logins[0].timePasswordChanged, "timeChanged not updated");
}
}
// Begin popup notification (doorhanger) functions //
const REMEMBER_BUTTON = 0;
-const NEVER_BUTTON = 1;
+const NEVER_BUTTON = 2;
const CHANGE_BUTTON = 0;
const DONT_CHANGE_BUTTON = 1;
/**
* Checks if we have a password capture popup notification
* of the right type and with the right label.
*
@@ -89,17 +89,17 @@ const DONT_CHANGE_BUTTON = 1;
function getCaptureDoorhanger(aKind, popupNotifications = PopupNotifications) {
ok(true, "Looking for " + aKind + " popup notification");
let notification = popupNotifications.getNotification("password");
if (notification) {
is(notification.options.passwordNotificationType, aKind, "Notification type matches.");
if (aKind == "password-change") {
is(notification.mainAction.label, "Update", "Main action label matches update doorhanger.");
} else if (aKind == "password-save") {
- is(notification.mainAction.label, "Remember", "Main action label matches save doorhanger.");
+ is(notification.mainAction.label, "Save", "Main action label matches save doorhanger.");
}
}
return notification;
}
/**
* Clicks the specified popup notification button.
*
--- a/toolkit/locales/en-US/chrome/passwordmgr/passwordmgr.properties
+++ b/toolkit/locales/en-US/chrome/passwordmgr/passwordmgr.properties
@@ -1,42 +1,47 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
rememberValue = Use Password Manager to remember this value.
rememberPassword = Use Password Manager to remember this password.
savePasswordTitle = Confirm
-# LOCALIZATION NOTE (rememberLoginMsg, rememberLoginMsgNoUser): %S is brandShortName
-rememberLoginMsg = Would you like %S to remember this login?
-rememberLoginMsgNoUser = Would you like %S to remember this password?
-rememberLoginButtonText = Remember
-rememberLoginButtonAccessKey = R
+# LOCALIZATION NOTE (saveLoginMsg, saveLoginMsgNoUser):
+# %1$S is brandShortName, %2$S is the login's hostname.
+saveLoginMsg = Would you like %1$S to save this login for %2$S?
+saveLoginMsgNoUser = Would you like %1$S to save this password for %2$S?
+saveLoginButtonAllow.label = Save
+saveLoginButtonAllow.accesskey = S
+saveLoginButtonDeny.label = Don’t Save
+saveLoginButtonDeny.accesskey = D
updateLoginMsg = Would you like to update this login?
updateLoginMsgNoUser = Would you like to update this password?
updateLoginButtonText = Update
updateLoginButtonAccessKey = U
+updateLoginButtonDeny.label = Don’t Update
+updateLoginButtonDeny.accesskey = D
# LOCALIZATION NOTE (rememberPasswordMsg):
# 1st string is the username for the login, 2nd is the login's hostname.
# Note that long usernames may be truncated.
rememberPasswordMsg = Would you like to remember the password for “%1$S” on %2$S?
# LOCALIZATION NOTE (rememberPasswordMsgNoUsername):
# String is the login's hostname.
rememberPasswordMsgNoUsername = Would you like to remember the password on %S?
# LOCALIZATION NOTE (noUsernamePlaceholder):
# This is displayed in place of the username when it is missing.
noUsernamePlaceholder=No username
togglePasswordLabel=Show password
togglePasswordAccessKey=S
notNowButtonText = &Not Now
notifyBarNotNowButtonText = Not Now
notifyBarNotNowButtonAccessKey = N
neverForSiteButtonText = Ne&ver for This Site
-notifyBarNeverRememberButtonText = Never Remember Password for This Site
-notifyBarNeverRememberButtonAccessKey = e
+notifyBarNeverRememberButtonText2 = Never Save
+notifyBarNeverRememberButtonAccessKey2 = e
rememberButtonText = &Remember
notifyBarRememberPasswordButtonText = Remember Password
notifyBarRememberPasswordButtonAccessKey = R
passwordChangeTitle = Confirm Password Change
# LOCALIZATION NOTE (updatePasswordMsg):
# String is the username for the login.
updatePasswordMsg = Would you like to update the saved password for “%S”?
updatePasswordMsgNoUser = Would you like to update the saved password?