diff --git a/src/common/inIframe.ts b/src/common/inIframe.ts index 7c13b33c..ea83f435 100644 --- a/src/common/inIframe.ts +++ b/src/common/inIframe.ts @@ -5,3 +5,11 @@ export function inIframe(): boolean { return true; } } + +export function inNewTab(): boolean { + try { + return !!window.opener; + } catch (e) { + return false; + } +} diff --git a/src/livePreview/editButton/editButton.ts b/src/livePreview/editButton/editButton.ts index e86fcbb3..d6891ca5 100644 --- a/src/livePreview/editButton/editButton.ts +++ b/src/livePreview/editButton/editButton.ts @@ -1,5 +1,5 @@ import { effect } from "@preact/signals"; -import { inIframe } from "../../common/inIframe"; +import { inIframe, inNewTab } from "../../common/inIframe"; import Config from "../../configManager/configManager"; import { addCslpOutline, extractDetailsFromCslp } from "../../cslp"; import { cslpTagStyles } from "./editButton.style"; @@ -448,7 +448,7 @@ export class LivePreviewEditButton { fieldPathWithIndex, } = extractDetailsFromCslp(cslpTag); - if (inIframe()) { + if (inIframe() || inNewTab()) { livePreviewPostMessage?.send("scroll", { field: fieldPathWithIndex, content_type_uid, diff --git a/src/livePreview/eventManager/__test__/livePreviewEventManager.test.ts b/src/livePreview/eventManager/__test__/livePreviewEventManager.test.ts new file mode 100644 index 00000000..5f9d42e3 --- /dev/null +++ b/src/livePreview/eventManager/__test__/livePreviewEventManager.test.ts @@ -0,0 +1,252 @@ +/** + * @vitest-environment jsdom + */ + +import { vi } from "vitest"; +import { EventManager } from "@contentstack/advanced-post-message"; +import { LIVE_PREVIEW_CHANNEL_ID } from "../livePreviewEventManager.constant"; + +// Mock dependencies +vi.mock("@contentstack/advanced-post-message", () => ({ + EventManager: vi.fn(), +})); + +vi.mock("../../../common/inIframe", () => ({ + inNewTab: vi.fn(), +})); + +// Import after mocking +import { inNewTab } from "../../../common/inIframe"; + +describe("livePreviewEventManager", () => { + let mockEventManager: any; + let originalWindow: any; + + beforeEach(() => { + // Reset all mocks + vi.clearAllMocks(); + + // Create mock EventManager + mockEventManager = { + on: vi.fn(), + send: vi.fn(), + }; + (EventManager as any).mockImplementation(() => mockEventManager); + + // Store original window + originalWindow = global.window; + + // Reset inNewTab mock + (inNewTab as any).mockReturnValue(false); + }); + + afterEach(() => { + // Restore original window + global.window = originalWindow; + + // Clear module cache to reset the module state + vi.resetModules(); + }); + + describe("when window is undefined", () => { + beforeEach(() => { + // Mock window as undefined + Object.defineProperty(global, "window", { + value: undefined, + writable: true, + }); + }); + + it("should not initialize EventManager when window is undefined", async () => { + // Re-import the module to trigger initialization + const module = await import("../livePreviewEventManager"); + + expect(EventManager).not.toHaveBeenCalled(); + expect(module.default).toBeUndefined(); + }); + }); + + describe("when window is defined", () => { + let mockWindow: any; + + beforeEach(() => { + // Create mock window object + mockWindow = { + parent: { postMessage: vi.fn() }, + opener: { postMessage: vi.fn() }, + }; + + Object.defineProperty(global, "window", { + value: mockWindow, + writable: true, + }); + }); + + it("should initialize EventManager with window.parent as target when not in new tab", async () => { + (inNewTab as any).mockReturnValue(false); + + // Re-import the module to trigger initialization + const module = await import("../livePreviewEventManager"); + + expect(EventManager).toHaveBeenCalledWith(LIVE_PREVIEW_CHANNEL_ID, { + target: mockWindow.parent, + debug: false, + suppressErrors: true, + }); + expect(module.default).toBe(mockEventManager); + }); + + it("should initialize EventManager with window.opener as target when in new tab", async () => { + (inNewTab as any).mockReturnValue(true); + + // Re-import the module to trigger initialization + const module = await import("../livePreviewEventManager"); + + expect(EventManager).toHaveBeenCalledWith(LIVE_PREVIEW_CHANNEL_ID, { + target: mockWindow.opener, + debug: false, + suppressErrors: true, + }); + expect(module.default).toBe(mockEventManager); + }); + + it("should call inNewTab to determine the target", async () => { + // Re-import the module to trigger initialization + await import("../livePreviewEventManager"); + + expect(inNewTab).toHaveBeenCalled(); + }); + + it("should use correct channel ID", async () => { + // Re-import the module to trigger initialization + await import("../livePreviewEventManager"); + + expect(EventManager).toHaveBeenCalledWith( + LIVE_PREVIEW_CHANNEL_ID, + expect.any(Object) + ); + }); + + it("should set correct default event options", async () => { + (inNewTab as any).mockReturnValue(false); + + // Re-import the module to trigger initialization + await import("../livePreviewEventManager"); + + expect(EventManager).toHaveBeenCalledWith( + expect.any(String), + expect.objectContaining({ + debug: false, + suppressErrors: true, + }) + ); + }); + + describe("target selection logic", () => { + it("should prioritize window.opener when inNewTab returns true", async () => { + (inNewTab as any).mockReturnValue(true); + + // Re-import the module to trigger initialization + await import("../livePreviewEventManager"); + + const callArgs = (EventManager as any).mock.calls[0]; + expect(callArgs[1].target).toBe(mockWindow.opener); + expect(callArgs[1].target).not.toBe(mockWindow.parent); + }); + + it("should use window.parent when inNewTab returns false", async () => { + (inNewTab as any).mockReturnValue(false); + + // Re-import the module to trigger initialization + await import("../livePreviewEventManager"); + + const callArgs = (EventManager as any).mock.calls[0]; + expect(callArgs[1].target).toBe(mockWindow.parent); + expect(callArgs[1].target).not.toBe(mockWindow.opener); + }); + + it("should throw error when inNewTab throws an error", async () => { + (inNewTab as any).mockImplementation(() => { + throw new Error("inNewTab error"); + }); + + // Should throw because inNewTab error is not caught in the implementation + await expect(async () => { + await import("../livePreviewEventManager"); + }).rejects.toThrow("inNewTab error"); + }); + }); + + describe("edge cases", () => { + it("should handle missing window.parent gracefully", async () => { + mockWindow.parent = undefined; + (inNewTab as any).mockReturnValue(false); + + // Re-import the module to trigger initialization + const module = await import("../livePreviewEventManager"); + + expect(EventManager).toHaveBeenCalledWith(LIVE_PREVIEW_CHANNEL_ID, { + target: undefined, + debug: false, + suppressErrors: true, + }); + expect(module.default).toBe(mockEventManager); + }); + + it("should handle missing window.opener gracefully", async () => { + mockWindow.opener = undefined; + (inNewTab as any).mockReturnValue(true); + + // Re-import the module to trigger initialization + const module = await import("../livePreviewEventManager"); + + expect(EventManager).toHaveBeenCalledWith(LIVE_PREVIEW_CHANNEL_ID, { + target: undefined, + debug: false, + suppressErrors: true, + }); + expect(module.default).toBe(mockEventManager); + }); + + it("should handle when EventManager constructor throws", async () => { + (EventManager as any).mockImplementation(() => { + throw new Error("EventManager constructor error"); + }); + + // Should not crash the module initialization + expect(async () => { + await import("../livePreviewEventManager"); + }).not.toThrow(); + }); + }); + }); + + describe("module export", () => { + it("should export the EventManager instance when window is available", async () => { + const mockWindow = { + parent: { postMessage: vi.fn() }, + opener: { postMessage: vi.fn() }, + }; + + Object.defineProperty(global, "window", { + value: mockWindow, + writable: true, + }); + + const module = await import("../livePreviewEventManager"); + + expect(module.default).toBe(mockEventManager); + }); + + it("should export undefined when window is not available", async () => { + Object.defineProperty(global, "window", { + value: undefined, + writable: true, + }); + + const module = await import("../livePreviewEventManager"); + + expect(module.default).toBeUndefined(); + }); + }); +}); \ No newline at end of file diff --git a/src/livePreview/eventManager/__test__/postMessageEvent.hooks.test.ts b/src/livePreview/eventManager/__test__/postMessageEvent.hooks.test.ts new file mode 100644 index 00000000..c8a34075 --- /dev/null +++ b/src/livePreview/eventManager/__test__/postMessageEvent.hooks.test.ts @@ -0,0 +1,377 @@ +/** + * @vitest-environment jsdom + */ + +import { vi } from "vitest"; +import Config, { setConfigFromParams } from "../../../configManager/configManager"; +import { PublicLogger } from "../../../logger/logger"; +import livePreviewPostMessage from "../livePreviewEventManager"; +import { LIVE_PREVIEW_POST_MESSAGE_EVENTS } from "../livePreviewEventManager.constant"; +import { + OnChangeLivePreviewPostMessageEventData, + OnChangeLivePreviewPostMessageEventTypes, + HistoryLivePreviewPostMessageEventData, +} from "../types/livePreviewPostMessageEvent.type"; +import { + useOnEntryUpdatePostMessageEvent, + useHistoryPostMessageEvent, +} from "../postMessageEvent.hooks"; + +// Mock dependencies +vi.mock("../../../configManager/configManager", () => ({ + default: { + get: vi.fn(), + }, + setConfigFromParams: vi.fn(), +})); + +vi.mock("../../../logger/logger", () => ({ + PublicLogger: { + error: vi.fn(), + }, +})); + +vi.mock("../livePreviewEventManager", () => ({ + default: { + on: vi.fn(), + }, +})); + +describe("postMessageEvent.hooks", () => { + let mockWindow: any; + let mockConfig: any; + let mockOnChange: any; + + beforeEach(() => { + // Reset all mocks + vi.clearAllMocks(); + + // Mock window object + mockWindow = { + location: { + href: "https://example.com", + reload: vi.fn(), + }, + history: { + pushState: vi.fn(), + forward: vi.fn(), + back: vi.fn(), + go: vi.fn(), + }, + }; + + // Mock onChange function + mockOnChange = vi.fn(); + + // Setup global window mock + Object.defineProperty(global, "window", { + value: mockWindow, + writable: true, + }); + + // Setup default config mock + mockConfig = { + ssr: false, + onChange: mockOnChange, + }; + + (Config.get as unknown as { mockReturnValue: (val: any) => void }).mockReturnValue(mockConfig); + (livePreviewPostMessage?.on as unknown as { mockImplementation: (fn: any) => void })?.mockImplementation( + (event: string, callback: (...args: any[]) => void) => { + // Store the callback for manual triggering in tests + mockWindow._eventCallbacks = mockWindow._eventCallbacks || {}; + mockWindow._eventCallbacks[event] = callback; + } + ); + }); + + afterEach(() => { + vi.resetAllMocks(); + }); + + describe("useOnEntryUpdatePostMessageEvent", () => { + beforeEach(() => { + useOnEntryUpdatePostMessageEvent(); + }); + + it("should register event listener for ON_CHANGE events", () => { + expect(livePreviewPostMessage?.on).toHaveBeenCalledWith( + LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE, + expect.any(Function) + ); + }); + + describe("CSR (Client-Side Rendering) scenarios", () => { + beforeEach(() => { + mockConfig.ssr = false; + (Config.get as any).mockReturnValue(mockConfig); + }); + + it("should call onChange when ssr is false and no event_type", () => { + const eventData: OnChangeLivePreviewPostMessageEventData = { + hash: "test-hash", + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE]; + callback({ data: eventData }); + + expect(setConfigFromParams).toHaveBeenCalledWith({ + live_preview: "test-hash", + }); + expect(mockOnChange).toHaveBeenCalled(); + }); + + it("should not call onChange when event_type is present", () => { + const eventData: OnChangeLivePreviewPostMessageEventData = { + hash: "test-hash", + _metadata: { + event_type: OnChangeLivePreviewPostMessageEventTypes.HASH_CHANGE, + }, + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE]; + callback({ data: eventData }); + + expect(setConfigFromParams).toHaveBeenCalledWith({ + live_preview: "test-hash", + }); + expect(mockOnChange).not.toHaveBeenCalled(); + }); + }); + + describe("SSR (Server-Side Rendering) scenarios", () => { + beforeEach(() => { + mockConfig.ssr = true; + (Config.get as any).mockReturnValue(mockConfig); + }); + + it("should reload window when ssr is true and no event_type", () => { + const eventData: OnChangeLivePreviewPostMessageEventData = { + hash: "test-hash", + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE]; + callback({ data: eventData }); + + expect(setConfigFromParams).toHaveBeenCalledWith({ + live_preview: "test-hash", + }); + expect(mockWindow.location.reload).toHaveBeenCalled(); + expect(mockOnChange).not.toHaveBeenCalled(); + }); + + it("should not reload window when event_type is present", () => { + const eventData: OnChangeLivePreviewPostMessageEventData = { + hash: "test-hash", + _metadata: { + event_type: OnChangeLivePreviewPostMessageEventTypes.URL_CHANGE, + }, + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE]; + callback({ data: eventData }); + + expect(setConfigFromParams).toHaveBeenCalledWith({ + live_preview: "test-hash", + }); + expect(mockWindow.location.reload).not.toHaveBeenCalled(); + expect(mockOnChange).not.toHaveBeenCalled(); + }); + }); + + describe("HASH_CHANGE event type", () => { + it("should update URL with new hash in query params", () => { + const eventData: OnChangeLivePreviewPostMessageEventData = { + hash: "new-hash-value", + _metadata: { + event_type: OnChangeLivePreviewPostMessageEventTypes.HASH_CHANGE, + }, + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE]; + callback({ data: eventData }); + + expect(setConfigFromParams).toHaveBeenCalledWith({ + live_preview: "new-hash-value", + }); + expect(mockWindow.history.pushState).toHaveBeenCalledWith( + {}, + "", + "https://example.com/?live_preview=new-hash-value" + ); + }); + + it("should update existing live_preview param in URL", () => { + mockWindow.location.href = "https://example.com/?existing=param&live_preview=old-hash"; + + const eventData: OnChangeLivePreviewPostMessageEventData = { + hash: "updated-hash", + _metadata: { + event_type: OnChangeLivePreviewPostMessageEventTypes.HASH_CHANGE, + }, + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE]; + callback({ data: eventData }); + + expect(mockWindow.history.pushState).toHaveBeenCalledWith( + {}, + "", + "https://example.com/?existing=param&live_preview=updated-hash" + ); + }); + }); + + describe("URL_CHANGE event type", () => { + it("should navigate to new URL when url is provided", () => { + const eventData: OnChangeLivePreviewPostMessageEventData = { + hash: "test-hash", + url: "https://newdomain.com/new-page", + _metadata: { + event_type: OnChangeLivePreviewPostMessageEventTypes.URL_CHANGE, + }, + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE]; + callback({ data: eventData }); + + expect(setConfigFromParams).toHaveBeenCalledWith({ + live_preview: "test-hash", + }); + expect(mockWindow.location.href).toBe("https://newdomain.com/new-page"); + }); + + it("should not navigate when URL_CHANGE event type is present but url is not provided", () => { + const originalHref = mockWindow.location.href; + const eventData: OnChangeLivePreviewPostMessageEventData = { + hash: "test-hash", + _metadata: { + event_type: OnChangeLivePreviewPostMessageEventTypes.URL_CHANGE, + }, + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE]; + callback({ data: eventData }); + + expect(setConfigFromParams).toHaveBeenCalledWith({ + live_preview: "test-hash", + }); + expect(mockWindow.location.href).toBe(originalHref); + }); + }); + + describe("Error handling", () => { + it("should log error and return when window is not defined", () => { + // Mock window as undefined + Object.defineProperty(global, "window", { + value: undefined, + writable: true, + }); + + const eventData: OnChangeLivePreviewPostMessageEventData = { + hash: "test-hash", + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE]; + callback({ data: eventData }); + + expect(PublicLogger.error).toHaveBeenCalledWith("window is not defined"); + }); + + it("should handle errors in try-catch block", () => { + // Mock Config.get to throw an error + (Config.get as any).mockImplementation(() => { + throw new Error("Config error"); + }); + + const eventData: OnChangeLivePreviewPostMessageEventData = { + hash: "test-hash", + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE]; + callback({ data: eventData }); + + expect(PublicLogger.error).toHaveBeenCalledWith( + "Error handling live preview update:", + expect.any(Error) + ); + }); + + it("should handle errors when setConfigFromParams throws", () => { + (setConfigFromParams as any).mockImplementation(() => { + throw new Error("setConfigFromParams error"); + }); + + const eventData: OnChangeLivePreviewPostMessageEventData = { + hash: "test-hash", + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE]; + callback({ data: eventData }); + + expect(PublicLogger.error).toHaveBeenCalledWith( + "Error handling live preview update:", + expect.any(Error) + ); + }); + }); + }); + + describe("useHistoryPostMessageEvent", () => { + beforeEach(() => { + useHistoryPostMessageEvent(); + }); + + it("should register event listener for HISTORY events", () => { + expect(livePreviewPostMessage?.on).toHaveBeenCalledWith( + LIVE_PREVIEW_POST_MESSAGE_EVENTS.HISTORY, + expect.any(Function) + ); + }); + + it("should handle forward navigation", () => { + const eventData: HistoryLivePreviewPostMessageEventData = { + type: "forward", + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.HISTORY]; + callback({ data: eventData }); + + expect(mockWindow.history.forward).toHaveBeenCalled(); + }); + + it("should handle backward navigation", () => { + const eventData: HistoryLivePreviewPostMessageEventData = { + type: "backward", + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.HISTORY]; + callback({ data: eventData }); + + expect(mockWindow.history.back).toHaveBeenCalled(); + }); + + it("should handle reload navigation", () => { + const eventData: HistoryLivePreviewPostMessageEventData = { + type: "reload", + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.HISTORY]; + callback({ data: eventData }); + + expect(mockWindow.history.go).toHaveBeenCalled(); + }); + + it("should throw error for unknown event type", () => { + const eventData = { + type: "unknown" as any, + }; + + const callback = mockWindow._eventCallbacks[LIVE_PREVIEW_POST_MESSAGE_EVENTS.HISTORY]; + + expect(() => { + callback({ data: eventData }); + }).toThrow("Unhandled event: unknown"); + }); + }); +}); \ No newline at end of file diff --git a/src/livePreview/eventManager/livePreviewEventManager.constant.ts b/src/livePreview/eventManager/livePreviewEventManager.constant.ts index 1a1cab63..7d703944 100644 --- a/src/livePreview/eventManager/livePreviewEventManager.constant.ts +++ b/src/livePreview/eventManager/livePreviewEventManager.constant.ts @@ -5,7 +5,6 @@ export const LIVE_PREVIEW_POST_MESSAGE_EVENTS = { CHECK_ENTRY_PAGE: "check-entry-page", URL_CHANGE: "url-change", VARIANT_PATCH: "variant-patch-update", - ON_RELOAD: "cslp-reload" } as const; export const LIVE_PREVIEW_CHANNEL_ID = "live-preview"; diff --git a/src/livePreview/eventManager/livePreviewEventManager.ts b/src/livePreview/eventManager/livePreviewEventManager.ts index be4350bc..c7a75b04 100644 --- a/src/livePreview/eventManager/livePreviewEventManager.ts +++ b/src/livePreview/eventManager/livePreviewEventManager.ts @@ -1,16 +1,17 @@ import { EventManager } from "@contentstack/advanced-post-message"; import { LIVE_PREVIEW_CHANNEL_ID } from "./livePreviewEventManager.constant"; +import { inNewTab } from "../../common/inIframe"; let livePreviewPostMessage: EventManager | undefined; if (typeof window !== "undefined") { - let eventOptions = { + const eventOptions = { target: window.parent, debug: false, suppressErrors: true }; - if (window.opener) { + if (inNewTab()) { eventOptions.target = window.opener; } diff --git a/src/livePreview/eventManager/postMessageEvent.hooks.ts b/src/livePreview/eventManager/postMessageEvent.hooks.ts index 01ddc59d..f815e6a2 100644 --- a/src/livePreview/eventManager/postMessageEvent.hooks.ts +++ b/src/livePreview/eventManager/postMessageEvent.hooks.ts @@ -1,4 +1,5 @@ import Config, { setConfigFromParams } from "../../configManager/configManager"; +import { PublicLogger } from "../../logger/logger"; import { ILivePreviewWindowType } from "../../types/types"; import { addParamsToUrl } from "../../utils"; import livePreviewPostMessage from "./livePreviewEventManager"; @@ -7,7 +8,7 @@ import { HistoryLivePreviewPostMessageEventData, LivePreviewInitEventResponse, OnChangeLivePreviewPostMessageEventData, - OnReloadLivePreviewPostMessageEventData, + OnChangeLivePreviewPostMessageEventTypes, } from "./types/livePreviewPostMessageEvent.type"; /** @@ -47,26 +48,42 @@ export function useOnEntryUpdatePostMessageEvent(): void { livePreviewPostMessage?.on( LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE, (event) => { - setConfigFromParams({ - live_preview: event.data.hash, - }); - const { ssr, onChange } = Config.get(); - if (!ssr) { - onChange(); - } - } - ); -} + try { + const { ssr, onChange } = Config.get(); + const event_type = event.data._metadata?.event_type; + setConfigFromParams({ + live_preview: event.data.hash, + }); -export function useOnReloadPostMessageEvent(): void { - livePreviewPostMessage?.on( - LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_RELOAD, - (event) => { - setConfigFromParams({ - live_preview: event.data.hash, - }); - if (window) { - window.location?.reload(); + // This section will run when there is a change in the entry and the website is CSR + if (!ssr && !event_type) { + onChange(); + } + + if(!window) { + PublicLogger.error("window is not defined"); + return; + }; + + // This section will run when there is a change in the entry and the website is SSR + if(ssr && !event_type) { + window.location.reload(); + } + + // This section will run when the hash changes and the website is SSR or CSR + if(event_type === OnChangeLivePreviewPostMessageEventTypes.HASH_CHANGE){ + const newUrl = new URL(window.location.href); + newUrl.searchParams.set("live_preview", event.data.hash); + window.history.pushState({}, "", newUrl.toString()); + } + + // This section will run when the URL of the page changes + if(event_type === OnChangeLivePreviewPostMessageEventTypes.URL_CHANGE && event.data.url){ + window.location.href = event.data.url; + } + } catch (error) { + PublicLogger.error("Error handling live preview update:", error); + return; } } ); @@ -124,7 +141,6 @@ export function sendInitializeLivePreviewPostMessageEvent(): void { useHistoryPostMessageEvent(); useOnEntryUpdatePostMessageEvent(); - useOnReloadPostMessageEvent(); }) .catch((e) => { // TODO: add debug logs that runs conditionally diff --git a/src/livePreview/eventManager/types/livePreviewPostMessageEvent.type.ts b/src/livePreview/eventManager/types/livePreviewPostMessageEvent.type.ts index 5e6f253c..1707184c 100644 --- a/src/livePreview/eventManager/types/livePreviewPostMessageEvent.type.ts +++ b/src/livePreview/eventManager/types/livePreviewPostMessageEvent.type.ts @@ -1,15 +1,22 @@ import { ILivePreviewWindowType } from "../../../types/types"; +export const OnChangeLivePreviewPostMessageEventTypes = { + HASH_CHANGE: "hash_change", + URL_CHANGE: "url_change" +} as const; + export interface HistoryLivePreviewPostMessageEventData { type: "forward" | "backward" | "reload"; } export interface OnChangeLivePreviewPostMessageEventData { hash: string; -} - -export interface OnReloadLivePreviewPostMessageEventData { - hash: string; + entry_uid?: string; + content_type_uid?: string; + url?: string; + _metadata?: { + event_type: typeof OnChangeLivePreviewPostMessageEventTypes[keyof typeof OnChangeLivePreviewPostMessageEventTypes]; + } } export interface LivePreviewInitEventResponse {