@optimizely/optimizely-sdk
Version:
JavaScript SDK for Optimizely X Full Stack
205 lines (187 loc) • 6.88 kB
JavaScript
/**
* 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,
};