mirror of
https://github.com/getpaseo/paseo.git
synced 2026-08-14 20:32:46 +00:00
167 lines
4.8 KiB
HTML
167 lines
4.8 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<title>Paseo Browser Capture Harness</title>
|
|
<style>
|
|
html,
|
|
body {
|
|
width: 100%;
|
|
height: 100%;
|
|
margin: 0;
|
|
background: #202020;
|
|
overflow: hidden;
|
|
font-family: Arial, sans-serif;
|
|
}
|
|
|
|
#paseo-browser-resident-webviews {
|
|
position: fixed;
|
|
left: -20000px;
|
|
top: 0;
|
|
width: 1280px;
|
|
height: 800px;
|
|
overflow: hidden;
|
|
opacity: 0;
|
|
pointer-events: none;
|
|
}
|
|
|
|
#target-webview {
|
|
display: inline-flex;
|
|
flex: 0 0 auto;
|
|
width: 1280px;
|
|
height: 800px;
|
|
border: 0;
|
|
background: transparent;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="paseo-browser-resident-webviews" aria-hidden="true"></div>
|
|
|
|
<script>
|
|
const RESIDENT_VIEWPORT_WIDTH = 1280;
|
|
const RESIDENT_VIEWPORT_HEIGHT = 800;
|
|
const host = document.getElementById("paseo-browser-resident-webviews");
|
|
const params = new URLSearchParams(window.location.search);
|
|
const activeTokens = new Set();
|
|
let nextTokenId = 0;
|
|
|
|
const webview = document.createElement("webview");
|
|
webview.id = "target-webview";
|
|
webview.setAttribute("data-paseo-browser-id", "capture-harness");
|
|
webview.setAttribute("partition", "persist:paseo-capture-harness");
|
|
webview.setAttribute("allowpopups", "true");
|
|
webview.setAttribute("spellcheck", "false");
|
|
webview.setAttribute("autosize", "on");
|
|
webview.src = params.get("targetUrl") || "bright.html";
|
|
host.appendChild(webview);
|
|
|
|
function applyParking() {
|
|
host.style.position = "fixed";
|
|
host.style.left = "-20000px";
|
|
host.style.top = "0";
|
|
host.style.width = `${RESIDENT_VIEWPORT_WIDTH}px`;
|
|
host.style.height = `${RESIDENT_VIEWPORT_HEIGHT}px`;
|
|
host.style.overflow = "hidden";
|
|
host.style.opacity = "0";
|
|
host.style.pointerEvents = "none";
|
|
host.style.zIndex = "";
|
|
host.style.clipPath = "";
|
|
host.style.visibility = "";
|
|
host.style.transform = "";
|
|
webview.style.display = "inline-flex";
|
|
webview.style.flex = "0 0 auto";
|
|
webview.style.width = `${RESIDENT_VIEWPORT_WIDTH}px`;
|
|
webview.style.height = `${RESIDENT_VIEWPORT_HEIGHT}px`;
|
|
webview.style.border = "0";
|
|
webview.style.background = "transparent";
|
|
}
|
|
|
|
function applyCapturePrep() {
|
|
host.style.position = "fixed";
|
|
host.style.left = "0";
|
|
host.style.top = "0";
|
|
host.style.width = "1px";
|
|
host.style.height = "1px";
|
|
host.style.overflow = "hidden";
|
|
host.style.opacity = "1";
|
|
host.style.pointerEvents = "none";
|
|
host.style.zIndex = "1";
|
|
host.style.clipPath = "";
|
|
host.style.visibility = "";
|
|
host.style.transform = "";
|
|
}
|
|
|
|
function waitFrames(count) {
|
|
return new Promise((resolve) => {
|
|
function step(remaining) {
|
|
if (remaining <= 0) {
|
|
resolve();
|
|
return;
|
|
}
|
|
requestAnimationFrame(() => step(remaining - 1));
|
|
}
|
|
step(count);
|
|
});
|
|
}
|
|
|
|
function state() {
|
|
const hostRect = host.getBoundingClientRect();
|
|
const webviewRect = webview.getBoundingClientRect();
|
|
return {
|
|
hostStyle: {
|
|
left: host.style.left,
|
|
top: host.style.top,
|
|
width: host.style.width,
|
|
height: host.style.height,
|
|
overflow: host.style.overflow,
|
|
opacity: host.style.opacity,
|
|
pointerEvents: host.style.pointerEvents,
|
|
},
|
|
hostRect: {
|
|
x: hostRect.x,
|
|
y: hostRect.y,
|
|
width: hostRect.width,
|
|
height: hostRect.height,
|
|
},
|
|
webviewRect: {
|
|
x: webviewRect.x,
|
|
y: webviewRect.y,
|
|
width: webviewRect.width,
|
|
height: webviewRect.height,
|
|
},
|
|
};
|
|
}
|
|
|
|
window.captureHarness = {
|
|
async waitForFrames(count = 2) {
|
|
await waitFrames(count);
|
|
return state();
|
|
},
|
|
async prepareForPixelCapture() {
|
|
const token = `capture-${++nextTokenId}`;
|
|
activeTokens.add(token);
|
|
applyCapturePrep();
|
|
await waitFrames(2);
|
|
webview.getBoundingClientRect();
|
|
return { token, state: state() };
|
|
},
|
|
async restorePixelCapture(token) {
|
|
activeTokens.delete(token);
|
|
if (activeTokens.size === 0) {
|
|
applyParking();
|
|
}
|
|
await waitFrames(2);
|
|
return state();
|
|
},
|
|
async restoreParking() {
|
|
activeTokens.clear();
|
|
applyParking();
|
|
await waitFrames(2);
|
|
return state();
|
|
},
|
|
};
|
|
</script>
|
|
</body>
|
|
</html>
|