import EventEmitter from "events";
class LocationApi extends EventEmitter {
constructor(ctx) {
super();
this.ctx = ctx;
this.window = ctx.window;
this.location = this.window.location;
this.WorkerLocation = this.ctx.worker ? this.window.WorkerLocation : null;
this.workerLocProto = this.WorkerLocation
? this.WorkerLocation.prototype
: {};
this.keys = [
"href",
"protocol",
"host",
"hostname",
"port",
"pathname",
"search",
"hash",
"origin",
];
this.HashChangeEvent = this.window.HashChangeEvent || null;
this.href = this.WorkerLocation
? ctx.nativeMethods.getOwnPropertyDescriptor(this.workerLocProto, "href")
: ctx.nativeMethods.getOwnPropertyDescriptor(this.location, "href");
}
overrideWorkerLocation(parse) {
if (!this.WorkerLocation) return false;
const uv = this;
for (const key of this.keys) {
this.ctx.overrideDescriptor(this.workerLocProto, key, {
get: () => {
return parse(uv.href.get.call(this.location))[key];
},
});
}
return true;
}
emulate(parse, wrap) {
const emulation = {};
const that = this;
for (const key of that.keys) {
this.ctx.nativeMethods.defineProperty(emulation, key, {
get() {
return parse(that.href.get.call(that.location))[key];
},
set:
key !== "origin"
? function (val) {
switch (key) {
case "href":
that.location.href = wrap(val);
break;
case "hash":
that.emit(
"hashchange",
emulation.href,
val.trim().startsWith("#")
? new URL(val.trim(), emulation.href).href
: new URL("#" + val.trim(), emulation.href).href,
that
);
break;
default:
{
const url = new URL(emulation.href);
url[key] = val;
that.location.href = wrap(url.href);
}
break;
}
}
: undefined,
configurable: false,
enumerable: true,
});
}
if ("reload" in this.location) {
this.ctx.nativeMethods.defineProperty(emulation, "reload", {
value: this.ctx.wrap(this.location, "reload", (target, that) => {
return target.call(that === emulation ? this.location : that);
}),
writable: false,
enumerable: true,
});
}
if ("replace" in this.location) {
this.ctx.nativeMethods.defineProperty(emulation, "replace", {
value: this.ctx.wrap(this.location, "assign", (target, that, args) => {
if (!args.length || that !== emulation) target.call(that);
that = this.location;
let [input] = args;
const url = new URL(input, emulation.href);
return target.call(
that === emulation ? this.location : that,
wrap(url.href)
);
}),
writable: false,
enumerable: true,
});
}
if ("assign" in this.location) {
this.ctx.nativeMethods.defineProperty(emulation, "assign", {
value: this.ctx.wrap(this.location, "assign", (target, that, args) => {
if (!args.length || that !== emulation) target.call(that);
that = this.location;
let [input] = args;
const url = new URL(input, emulation.href);
return target.call(
that === emulation ? this.location : that,
wrap(url.href)
);
}),
writable: false,
enumerable: true,
});
}
if ("ancestorOrigins" in this.location) {
this.ctx.nativeMethods.defineProperty(emulation, "ancestorOrigins", {
get() {
const arr = [];
if (that.window.DOMStringList)
that.ctx.nativeMethods.setPrototypeOf(
arr,
that.window.DOMStringList.prototype
);
return arr;
},
set: undefined,
enumerable: true,
});
}
this.ctx.nativeMethods.defineProperty(emulation, "toString", {
value: this.ctx.wrap(this.location, "toString", () => {
return emulation.href;
}),
enumerable: true,
writable: false,
});
this.ctx.nativeMethods.defineProperty(emulation, Symbol.toPrimitive, {
value: () => emulation.href,
writable: false,
enumerable: false,
});
if (this.ctx.window.Location)
this.ctx.nativeMethods.setPrototypeOf(
emulation,
this.ctx.window.Location.prototype
);
return emulation;
}
}
export default LocationApi;