michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: this.EXPORTED_SYMBOLS = ["Notifications", "Notification", "NotificationButton"]; michael@0: michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cr = Components.results; michael@0: const Cu = Components.utils; michael@0: michael@0: Cu.import("resource://services-common/observers.js"); michael@0: Cu.import("resource://gre/modules/Log.jsm"); michael@0: Cu.import("resource://services-sync/util.js"); michael@0: michael@0: this.Notifications = { michael@0: // Match the referenced values in toolkit/content/widgets/notification.xml. michael@0: get PRIORITY_INFO() 1, // PRIORITY_INFO_LOW michael@0: get PRIORITY_WARNING() 4, // PRIORITY_WARNING_LOW michael@0: get PRIORITY_ERROR() 7, // PRIORITY_CRITICAL_LOW michael@0: michael@0: // FIXME: instead of making this public, dress the Notifications object michael@0: // to behave like an iterator (using generators?) and have callers access michael@0: // this array through the Notifications object. michael@0: notifications: [], michael@0: michael@0: _observers: [], michael@0: michael@0: // XXX Should we have a helper method for adding a simple notification? michael@0: // I.e. something like |function notify(title, description, priority)|. michael@0: michael@0: add: function Notifications_add(notification) { michael@0: this.notifications.push(notification); michael@0: Observers.notify("weave:notification:added", notification, null); michael@0: }, michael@0: michael@0: remove: function Notifications_remove(notification) { michael@0: let index = this.notifications.indexOf(notification); michael@0: michael@0: if (index != -1) { michael@0: this.notifications.splice(index, 1); michael@0: Observers.notify("weave:notification:removed", notification, null); michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Replace an existing notification. michael@0: */ michael@0: replace: function Notifications_replace(oldNotification, newNotification) { michael@0: let index = this.notifications.indexOf(oldNotification); michael@0: michael@0: if (index != -1) michael@0: this.notifications.splice(index, 1, newNotification); michael@0: else { michael@0: this.notifications.push(newNotification); michael@0: // XXX Should we throw because we didn't find the existing notification? michael@0: // XXX Should we notify observers about weave:notification:added? michael@0: } michael@0: michael@0: // XXX Should we notify observers about weave:notification:replaced? michael@0: }, michael@0: michael@0: /** michael@0: * Remove all notifications that match a title. If no title is provided, all michael@0: * notifications are removed. michael@0: * michael@0: * @param title [optional] michael@0: * Title of notifications to remove; falsy value means remove all michael@0: */ michael@0: removeAll: function Notifications_removeAll(title) { michael@0: this.notifications.filter(function(old) old.title == title || !title). michael@0: forEach(function(old) this.remove(old), this); michael@0: }, michael@0: michael@0: // replaces all existing notifications with the same title as the new one michael@0: replaceTitle: function Notifications_replaceTitle(notification) { michael@0: this.removeAll(notification.title); michael@0: this.add(notification); michael@0: } michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * A basic notification. Subclass this to create more complex notifications. michael@0: */ michael@0: this.Notification = michael@0: function Notification(title, description, iconURL, priority, buttons) { michael@0: this.title = title; michael@0: this.description = description; michael@0: michael@0: if (iconURL) michael@0: this.iconURL = iconURL; michael@0: michael@0: if (priority) michael@0: this.priority = priority; michael@0: michael@0: if (buttons) michael@0: this.buttons = buttons; michael@0: } michael@0: michael@0: // We set each prototype property individually instead of redefining michael@0: // the entire prototype to avoid blowing away existing properties michael@0: // of the prototype like the the "constructor" property, which we use michael@0: // to bind notification objects to their XBL representations. michael@0: Notification.prototype.priority = Notifications.PRIORITY_INFO; michael@0: Notification.prototype.iconURL = null; michael@0: Notification.prototype.buttons = []; michael@0: michael@0: /** michael@0: * A button to display in a notification. michael@0: */ michael@0: this.NotificationButton = michael@0: function NotificationButton(label, accessKey, callback) { michael@0: function callbackWrapper() { michael@0: try { michael@0: callback.apply(this, arguments); michael@0: } catch (e) { michael@0: let logger = Log.repository.getLogger("Sync.Notifications"); michael@0: logger.error("An exception occurred: " + Utils.exceptionStr(e)); michael@0: logger.info(Utils.stackTrace(e)); michael@0: throw e; michael@0: } michael@0: } michael@0: michael@0: this.label = label; michael@0: this.accessKey = accessKey; michael@0: this.callback = callbackWrapper; michael@0: }