mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 06:35:42 +00:00
e32bf05b2b
--HG-- extra : rebase_source : f11a0bd549f7e13891f34bf56167c03c17468f9f
264 lines
7.4 KiB
JavaScript
264 lines
7.4 KiB
JavaScript
/* 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/. */
|
|
|
|
"use strict";
|
|
|
|
const React = require("devtools/client/shared/vendor/react");
|
|
const Immutable = require("devtools/client/shared/vendor/immutable");
|
|
const { LocalizationHelper } = require("devtools/shared/l10n");
|
|
const l10n = new LocalizationHelper("devtools/locale/components.properties");
|
|
|
|
// Shortcuts
|
|
const { PropTypes, createClass, DOM } = React;
|
|
const { div, span, button } = DOM;
|
|
|
|
// Priority Levels
|
|
const PriorityLevels = {
|
|
PRIORITY_INFO_LOW: 1,
|
|
PRIORITY_INFO_MEDIUM: 2,
|
|
PRIORITY_INFO_HIGH: 3,
|
|
PRIORITY_WARNING_LOW: 4,
|
|
PRIORITY_WARNING_MEDIUM: 5,
|
|
PRIORITY_WARNING_HIGH: 6,
|
|
PRIORITY_CRITICAL_LOW: 7,
|
|
PRIORITY_CRITICAL_MEDIUM: 8,
|
|
PRIORITY_CRITICAL_HIGH: 9,
|
|
PRIORITY_CRITICAL_BLOCK: 10,
|
|
};
|
|
|
|
/**
|
|
* This component represents Notification Box - HTML alternative for
|
|
* <xul:notifictionbox> binding.
|
|
*
|
|
* See also MDN for more info about <xul:notificationbox>:
|
|
* https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/notificationbox
|
|
*/
|
|
var NotificationBox = createClass({
|
|
displayName: "NotificationBox",
|
|
|
|
propTypes: {
|
|
// List of notifications appended into the box.
|
|
notifications: PropTypes.arrayOf(PropTypes.shape({
|
|
// label to appear on the notification.
|
|
label: PropTypes.string.isRequired,
|
|
|
|
// Value used to identify the notification
|
|
value: PropTypes.string.isRequired,
|
|
|
|
// URL of image to appear on the notification. If "" then an icon
|
|
// appropriate for the priority level is used.
|
|
image: PropTypes.string.isRequired,
|
|
|
|
// Notification priority; see Priority Levels.
|
|
priority: PropTypes.number.isRequired,
|
|
|
|
// Array of button descriptions to appear on the notification.
|
|
buttons: PropTypes.arrayOf(PropTypes.shape({
|
|
// Function to be called when the button is activated.
|
|
// This function is passed three arguments:
|
|
// 1) the NotificationBox component the button is associated with
|
|
// 2) the button description as passed to appendNotification.
|
|
// 3) the element which was the target of the button press event.
|
|
// If the return value from this function is not True, then the
|
|
// notification is closed. The notification is also not closed
|
|
// if an error is thrown.
|
|
callback: PropTypes.func.isRequired,
|
|
|
|
// The label to appear on the button.
|
|
label: PropTypes.string.isRequired,
|
|
|
|
// The accesskey attribute set on the <button> element.
|
|
accesskey: PropTypes.string,
|
|
})),
|
|
|
|
// A function to call to notify you of interesting things that happen
|
|
// with the notification box.
|
|
eventCallback: PropTypes.func,
|
|
})),
|
|
|
|
// Message that should be shown when hovering over the close button
|
|
closeButtonTooltip: PropTypes.string
|
|
},
|
|
|
|
getDefaultProps() {
|
|
return {
|
|
closeButtonTooltip: l10n.getStr("notificationBox.closeTooltip")
|
|
};
|
|
},
|
|
|
|
getInitialState() {
|
|
return {
|
|
notifications: new Immutable.OrderedMap()
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Create a new notification and display it. If another notification is
|
|
* already present with a higher priority, the new notification will be
|
|
* added behind it. See `propTypes` for arguments description.
|
|
*/
|
|
appendNotification(label, value, image, priority, buttons = [],
|
|
eventCallback) {
|
|
// Priority level must be within expected interval
|
|
// (see priority levels at the top of this file).
|
|
if (priority < PriorityLevels.PRIORITY_INFO_LOW ||
|
|
priority > PriorityLevels.PRIORITY_CRITICAL_BLOCK) {
|
|
throw new Error("Invalid notification priority " + priority);
|
|
}
|
|
|
|
// Custom image URL is not supported yet.
|
|
if (image) {
|
|
throw new Error("Custom image URL is not supported yet");
|
|
}
|
|
|
|
let type = "warning";
|
|
if (priority >= PriorityLevels.PRIORITY_CRITICAL_LOW) {
|
|
type = "critical";
|
|
} else if (priority <= PriorityLevels.PRIORITY_INFO_HIGH) {
|
|
type = "info";
|
|
}
|
|
|
|
let notifications = this.state.notifications.set(value, {
|
|
label: label,
|
|
value: value,
|
|
image: image,
|
|
priority: priority,
|
|
type: type,
|
|
buttons: buttons,
|
|
eventCallback: eventCallback,
|
|
});
|
|
|
|
// High priorities must be on top.
|
|
notifications = notifications.sortBy((val, key) => {
|
|
return -val.priority;
|
|
});
|
|
|
|
this.setState({
|
|
notifications: notifications
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Remove specific notification from the list.
|
|
*/
|
|
removeNotification(notification) {
|
|
this.close(this.state.notifications.get(notification.value));
|
|
},
|
|
|
|
/**
|
|
* Returns an object that represents a notification. It can be
|
|
* used to close it.
|
|
*/
|
|
getNotificationWithValue(value) {
|
|
let notification = this.state.notifications.get(value);
|
|
if (!notification) {
|
|
return null;
|
|
}
|
|
|
|
// Return an object that can be used to remove the notification
|
|
// later (using `removeNotification` method) or directly close it.
|
|
return Object.assign({}, notification, {
|
|
close: () => {
|
|
this.close(notification);
|
|
}
|
|
});
|
|
},
|
|
|
|
getCurrentNotification() {
|
|
return this.state.notifications.first();
|
|
},
|
|
|
|
/**
|
|
* Close specified notification.
|
|
*/
|
|
close(notification) {
|
|
if (!notification) {
|
|
return;
|
|
}
|
|
|
|
if (notification.eventCallback) {
|
|
notification.eventCallback("removed");
|
|
}
|
|
|
|
this.setState({
|
|
notifications: this.state.notifications.remove(notification.value)
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Render a button. A notification can have a set of custom buttons.
|
|
* These are used to execute custom callback.
|
|
*/
|
|
renderButton(props, notification) {
|
|
let onClick = event => {
|
|
if (props.callback) {
|
|
let result = props.callback(this, props, event.target);
|
|
if (!result) {
|
|
this.close(notification);
|
|
}
|
|
event.stopPropagation();
|
|
}
|
|
};
|
|
|
|
return (
|
|
button({
|
|
key: props.label,
|
|
className: "notification-button",
|
|
accesskey: props.accesskey,
|
|
onClick: onClick},
|
|
props.label
|
|
)
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Render a notification.
|
|
*/
|
|
renderNotification(notification) {
|
|
return (
|
|
div({
|
|
key: notification.value,
|
|
className: "notification",
|
|
"data-type": notification.type},
|
|
div({className: "notificationInner"},
|
|
div({className: "details"},
|
|
div({
|
|
className: "messageImage",
|
|
"data-type": notification.type}),
|
|
span({className: "messageText"},
|
|
notification.label
|
|
),
|
|
notification.buttons.map(props =>
|
|
this.renderButton(props, notification)
|
|
)
|
|
),
|
|
div({
|
|
className: "messageCloseButton",
|
|
title: this.props.closeButtonTooltip,
|
|
onClick: this.close.bind(this, notification)}
|
|
)
|
|
)
|
|
)
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Render the top (highest priority) notification. Only one
|
|
* notification is rendered at a time.
|
|
*/
|
|
render() {
|
|
let notification = this.state.notifications.first();
|
|
let content = notification ?
|
|
this.renderNotification(notification) :
|
|
null;
|
|
|
|
return div({className: "notificationbox"},
|
|
content
|
|
);
|
|
},
|
|
});
|
|
|
|
module.exports.NotificationBox = NotificationBox;
|
|
module.exports.PriorityLevels = PriorityLevels;
|