Spaces:
Runtime error
Runtime error
| ; | |
| const { kForOnEventAttribute, kListener } = require('./constants'); | |
| const kCode = Symbol('kCode'); | |
| const kData = Symbol('kData'); | |
| const kError = Symbol('kError'); | |
| const kMessage = Symbol('kMessage'); | |
| const kReason = Symbol('kReason'); | |
| const kTarget = Symbol('kTarget'); | |
| const kType = Symbol('kType'); | |
| const kWasClean = Symbol('kWasClean'); | |
| /** | |
| * Class representing an event. | |
| */ | |
| class Event { | |
| /** | |
| * Create a new `Event`. | |
| * | |
| * @param {String} type The name of the event | |
| * @throws {TypeError} If the `type` argument is not specified | |
| */ | |
| constructor(type) { | |
| this[kTarget] = null; | |
| this[kType] = type; | |
| } | |
| /** | |
| * @type {*} | |
| */ | |
| get target() { | |
| return this[kTarget]; | |
| } | |
| /** | |
| * @type {String} | |
| */ | |
| get type() { | |
| return this[kType]; | |
| } | |
| } | |
| Object.defineProperty(Event.prototype, 'target', { enumerable: true }); | |
| Object.defineProperty(Event.prototype, 'type', { enumerable: true }); | |
| /** | |
| * Class representing a close event. | |
| * | |
| * @extends Event | |
| */ | |
| class CloseEvent extends Event { | |
| /** | |
| * Create a new `CloseEvent`. | |
| * | |
| * @param {String} type The name of the event | |
| * @param {Object} [options] A dictionary object that allows for setting | |
| * attributes via object members of the same name | |
| * @param {Number} [options.code=0] The status code explaining why the | |
| * connection was closed | |
| * @param {String} [options.reason=''] A human-readable string explaining why | |
| * the connection was closed | |
| * @param {Boolean} [options.wasClean=false] Indicates whether or not the | |
| * connection was cleanly closed | |
| */ | |
| constructor(type, options = {}) { | |
| super(type); | |
| this[kCode] = options.code === undefined ? 0 : options.code; | |
| this[kReason] = options.reason === undefined ? '' : options.reason; | |
| this[kWasClean] = options.wasClean === undefined ? false : options.wasClean; | |
| } | |
| /** | |
| * @type {Number} | |
| */ | |
| get code() { | |
| return this[kCode]; | |
| } | |
| /** | |
| * @type {String} | |
| */ | |
| get reason() { | |
| return this[kReason]; | |
| } | |
| /** | |
| * @type {Boolean} | |
| */ | |
| get wasClean() { | |
| return this[kWasClean]; | |
| } | |
| } | |
| Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true }); | |
| Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true }); | |
| Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true }); | |
| /** | |
| * Class representing an error event. | |
| * | |
| * @extends Event | |
| */ | |
| class ErrorEvent extends Event { | |
| /** | |
| * Create a new `ErrorEvent`. | |
| * | |
| * @param {String} type The name of the event | |
| * @param {Object} [options] A dictionary object that allows for setting | |
| * attributes via object members of the same name | |
| * @param {*} [options.error=null] The error that generated this event | |
| * @param {String} [options.message=''] The error message | |
| */ | |
| constructor(type, options = {}) { | |
| super(type); | |
| this[kError] = options.error === undefined ? null : options.error; | |
| this[kMessage] = options.message === undefined ? '' : options.message; | |
| } | |
| /** | |
| * @type {*} | |
| */ | |
| get error() { | |
| return this[kError]; | |
| } | |
| /** | |
| * @type {String} | |
| */ | |
| get message() { | |
| return this[kMessage]; | |
| } | |
| } | |
| Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true }); | |
| Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true }); | |
| /** | |
| * Class representing a message event. | |
| * | |
| * @extends Event | |
| */ | |
| class MessageEvent extends Event { | |
| /** | |
| * Create a new `MessageEvent`. | |
| * | |
| * @param {String} type The name of the event | |
| * @param {Object} [options] A dictionary object that allows for setting | |
| * attributes via object members of the same name | |
| * @param {*} [options.data=null] The message content | |
| */ | |
| constructor(type, options = {}) { | |
| super(type); | |
| this[kData] = options.data === undefined ? null : options.data; | |
| } | |
| /** | |
| * @type {*} | |
| */ | |
| get data() { | |
| return this[kData]; | |
| } | |
| } | |
| Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true }); | |
| /** | |
| * This provides methods for emulating the `EventTarget` interface. It's not | |
| * meant to be used directly. | |
| * | |
| * @mixin | |
| */ | |
| const EventTarget = { | |
| /** | |
| * Register an event listener. | |
| * | |
| * @param {String} type A string representing the event type to listen for | |
| * @param {(Function|Object)} handler The listener to add | |
| * @param {Object} [options] An options object specifies characteristics about | |
| * the event listener | |
| * @param {Boolean} [options.once=false] A `Boolean` indicating that the | |
| * listener should be invoked at most once after being added. If `true`, | |
| * the listener would be automatically removed when invoked. | |
| * @public | |
| */ | |
| addEventListener(type, handler, options = {}) { | |
| for (const listener of this.listeners(type)) { | |
| if ( | |
| !options[kForOnEventAttribute] && | |
| listener[kListener] === handler && | |
| !listener[kForOnEventAttribute] | |
| ) { | |
| return; | |
| } | |
| } | |
| let wrapper; | |
| if (type === 'message') { | |
| wrapper = function onMessage(data, isBinary) { | |
| const event = new MessageEvent('message', { | |
| data: isBinary ? data : data.toString() | |
| }); | |
| event[kTarget] = this; | |
| callListener(handler, this, event); | |
| }; | |
| } else if (type === 'close') { | |
| wrapper = function onClose(code, message) { | |
| const event = new CloseEvent('close', { | |
| code, | |
| reason: message.toString(), | |
| wasClean: this._closeFrameReceived && this._closeFrameSent | |
| }); | |
| event[kTarget] = this; | |
| callListener(handler, this, event); | |
| }; | |
| } else if (type === 'error') { | |
| wrapper = function onError(error) { | |
| const event = new ErrorEvent('error', { | |
| error, | |
| message: error.message | |
| }); | |
| event[kTarget] = this; | |
| callListener(handler, this, event); | |
| }; | |
| } else if (type === 'open') { | |
| wrapper = function onOpen() { | |
| const event = new Event('open'); | |
| event[kTarget] = this; | |
| callListener(handler, this, event); | |
| }; | |
| } else { | |
| return; | |
| } | |
| wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute]; | |
| wrapper[kListener] = handler; | |
| if (options.once) { | |
| this.once(type, wrapper); | |
| } else { | |
| this.on(type, wrapper); | |
| } | |
| }, | |
| /** | |
| * Remove an event listener. | |
| * | |
| * @param {String} type A string representing the event type to remove | |
| * @param {(Function|Object)} handler The listener to remove | |
| * @public | |
| */ | |
| removeEventListener(type, handler) { | |
| for (const listener of this.listeners(type)) { | |
| if (listener[kListener] === handler && !listener[kForOnEventAttribute]) { | |
| this.removeListener(type, listener); | |
| break; | |
| } | |
| } | |
| } | |
| }; | |
| module.exports = { | |
| CloseEvent, | |
| ErrorEvent, | |
| Event, | |
| EventTarget, | |
| MessageEvent | |
| }; | |
| /** | |
| * Call an event listener | |
| * | |
| * @param {(Function|Object)} listener The listener to call | |
| * @param {*} thisArg The value to use as `this`` when calling the listener | |
| * @param {Event} event The event to pass to the listener | |
| * @private | |
| */ | |
| function callListener(listener, thisArg, event) { | |
| if (typeof listener === 'object' && listener.handleEvent) { | |
| listener.handleEvent.call(listener, event); | |
| } else { | |
| listener.call(thisArg, event); | |
| } | |
| } | |