UNPKG

@ouroboros/subscribe

Version:

A class that allows adding easy subscription and notification abilities by extending it

161 lines (160 loc) 4.59 kB
/** * Subscribe * * Contains a class meant to be extended in order to easily add the ability for * users to subscribe / unsubscribe to changes on the instance * * @author Chris Nasr <chris@ouroboroscoding.com> * @copyright Ouroboros Coding Inc. * @created 2023-02-24 */ import clone, { Clone } from '@ouroboros/clone'; import { compare } from '@ouroboros/tools'; /** * Subscribe * * This class contains methods to manage subscription to the instance * * @name Subscribe * @access public */ export default class Subscribe extends Clone { // The list of callbacks to notify on changes subscribeCallbacks; // The current set of data subscribeData; // The clone flag cloneFlag; /** * Constructor * * Creates a new instance * * @name Subscribe * @access public * @param data The initial data to * @param cloneFlag Optional, set to false to always return real data */ constructor(data = null, cloneFlag = true) { // Call the Clone constructor super(); // Init the list of callbacks this.subscribeCallbacks = []; // Store the initial data this.subscribeData = data; // Store the clone flag this.cloneFlag = cloneFlag; } /** * Get * * Returns a copy of the data currently stored * * @name get * @access public * @returns whatever the instance is currently storing as data */ get() { // Return the actual data, or a clone, based on the flag return this.cloneFlag ? clone(this.subscribeData) : this.subscribeData; } /** * Notify * * Calls all the subscriber callbacks * * @name notify * @access public * @returns void */ notify() { // Go through each callback and notify of the data change for (const f of this.subscribeCallbacks) { // Send the actual data, or a clone, based on the flag f(this.cloneFlag ? clone(this.subscribeData) : this.subscribeData); } } /** * Set * * If the data has changed, stores the new data and sends a copy of it to * all callbacks (if notify is not set to false), then returns true. * Else, returns false and does nothing * * @name set * @access public * @param data The new data to set and then send * @param notify Set to false to not notify subscribers * @returns bool */ set(data, notify = true) { // If the data hasn't changed, do nothing if (compare(data, this.subscribeData)) { return false; } // Store the new data this.subscribeData = data; // Notify subscribers if (notify) { this.notify(); } // Return OK return true; } /** * Subscribe * * Stores a callback function to be called whenever the option data needs * to change * * @name subscribe * @access public * @param callback The function to call when data changes * @returns current data */ subscribe(callback) { // Add it to the list this.subscribeCallbacks.push(callback); // Clone the current data if the flag is set const mData = this.cloneFlag ? clone(this.subscribeData) : this.subscribeData; // Call the callback with the current data callback(mData); // Return the current data as well as a function to unsubscribe return { data: mData, unsubscribe: () => { return this.unsubscribe(callback); } }; } /** * Unsubscribe * * Not meant to be called publicaly, but kept as such in order to support * code using old style subscrube/unsubscribe methods. Searches for the * callback and then removes it from the list if found. * * @name unsubscribe * @access public * @param callback The function to look for to remove * @returns if the callback was removed or not */ unsubscribe(callback) { // Search for the index of the callback const i = this.subscribeCallbacks.indexOf(callback); // If it's found if (i > -1) { // Splice it out of the callbacks and return success this.subscribeCallbacks.splice(i, 1); return true; } // Return that it was not removed return false; } }