You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
4.2 KiB

4 years ago
  1. 'use strict';
  2. /**
  3. * Class representing an event.
  4. *
  5. * @private
  6. */
  7. class Event {
  8. /**
  9. * Create a new `Event`.
  10. *
  11. * @param {String} type The name of the event
  12. * @param {Object} target A reference to the target to which the event was dispatched
  13. */
  14. constructor(type, target) {
  15. this.target = target;
  16. this.type = type;
  17. }
  18. }
  19. /**
  20. * Class representing a message event.
  21. *
  22. * @extends Event
  23. * @private
  24. */
  25. class MessageEvent extends Event {
  26. /**
  27. * Create a new `MessageEvent`.
  28. *
  29. * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The received data
  30. * @param {WebSocket} target A reference to the target to which the event was dispatched
  31. */
  32. constructor(data, target) {
  33. super('message', target);
  34. this.data = data;
  35. }
  36. }
  37. /**
  38. * Class representing a close event.
  39. *
  40. * @extends Event
  41. * @private
  42. */
  43. class CloseEvent extends Event {
  44. /**
  45. * Create a new `CloseEvent`.
  46. *
  47. * @param {Number} code The status code explaining why the connection is being closed
  48. * @param {String} reason A human-readable string explaining why the connection is closing
  49. * @param {WebSocket} target A reference to the target to which the event was dispatched
  50. */
  51. constructor(code, reason, target) {
  52. super('close', target);
  53. this.wasClean = target._closeFrameReceived && target._closeFrameSent;
  54. this.reason = reason;
  55. this.code = code;
  56. }
  57. }
  58. /**
  59. * Class representing an open event.
  60. *
  61. * @extends Event
  62. * @private
  63. */
  64. class OpenEvent extends Event {
  65. /**
  66. * Create a new `OpenEvent`.
  67. *
  68. * @param {WebSocket} target A reference to the target to which the event was dispatched
  69. */
  70. constructor(target) {
  71. super('open', target);
  72. }
  73. }
  74. /**
  75. * Class representing an error event.
  76. *
  77. * @extends Event
  78. * @private
  79. */
  80. class ErrorEvent extends Event {
  81. /**
  82. * Create a new `ErrorEvent`.
  83. *
  84. * @param {Object} error The error that generated this event
  85. * @param {WebSocket} target A reference to the target to which the event was dispatched
  86. */
  87. constructor(error, target) {
  88. super('error', target);
  89. this.message = error.message;
  90. this.error = error;
  91. }
  92. }
  93. /**
  94. * This provides methods for emulating the `EventTarget` interface. It's not
  95. * meant to be used directly.
  96. *
  97. * @mixin
  98. */
  99. const EventTarget = {
  100. /**
  101. * Register an event listener.
  102. *
  103. * @param {String} type A string representing the event type to listen for
  104. * @param {Function} listener The listener to add
  105. * @param {Object} options An options object specifies characteristics about
  106. * the event listener
  107. * @param {Boolean} options.once A `Boolean`` indicating that the listener
  108. * should be invoked at most once after being added. If `true`, the
  109. * listener would be automatically removed when invoked.
  110. * @public
  111. */
  112. addEventListener(type, listener, options) {
  113. if (typeof listener !== 'function') return;
  114. function onMessage(data) {
  115. listener.call(this, new MessageEvent(data, this));
  116. }
  117. function onClose(code, message) {
  118. listener.call(this, new CloseEvent(code, message, this));
  119. }
  120. function onError(error) {
  121. listener.call(this, new ErrorEvent(error, this));
  122. }
  123. function onOpen() {
  124. listener.call(this, new OpenEvent(this));
  125. }
  126. const method = options && options.once ? 'once' : 'on';
  127. if (type === 'message') {
  128. onMessage._listener = listener;
  129. this[method](type, onMessage);
  130. } else if (type === 'close') {
  131. onClose._listener = listener;
  132. this[method](type, onClose);
  133. } else if (type === 'error') {
  134. onError._listener = listener;
  135. this[method](type, onError);
  136. } else if (type === 'open') {
  137. onOpen._listener = listener;
  138. this[method](type, onOpen);
  139. } else {
  140. this[method](type, listener);
  141. }
  142. },
  143. /**
  144. * Remove an event listener.
  145. *
  146. * @param {String} type A string representing the event type to remove
  147. * @param {Function} listener The listener to remove
  148. * @public
  149. */
  150. removeEventListener(type, listener) {
  151. const listeners = this.listeners(type);
  152. for (let i = 0; i < listeners.length; i++) {
  153. if (listeners[i] === listener || listeners[i]._listener === listener) {
  154. this.removeListener(type, listeners[i]);
  155. }
  156. }
  157. }
  158. };
  159. module.exports = EventTarget;