Bug 1291642 - Part 1 - Add an optional checkbox to PopupNotifications. r=paolo

MozReview-Commit-ID: 9wzV6kNt5pV

--HG--
extra : rebase_source : b0fa1dea0c23197a795076e1cb3c1be091c18872
This commit is contained in:
Johann Hofmann 2016-09-06 18:36:23 +02:00
Родитель 2963c2ebb3
Коммит aa0121a4fe
5 изменённых файлов: 107 добавлений и 16 удалений

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

@ -347,8 +347,8 @@ function prompt(aBrowser, aRequest) {
secondaryActions.unshift({
label: stringBundle.getString("getUserMedia.always.label"),
accessKey: stringBundle.getString("getUserMedia.always.accesskey"),
callback: function () {
mainAction.callback(true);
callback: function (aState) {
mainAction.callback(aState, true);
}
});
}
@ -519,7 +519,7 @@ function prompt(aBrowser, aRequest) {
if (!sharingAudio)
listDevices(micMenupopup, audioDevices);
this.mainAction.callback = function(aRemember) {
this.mainAction.callback = function(aState, aRemember) {
let allowedDevices = [];
let perms = Services.perms;
if (videoDevices.length) {

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

@ -493,6 +493,9 @@
<children includes="popupnotificationcontent"/>
<xul:label class="text-link popup-notification-learnmore-link"
xbl:inherits="onclick=learnmoreclick,href=learnmoreurl">&learnMore;</xul:label>
<xul:checkbox anonid="checkbox"
xbl:inherits="hidden=checkboxhidden,checked=checkboxchecked,label=checkboxlabel,oncommand=checkboxcommand" />
<xul:description class="popup-notification-warning" xbl:inherits="hidden=warninghidden,xbl:text=warninglabel"/>
<xul:spacer flex="1"/>
<xul:hbox class="popup-notification-button-container"
pack="end" align="center">
@ -500,7 +503,7 @@
<xul:button anonid="button"
class="popup-notification-menubutton"
type="menu-button"
xbl:inherits="oncommand=buttoncommand,onpopupshown=buttonpopupshown,label=buttonlabel,accesskey=buttonaccesskey">
xbl:inherits="oncommand=buttoncommand,onpopupshown=buttonpopupshown,label=buttonlabel,accesskey=buttonaccesskey,disabled=mainactiondisabled">
<xul:menupopup anonid="menupopup"
xbl:inherits="oncommand=menucommand">
<children/>
@ -516,6 +519,9 @@
<stylesheet src="chrome://global/skin/notification.css"/>
</resources>
<implementation>
<field name="checkbox" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "checkbox");
</field>
<field name="closebutton" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "closebutton");
</field>

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

@ -55,6 +55,18 @@ function getAnchorFromBrowser(aBrowser, aAnchorID) {
return null;
}
function getNotificationFromElement(aElement) {
// Need to find the associated notification object, which is a bit tricky
// since it isn't associated with the element directly - this is kind of
// gross and very dependent on the structure of the popupnotification
// binding's content.
let notificationEl;
let parent = aElement;
while (parent && (parent = aElement.ownerDocument.getBindingParent(parent)))
notificationEl = parent;
return notificationEl;
}
/**
* Notification object describes a single popup notification.
*
@ -72,6 +84,8 @@ function Notification(id, message, anchorID, mainAction, secondaryActions,
this.options = options || {};
this._dismissed = false;
// Will become a boolean when manually toggled by the user.
this._checkboxChecked = null;
this.wasDismissed = false;
this.recordedTelemetryStats = new Set();
this.isPrivate = PrivateBrowsingUtils.isWindowPrivate(
@ -274,7 +288,8 @@ PopupNotifications.prototype = {
* - label (string): the button's label.
* - accessKey (string): the button's accessKey.
* - callback (function): a callback to be invoked when the button is
* pressed.
* pressed, is passed an object that contains the following fields:
* - checkboxChecked: (boolean) If the optional checkbox is checked.
* - [optional] dismiss (boolean): If this is true, the notification
* will be dismissed instead of removed after running the callback.
* If null, the notification will not have a button, and
@ -332,6 +347,26 @@ PopupNotifications.prototype = {
* removed when they would have otherwise been dismissed
* (i.e. any time the popup is closed due to user
* interaction).
* checkbox: An object that allows you to add a checkbox and
* control its behavior with these fields:
* label:
* (required) Label to be shown next to the checkbox.
* checked:
* (optional) Whether the checkbox should be checked
* by default. Defaults to false.
* checkedState:
* (optional) An object that allows you to customize
* the notification state when the checkbox is checked.
* disableMainAction:
* (optional) Whether the mainAction is disabled.
* Defaults to false.
* warningLabel:
* (optional) A (warning) text that is shown below the
* checkbox. Pass null to hide.
* uncheckedState:
* (optional) An object that allows you to customize
* the notification state when the checkbox is not checked.
* Has the same attributes as checkedState.
* hideNotNow: If true, indicates that the 'Not Now' menuitem should
* not be shown. If 'Not Now' is hidden, it needs to be
* replaced by another 'do nothing' item, so providing at
@ -705,6 +740,25 @@ PopupNotifications.prototype = {
}
}
let checkbox = n.options.checkbox;
if (checkbox && checkbox.label) {
let checked = n._checkboxChecked != null ? n._checkboxChecked : !!checkbox.checked;
popupnotification.setAttribute("checkboxhidden", "false");
popupnotification.setAttribute("checkboxchecked", checked);
popupnotification.setAttribute("checkboxlabel", checkbox.label);
popupnotification.setAttribute("checkboxcommand", "PopupNotifications._onCheckboxCommand(event);");
if (checked) {
this._setNotificationUIState(popupnotification, checkbox.checkedState);
} else {
this._setNotificationUIState(popupnotification, checkbox.uncheckedState);
}
} else {
popupnotification.setAttribute("checkboxhidden", "true");
}
this.panel.appendChild(popupnotification);
// The popupnotification may be hidden if we got it from the chrome
@ -713,6 +767,32 @@ PopupNotifications.prototype = {
}, this);
},
_setNotificationUIState(notification, state={}) {
notification.setAttribute("mainactiondisabled", state.disableMainAction || "false");
if (state.warningLabel) {
notification.setAttribute("warninglabel", state.warningLabel);
notification.setAttribute("warninghidden", "false");
} else {
notification.setAttribute("warninghidden", "true");
}
},
_onCheckboxCommand(event) {
let notificationEl = getNotificationFromElement(event.originalTarget);
let checked = notificationEl.checkbox.checked;
let notification = notificationEl.notification;
// Save checkbox state to be able to persist it when re-opening the doorhanger.
notification._checkboxChecked = checked;
if (checked) {
this._setNotificationUIState(notificationEl, notification.options.checkbox.checkedState);
} else {
this._setNotificationUIState(notificationEl, notification.options.checkbox.uncheckedState);
}
},
_showPanel: function PopupNotifications_showPanel(notificationsToShow, anchorElement) {
this.panel.hidden = false;
@ -1102,15 +1182,7 @@ PopupNotifications.prototype = {
},
_onButtonEvent(event, type) {
// Need to find the associated notification object, which is a bit tricky
// since it isn't associated with the button directly - this is kind of
// gross and very dependent on the structure of the popupnotification
// binding's content.
let target = event.originalTarget;
let notificationEl;
let parent = target;
while (parent && (parent = target.ownerDocument.getBindingParent(parent)))
notificationEl = parent;
let notificationEl = getNotificationFromElement(event.originalTarget);
if (!notificationEl)
throw "PopupNotifications._onButtonEvent: couldn't find notification element";
@ -1150,7 +1222,9 @@ PopupNotifications.prototype = {
notification._recordTelemetryStat(TELEMETRY_STAT_ACTION_1);
try {
notification.mainAction.callback.call();
notification.mainAction.callback.call(undefined, {
checkboxChecked: notificationEl.checkbox.checked
});
} catch (error) {
Cu.reportError(error);
}
@ -1169,12 +1243,15 @@ PopupNotifications.prototype = {
if (!target.action || !target.notification)
throw "menucommand target has no associated action/notification";
let notificationEl = target.parentElement;
event.stopPropagation();
target.notification._recordTelemetryStat(target.action.telemetryStatId);
try {
target.action.callback.call();
target.action.callback.call(undefined, {
checkboxChecked: notificationEl.checkbox.checked
});
} catch (error) {
Cu.reportError(error);
}

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

@ -200,3 +200,7 @@ notification[type="info"]:not([value="translation"]) .close-icon:not(:hover) {
.popup-notification-menubutton > .button-menubutton-button[disabled] {
opacity: 0.5;
}
.popup-notification-warning {
color: #aa1b08;
}

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

@ -207,3 +207,7 @@ XXX: apply styles to all themes until bug 509642 is fixed
.popup-notification-menubutton > .button-menubutton-button[disabled] {
opacity: 0.5;
}
@media (-moz-windows-default-theme) {
color: #aa1b08;
}