-
Notifications
You must be signed in to change notification settings - Fork 0
/
PE.js
106 lines (106 loc) · 4.76 KB
/
PE.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
export class PE {
#abortControllers = [];
#evTg2DMN2OMN2ET2AC = new WeakMap();
#waitingForDisconnect = new WeakSet();
async do(proxy, originMethodName, vals) {
//this.disconnect(originMethodName);
const controller = proxy.controller;
if (!(controller instanceof EventTarget))
throw ("Controller must extend EventTarget");
if (!this.#waitingForDisconnect.has(controller)) {
controller.addEventListener('was-decorated', e => {
this.disconnectAll();
}, { once: true });
this.#waitingForDisconnect.add(controller);
}
if (vals[0] !== undefined) {
Object.assign(proxy, vals[0]);
}
if (vals[1] !== undefined) {
for (const methodName in vals[1]) {
const ec = vals[1][methodName];
if (ec === true) {
const ret = await controller[methodName](proxy);
this.recurse(ret, proxy, methodName);
return;
}
const { on, abort, options } = ec;
if (on !== undefined) {
const { of, doInit } = ec;
if (!(of instanceof EventTarget))
throw { of, msg: 'not an EventTarget' };
let dmn2omn2et2ac = this.#evTg2DMN2OMN2ET2AC.get(of);
if (dmn2omn2et2ac === undefined) {
dmn2omn2et2ac = new Map();
this.#evTg2DMN2OMN2ET2AC.set(of, dmn2omn2et2ac);
}
let omn2et2ac = dmn2omn2et2ac.get(methodName);
if (omn2et2ac === undefined) {
omn2et2ac = new Map();
dmn2omn2et2ac.set(methodName, omn2et2ac);
}
let et2ac = omn2et2ac.get(originMethodName);
if (et2ac === undefined) {
et2ac = new Map();
omn2et2ac.set(originMethodName, et2ac);
}
let ac = et2ac.get(on);
if (ac === undefined) {
ac = new AbortController();
this.#abortControllers.push(ac);
et2ac.set(on, ac);
}
const method = controller[methodName];
const isAsync = method.constructor.name === 'AsyncFunction';
//console.log({method, isAsync, key, ec});
const addEventListenerOptions = options || {};
addEventListenerOptions.signal = ac.signal;
of.addEventListener(on, async (e) => {
const { composedPathMatches } = ec;
let foundEl;
if (composedPathMatches !== undefined) {
const composedPath = e.composedPath(); // as Element[];
for (const el of composedPath) {
if ((el instanceof Element) && el.matches(composedPathMatches)) {
foundEl = el;
break;
}
}
if (foundEl === undefined)
return;
}
const ret = isAsync ? await controller[methodName](proxy, e, foundEl) : controller[methodName](proxy, e, foundEl);
await this.recurse(ret, proxy, methodName);
}, addEventListenerOptions);
if (doInit) {
const ret = isAsync ? await controller[methodName](proxy) : controller[methodName](proxy);
await this.recurse(ret, proxy, methodName);
}
}
if (abort !== undefined) {
const { of, origMethName, on } = abort;
if (!(of instanceof EventTarget))
throw { of, msg: 'not an EventTarget' };
const et2ac = this.#evTg2DMN2OMN2ET2AC.get(of)?.get(methodName)?.get(origMethName);
const ac = et2ac?.get(on);
if (ac !== undefined) {
ac.abort();
et2ac?.set(on, new AbortController());
}
}
}
}
}
async recurse(ret, proxy, methodName) {
if (ret === undefined)
return;
const arg = (Array.isArray(ret) ? ret : [ret]);
const pe = new PE();
await pe.do(proxy, methodName, arg);
}
disconnectAll() {
for (const ac of this.#abortControllers) {
ac.abort();
}
}
}