forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			267 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			267 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | 'use strict'; | ||
|  | 
 | ||
|  | 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} listener 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, listener, options = {}) { | ||
|  |     let wrapper; | ||
|  | 
 | ||
|  |     if (type === 'message') { | ||
|  |       wrapper = function onMessage(data, isBinary) { | ||
|  |         const event = new MessageEvent('message', { | ||
|  |           data: isBinary ? data : data.toString() | ||
|  |         }); | ||
|  | 
 | ||
|  |         event[kTarget] = this; | ||
|  |         listener.call(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; | ||
|  |         listener.call(this, event); | ||
|  |       }; | ||
|  |     } else if (type === 'error') { | ||
|  |       wrapper = function onError(error) { | ||
|  |         const event = new ErrorEvent('error', { | ||
|  |           error, | ||
|  |           message: error.message | ||
|  |         }); | ||
|  | 
 | ||
|  |         event[kTarget] = this; | ||
|  |         listener.call(this, event); | ||
|  |       }; | ||
|  |     } else if (type === 'open') { | ||
|  |       wrapper = function onOpen() { | ||
|  |         const event = new Event('open'); | ||
|  | 
 | ||
|  |         event[kTarget] = this; | ||
|  |         listener.call(this, event); | ||
|  |       }; | ||
|  |     } else { | ||
|  |       return; | ||
|  |     } | ||
|  | 
 | ||
|  |     wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute]; | ||
|  |     wrapper[kListener] = listener; | ||
|  | 
 | ||
|  |     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} 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 | ||
|  | }; |