EventBus.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import { DEFAULT_EVENT_PRIORITY } from '../../constants/priority';
  2. import { AnyFunction } from '../../types';
  3. import { forOwn, push, slice, toArray } from '../../utils';
  4. /**
  5. * The interface for the EventBus instance.
  6. *
  7. * @since 3.0.0
  8. */
  9. export interface EventBusObject {
  10. on( events: string | string[], callback: EventBusCallback, key?: object, priority?: number ): void;
  11. off( events: string | string[], key?: object ): void;
  12. offBy( key: object ): void;
  13. emit( event: string, ...args: any[] ): void;
  14. destroy(): void;
  15. }
  16. /**
  17. * The interface for each event handler object.
  18. *
  19. * @since 3.0.0
  20. */
  21. export interface EventHandler {
  22. _event: string;
  23. _callback: AnyFunction;
  24. _namespace: string;
  25. _priority: number;
  26. _key?: object;
  27. }
  28. /**
  29. * The type for a callback function of the EventBus.
  30. *
  31. * @since 3.0.0
  32. */
  33. export type EventBusCallback = AnyFunction;
  34. /**
  35. * The constructor to provided a simple event system.
  36. *
  37. * @since 3.0.0
  38. *
  39. * @return An EventBus object.
  40. */
  41. export function EventBus(): EventBusObject {
  42. /**
  43. * The collection of registered handlers.
  44. */
  45. let handlers: Record<string, EventHandler[]> = {};
  46. /**
  47. * Registers an event handler.
  48. *
  49. * @param events - An event name or names separated by spaces. Use a dot(.) to add a namespace.
  50. * @param callback - A callback function to register.
  51. * @param key - Optional. An object for an identifier of the handler.
  52. * @param priority - Optional. A priority number for the order in which the callbacks are invoked.
  53. * Lower numbers correspond with earlier execution. The default value is 10.
  54. */
  55. function on(
  56. events: string | string[],
  57. callback: EventBusCallback,
  58. key?: object,
  59. priority = DEFAULT_EVENT_PRIORITY
  60. ): void {
  61. forEachEvent( events, ( event, namespace ) => {
  62. handlers[ event ] = handlers[ event ] || [];
  63. push( handlers[ event ], {
  64. _event : event,
  65. _callback : callback,
  66. _namespace: namespace,
  67. _priority : priority,
  68. _key : key,
  69. } ).sort( ( handler1, handler2 ) => handler1._priority - handler2._priority );
  70. } );
  71. }
  72. /**
  73. * Removes event handlers registered by `on()`.
  74. * If only the event name is provided, all handlers that associate with the event are removed.
  75. * If the event name and namespace are specified, handlers that associate with the event and namespace are removed.
  76. *
  77. * @param events - An event name or names separated by spaces. Use a dot(.) to add a namespace.
  78. * @param key - Optional. An object for an identifier of the handler.
  79. */
  80. function off( events: string | string[], key?: object ): void {
  81. forEachEvent( events, ( event, namespace ) => {
  82. const eventHandlers = handlers[ event ];
  83. handlers[ event ] = eventHandlers && eventHandlers.filter( handler => {
  84. return handler._key ? handler._key !== key : key || handler._namespace !== namespace;
  85. } );
  86. } );
  87. }
  88. /**
  89. * Removes all handlers locked by the specified key.
  90. *
  91. * @param key - A key.
  92. */
  93. function offBy( key: object ): void {
  94. forOwn( handlers, ( eventHandlers, event ) => {
  95. off( event, key );
  96. } );
  97. }
  98. /**
  99. * Triggers callback functions.
  100. * This accepts additional arguments and passes them to callbacks.
  101. *
  102. * @param event - An event name.
  103. */
  104. function emit( event: string ): void {
  105. ( handlers[ event ] || [] ).forEach( handler => {
  106. // eslint-disable-next-line prefer-rest-params, prefer-spread
  107. handler._callback.apply( handler, slice( arguments, 1 ) );
  108. } );
  109. }
  110. /**
  111. * Removes all handlers.
  112. */
  113. function destroy(): void {
  114. handlers = {};
  115. }
  116. /**
  117. * Parses provided events and iterates over them.
  118. *
  119. * @param events - An event or events.
  120. * @param iteratee - An iteratee function.
  121. */
  122. function forEachEvent( events: string | string[], iteratee: ( event: string, namespace: string ) => void ): void {
  123. toArray( events ).join( ' ' ).split( ' ' ).forEach( eventNS => {
  124. const fragments = eventNS.split( '.' );
  125. iteratee( fragments[ 0 ], fragments[ 1 ] );
  126. } );
  127. }
  128. return {
  129. on,
  130. off,
  131. offBy,
  132. emit,
  133. destroy,
  134. };
  135. }