Index: lib/notification.js |
=================================================================== |
deleted file mode 100644 |
--- a/lib/notification.js |
+++ /dev/null |
@@ -1,412 +0,0 @@ |
-/* |
- * This file is part of Adblock Plus <https://adblockplus.org/>, |
- * Copyright (C) 2006-2016 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"); |
- |
-var {Prefs} = require("prefs"); |
-var {Downloader, Downloadable, MILLIS_IN_MINUTE, MILLIS_IN_HOUR, MILLIS_IN_DAY} = require("downloader"); |
-var {Utils} = require("utils"); |
-var {Matcher, defaultMatcher} = require("matcher"); |
-var {Filter, RegExpFilter, WhitelistFilter} = require("filterClasses"); |
- |
-var INITIAL_DELAY = 1 * MILLIS_IN_MINUTE; |
-var CHECK_INTERVAL = 1 * MILLIS_IN_HOUR; |
-var EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY; |
-var TYPE = { |
- information: 0, |
- question: 1, |
- critical: 2 |
-}; |
- |
-var showListeners = []; |
-var questionListeners = {}; |
- |
-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 |
- */ |
-var downloader = null; |
-var localData = []; |
- |
-/** |
- * Regularly fetches notifications and decides which to show. |
- * @class |
- */ |
-var Notification = exports.Notification = |
-{ |
- /** |
- * Called on module startup. |
- */ |
- init: function() |
- { |
- downloader = new Downloader(this._getDownloadables.bind(this), INITIAL_DELAY, CHECK_INTERVAL); |
- downloader.onExpirationChange = this._onExpirationChange.bind(this); |
- downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this); |
- downloader.onDownloadError = this._onDownloadError.bind(this); |
- onShutdown.add(() => downloader.cancel()); |
- }, |
- |
- /** |
- * 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; |
- if (typeof Prefs.notificationdata.downloadCount === "number") |
- downloadable.downloadCount = Prefs.notificationdata.downloadCount; |
- 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); |
- Prefs.notificationdata.downloadCount = downloadable.downloadCount; |
- saveNotificationData(); |
- |
- Notification.showNext(); |
- }, |
- |
- _onDownloadError: function(downloadable, downloadURL, error, channelStatus, responseStatus, redirectCallback) |
- { |
- Prefs.notificationdata.lastError = Date.now(); |
- Prefs.notificationdata.downloadStatus = error; |
- saveNotificationData(); |
- }, |
- |
- /** |
- * Adds a listener for notifications to be shown. |
- * @param {Function} listener Listener to be invoked when a notification is |
- * to be shown |
- */ |
- addShowListener: function(listener) |
- { |
- if (showListeners.indexOf(listener) == -1) |
- showListeners.push(listener); |
- }, |
- |
- /** |
- * Removes the supplied listener. |
- * @param {Function} listener Listener that was added via addShowListener() |
- */ |
- removeShowListener: function(listener) |
- { |
- let index = showListeners.indexOf(listener); |
- if (index != -1) |
- showListeners.splice(index, 1); |
- }, |
- |
- /** |
- * 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; |
- |
- 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") |
- { |
- let shown = Prefs.notificationdata.shown; |
- if (shown instanceof Array && shown.indexOf(notification.id) != -1) |
- continue; |
- if (Prefs.notifications_ignoredcategories.indexOf("*") != -1) |
- continue; |
- } |
- |
- if (typeof url === "string" || notification.urlFilters instanceof Array) |
- { |
- if (Prefs.enabled && typeof url === "string" && notification.urlFilters instanceof Array) |
- { |
- let host; |
- if (typeof URL == "function") |
- host = new URL(url).hostname; |
- else |
- { |
- try |
- { |
- host = Services.io.newURI(url, null, null).host; |
- } |
- catch (e) |
- { |
- // Ignore, an exception is expected for about: and similar schemes |
- host = ""; |
- } |
- } |
- let exception = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, host, false, null); |
- if (exception instanceof WhitelistFilter) |
- continue; |
- |
- let matcher = new Matcher(); |
- for (let urlFilter of notification.urlFilters) |
- matcher.add(Filter.fromText(urlFilter)); |
- if (!matcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, host, false, null)) |
- 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; |
- } |
- |
- return notificationToShow; |
- }, |
- |
- /** |
- * Invokes the listeners added via addShowListener() with the next |
- * notification to be shown. |
- * @param {String} url URL to match notifications to (optional) |
- */ |
- showNext: function(url) |
- { |
- let notification = Notification._getNextToShow(url); |
- if (notification) |
- for (let showListener of showListeners) |
- showListener(notification); |
- }, |
- |
- /** |
- * Marks a notification as shown. |
- * @param {String} id ID of the notification to be marked as shown |
- */ |
- markAsShown: function(id) |
- { |
- var data = Prefs.notificationdata; |
- |
- if (!(data.shown instanceof Array)) |
- data.shown = []; |
- if (data.shown.indexOf(id) != -1) |
- return; |
- |
- data.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 questionListeners)) |
- questionListeners[id] = []; |
- if (questionListeners[id].indexOf(listener) === -1) |
- questionListeners[id].push(listener); |
- }, |
- |
- /** |
- * Removes a listener that was previously added via addQuestionListener |
- */ |
- removeQuestionListener: function(/**string*/ id, /**function(approved)*/ listener) |
- { |
- if (!(id in questionListeners)) |
- return; |
- let index = questionListeners[id].indexOf(listener); |
- if (index > -1) |
- questionListeners[id].splice(index, 1); |
- if (questionListeners[id].length === 0) |
- delete questionListeners[id]; |
- }, |
- |
- /** |
- * Notifies question 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 questionListeners)) |
- return; |
- let listeners = questionListeners[id]; |
- for (let listener of listeners) |
- listener(approved); |
- }, |
- |
- /** |
- * Toggles whether notifications of a specific category should be ignored |
- * @param {String} category notification category identifier |
- * @param {Boolean} [forceValue] force specified value |
- */ |
- toggleIgnoreCategory: function(category, forceValue) |
- { |
- let categories = Prefs.notifications_ignoredcategories; |
- let index = categories.indexOf(category); |
- if (index == -1 && forceValue !== false) |
- { |
- categories.push(category); |
- Prefs.notifications_showui = true; |
- } |
- else if (index != -1 && forceValue !== true) |
- categories.splice(index, 1); |
- |
- // HACK: JSON values aren't saved unless they are assigned a different object. |
- Prefs.notifications_ignoredcategories = JSON.parse(JSON.stringify(categories)); |
- } |
-}; |
-Notification.init(); |