EventTrigger.ts

import { isObject, isArray, toArray } from "@daybrush/utils";
import { CallbackType, EventParameter } from "./types";

/**
* attach and trigger event handlers.
*/
class EventTrigger {
    public events: { [name: string]: CallbackType[] };
    /**
      * @example
  const et = new Scene.EventTrigger();
  const scene = new Scene();

  scene.on("call", e => {
      console.log(e.param);
  });
  et.on("call", e => {
      console.log(e.param);
  });
  scene.trigger("call", {param: 1});
  et.trigger("call", {param: 1});
       */
    constructor() {
        this.events = {};
    }
    public _on(name: string | EventParameter, callback?: CallbackType | CallbackType[], once?: boolean) {
        const events = this.events;

        if (isObject(name)) {
            for (const n in name) {
                this._on(n, name[n], once);
            }
            return;
        }
        if (!(name in events)) {
            events[name] = [];
        }
        if (!callback) {
            return;
        }
        if (isArray(callback)) {
            callback.forEach(func => this._on(name, func, once));
            return;
        }
        events[name].push(once ? function callback2(...args) {
            callback(...args);
            this.off(name, callback2);
        } : callback);
    }
    /**
      * Attach an event handler function for one or more events to target
      * @param - event's name
      * @param - function to execute when the event is triggered.
      * @return {EventTrigger} An Instance itself.
      * @example
  target.on("animate", function() {
      console.log("animate");
  });

  target.trigger("animate");

    */
    public on(name: string | EventParameter, callback?: CallbackType | CallbackType[]) {
        this._on(name, callback);
        return this;
    }
    /**
      * Dettach an event handler function for one or more events to target
      * @param - event's name
      * @param -  function to execute when the event is triggered.
      * @return {EventTrigger} An Instance itself.
      * @example
  const callback = function() {
      console.log("animate");
  };
  target.on("animate", callback);

  target.off("animate", callback);
  target.off("animate");

      */
    public off(name?: string, callback?: CallbackType) {
        if (!name) {
            this.events = {};
        } else if (!callback) {
            this.events[name] = [];
        } else {
            const callbacks = this.events[name];

            if (!callbacks) {
                return this;
            }
            const index = callbacks.indexOf(callback);

            if (index !== -1) {
                callbacks.splice(index, 1);
            }
        }
        return this;
    }
    /**
      * execute event handler
      * @param - event's name
      * @param - event handler's additional parameter
      * @return {EventTrigger} An Instance itself.
      * @example
  target.on("animate", function(a1, a2) {
      console.log("animate", a1, a2);
  });

  target.trigger("animate", [1, 2]); // log => "animate", 1, 2

      */
    public trigger(name: string, ...data: any[]) {
        const events = this.events;

        if (!(name in events)) {
            return this;
        }

        const args = data || [];

        !args[0] && (args[0] = {});
        const event = events[name];
        const target = args[0];

        target.type = name;
        target.currentTarget = this;
        !target.target && (target.target = this);
        toArray(events[name]).forEach(callback => {
            callback.apply(this, data);
        });

        return this;
    }
    public once(name: string | EventParameter, callback?: CallbackType | CallbackType[]) {
        this._on(name, callback, true);
        return this;
    }
}
export default EventTrigger;