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