Initial commit
This commit is contained in:
92
static/html-view.html
Normal file
92
static/html-view.html
Normal file
@@ -0,0 +1,92 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>HTML Viewer</title>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: stretch;
|
||||
}
|
||||
|
||||
#viewer-frame {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="module">
|
||||
import { Subscription_Endpoint } from './subscription.mjs';
|
||||
|
||||
function get_source_name() {
|
||||
const params = new URLSearchParams(location.search);
|
||||
return params.get('source') || 'default-html';
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const viewer_frame = document.getElementById('viewer-frame');
|
||||
|
||||
const ep = new Subscription_Endpoint();
|
||||
await ep.connect('/subscription');
|
||||
|
||||
const source = get_source_name();
|
||||
ep.subscribe(source);
|
||||
|
||||
let current_url = null;
|
||||
let pending_scroll = null;
|
||||
|
||||
ep.addEventListener('message', (ev) => {
|
||||
// Capture current scroll position (best-effort)
|
||||
try {
|
||||
const win = viewer_frame.contentWindow;
|
||||
if (win) {
|
||||
pending_scroll = {
|
||||
x: win.scrollX,
|
||||
y: win.scrollY
|
||||
};
|
||||
}
|
||||
} catch {
|
||||
pending_scroll = null;
|
||||
}
|
||||
|
||||
if (current_url) {
|
||||
URL.revokeObjectURL(current_url);
|
||||
}
|
||||
|
||||
current_url = URL.createObjectURL(ev.detail);
|
||||
viewer_frame.src = current_url;
|
||||
});
|
||||
|
||||
// Restore scroll after the new document loads
|
||||
viewer_frame.addEventListener('load', () => {
|
||||
if (!pending_scroll) return;
|
||||
|
||||
try {
|
||||
viewer_frame.contentWindow.scrollTo(
|
||||
pending_scroll.x,
|
||||
pending_scroll.y
|
||||
);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
pending_scroll = null;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="viewer-frame"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
92
static/image-view.html
Normal file
92
static/image-view.html
Normal file
@@ -0,0 +1,92 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test of remote view</title>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
|
||||
|
||||
/* Two 50/50 linear gradients – one horizontal, one vertical */
|
||||
background-image:
|
||||
linear-gradient(0deg, #f1f1f1 0% 50%, #d1d1d1 50% 100%),
|
||||
linear-gradient(90deg, #f1f1f1 0% 50%, #d1d1d1 50% 100%);
|
||||
|
||||
/* Each square is 8 px; the pattern repeats */
|
||||
background-size: 16px 16px;
|
||||
background-repeat: repeat;
|
||||
|
||||
/* Blend the two gradients – multiply gives a proper “XOR” look */
|
||||
background-blend-mode: multiply;
|
||||
|
||||
|
||||
}
|
||||
|
||||
body.full {
|
||||
display: block;
|
||||
width: none;
|
||||
height: none;
|
||||
}
|
||||
|
||||
|
||||
#viewer-image {
|
||||
display: block;
|
||||
border: 1px solid #864;
|
||||
max-width: 100vw;
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
||||
body.full #viewer-image {
|
||||
border: none;
|
||||
max-width: none;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script type="module">
|
||||
import { Subscription_Endpoint } from './subscription.mjs';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
const viewer_image = document.getElementById('viewer-image')
|
||||
|
||||
viewer_image.addEventListener('click', () => {
|
||||
document.body.classList.toggle('full');
|
||||
})
|
||||
|
||||
|
||||
const ep = new Subscription_Endpoint();
|
||||
await ep.connect('/subscription');
|
||||
|
||||
ep.subscribe('demo');
|
||||
|
||||
ep.addEventListener('message', (ev) => {
|
||||
viewer_image.src = URL.createObjectURL(ev.detail);
|
||||
|
||||
console.log("Got image", ev.detail);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<img id="viewer-image">
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
29
static/post-event.html
Normal file
29
static/post-event.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test of posting event</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<form action="/emit-multipart" method="post" enctype="multipart/form-data">
|
||||
<div>
|
||||
<label>
|
||||
Resource ID:
|
||||
<input type="text" name="resource" required>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
File:
|
||||
<input type="file" name="file" required>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button type="submit">Post</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
41
static/subscription.mjs
Normal file
41
static/subscription.mjs
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
export class Subscription_Endpoint extends EventTarget {
|
||||
|
||||
async connect(path) {
|
||||
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const wsUrl = `${wsProtocol}//${location.host}${path}`;
|
||||
|
||||
const ws = new WebSocket(wsUrl);
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
ws.addEventListener('open', resolve, { once: true });
|
||||
ws.addEventListener('error', reject, { once: true });
|
||||
});
|
||||
|
||||
ws.addEventListener('message', ev => {
|
||||
this.dispatchEvent(new CustomEvent('message', { detail: ev.data }));
|
||||
});
|
||||
|
||||
ws.addEventListener('close', () => {
|
||||
this.dispatchEvent(new Event('close'));
|
||||
});
|
||||
|
||||
ws.addEventListener('error', err => {
|
||||
this.dispatchEvent(new CustomEvent('error', { detail: err }));
|
||||
});
|
||||
|
||||
this.ws = ws;
|
||||
return ws;
|
||||
}
|
||||
|
||||
subscribe(resource) {
|
||||
const { ws } = this;
|
||||
ws.send(JSON.stringify({
|
||||
cmd: 'subscribe',
|
||||
resource
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user