node_modules/@scena/event-emitter/src/EventEmitter.ts

  1. import { findIndex, isObject } from "@daybrush/utils";
  2. import { EventListener, EventHash, EventInfo, EventOptions, OnEvent, TargetParam } from "./types";
  3. /**
  4. * Implement EventEmitter on object or component.
  5. */
  6. class EventEmitter<Events extends {} = { [key: string]: { [key: string]: any } }> {
  7. private _events: {
  8. [name: string]: EventInfo[],
  9. } = {};
  10. public on<Name extends keyof Events, Param = Events[Name]>(
  11. eventName: Name, listener: EventListener<Param, this>): this;
  12. public on(events: EventHash<Events, this>): this;
  13. /**
  14. * Add a listener to the registered event.
  15. * @param - Name of the event to be added
  16. * @param - listener function of the event to be added
  17. * @example
  18. * import EventEmitter from "@scena/event-emitter";
  19. * cosnt emitter = new EventEmitter();
  20. *
  21. * // Add listener in "a" event
  22. * emitter.on("a", () => {
  23. * });
  24. * // Add listeners
  25. * emitter.on({
  26. * a: () => {},
  27. * b: () => {},
  28. * });
  29. */
  30. public on(eventName: string | object, listener?: EventListener<Events[any], this>): this {
  31. if (isObject(eventName)) {
  32. for (const name in eventName) {
  33. this.on<any>(name, eventName[name]);
  34. }
  35. } else {
  36. this._addEvent(eventName, listener, {});
  37. }
  38. return this;
  39. }
  40. public off<Name extends keyof Events, Param = Events[Name]>(
  41. eventName?: Name, listener?: EventListener<Param, this>): this;
  42. public off(events: EventHash<Events, this>): this;
  43. /**
  44. * Remove listeners registered in the event target.
  45. * @param - Name of the event to be removed
  46. * @param - listener function of the event to be removed
  47. * @example
  48. * import EventEmitter from "@scena/event-emitter";
  49. * cosnt emitter = new EventEmitter();
  50. *
  51. * // Remove all listeners.
  52. * emitter.off();
  53. *
  54. * // Remove all listeners in "A" event.
  55. * emitter.off("a");
  56. *
  57. *
  58. * // Remove "listener" listener in "a" event.
  59. * emitter.off("a", listener);
  60. */
  61. public off(eventName?: string | object, listener?: EventListener<Events[any], this>): this {
  62. if (!eventName) {
  63. this._events = {};
  64. } else if(isObject(eventName)) {
  65. for (const name in eventName) {
  66. this.off<any>(name);
  67. }
  68. } else if (!listener) {
  69. this._events[eventName] = [];
  70. } else {
  71. const events = this._events[eventName];
  72. if (events) {
  73. const index = findIndex(events, e => e.listener === listener);
  74. if (index > -1) {
  75. events.splice(index, 1);
  76. }
  77. }
  78. }
  79. return this;
  80. }
  81. /**
  82. * Add a disposable listener and Use promise to the registered event.
  83. * @param - Name of the event to be added
  84. * @param - disposable listener function of the event to be added
  85. * @example
  86. * import EventEmitter from "@scena/event-emitter";
  87. * cosnt emitter = new EventEmitter();
  88. *
  89. * // Add a disposable listener in "a" event
  90. * emitter.once("a", () => {
  91. * });
  92. *
  93. * // Use Promise
  94. * emitter.once("a").then(e => {
  95. * });
  96. */
  97. public once<Name extends keyof Events & string, Param = Events[Name]>(
  98. eventName: Name, listener?: EventListener<Param, this>): Promise<OnEvent<Param, this>> {
  99. if (listener) {
  100. this._addEvent(eventName, listener, { once: true });
  101. }
  102. return new Promise<OnEvent<Param, this>>(resolve => {
  103. this._addEvent(eventName, resolve, { once: true });
  104. });
  105. }
  106. public emit<Name extends keyof Events, Param = Events[Name]>(
  107. eventName: {} extends Param ? Name : never): boolean;
  108. public emit<Name extends keyof Events, Param = Events[Name]>(
  109. eventName: Name, param: TargetParam<Param>): boolean;
  110. /**
  111. * Fires an event to call listeners.
  112. * @param - Event name
  113. * @param - Event parameter
  114. * @return If false, stop the event.
  115. * @example
  116. *
  117. * import EventEmitter from "@scena/event-emitter";
  118. *
  119. *
  120. * const emitter = new EventEmitter();
  121. *
  122. * emitter.on("a", e => {
  123. * });
  124. *
  125. *
  126. * emitter.emit("a", {
  127. * a: 1,
  128. * });
  129. */
  130. public emit(eventName: string, param: TargetParam<any> = {}): boolean {
  131. const events = this._events[eventName];
  132. if (!eventName || !events) {
  133. return true;
  134. }
  135. let isStop = false;
  136. param.eventType = eventName;
  137. param.stop = () => {
  138. isStop = true;
  139. };
  140. param.currentTarget = this;
  141. [...events].forEach(info => {
  142. info.listener(param);
  143. if (info.once) {
  144. this.off<any>(eventName, info.listener);
  145. }
  146. });
  147. return !isStop;
  148. }
  149. public trigger<Name extends keyof Events, Param = Events[Name]>(eventName: {} extends TargetParam<Param> ? Name : never): boolean;
  150. public trigger<Name extends keyof Events, Param = Events[Name]>(eventName: Name, param: TargetParam<Param>): boolean;
  151. /**
  152. * Fires an event to call listeners.
  153. * @param - Event name
  154. * @param - Event parameter
  155. * @return If false, stop the event.
  156. * @example
  157. *
  158. * import EventEmitter from "@scena/event-emitter";
  159. *
  160. *
  161. * const emitter = new EventEmitter();
  162. *
  163. * emitter.on("a", e => {
  164. * });
  165. *
  166. *
  167. * emitter.emit("a", {
  168. * a: 1,
  169. * });
  170. *//**
  171. * Fires an event to call listeners.
  172. * @param - Event name
  173. * @param - Event parameter
  174. * @return If false, stop the event.
  175. * @example
  176. *
  177. * import EventEmitter from "@scena/event-emitter";
  178. *
  179. *
  180. * const emitter = new EventEmitter();
  181. *
  182. * emitter.on("a", e => {
  183. * });
  184. *
  185. * // emit
  186. * emitter.trigger("a", {
  187. * a: 1,
  188. * });
  189. */
  190. public trigger<Name extends keyof Events>(eventName: Name, param: TargetParam<any>= {}): boolean {
  191. return this.emit<any>(eventName, param);
  192. }
  193. private _addEvent(eventName: string, listener: EventListener<Events[any], this>, options: Partial<EventOptions>) {
  194. const events = this._events;
  195. events[eventName] = events[eventName] || [];
  196. const listeners = events[eventName];
  197. listeners.push({ listener, ...options });
  198. }
  199. }
  200. export default EventEmitter;