Skip to content

Commit 9c9282b

Browse files
committed
add fullscreen proxy
1 parent d214f8d commit 9c9282b

1 file changed

Lines changed: 149 additions & 0 deletions

File tree

fullscreen-proxy.html

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<title>Fullscreen Proxy</title>
7+
<meta name="robots" content="noindex">
8+
</head>
9+
<body>
10+
<header hidden id="toolbar">
11+
<div>
12+
<p>Loaded URL</p>
13+
<a class="url" id="target-link" href="#" rel="noopener noreferrer" target="_blank"></a>
14+
</div>
15+
<div>
16+
<button id="fullscreen-button" type="button">MAKE FULLSCREEN</button>
17+
</div>
18+
</header>
19+
20+
<main hidden id="message"></main>
21+
22+
<section hidden id="frame-shell">
23+
<iframe
24+
id="target-frame"
25+
title="Fullscreen proxy target"
26+
allow="fullscreen; autoplay; clipboard-read; clipboard-write"
27+
allowfullscreen
28+
referrerpolicy="no-referrer"
29+
width="100%"
30+
height="900"
31+
></iframe>
32+
</section>
33+
34+
<script>
35+
const toolbar = document.getElementById('toolbar');
36+
const message = document.getElementById('message');
37+
const frameShell = document.getElementById('frame-shell');
38+
const targetFrame = document.getElementById('target-frame');
39+
const targetLink = document.getElementById('target-link');
40+
const fullscreenButton = document.getElementById('fullscreen-button');
41+
42+
function showMessage(html) {
43+
message.innerHTML = html;
44+
message.hidden = false;
45+
toolbar.hidden = true;
46+
frameShell.hidden = true;
47+
}
48+
49+
function parseTargetUrl(value) {
50+
if (!value) {
51+
return null;
52+
}
53+
54+
try {
55+
const parsed = new URL(value);
56+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
57+
return null;
58+
}
59+
return parsed;
60+
} catch (error) {
61+
return null;
62+
}
63+
}
64+
65+
async function requestFullscreenFor(element) {
66+
if (element.requestFullscreen) {
67+
return element.requestFullscreen();
68+
}
69+
if (element.webkitRequestFullscreen) {
70+
return element.webkitRequestFullscreen();
71+
}
72+
throw new Error('Fullscreen API not supported in this browser.');
73+
}
74+
75+
function getRawUrlParam() {
76+
const query = window.location.search.startsWith('?')
77+
? window.location.search.slice(1)
78+
: window.location.search;
79+
80+
const urlPrefixIndex = query.indexOf('url=');
81+
if (urlPrefixIndex === -1) {
82+
return null;
83+
}
84+
85+
return query.slice(urlPrefixIndex + 4) || null;
86+
}
87+
88+
function isFrameShellFullscreen() {
89+
return document.fullscreenElement === frameShell || document.webkitFullscreenElement === frameShell;
90+
}
91+
92+
function syncFrameSize() {
93+
if (isFrameShellFullscreen()) {
94+
targetFrame.width = String(window.innerWidth);
95+
targetFrame.height = String(window.innerHeight);
96+
return;
97+
}
98+
99+
targetFrame.width = '100%';
100+
targetFrame.height = String(Math.max(900, window.innerHeight - toolbar.offsetHeight - 16));
101+
}
102+
103+
const targetUrl = parseTargetUrl(getRawUrlParam());
104+
105+
if (!targetUrl) {
106+
showMessage(
107+
'<h1>Missing or invalid URL</h1>' +
108+
'<p>Open this page with a <code>?url=</code> query parameter containing an <code>http://</code> or <code>https://</code> URL.</p>' +
109+
'<p>Example: <code>?url=https://example.com</code></p>'
110+
);
111+
} else {
112+
document.title = 'Fullscreen Proxy: ' + targetUrl.hostname;
113+
targetFrame.src = targetUrl.toString();
114+
targetLink.href = targetUrl.toString();
115+
targetLink.textContent = targetUrl.toString();
116+
117+
toolbar.hidden = false;
118+
frameShell.hidden = false;
119+
syncFrameSize();
120+
121+
fullscreenButton.addEventListener('click', async () => {
122+
try {
123+
await requestFullscreenFor(frameShell);
124+
} catch (error) {
125+
showMessage(
126+
'<h1>Could not enter fullscreen</h1>' +
127+
'<p>' + error.message + '</p>'
128+
);
129+
}
130+
});
131+
132+
targetFrame.addEventListener('load', () => {
133+
fullscreenButton.disabled = false;
134+
});
135+
136+
window.addEventListener('resize', syncFrameSize);
137+
document.addEventListener('fullscreenchange', syncFrameSize);
138+
document.addEventListener('webkitfullscreenchange', syncFrameSize);
139+
140+
targetFrame.addEventListener('error', () => {
141+
showMessage(
142+
'<h1>Unable to load the requested site</h1>' +
143+
'<p>The target may block being embedded in an iframe with <code>X-Frame-Options</code> or CSP <code>frame-ancestors</code>.</p>'
144+
);
145+
});
146+
}
147+
</script>
148+
</body>
149+
</html>

0 commit comments

Comments
 (0)