Home Reference Source

props/classes/PropEvents.js

import events from '../events/events.js'
/**
 * The Prop Event Class
 */
class PropEvents {
  /**
 * @param {any} value - The initial value of the property
 * @param {OBJECT} parent - The Parent Object to which this Property is a member of ({@link Object})
 */
  constructor (parent) {
    this.parent = parent
    this._event = {}
    // this.isObservable = true
    this.eventCallbacks = Object.values(events).reduce((acc, key) => {
      acc[key] = []
      return acc
    }, {})
    Object.values(events).forEach(eventName => {
      this._event[eventName] = (target = this) => {
        this._processEvent(eventName, target)
      }
    })
  }
  /**
 * @ignore
 */
  static isObservable = true
  isObservable = true

  // static isObservable () {
  //   return true
  // }

  /**
   * Bind an event listener
 * @param {Event} eventName - The event being listening to, enumerated in the events file
 * @param {Function} callback - The method called when the event is fired
 */
  on (eventName, callback) {
    if (!(Object.values(events).includes(eventName))) throw new Error(`${eventName} is not a valid event`)
    if (!(callback instanceof Function)) throw new Error('Event listener is not a function')
    this.eventCallbacks[eventName].push(callback)
  }

  /**
   * Unbinds an event listener
 * @param {Event} eventName - The event being listening to, enumerated in the events file
 * @param {Function} callback - The method called when the event is fired
 */
  off (eventName, callback) {
    const idx = this.eventCallbacks[eventName].indexOf(callback)
    if (idx >= 0) this.eventCallbacks[eventName].splice(idx, 1)
  }

  /**
   * Calls event bubbling on the parent Observable
 * @param {Event} eventName - The event being listening to, enumerated in the events file
 * @param {Prop} target - The Prop that was the source of the Event
 */
  _bubble (eventName, target) {
    this._processEvent(eventName, target, { bubble: true })
  }

  /**
   * Calls the listeners for the Event triggered
 * @param {Event} eventName - The event being listening to, enumerated in the events file
 * @param {Prop} target - The Prop that was the source of the Event
 * @param {Object} [additional]
 * @param {Boolean} [additional.bubble = false] - A boolean that indicates that the event firing is bubbled from a child Prop
 */
  async _processEvent (eventName, target, { bubble = false } = { }) {
    if (!this.eventCallbacks[eventName]) throw new Error(`Cannot process event ${eventName}`)
    for (let c = this.eventCallbacks[eventName].length - 1; c >= 0; c--) {
      try {
        // console.log(eventName,target.toJSON())
        const response = await this.eventCallbacks[eventName][c](target, bubble)
        if (response === false) this.eventCallbacks[eventName].splice(c, 1)
      } catch (e) {
        this.eventCallbacks[eventName].splice(c, 1)
      }
    }
    if (this.parent && this.parent._bubble) {
      this.parent._bubble(eventName, target)
    }
  }
}
export default PropEvents