UNPKG

@ouroboros/subscribe

Version:

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

179 lines (150 loc) 3.98 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'; // Types export type SubscribeCallback = (data: any) => void; export type SubscribeReturn = { data: any, unsubscribe: () => boolean } /** * 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 protected subscribeCallbacks: SubscribeCallback[]; // The current set of data protected subscribeData: any; // The clone flag protected cloneFlag: boolean; /** * 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: any = null, cloneFlag: boolean = 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(): any { // Return the actual data, or a clone, based on the flag return 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, then returns true. Else, returns false and does nothing * * @name set * @access public * @param data The new data to set and then send * @returns bool */ set(data: any): boolean { // If the data hasn't changed, do nothing if(compare(data, this.subscribeData)) { return false; } // Store the new data this.subscribeData = data; // 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 ); } // 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: SubscribeCallback): SubscribeReturn { // 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: SubscribeCallback): boolean { // 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; } }