mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-13 06:20:02 -04:00
165 lines
4 KiB
TypeScript
165 lines
4 KiB
TypeScript
import { iswindow } from "..";
|
|
import { SCRAMJETCLIENT } from "../../symbols";
|
|
import { ScramjetClient } from "../client";
|
|
import { getOwnPropertyDescriptorHandler } from "../helpers";
|
|
import { nativeGetOwnPropertyDescriptor } from "../natives";
|
|
import { unproxy } from "./unproxy";
|
|
|
|
const realOnEvent = Symbol.for("scramjet original onevent function");
|
|
|
|
export default function (client: ScramjetClient, self: Self) {
|
|
const handlers = {
|
|
message: {
|
|
_init() {
|
|
if (typeof this.data === "object" && "$scramjet$type" in this.data) {
|
|
// this is a ctl message
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
ports() {
|
|
// don't know why i have to do this?
|
|
return this.ports;
|
|
},
|
|
source() {
|
|
let scram: ScramjetClient = this.source[SCRAMJETCLIENT];
|
|
|
|
if (scram) return scram.globalProxy;
|
|
|
|
return this.source;
|
|
},
|
|
origin() {
|
|
if (typeof this.data === "object" && "$scramjet$origin" in this.data)
|
|
return this.data.$scramjet$origin;
|
|
|
|
// then it must be from a worker, which we aren't currently rewriting
|
|
return client.url.origin;
|
|
},
|
|
data() {
|
|
if (typeof this.data === "object" && "$scramjet$data" in this.data)
|
|
return this.data.$scramjet$data;
|
|
|
|
return this.data;
|
|
},
|
|
},
|
|
};
|
|
|
|
function wraplistener(listener: (...args: any) => any) {
|
|
return new Proxy(listener, {
|
|
apply(target, thisArg, argArray) {
|
|
const realEvent: Event = argArray[0];
|
|
|
|
// we only need to handle events dispatched from the browser
|
|
if (realEvent.isTrusted) {
|
|
const type = realEvent.type;
|
|
|
|
if (type in handlers) {
|
|
const handler = handlers[type];
|
|
|
|
if (handler._init) {
|
|
if (handler._init.call(realEvent) === false) return;
|
|
}
|
|
|
|
argArray[0] = new Proxy(realEvent, {
|
|
get(_target, prop, reciever) {
|
|
if (prop in handler) {
|
|
return handler[prop].call(_target);
|
|
}
|
|
|
|
return Reflect.get(target, prop, reciever);
|
|
},
|
|
getOwnPropertyDescriptor: getOwnPropertyDescriptorHandler,
|
|
});
|
|
}
|
|
}
|
|
|
|
return Reflect.apply(target, thisArg, argArray);
|
|
},
|
|
getOwnPropertyDescriptor: getOwnPropertyDescriptorHandler,
|
|
});
|
|
}
|
|
|
|
client.Proxy("EventTarget.prototype.addEventListener", {
|
|
apply(ctx) {
|
|
unproxy(ctx, client);
|
|
if (typeof ctx.args[1] !== "function") return;
|
|
|
|
const origlistener = ctx.args[1];
|
|
const proxylistener = wraplistener(origlistener);
|
|
|
|
ctx.args[1] = proxylistener;
|
|
|
|
let arr = client.eventcallbacks.get(ctx.this);
|
|
arr ||= [] as any;
|
|
arr.push({
|
|
event: ctx.args[0] as string,
|
|
originalCallback: origlistener,
|
|
proxiedCallback: proxylistener,
|
|
});
|
|
client.eventcallbacks.set(ctx.this, arr);
|
|
},
|
|
});
|
|
|
|
client.Proxy("EventTarget.prototype.removeEventListener", {
|
|
apply(ctx) {
|
|
unproxy(ctx, client);
|
|
if (typeof ctx.args[1] !== "function") return;
|
|
|
|
const arr = client.eventcallbacks.get(ctx.this);
|
|
if (!arr) return;
|
|
|
|
const i = arr.findIndex(
|
|
(e) => e.event === ctx.args[0] && e.originalCallback === ctx.args[1]
|
|
);
|
|
if (i === -1) return;
|
|
|
|
const r = arr.splice(i, 1);
|
|
client.eventcallbacks.set(ctx.this, arr);
|
|
|
|
ctx.args[1] = r[0].proxiedCallback;
|
|
},
|
|
});
|
|
|
|
client.Proxy("EventTarget.prototype.dispatchEvent", {
|
|
apply(ctx) {
|
|
unproxy(ctx, client);
|
|
},
|
|
});
|
|
|
|
if (!iswindow) return;
|
|
|
|
const targets = [self.window, self.HTMLElement.prototype];
|
|
|
|
for (const target of targets) {
|
|
const keys = Reflect.ownKeys(target);
|
|
|
|
for (const key of keys) {
|
|
if (
|
|
typeof key === "string" &&
|
|
key.startsWith("on") &&
|
|
handlers[key.slice(2)]
|
|
) {
|
|
const descriptor = nativeGetOwnPropertyDescriptor(target, key);
|
|
if (!descriptor.get || !descriptor.set || !descriptor.configurable)
|
|
continue;
|
|
|
|
// these are the `onmessage`, `onclick`, etc. properties
|
|
client.RawTrap(target, key, {
|
|
get(ctx) {
|
|
if (this[realOnEvent]) return this[realOnEvent];
|
|
|
|
return ctx.get();
|
|
},
|
|
set(ctx, value: any) {
|
|
this[realOnEvent] = value;
|
|
|
|
if (typeof value !== "function") return ctx.set(value);
|
|
|
|
ctx.set(wraplistener(value));
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|