JavaScript 65.5%
Python 17.8%
CSS 13%
HTML 3.7%
1'use strict';23const { kForOnEventAttribute, kListener } = require('./constants');45const kCode = Symbol('kCode');6const kData = Symbol('kData');7const kError = Symbol('kError');8const kMessage = Symbol('kMessage');9const kReason = Symbol('kReason');10const kTarget = Symbol('kTarget');11const kType = Symbol('kType');12const kWasClean = Symbol('kWasClean');1314/**15 * Class representing an event.16 */17class Event {18 /**19 * Create a new `Event`.20 *21 * @param {String} type The name of the event22 * @throws {TypeError} If the `type` argument is not specified23 */24 constructor(type) {25 this[kTarget] = null;26 this[kType] = type;27 }2829 /**30 * @type {*}31 */32 get target() {33 return this[kTarget];34 }3536 /**37 * @type {String}38 */39 get type() {40 return this[kType];41 }42}4344Object.defineProperty(Event.prototype, 'target', { enumerable: true });45Object.defineProperty(Event.prototype, 'type', { enumerable: true });4647/**48 * Class representing a close event.49 *50 * @extends Event51 */52class CloseEvent extends Event {53 /**54 * Create a new `CloseEvent`.55 *56 * @param {String} type The name of the event57 * @param {Object} [options] A dictionary object that allows for setting58 * attributes via object members of the same name59 * @param {Number} [options.code=0] The status code explaining why the60 * connection was closed61 * @param {String} [options.reason=''] A human-readable string explaining why62 * the connection was closed63 * @param {Boolean} [options.wasClean=false] Indicates whether or not the64 * connection was cleanly closed65 */66 constructor(type, options = {}) {67 super(type);6869 this[kCode] = options.code === undefined ? 0 : options.code;70 this[kReason] = options.reason === undefined ? '' : options.reason;71 this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;72 }7374 /**75 * @type {Number}76 */77 get code() {78 return this[kCode];79 }8081 /**82 * @type {String}83 */84 get reason() {85 return this[kReason];86 }8788 /**89 * @type {Boolean}90 */91 get wasClean() {92 return this[kWasClean];93 }94}9596Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });97Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });98Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });99100/**101 * Class representing an error event.102 *103 * @extends Event104 */105class ErrorEvent extends Event {106 /**107 * Create a new `ErrorEvent`.108 *109 * @param {String} type The name of the event110 * @param {Object} [options] A dictionary object that allows for setting111 * attributes via object members of the same name112 * @param {*} [options.error=null] The error that generated this event113 * @param {String} [options.message=''] The error message114 */115 constructor(type, options = {}) {116 super(type);117118 this[kError] = options.error === undefined ? null : options.error;119 this[kMessage] = options.message === undefined ? '' : options.message;120 }121122 /**123 * @type {*}124 */125 get error() {126 return this[kError];127 }128129 /**130 * @type {String}131 */132 get message() {133 return this[kMessage];134 }135}136137Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });138Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });139140/**141 * Class representing a message event.142 *143 * @extends Event144 */145class MessageEvent extends Event {146 /**147 * Create a new `MessageEvent`.148 *149 * @param {String} type The name of the event150 * @param {Object} [options] A dictionary object that allows for setting151 * attributes via object members of the same name152 * @param {*} [options.data=null] The message content153 */154 constructor(type, options = {}) {155 super(type);156157 this[kData] = options.data === undefined ? null : options.data;158 }159160 /**161 * @type {*}162 */163 get data() {164 return this[kData];165 }166}167168Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });169170/**171 * This provides methods for emulating the `EventTarget` interface. It's not172 * meant to be used directly.173 *174 * @mixin175 */176const EventTarget = {177 /**178 * Register an event listener.179 *180 * @param {String} type A string representing the event type to listen for181 * @param {(Function|Object)} handler The listener to add182 * @param {Object} [options] An options object specifies characteristics about183 * the event listener184 * @param {Boolean} [options.once=false] A `Boolean` indicating that the185 * listener should be invoked at most once after being added. If `true`,186 * the listener would be automatically removed when invoked.187 * @public188 */189 addEventListener(type, handler, options = {}) {190 for (const listener of this.listeners(type)) {191 if (192 !options[kForOnEventAttribute] &&193 listener[kListener] === handler &&194 !listener[kForOnEventAttribute]195 ) {196 return;197 }198 }199200 let wrapper;201202 if (type === 'message') {203 wrapper = function onMessage(data, isBinary) {204 const event = new MessageEvent('message', {205 data: isBinary ? data : data.toString()206 });207208 event[kTarget] = this;209 callListener(handler, this, event);210 };211 } else if (type === 'close') {212 wrapper = function onClose(code, message) {213 const event = new CloseEvent('close', {214 code,215 reason: message.toString(),216 wasClean: this._closeFrameReceived && this._closeFrameSent217 });218219 event[kTarget] = this;220 callListener(handler, this, event);221 };222 } else if (type === 'error') {223 wrapper = function onError(error) {224 const event = new ErrorEvent('error', {225 error,226 message: error.message227 });228229 event[kTarget] = this;230 callListener(handler, this, event);231 };232 } else if (type === 'open') {233 wrapper = function onOpen() {234 const event = new Event('open');235236 event[kTarget] = this;237 callListener(handler, this, event);238 };239 } else {240 return;241 }242243 wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];244 wrapper[kListener] = handler;245246 if (options.once) {247 this.once(type, wrapper);248 } else {249 this.on(type, wrapper);250 }251 },252253 /**254 * Remove an event listener.255 *256 * @param {String} type A string representing the event type to remove257 * @param {(Function|Object)} handler The listener to remove258 * @public259 */260 removeEventListener(type, handler) {261 for (const listener of this.listeners(type)) {262 if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {263 this.removeListener(type, listener);264 break;265 }266 }267 }268};269270module.exports = {271 CloseEvent,272 ErrorEvent,273 Event,274 EventTarget,275 MessageEvent276};277278/**279 * Call an event listener280 *281 * @param {(Function|Object)} listener The listener to call282 * @param {*} thisArg The value to use as `this`` when calling the listener283 * @param {Event} event The event to pass to the listener284 * @private285 */286function callListener(listener, thisArg, event) {287 if (typeof listener === 'object' && listener.handleEvent) {288 listener.handleEvent.call(listener, event);289 } else {290 listener.call(thisArg, event);291 }292}293