Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions docs/dist/v1/chartifact.host.umd.js
Original file line number Diff line number Diff line change
Expand Up @@ -2938,6 +2938,8 @@ ${guardedJs}
__publicField(this, "onSetMode");
__publicField(this, "removeInteractionHandlers");
__publicField(this, "sandboxConstructor");
__publicField(this, "currentMarkdown", "");
__publicField(this, "visibilityChangeHandler");
this.sandboxConstructor = options.sandboxConstructor || Sandbox;
this.options = { ...defaultOptions, ...options == null ? void 0 : options.options };
this.onApprove = options.onApprove;
Expand Down Expand Up @@ -2974,6 +2976,7 @@ ${guardedJs}
show(this.loadingDiv, false);
show(this.helpDiv, true);
}
this.setupPageVisibilityHandling();
}
createSandbox(markdown) {
if (this.sandbox) {
Expand Down Expand Up @@ -3079,6 +3082,7 @@ ${details}`;
}
renderMarkdown(markdown) {
this.hideLoadingAndHelp();
this.currentMarkdown = markdown;
try {
postStatus(this.options.postMessageTarget, { type: "hostStatus", hostStatus: "rendering", details: "Starting markdown rendering" });
if (!this.sandbox || !this.sandboxReady) {
Expand All @@ -3096,6 +3100,57 @@ ${details}`;
postStatus(this.options.postMessageTarget, { type: "hostStatus", hostStatus: "error", details: `Rendering failed: ${error.message}` });
}
}
/**
* Setup page visibility event handling to detect when tab is restored from tombstoning
*/
setupPageVisibilityHandling() {
this.visibilityChangeHandler = () => {
if (document.visibilityState === "visible") {
this.handlePageBecameVisible();
}
};
document.addEventListener("visibilitychange", this.visibilityChangeHandler);
}
/**
* Handle when page becomes visible - check if sandbox needs to be restored
*/
handlePageBecameVisible() {
if (this.currentMarkdown && this.sandbox) {
if (!this.isSandboxFunctional()) {
this.createSandbox(this.currentMarkdown);
show(this.sandbox.element, true);
}
}
}
/**
* Check if the sandbox iframe is still functional by testing if we can access its content window
*/
isSandboxFunctional() {
try {
if (!this.sandbox || !this.sandbox.iframe) {
return false;
}
const iframe = this.sandbox.iframe;
const contentWindow = iframe.contentWindow;
if (!contentWindow || !iframe.src || iframe.src === "about:blank") {
return false;
}
return true;
} catch (error) {
return false;
}
}
/**
* Cleanup method to remove event listeners
*/
destroy() {
if (this.visibilityChangeHandler) {
document.removeEventListener("visibilitychange", this.visibilityChangeHandler);
}
if (this.sandbox) {
this.sandbox.destroy();
}
}
}
const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
Expand Down
73 changes: 73 additions & 0 deletions packages/host/src/listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export class Listener {

private removeInteractionHandlers: (() => void)[];
private sandboxConstructor?: typeof Sandbox;
private currentMarkdown: string = '';
private visibilityChangeHandler: () => void;

constructor(options: InitializeOptions) {
this.sandboxConstructor = options.sandboxConstructor || Sandbox;
Expand Down Expand Up @@ -114,6 +116,9 @@ export class Listener {
show(this.loadingDiv, false);
show(this.helpDiv, true);
}

// Setup page visibility handling for mobile tombstoning
this.setupPageVisibilityHandling();
}

public createSandbox(markdown: string) {
Expand Down Expand Up @@ -232,6 +237,9 @@ export class Listener {

public renderMarkdown(markdown: string) {
this.hideLoadingAndHelp();

// Store current markdown for potential restoration
this.currentMarkdown = markdown;

try {
postStatus(this.options.postMessageTarget, { type: 'hostStatus', hostStatus: 'rendering', details: 'Starting markdown rendering' });
Expand All @@ -251,4 +259,69 @@ export class Listener {
}
}

/**
* Setup page visibility event handling to detect when tab is restored from tombstoning
*/
private setupPageVisibilityHandling() {
this.visibilityChangeHandler = () => {
if (document.visibilityState === 'visible') {
this.handlePageBecameVisible();
}
};

document.addEventListener('visibilitychange', this.visibilityChangeHandler);
}

/**
* Handle when page becomes visible - check if sandbox needs to be restored
*/
private handlePageBecameVisible() {
// Only restore if we have content to restore and sandbox exists
if (this.currentMarkdown && this.sandbox) {
// Check if the sandbox iframe is still accessible
if (!this.isSandboxFunctional()) {
// Recreate the sandbox with the current content
this.createSandbox(this.currentMarkdown);
show(this.sandbox.element, true);
}
}
}

/**
* Check if the sandbox iframe is still functional by testing if we can access its content window
*/
private isSandboxFunctional(): boolean {
try {
if (!this.sandbox || !this.sandbox.iframe) {
return false;
}

// Try to access the iframe's content window and check if the src is still valid
const iframe = this.sandbox.iframe;
const contentWindow = iframe.contentWindow;

// If we can't access the content window or the src is invalid, sandbox is not functional
if (!contentWindow || !iframe.src || iframe.src === 'about:blank') {
return false;
}

return true;
} catch (error) {
// If accessing iframe throws an error, it's not functional
return false;
}
}

/**
* Cleanup method to remove event listeners
*/
public destroy() {
if (this.visibilityChangeHandler) {
document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
}
if (this.sandbox) {
this.sandbox.destroy();
}
}

}