| 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(); |