output-frame.ts

84 lines | 2.533 kB Blame History Raw Download
import { BaseElement } from "../_base";
import './output-frame.less';
import { NotificationBubbles } from "../notification-bubbles/notification-bubbles";
import { GetOutputFrameUrl } from "../../../shared/url-helpers";
import { GetNotificationBubbles } from "../../../shared/getdom";
import { postMessage } from "../../../shared/post-message";

export class OutputFrame extends BaseElement {
    public Iframe: HTMLIFrameElement | null = null;
    public CurrentIframeScriptRemoveResponseListener: Function | null = null;

    constructor() {
        super();
    }

    onInit(): void {
        this.reset();
    }

    onUpdate(): void {
    }

    reset(resetNotificationBubbles: boolean = true) {
        if (this.CurrentIframeScriptRemoveResponseListener != null) {
            this.CurrentIframeScriptRemoveResponseListener();
            this.CurrentIframeScriptRemoveResponseListener = null;
        }

        if (this.Iframe && this.hasChild(this.Iframe)) {
            this.removeChild(this.Iframe);
        }

        this.Iframe = document.createElement("iframe");
        this.Iframe.setAttribute("sandbox", "allow-pointer-lock allow-same-origin allow-scripts");
        this.Iframe.src = GetOutputFrameUrl();
        this.appendChild(this.Iframe);

        if (resetNotificationBubbles) {
            var bubbles = GetNotificationBubbles();
            if (bubbles && bubbles.reset) {
                bubbles.reset();
            }
        }
    }

    setError() {
        this.reset();
        if (this.Iframe) {
            this.Iframe.src = GetOutputFrameUrl() + "execution-time-error.html";
        }
    }

    preventInfiniteLoop(value: string) {
        return value.replace("while (true)", "while (false)");
    }

    setScript(value: string) {
        this.reset();
        this.onIframeLoaded(() => {
            this.CurrentIframeScriptRemoveResponseListener = postMessage(this.Iframe?.contentWindow, "script", value, (executeTimeInMs, exceedTimeInMs) => {
                if (executeTimeInMs === -1) {
                    this.setError();
                }
                else {
                    var bubbles = GetNotificationBubbles();
                    bubbles.add("code executed in: " + executeTimeInMs + "ms", "info");
                }
            });
        });
    }

    onIframeLoaded(fn: Function) {
        if (this.Iframe) {
            this.Iframe.onload = () => {
                fn();
            }
        }
        else {
            this.waitFor(this.Iframe, () => {
                this.onIframeLoaded(fn);
            });
        }
    }
}