UNPKG

@optimizely/optimizely-sdk

Version:
205 lines (187 loc) 6.88 kB
/** * Copyright 2017, 2019-2020, Optimizely * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { sprintf, objectValues } from '@optimizely/js-sdk-utils'; import { LOG_LEVEL, LOG_MESSAGES, NOTIFICATION_TYPES, } from '../../utils/enums'; var MODULE_NAME = 'NOTIFICATION_CENTER'; /** * NotificationCenter allows registration and triggering of callback functions using * notification event types defined in NOTIFICATION_TYPES of utils/enums/index.js: * - ACTIVATE: An impression event will be sent to Optimizely. * - TRACK a conversion event will be sent to Optimizely * @constructor * @param {Object} options * @param {Object} options.logger An instance of a logger to log messages with * @param {object} options.errorHandler An instance of errorHandler to handle any unexpected error * @returns {Object} */ function NotificationCenter(options) { this.logger = options.logger; this.errorHandler = options.errorHandler; this.__notificationListeners = {}; objectValues(NOTIFICATION_TYPES).forEach( function(notificationTypeEnum) { this.__notificationListeners[notificationTypeEnum] = []; }.bind(this) ); this.__listenerId = 1; } /** * Add a notification callback to the notification center * @param {string} notificationType One of the values from NOTIFICATION_TYPES in utils/enums/index.js * @param {Function} callback Function that will be called when the event is triggered * @returns {number} If the callback was successfully added, returns a listener ID which can be used * to remove the callback by calling removeNotificationListener. The ID is a number greater than 0. * If there was an error and the listener was not added, addNotificationListener returns -1. This * can happen if the first argument is not a valid notification type, or if the same callback * function was already added as a listener by a prior call to this function. */ NotificationCenter.prototype.addNotificationListener = function(notificationType, callback) { try { var isNotificationTypeValid = objectValues(NOTIFICATION_TYPES).indexOf(notificationType) > -1; if (!isNotificationTypeValid) { return -1; } if (!this.__notificationListeners[notificationType]) { this.__notificationListeners[notificationType] = []; } var callbackAlreadyAdded = false; (this.__notificationListeners[notificationType] || []).forEach(function(listenerEntry) { if (listenerEntry.callback === callback) { callbackAlreadyAdded = true; return false; } }); if (callbackAlreadyAdded) { return -1; } this.__notificationListeners[notificationType].push({ id: this.__listenerId, callback: callback, }); var returnId = this.__listenerId; this.__listenerId += 1; return returnId; } catch (e) { this.logger.log(LOG_LEVEL.ERROR, e.message); this.errorHandler.handleError(e); return -1; } }; /** * Remove a previously added notification callback * @param {number} listenerId ID of listener to be removed * @returns {boolean} Returns true if the listener was found and removed, and false * otherwise. */ NotificationCenter.prototype.removeNotificationListener = function(listenerId) { try { var indexToRemove; var typeToRemove; Object.keys(this.__notificationListeners).some( function(notificationType) { var listenersForType = this.__notificationListeners[notificationType]; (listenersForType || []).every(function(listenerEntry, i) { if (listenerEntry.id === listenerId) { indexToRemove = i; typeToRemove = notificationType; return false; } return true; }); if (indexToRemove !== undefined && typeToRemove !== undefined) { return true; } }.bind(this) ); if (indexToRemove !== undefined && typeToRemove !== undefined) { this.__notificationListeners[typeToRemove].splice(indexToRemove, 1); return true; } } catch (e) { this.logger.log(LOG_LEVEL.ERROR, e.message); this.errorHandler.handleError(e); } return false; }; /** * Removes all previously added notification listeners, for all notification types */ NotificationCenter.prototype.clearAllNotificationListeners = function() { try { objectValues(NOTIFICATION_TYPES).forEach( function(notificationTypeEnum) { this.__notificationListeners[notificationTypeEnum] = []; }.bind(this) ); } catch (e) { this.logger.log(LOG_LEVEL.ERROR, e.message); this.errorHandler.handleError(e); } }; /** * Remove all previously added notification listeners for the argument type * @param {string} notificationType One of NOTIFICATION_TYPES */ NotificationCenter.prototype.clearNotificationListeners = function(notificationType) { try { this.__notificationListeners[notificationType] = []; } catch (e) { this.logger.log(LOG_LEVEL.ERROR, e.message); this.errorHandler.handleError(e); } }; /** * Fires notifications for the argument type. All registered callbacks for this type will be * called. The notificationData object will be passed on to callbacks called. * @param {string} notificationType One of NOTIFICATION_TYPES * @param {Object} notificationData Will be passed to callbacks called */ NotificationCenter.prototype.sendNotifications = function(notificationType, notificationData) { try { (this.__notificationListeners[notificationType] || []).forEach( function(listenerEntry) { var callback = listenerEntry.callback; try { callback(notificationData); } catch (ex) { this.logger.log( LOG_LEVEL.ERROR, sprintf(LOG_MESSAGES.NOTIFICATION_LISTENER_EXCEPTION, MODULE_NAME, notificationType, ex.message) ); } }.bind(this) ); } catch (e) { this.logger.log(LOG_LEVEL.ERROR, e.message); this.errorHandler.handleError(e); } }; /** * Create an instance of NotificationCenter * @param {Object} options * @param {Object} options.logger An instance of a logger to log messages with * @returns {Object} An instance of NotificationCenter */ export var createNotificationCenter = function(options) { return new NotificationCenter(options); }; export default { createNotificationCenter: createNotificationCenter, };