EventHolder.js

/**
 * @class EventHolder
 * @description holds events and further sub event holders
 * @property {Array<Function>} callbacks - array of callback function to be used
 * called when the event is triggered
 * @property {Array<Function>} allSubCallbacks - array of all callbacks
 * functions in this EventHolder and all subEventHolders
 * @property {object} subEvents - gets the subevents
 */
class EventHolder {
    _callbacks = [];
    _subEvents = {};

    constructor() {}

    get callbacks() {
        return this._callbacks;
    }

    get subEvents() {
        return this._subEvents;
    }

    get allSubCallbacks() {
        return Object.values(this._subEvents).reduce(
            (acc, el) => [...acc, ...el.callbacks, ...el.allSubCallbacks],
            []
        );
    }

    /**
     * @function getSubEvent
     * @description returns the subEvent from the name passed in
     * @memberof EventHolder
     * @instance
     * @param {string} name - the name of the sub event to return
     * @returns {EventHolder} - the sub event holder
     */
    getSubEvent(name) {
        return this._subEvents[name];
    }

    /**
     * @function getCallbacks
     * @description gets the callbacks from the path, will call sub event
     * holders to get events
     * @memberof EventHolder
     * @instance
     * @param {Array<string>} path - path the the event
     * @returns {Array<Function>} - the callbacks
     */
    getCallbacks(path) {
        if (path.length === 0) {
            return this._callbacks;
        } else if (path[0] === '**') {
            return Object.values(this._subEvents).reduce(
                (acc, el) => [...acc, ...el.getCallbacks(path.slice(1))],
                []
            );
        } else if (path[0] === '***') {
            return this.allSubCallbacks;
        } else if (typeof this._subEvents[path[0]] !== 'undefined') {
            return this._subEvents[path[0]].getCallbacks(path.slice(1));
        } else {
            return [];
        }
    }

    /**
     * @function addCallback
     * @description adds a callback to this events callbacks
     * @memberof EventHolder
     * @instance
     * @param {Event} event - the event to add
     */
    addCallback(event) {
        event.removeCallback = this._removeCallback;
        this._callbacks.push(event);
    }

    /**
     * @function addSubEvent
     * @description adds a sub EventHolder
     * @memberof EventHolder
     * @instance
     * @param {string} name - the name of the subevent to add
     */
    addSubEvent(name) {
        if (typeof this._subEvents[name] === 'undefined') {
            this._subEvents[name] = new EventHolder();
        }
    }

    /**
     * @function add
     * @description adds an event to this event holder of a sub event holder
     * @memberof EventHolder
     * @instance
     * @param {Array<string>} path - the path to the event
     * @param {Event} event - the event to add
     */
    add(path, event) {
        if (path.length > 0) {
            this.addSubEvent(path[0]);
            this._subEvents[path[0]].add(path.slice(1), event);
        } else {
            this.addCallback(event);
        }
    }

    /**
     * @function remove
     * @description removes a event from the event holder
     * @memberof EventHolder
     * @instance
     * @param {Array<string>} path - path to event
     * @param {Event} event - the event to remove
     */
    remove(path, event) {
        if (path.length > 0) {
            if (typeof this._subEvents[path[0]] !== 'undefined') {
                this._subEvents[path[0]].remove(path.slice(1), event);
            }
        } else {
            this._removeCallback(event);
        }
    }

    /**
     * @function _removeCallback
     * @description removes a callback from the callbacks
     * @memberof EventHolder
     * @instance
     * @private
     * @param {Event} event - the event to remove
     */
    _removeCallback(event) {
        this._callbacks = this._callbacks.filter((el) => el.id !== event.id);
    }
}

module.exports = EventHolder;