summaryrefslogtreecommitdiff
path: root/data/extensions/spyblock@gnu.org/lib/notification.js
diff options
context:
space:
mode:
authorRuben Rodriguez <ruben@gnu.org>2014-10-20 02:24:51 +0200
committerRuben Rodriguez <ruben@gnu.org>2014-10-20 02:24:51 +0200
commit6e7918b6ccb69876d339a320091fdee811445395 (patch)
tree31cb88ee438d652fddefca1193f70289a8b3dcc8 /data/extensions/spyblock@gnu.org/lib/notification.js
parent60e5b13c35d4d3ba21bb03b026750a0a414f6c77 (diff)
Generalize data directory
Diffstat (limited to 'data/extensions/spyblock@gnu.org/lib/notification.js')
-rw-r--r--data/extensions/spyblock@gnu.org/lib/notification.js339
1 files changed, 339 insertions, 0 deletions
diff --git a/data/extensions/spyblock@gnu.org/lib/notification.js b/data/extensions/spyblock@gnu.org/lib/notification.js
new file mode 100644
index 0000000..06e949e
--- /dev/null
+++ b/data/extensions/spyblock@gnu.org/lib/notification.js
@@ -0,0 +1,339 @@
+/*
+ * This file is part of Adblock Plus <http://adblockplus.org/>,
+ * Copyright (C) 2006-2014 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @fileOverview Handles notifications.
+ */
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+let {TimeLine} = require("timeline");
+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)
+{
+ return (notification.type in TYPE ? TYPE[notification.type] : TYPE.information);
+}
+
+function saveNotificationData()
+{
+ // HACK: JSON values aren't saved unless they are assigned a different object.
+ Prefs.notificationdata = JSON.parse(JSON.stringify(Prefs.notificationdata));
+}
+
+function localize(translations, locale)
+{
+ if (locale in translations)
+ return translations[locale];
+
+ let languagePart = locale.substring(0, locale.indexOf("-"));
+ if (languagePart && languagePart in translations)
+ return translations[languagePart];
+
+ let defaultLocale = "en-US";
+ return translations[defaultLocale];
+}
+
+/**
+ * The object providing actual downloading functionality.
+ * @type Downloader
+ */
+let downloader = null;
+let localData = [];
+
+/**
+ * Regularly fetches notifications and decides which to show.
+ * @class
+ */
+let Notification = exports.Notification =
+{
+ /**
+ * Called on module startup.
+ */
+ init: function()
+ {
+ TimeLine.enter("Entered Notification.init()");
+
+ downloader = new Downloader(this._getDownloadables.bind(this), INITIAL_DELAY, CHECK_INTERVAL);
+ onShutdown.add(function()
+ {
+ downloader.cancel();
+ });
+
+ downloader.onExpirationChange = this._onExpirationChange.bind(this);
+ downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this);
+ downloader.onDownloadError = this._onDownloadError.bind(this);
+
+ TimeLine.leave("Notification.init() done");
+ },
+
+ /**
+ * Yields a Downloadable instances for the notifications download.
+ */
+ _getDownloadables: function()
+ {
+ let downloadable = new Downloadable(Prefs.notificationurl);
+ if (typeof Prefs.notificationdata.lastError === "number")
+ downloadable.lastError = Prefs.notificationdata.lastError;
+ if (typeof Prefs.notificationdata.lastCheck === "number")
+ downloadable.lastCheck = Prefs.notificationdata.lastCheck;
+ if (typeof Prefs.notificationdata.data === "object" && "version" in Prefs.notificationdata.data)
+ downloadable.lastVersion = Prefs.notificationdata.data.version;
+ if (typeof Prefs.notificationdata.softExpiration === "number")
+ downloadable.softExpiration = Prefs.notificationdata.softExpiration;
+ if (typeof Prefs.notificationdata.hardExpiration === "number")
+ downloadable.hardExpiration = Prefs.notificationdata.hardExpiration;
+ yield downloadable;
+ },
+
+ _onExpirationChange: function(downloadable)
+ {
+ Prefs.notificationdata.lastCheck = downloadable.lastCheck;
+ Prefs.notificationdata.softExpiration = downloadable.softExpiration;
+ Prefs.notificationdata.hardExpiration = downloadable.hardExpiration;
+ saveNotificationData();
+ },
+
+ _onDownloadSuccess: function(downloadable, responseText, errorCallback, redirectCallback)
+ {
+ try
+ {
+ let data = JSON.parse(responseText);
+ for (let notification of data.notifications)
+ {
+ if ("severity" in notification)
+ {
+ if (!("type" in notification))
+ notification.type = notification.severity;
+ delete notification.severity;
+ }
+ }
+ Prefs.notificationdata.data = data;
+ }
+ catch (e)
+ {
+ Cu.reportError(e);
+ errorCallback("synchronize_invalid_data");
+ return;
+ }
+
+ Prefs.notificationdata.lastError = 0;
+ Prefs.notificationdata.downloadStatus = "synchronize_ok";
+ [Prefs.notificationdata.softExpiration, Prefs.notificationdata.hardExpiration] = downloader.processExpirationInterval(EXPIRATION_INTERVAL);
+ saveNotificationData();
+ },
+
+ _onDownloadError: function(downloadable, downloadURL, error, channelStatus, responseStatus, redirectCallback)
+ {
+ Prefs.notificationdata.lastError = Date.now();
+ Prefs.notificationdata.downloadStatus = error;
+ saveNotificationData();
+ },
+
+ /**
+ * Determines which notification is to be shown next.
+ * @param {String} url URL to match notifications to (optional)
+ * @return {Object} notification to be shown, or null if there is none
+ */
+ getNextToShow: function(url)
+ {
+ function checkTarget(target, parameter, name, version)
+ {
+ let minVersionKey = parameter + "MinVersion";
+ let maxVersionKey = parameter + "MaxVersion";
+ 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));
+ }
+
+ 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))
+ {
+ Prefs.notificationdata.shown = [];
+ saveNotificationData();
+ }
+
+ let notifications = localData.concat(remoteData);
+ if (notifications.length === 0)
+ return null;
+
+ let {addonName, addonVersion, application, applicationVersion, platform, platformVersion} = require("info");
+ let notificationToShow = null;
+ for (let notification of notifications)
+ {
+ 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 (let urlFilter of notification.urlFilters)
+ matcher.add(Filter.fromText(urlFilter));
+ if (!matcher.matchesAny(url, "DOCUMENT", url))
+ continue;
+ }
+ else
+ continue;
+ }
+
+ if (notification.targets instanceof Array)
+ {
+ let match = false;
+ for (let target of notification.targets)
+ {
+ if (checkTarget(target, "extension", addonName, addonVersion) &&
+ checkTarget(target, "application", application, applicationVersion) &&
+ checkTarget(target, "platform", platform, platformVersion))
+ {
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ continue;
+ }
+
+ if (!notificationToShow
+ || getNumericalSeverity(notification) > getNumericalSeverity(notificationToShow))
+ notificationToShow = notification;
+ }
+
+ if (notificationToShow && "id" in notificationToShow)
+ {
+ 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
+ * @param {String} locale the target locale (optional, defaults to the
+ * application locale)
+ * @return {Object} the translated texts
+ */
+ getLocalizedTexts: function(notification, locale)
+ {
+ locale = locale || Utils.appLocale;
+ let textKeys = ["title", "message"];
+ let localizedTexts = [];
+ for (let key of textKeys)
+ {
+ if (key in notification)
+ {
+ 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;
+ let questionListeners = listeners[id];
+ for (let listener of questionListeners)
+ listener(approved);
+ }
+};
+Notification.init();