2024-03-20 09:01:03 +00:00
|
|
|
export class Builder {
|
|
|
|
|
builderWindow: Window | null;
|
|
|
|
|
|
|
|
|
|
onMessageMap: Map<string, ((data: unknown) => void)[]> = new Map();
|
|
|
|
|
|
|
|
|
|
handleMessageBound = this.handleMessage.bind(this);
|
|
|
|
|
|
|
|
|
|
constructor() {
|
2024-12-06 10:33:40 +00:00
|
|
|
// when we add new widget, we add a /add to the url , so before opening the builder, we need to remove it
|
|
|
|
|
const path = window.location.pathname.replace(/\/add$/, "");
|
|
|
|
|
|
|
|
|
|
this.builderWindow = window.open(`${path}/builder`, "_blank");
|
2023-12-28 06:46:28 +00:00
|
|
|
|
2024-03-20 09:01:03 +00:00
|
|
|
window?.addEventListener("message", this.handleMessageBound);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleMessage(event: MessageEvent) {
|
|
|
|
|
if (event.source === this.builderWindow) {
|
|
|
|
|
const handlerList = this.onMessageMap.get(event.data.type);
|
2023-12-28 06:46:28 +00:00
|
|
|
|
2024-03-20 09:01:03 +00:00
|
|
|
if (handlerList) {
|
|
|
|
|
handlerList.forEach((fn) => fn?.(event.data));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-28 06:46:28 +00:00
|
|
|
|
2024-03-20 09:01:03 +00:00
|
|
|
onMessage(type: string, fn: (data: unknown) => void) {
|
|
|
|
|
let eventHandlerList = this.onMessageMap.get(type);
|
2023-12-28 06:46:28 +00:00
|
|
|
|
|
|
|
|
if (eventHandlerList && eventHandlerList instanceof Array) {
|
|
|
|
|
eventHandlerList.push(fn);
|
|
|
|
|
} else {
|
|
|
|
|
eventHandlerList = [fn];
|
2024-03-20 09:01:03 +00:00
|
|
|
this.onMessageMap.set(type, eventHandlerList);
|
2023-12-28 06:46:28 +00:00
|
|
|
}
|
2024-03-20 09:01:03 +00:00
|
|
|
|
2023-12-28 06:46:28 +00:00
|
|
|
return () => {
|
|
|
|
|
if (eventHandlerList) {
|
|
|
|
|
const index = eventHandlerList.indexOf(fn);
|
|
|
|
|
|
|
|
|
|
if (index > -1) {
|
|
|
|
|
eventHandlerList.splice(index, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-20 09:01:03 +00:00
|
|
|
postMessage(message: unknown) {
|
|
|
|
|
this.builderWindow?.postMessage(message, "*");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isConnected() {
|
|
|
|
|
return !this.builderWindow?.closed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
focus() {
|
|
|
|
|
this.builderWindow?.focus();
|
|
|
|
|
}
|
2023-12-28 06:46:28 +00:00
|
|
|
|
2024-03-20 09:01:03 +00:00
|
|
|
close(closeWindow: boolean) {
|
|
|
|
|
if (closeWindow) {
|
|
|
|
|
this.builderWindow?.close();
|
|
|
|
|
}
|
2023-12-28 06:46:28 +00:00
|
|
|
|
2024-03-20 09:01:03 +00:00
|
|
|
window?.removeEventListener("message", this.handleMessageBound);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-28 06:46:28 +00:00
|
|
|
|
|
|
|
|
export default class CustomWidgetBuilderService {
|
2024-03-20 09:01:03 +00:00
|
|
|
private static builderWindowConnections: Map<string, Builder> = new Map();
|
|
|
|
|
|
|
|
|
|
// For unit testing purposes
|
|
|
|
|
private static builderFactory = Builder;
|
|
|
|
|
|
|
|
|
|
// For unit testing purposes
|
|
|
|
|
static setBuilderFactory(builder: typeof Builder) {
|
|
|
|
|
this.builderFactory = builder;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static createBuilder(widgetId: string) {
|
|
|
|
|
const builder = new this.builderFactory();
|
2023-12-28 06:46:28 +00:00
|
|
|
|
2024-03-20 09:01:03 +00:00
|
|
|
this.builderWindowConnections.set(widgetId, builder);
|
|
|
|
|
|
|
|
|
|
return builder;
|
2023-12-28 06:46:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static isConnected(widgetId: string) {
|
2024-03-20 09:01:03 +00:00
|
|
|
const builder = this.builderWindowConnections.get(widgetId);
|
2023-12-28 06:46:28 +00:00
|
|
|
|
2024-03-20 09:01:03 +00:00
|
|
|
return builder?.isConnected();
|
2023-12-28 06:46:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static focus(widgetId: string) {
|
|
|
|
|
if (this.isConnected(widgetId)) {
|
2024-03-20 09:01:03 +00:00
|
|
|
this.builderWindowConnections.get(widgetId)?.focus();
|
2023-12-28 06:46:28 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-20 09:01:03 +00:00
|
|
|
static getBuilder(widgetId: string) {
|
2023-12-28 06:46:28 +00:00
|
|
|
if (this.isConnected(widgetId)) {
|
2024-03-20 09:01:03 +00:00
|
|
|
const builder = this.builderWindowConnections.get(widgetId) as Builder;
|
|
|
|
|
|
|
|
|
|
return builder;
|
2023-12-28 06:46:28 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-20 09:01:03 +00:00
|
|
|
static closeBuilder(widgetId: string, closeWindow: boolean) {
|
2023-12-28 06:46:28 +00:00
|
|
|
if (this.builderWindowConnections.has(widgetId)) {
|
2024-03-20 09:01:03 +00:00
|
|
|
const builder = this.builderWindowConnections.get(widgetId);
|
2023-12-28 06:46:28 +00:00
|
|
|
|
2024-03-20 09:01:03 +00:00
|
|
|
builder?.close(closeWindow);
|
2023-12-28 06:46:28 +00:00
|
|
|
|
|
|
|
|
this.builderWindowConnections.delete(widgetId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|