mirror of
https://github.com/DustinBrett/daedalOS.git
synced 2025-12-06 12:20:20 +01:00
126 lines
3.8 KiB
TypeScript
126 lines
3.8 KiB
TypeScript
import { useState, useEffect, useCallback, useLayoutEffect } from "react";
|
|
import useFileDrop from "components/system/Files/FileManager/useFileDrop";
|
|
import { PREVENT_SCROLL } from "utils/constants";
|
|
import { useProcesses } from "contexts/process";
|
|
import { useSession } from "contexts/session";
|
|
|
|
const createCanvas = (hostDocument: Document): HTMLCanvasElement => {
|
|
const canvas = hostDocument.createElement("canvas");
|
|
|
|
canvas.id = "canvas";
|
|
canvas.style.width = "100%";
|
|
canvas.style.height = "100%";
|
|
canvas.tabIndex = -1;
|
|
|
|
hostDocument.body.append(canvas);
|
|
|
|
return canvas;
|
|
};
|
|
|
|
const createIframe = (
|
|
id: string,
|
|
container: HTMLDivElement
|
|
): HTMLIFrameElement => {
|
|
const iframe = document.createElement("iframe");
|
|
|
|
iframe.title = id;
|
|
|
|
container.append(iframe);
|
|
|
|
const contentDocument = iframe.contentDocument as Document;
|
|
|
|
contentDocument.open();
|
|
contentDocument.write("<!DOCTYPE html><head /><body />");
|
|
contentDocument.close();
|
|
|
|
const contentWindow = iframe.contentWindow as Window;
|
|
|
|
contentWindow.document.documentElement.style.height = "100%";
|
|
contentWindow.document.documentElement.style.width = "100%";
|
|
|
|
contentWindow.document.body.style.height = "100%";
|
|
contentWindow.document.body.style.width = "100%";
|
|
contentWindow.document.body.style.margin = "0";
|
|
contentWindow.document.body.style.overflow = "hidden";
|
|
|
|
return iframe;
|
|
};
|
|
|
|
type IsolatedContentWindow = (() => Window | undefined) | undefined;
|
|
|
|
const useIsolatedContentWindow = (
|
|
id: string,
|
|
containerRef: React.RefObject<HTMLDivElement | null>,
|
|
withCanvas = false
|
|
): IsolatedContentWindow => {
|
|
const [container, setContainer] = useState<HTMLDivElement>();
|
|
const [contentWindow, setContentWindow] = useState<Window>();
|
|
const { onDragOver, onDrop } = useFileDrop({ id });
|
|
const { processes: { [id]: { maximized } = {} } = {} } = useProcesses();
|
|
const { foregroundId, setForegroundId } = useSession();
|
|
const createContentWindow = useCallback((): Window | undefined => {
|
|
if (!container) return undefined;
|
|
|
|
container.querySelector("iframe")?.remove();
|
|
|
|
const iframe = createIframe(id, container);
|
|
const newContentWindow = iframe.contentWindow as Window;
|
|
|
|
let canvas: HTMLCanvasElement;
|
|
|
|
if (withCanvas) canvas = createCanvas(iframe.contentDocument as Document);
|
|
|
|
const focusContentWindow = (): void => {
|
|
if (withCanvas && canvas) canvas.focus(PREVENT_SCROLL);
|
|
else newContentWindow.focus();
|
|
|
|
setForegroundId(id);
|
|
};
|
|
|
|
newContentWindow.addEventListener("click", focusContentWindow);
|
|
newContentWindow.addEventListener("focus", focusContentWindow);
|
|
newContentWindow.addEventListener("blur", () => setForegroundId(""));
|
|
newContentWindow.addEventListener("dragover", onDragOver);
|
|
newContentWindow.addEventListener("drop", onDrop);
|
|
|
|
setContentWindow(newContentWindow);
|
|
|
|
return newContentWindow;
|
|
}, [container, id, onDragOver, onDrop, setForegroundId, withCanvas]);
|
|
|
|
useLayoutEffect(() => {
|
|
if (contentWindow && foregroundId === id) {
|
|
requestAnimationFrame(() => {
|
|
if (withCanvas) {
|
|
contentWindow.document
|
|
.querySelector<HTMLCanvasElement>("canvas")
|
|
?.focus(PREVENT_SCROLL);
|
|
} else {
|
|
contentWindow.focus();
|
|
}
|
|
});
|
|
}
|
|
// eslint-disable-next-line react-hooks-addons/no-unused-deps
|
|
}, [contentWindow, foregroundId, id, maximized, withCanvas]);
|
|
|
|
useEffect(() => {
|
|
if (!container) {
|
|
const getContainer = (): void => {
|
|
requestAnimationFrame(() => {
|
|
if (containerRef.current) {
|
|
setContainer(containerRef.current);
|
|
} else {
|
|
getContainer();
|
|
}
|
|
});
|
|
};
|
|
|
|
getContainer();
|
|
}
|
|
}, [container, containerRef]);
|
|
|
|
return container ? createContentWindow : undefined;
|
|
};
|
|
|
|
export default useIsolatedContentWindow;
|