Index: lib/notification.js |
=================================================================== |
--- a/lib/notification.js |
+++ b/lib/notification.js |
@@ -25,15 +25,23 @@ |
let {Prefs} = require("prefs"); |
let {Downloader, Downloadable, MILLIS_IN_MINUTE, MILLIS_IN_HOUR, MILLIS_IN_DAY} = require("downloader"); |
let {Utils} = require("utils"); |
+let {Matcher} = require("matcher"); |
+let {Filter} = require("filterClasses"); |
let INITIAL_DELAY = 12 * MILLIS_IN_MINUTE; |
let CHECK_INTERVAL = 1 * MILLIS_IN_HOUR; |
let EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY; |
+let TYPE = { |
+ information: 0, |
+ question: 1, |
+ critical: 2 |
+}; |
+ |
+let listeners = {}; |
function getNumericalSeverity(notification) |
{ |
- let levels = {information: 0, critical: 1}; |
- return (notification.severity in levels ? levels[notification.severity] : levels.information); |
+ return (notification.type in TYPE ? TYPE[notification.type] : TYPE.information); |
} |
function saveNotificationData() |
@@ -60,6 +68,7 @@ |
* @type Downloader |
*/ |
let downloader = null; |
+let localData = []; |
/** |
* Regularly fetches notifications and decides which to show. |
@@ -118,7 +127,17 @@ |
{ |
try |
{ |
- Prefs.notificationdata.data = JSON.parse(responseText); |
+ let data = JSON.parse(responseText); |
+ for each (let notification in data.notifications) |
+ { |
+ if ("severity" in notification) |
+ { |
+ if (!("type" in notification)) |
+ notification.type = notification.severity; |
+ delete notification.severity; |
+ } |
+ } |
+ Prefs.notificationdata.data = data; |
} |
catch (e) |
{ |
@@ -142,10 +161,10 @@ |
/** |
* Determines which notification is to be shown next. |
- * @param {Array of Object} notifications active notifications |
+ * @param {String} url URL to match notifications to (optional) |
* @return {Object} notification to be shown, or null if there is none |
*/ |
- getNextToShow: function() |
+ getNextToShow: function(url) |
{ |
function checkTarget(target, parameter, name, version) |
{ |
@@ -154,11 +173,11 @@ |
return !((parameter in target && target[parameter] != name) || |
(minVersionKey in target && Services.vc.compare(version, target[minVersionKey]) < 0) || |
(maxVersionKey in target && Services.vc.compare(version, target[maxVersionKey]) > 0)); |
- |
} |
- if (typeof Prefs.notificationdata.data != "object" || !(Prefs.notificationdata.data.notifications instanceof Array)) |
- return null; |
+ let remoteData = []; |
+ if (typeof Prefs.notificationdata.data == "object" && Prefs.notificationdata.data.notifications instanceof Array) |
+ remoteData = Prefs.notificationdata.data.notifications; |
if (!(Prefs.notificationdata.shown instanceof Array)) |
{ |
@@ -166,15 +185,32 @@ |
saveNotificationData(); |
} |
+ let notifications = localData.concat(remoteData); |
+ if (notifications.length === 0) |
+ return null; |
+ |
let {addonName, addonVersion, application, applicationVersion, platform, platformVersion} = require("info"); |
- let notifications = Prefs.notificationdata.data.notifications; |
let notificationToShow = null; |
for each (let notification in notifications) |
{ |
- if ((typeof notification.severity === "undefined" || notification.severity === "information") |
+ if ((typeof notification.type === "undefined" || notification.type !== "critical") |
&& Prefs.notificationdata.shown.indexOf(notification.id) !== -1) |
continue; |
+ if (typeof url === "string" || notification.urlFilters instanceof Array) |
+ { |
+ if (typeof url === "string" && notification.urlFilters instanceof Array) |
+ { |
+ let matcher = new Matcher(); |
+ for each (let urlFilter in notification.urlFilters) |
+ matcher.add(Filter.fromText(urlFilter)); |
+ if (!matcher.matchesAny(url, "DOCUMENT", url)) |
+ continue; |
+ } |
+ else |
+ continue; |
+ } |
+ |
if (notification.targets instanceof Array) |
{ |
let match = false; |
@@ -199,13 +235,22 @@ |
if (notificationToShow && "id" in notificationToShow) |
{ |
- Prefs.notificationdata.shown.push(notificationToShow.id); |
- saveNotificationData(); |
+ if (notificationToShow.type !== "question") |
+ this.markAsShown(notificationToShow.id); |
} |
return notificationToShow; |
}, |
+ markAsShown: function(id) |
+ { |
+ if (Prefs.notificationdata.shown.indexOf(id) > -1) |
+ return; |
+ |
+ Prefs.notificationdata.shown.push(id); |
+ saveNotificationData(); |
+ }, |
+ |
/** |
* Localizes the texts of the supplied notification. |
* @param {Object} notification notification to translate |
@@ -221,9 +266,73 @@ |
for each (let key in textKeys) |
{ |
if (key in notification) |
- localizedTexts[key] = localize(notification[key], locale); |
+ { |
+ if (typeof notification[key] == "string") |
+ localizedTexts[key] = notification[key]; |
+ else |
+ localizedTexts[key] = localize(notification[key], locale); |
+ } |
} |
return localizedTexts; |
+ }, |
+ |
+ /** |
+ * Adds a local notification. |
+ * @param {Object} notification notification to add |
+ */ |
+ addNotification: function(notification) |
+ { |
+ if (localData.indexOf(notification) == -1) |
+ localData.push(notification); |
+ }, |
+ |
+ /** |
+ * Removes an existing local notification. |
+ * @param {Object} notification notification to remove |
+ */ |
+ removeNotification: function(notification) |
+ { |
+ let index = localData.indexOf(notification); |
+ if (index > -1) |
+ localData.splice(index, 1); |
+ }, |
+ |
+ /** |
+ * Adds a listener for question-type notifications |
+ */ |
+ addQuestionListener: function(/**string*/ id, /**function(approved)*/ listener) |
+ { |
+ if (!(id in listeners)) |
+ listeners[id] = []; |
+ if (listeners[id].indexOf(listener) === -1) |
+ listeners[id].push(listener); |
+ }, |
+ |
+ /** |
+ * Removes a listener that was previously added via addQuestionListener |
+ */ |
+ removeQuestionListener: function(/**string*/ id, /**function(approved)*/ listener) |
+ { |
+ if (!(id in listeners)) |
+ return; |
+ let index = listeners[id].indexOf(listener); |
+ if (index > -1) |
+ listeners[id].splice(index, 1); |
+ if (listeners[id].length === 0) |
+ delete listeners[id]; |
+ }, |
+ |
+ /** |
+ * Notifies listeners about interactions with a notification |
+ * @param {String} id notification ID |
+ * @param {Boolean} approved indicator whether notification has been approved or not |
+ */ |
+ triggerQuestionListeners: function(id, approved) |
+ { |
+ if (!(id in listeners)) |
+ return; |
+ for each (let listener in listeners[id]) |
+ listener(approved); |
} |
}; |
Notification.init(); |