secondaryAction, options ); let existingIndex = this._notifications.findIndex(n => n.id == id); if (existingIndex != -1) { this._notifications.splice(existingIndex, 1); } // We don't want to clobber doorhanger notifications just to show a badge, // so don't dismiss any of them and the badge will show once the doorhanger // gets resolved. if (!options.badgeOnly && !options.dismissed) { this._notifications.forEach(n => { n.dismissed = true; }); } // Since notifications are generally somewhat pressing, the ideal case is that // we never have two notifications at once. However, in the event that we do, // it's more likely that the older notification has been sitting around for a // bit, and so we don't want to hide the new notification behind it. Thus, // we want our notifications to behave like a stack instead of a queue. this._notifications.unshift(notification); this._lazyInit(); this._updateNotifications(); return notification; }, showBadgeOnlyNotification(id) { return this.showNotification(id, null, null, { badgeOnly: true }); }, removeNotification(id) { let notifications; if (typeof id == "string") { notifications = this._notifications.filter(n => n.id == id); } else { // If it's not a string, assume RegExp notifications = this._notifications.filter(n => id.test(n.id)); } // _updateNotifications can be expensive if it forces attachment of XBL // bindings that haven't been used yet, so return early if we haven't found // any notification to remove, as callers may expect this removeNotification // method to be a no-op for non-existent notifications. if (!notifications.length) { return; } notifications.forEach(n => { this._removeNotification(n); }); this._updateNotifications(); }, dismissNotification(id) { let notifications; if (typeof id == "string") { notifications = this._notifications.filter(n => n.id == id); } else { // If it's not a string, assume RegExp notifications = this._notifications.filter(n => id.test(n.id)); } notifications.forEach(n => { n.dismissed = true; if (n.options.onDismissed) { n.options.onDismissed(); } }); this._updateNotifications(); }, callMainAction(win, notification, fromDoorhanger) { let action = notification.mainAction; this._callAction(win, notification, action, fromDoorhanger); }, callSecondaryAction(win, notification) { let action = notification.secondaryAction; this._callAction(win, notification, action, true); }, _callAction(win, notification, action, fromDoorhanger) { let dismiss = true; if (action) { try { action.callback(win, fromDoorhanger); } catch (error) { console.error(error); } dismiss = action.dismiss; } if (dismiss) { notification.dismissed = true; } else { this._removeNotification(notification); } this._updateNotifications(); }, _removeNotification(notification) { // This notification may already be removed, in which case let's just ignore. let notifications = this._notifications; if (!notifications) { return; } var index = notifications.indexOf(notification); if (index == -1) { return; } // Remove the notification notifications.splice(index, 1); }, _updateNotifications() { Services.obs.notifyObservers(null, "appMenu-notifications", "update"); }, }; PK