1 | 'use strict';
|
2 |
|
3 | const { kForOnEventAttribute, kListener } = require('./constants');
|
4 |
|
5 | const kCode = Symbol('kCode');
|
6 | const kData = Symbol('kData');
|
7 | const kError = Symbol('kError');
|
8 | const kMessage = Symbol('kMessage');
|
9 | const kReason = Symbol('kReason');
|
10 | const kTarget = Symbol('kTarget');
|
11 | const kType = Symbol('kType');
|
12 | const kWasClean = Symbol('kWasClean');
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | class Event {
|
18 | |
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | constructor(type) {
|
25 | this[kTarget] = null;
|
26 | this[kType] = type;
|
27 | }
|
28 |
|
29 | |
30 |
|
31 |
|
32 | get target() {
|
33 | return this[kTarget];
|
34 | }
|
35 |
|
36 | |
37 |
|
38 |
|
39 | get type() {
|
40 | return this[kType];
|
41 | }
|
42 | }
|
43 |
|
44 | Object.defineProperty(Event.prototype, 'target', { enumerable: true });
|
45 | Object.defineProperty(Event.prototype, 'type', { enumerable: true });
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 | class CloseEvent extends Event {
|
53 | |
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 | constructor(type, options = {}) {
|
67 | super(type);
|
68 |
|
69 | 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 | }
|
73 |
|
74 | |
75 |
|
76 |
|
77 | get code() {
|
78 | return this[kCode];
|
79 | }
|
80 |
|
81 | |
82 |
|
83 |
|
84 | get reason() {
|
85 | return this[kReason];
|
86 | }
|
87 |
|
88 | |
89 |
|
90 |
|
91 | get wasClean() {
|
92 | return this[kWasClean];
|
93 | }
|
94 | }
|
95 |
|
96 | Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });
|
97 | Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });
|
98 | Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | class ErrorEvent extends Event {
|
106 | |
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 | constructor(type, options = {}) {
|
116 | super(type);
|
117 |
|
118 | this[kError] = options.error === undefined ? null : options.error;
|
119 | this[kMessage] = options.message === undefined ? '' : options.message;
|
120 | }
|
121 |
|
122 | |
123 |
|
124 |
|
125 | get error() {
|
126 | return this[kError];
|
127 | }
|
128 |
|
129 | |
130 |
|
131 |
|
132 | get message() {
|
133 | return this[kMessage];
|
134 | }
|
135 | }
|
136 |
|
137 | Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });
|
138 | Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 | class MessageEvent extends Event {
|
146 | |
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 | constructor(type, options = {}) {
|
155 | super(type);
|
156 |
|
157 | this[kData] = options.data === undefined ? null : options.data;
|
158 | }
|
159 |
|
160 | |
161 |
|
162 |
|
163 | get data() {
|
164 | return this[kData];
|
165 | }
|
166 | }
|
167 |
|
168 | Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 | const EventTarget = {
|
177 | |
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
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 | }
|
199 |
|
200 | let wrapper;
|
201 |
|
202 | if (type === 'message') {
|
203 | wrapper = function onMessage(data, isBinary) {
|
204 | const event = new MessageEvent('message', {
|
205 | data: isBinary ? data : data.toString()
|
206 | });
|
207 |
|
208 | 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._closeFrameSent
|
217 | });
|
218 |
|
219 | 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.message
|
227 | });
|
228 |
|
229 | event[kTarget] = this;
|
230 | callListener(handler, this, event);
|
231 | };
|
232 | } else if (type === 'open') {
|
233 | wrapper = function onOpen() {
|
234 | const event = new Event('open');
|
235 |
|
236 | event[kTarget] = this;
|
237 | callListener(handler, this, event);
|
238 | };
|
239 | } else {
|
240 | return;
|
241 | }
|
242 |
|
243 | wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];
|
244 | wrapper[kListener] = handler;
|
245 |
|
246 | if (options.once) {
|
247 | this.once(type, wrapper);
|
248 | } else {
|
249 | this.on(type, wrapper);
|
250 | }
|
251 | },
|
252 |
|
253 | |
254 |
|
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
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 | };
|
269 |
|
270 | module.exports = {
|
271 | CloseEvent,
|
272 | ErrorEvent,
|
273 | Event,
|
274 | EventTarget,
|
275 | MessageEvent
|
276 | };
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 | function 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 | }
|