|
'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 Event { |
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(type) { |
|
this[kTarget] = null; |
|
this[kType] = type; |
|
} |
|
|
|
|
|
|
|
|
|
get target() { |
|
return this[kTarget]; |
|
} |
|
|
|
|
|
|
|
|
|
get type() { |
|
return this[kType]; |
|
} |
|
} |
|
|
|
Object.defineProperty(Event.prototype, 'target', { enumerable: true }); |
|
Object.defineProperty(Event.prototype, 'type', { enumerable: true }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
class CloseEvent extends Event { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
} |
|
|
|
|
|
|
|
|
|
get code() { |
|
return this[kCode]; |
|
} |
|
|
|
|
|
|
|
|
|
get reason() { |
|
return this[kReason]; |
|
} |
|
|
|
|
|
|
|
|
|
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 ErrorEvent extends Event { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(type, options = {}) { |
|
super(type); |
|
|
|
this[kError] = options.error === undefined ? null : options.error; |
|
this[kMessage] = options.message === undefined ? '' : options.message; |
|
} |
|
|
|
|
|
|
|
|
|
get error() { |
|
return this[kError]; |
|
} |
|
|
|
|
|
|
|
|
|
get message() { |
|
return this[kMessage]; |
|
} |
|
} |
|
|
|
Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true }); |
|
Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
class MessageEvent extends Event { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(type, options = {}) { |
|
super(type); |
|
|
|
this[kData] = options.data === undefined ? null : options.data; |
|
} |
|
|
|
|
|
|
|
|
|
get data() { |
|
return this[kData]; |
|
} |
|
} |
|
|
|
Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const EventTarget = { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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); |
|
} |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function callListener(listener, thisArg, event) { |
|
if (typeof listener === 'object' && listener.handleEvent) { |
|
listener.handleEvent.call(listener, event); |
|
} else { |
|
listener.call(thisArg, event); |
|
} |
|
} |
|
|