Bug 1282768 - Part 3 - Convert permission notifications to use two buttons and a checkbox instead of multiple secondary actions. r=florian

MozReview-Commit-ID: KNf04CBaLKB

--HG--
extra : rebase_source : 6c89da5ce541922f55db3853a7bf6f3b6cbc74fa
This commit is contained in:
Panos Astithas 2016-11-20 18:40:26 +01:00
Родитель 64baf2d729
Коммит e0efffb708
15 изменённых файлов: 287 добавлений и 292 удалений

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

@ -5970,8 +5970,12 @@ var OfflineApps = {
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.
@ -6030,8 +6034,8 @@ var OfflineApps = {
]);
} 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);
@ -6039,19 +6043,20 @@ var OfflineApps = {
}
};
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,
@ -6133,12 +6138,13 @@ var IndexedDBPromptHelper = {
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;
}
@ -6146,8 +6152,8 @@ var IndexedDBPromptHelper = {
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);
@ -6156,8 +6162,8 @@ var IndexedDBPromptHelper = {
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);
@ -6167,7 +6173,10 @@ var IndexedDBPromptHelper = {
PopupNotifications.show(browser, topic, message,
this._notificationIcon, mainAction,
secondaryActions, { persistent: true });
secondaryActions, {
persistent: true,
hideClose: true,
});
}
};

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

@ -22,7 +22,7 @@
<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>

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

@ -48,7 +48,7 @@ var tests = [
}
},
{ id: "Test#2b",
run: function () {
run: function() {
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.secondaryActions.push({
label: "Extra Secondary Action",
@ -57,18 +57,18 @@ var tests = [
});
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",
@ -81,11 +81,11 @@ var tests = [
});
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");

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

@ -474,7 +474,7 @@ var gTests = [
},
{
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;
@ -494,16 +494,16 @@ var gTests = [
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);

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

@ -305,28 +305,17 @@ 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() {

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

@ -24,9 +24,9 @@ add_task(function* test() {
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();

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

@ -315,13 +315,11 @@ newWindowButton.tooltip=Open a new window (%S)
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=Dont 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
@ -368,24 +366,21 @@ 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=Dont 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=Dont 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.
@ -473,19 +468,19 @@ 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 tabs 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 tabs audio and your screen with %S?
getUserMedia.shareAudioCapture.message = Would you like to share this tabs 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 tabs 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 tabs audio and see your screen or application window?
getUserMedia.shareAudioCapture2.message = Will you allow %S to listen to this tabs 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
@ -515,22 +510,18 @@ getUserMedia.shareMonitor.label = Screen %S
# 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 = Dont 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 = Dont 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 tabs 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

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

@ -226,7 +226,10 @@ this.PermissionPromptPrototype = {
*
* 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 [];
@ -297,14 +300,14 @@ this.PermissionPromptPrototype = {
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,
@ -337,7 +340,9 @@ this.PermissionPromptPrototype = {
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,
@ -414,9 +419,25 @@ GeolocationPermissionPrompt.prototype = {
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() {
@ -430,9 +451,14 @@ GeolocationPermissionPrompt.prototype = {
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;
},
@ -449,44 +475,33 @@ GeolocationPermissionPrompt.prototype = {
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() {
@ -521,25 +536,23 @@ DesktopNotificationPermissionPrompt.prototype = {
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 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();
}
let checkbox = {
show: true,
checked: true,
label: gBrowserBundle.GetStringFromName("webNotifications.remember")
};
// 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
};
},
@ -552,43 +565,35 @@ DesktopNotificationPermissionPrompt.prototype = {
},
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,
},
];
},
};

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

@ -252,6 +252,13 @@ add_task(function* test_with_permission_key() {
permissionKey: kTestPermissionKey,
message: kTestMessage,
promptActions: [mainAction, secondaryAction],
popupOptions: {
checkbox: {
label: "Remember this decision",
show: true,
checked: true
}
}
};
let shownPromise =

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

@ -18,6 +18,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
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);
@ -155,20 +159,10 @@ this.webrtcUI = {
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) {
@ -294,21 +288,13 @@ function prompt(aBrowser, aRequest) {
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.
@ -317,46 +303,46 @@ function prompt(aBrowser, aRequest) {
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);
}
});
}
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);
}
});
let productName = gBrandBundle.GetStringFromName("brandShortName");
// 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;
@ -604,7 +590,8 @@ function prompt(aBrowser, aRequest) {
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) {
@ -618,7 +605,7 @@ function prompt(aBrowser, aRequest) {
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);
}
@ -629,7 +616,7 @@ function prompt(aBrowser, aRequest) {
let allowMic = audioDeviceIndex != "-1";
if (allowMic)
allowedDevices.push(audioDeviceIndex);
if (aRemember) {
if (remember) {
perms.add(uri, "microphone",
allowMic ? perms.ALLOW_ACTION : perms.DENY_ACTION);
}
@ -644,7 +631,7 @@ function prompt(aBrowser, 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 || [];

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

@ -96,16 +96,3 @@ add_task(function* test_requestPermission_denied() {
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");
});

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

@ -772,10 +772,12 @@ LoginManagerPrompter.prototype = {
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 = {
@ -783,6 +785,8 @@ LoginManagerPrompter.prototype = {
: "updateLoginMsg",
buttonLabel: "updateLoginButtonText",
buttonAccessKey: "updateLoginButtonAccessKey",
secondaryButtonLabel: "updateLoginButtonDeny.label",
secondaryButtonAccessKey: "updateLoginButtonDeny.accesskey",
};
let initialMsgNames = type == "password-save" ? saveMsgNames
@ -790,7 +794,8 @@ LoginManagerPrompter.prototype = {
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"
@ -919,7 +924,7 @@ LoginManagerPrompter.prototype = {
}
};
// 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),
@ -934,16 +939,26 @@ LoginManagerPrompter.prototype = {
}
};
// 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");
@ -957,10 +972,10 @@ LoginManagerPrompter.prototype = {
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":
@ -1025,9 +1040,9 @@ LoginManagerPrompter.prototype = {
// 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 =

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

@ -380,9 +380,9 @@ add_task(function* test_checkUPSaveText() {
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();
});
@ -398,9 +398,9 @@ add_task(function* test_checkPSaveText() {
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();
});

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

@ -73,7 +73,7 @@ function checkOnlyLoginWasUsedTwice({ justChanged }) {
// 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;
@ -94,7 +94,7 @@ function getCaptureDoorhanger(aKind, popupNotifications = PopupNotifications) {
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;

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

@ -5,15 +5,20 @@
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 = Dont 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 = Dont 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.
@ -30,8 +35,8 @@ 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