94 lines
2.8 KiB
HTML
94 lines
2.8 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>forum</title>
|
|
<style>
|
|
body { font: 14px ui-monospace, monospace; margin: 2rem; background: #f7f7f4; color: #171717; }
|
|
#status { color: #888; font-size: 12px; }
|
|
#doc { display: grid; gap: 24px; margin-top: 1rem; }
|
|
.form-table h2 { margin: 0 0 8px; font-size: 16px; }
|
|
.table-wrap { overflow-x: auto; border: 1px solid #d7d7cf; background: #fff; }
|
|
table { width: 100%; border-collapse: collapse; min-width: 920px; }
|
|
th, td { border-bottom: 1px solid #e6e6df; padding: 8px 10px; text-align: left; vertical-align: top; }
|
|
th { position: sticky; top: 0; background: #efefea; color: #555; font-size: 12px; }
|
|
tbody tr:hover { background: #fafaf7; }
|
|
td { overflow-wrap: anywhere; white-space: pre-wrap; }
|
|
code { font-weight: 700; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="status">connecting…</div>
|
|
<main id="doc"><!-- FORMS_HTML --></main>
|
|
<script>
|
|
const status = document.getElementById("status");
|
|
const doc = document.getElementById("doc");
|
|
|
|
const url = (location.protocol === "https:" ? "wss://" : "ws://") + location.host + "/ws";
|
|
let ws = null;
|
|
let heartbeat = null;
|
|
let reconnectTimer = null;
|
|
let reconnectDelay = 500;
|
|
|
|
function send(obj) {
|
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
ws.send(JSON.stringify(obj));
|
|
}
|
|
}
|
|
|
|
function stopHeartbeat() {
|
|
if (heartbeat) clearInterval(heartbeat);
|
|
heartbeat = null;
|
|
}
|
|
|
|
function scheduleReconnect() {
|
|
if (reconnectTimer) return;
|
|
|
|
status.textContent = "disconnected; reconnecting…";
|
|
stopHeartbeat();
|
|
|
|
reconnectTimer = setTimeout(() => {
|
|
reconnectTimer = null;
|
|
connect();
|
|
}, reconnectDelay);
|
|
|
|
reconnectDelay = Math.min(reconnectDelay * 2, 10000);
|
|
}
|
|
|
|
function connect() {
|
|
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
|
|
return;
|
|
}
|
|
|
|
status.textContent = "connecting…";
|
|
ws = new WebSocket(url);
|
|
|
|
ws.addEventListener("open", () => {
|
|
reconnectDelay = 500;
|
|
status.textContent = "connected";
|
|
send({type: "get_doc"});
|
|
stopHeartbeat();
|
|
heartbeat = setInterval(() => send({type: "ping"}), 25000);
|
|
});
|
|
|
|
ws.addEventListener("message", (e) => {
|
|
const msg = JSON.parse(e.data);
|
|
if (msg.type === "doc") {
|
|
doc.innerHTML = msg.html;
|
|
status.textContent = "rendered backend document at " + new Date().toLocaleTimeString();
|
|
}
|
|
});
|
|
|
|
ws.addEventListener("close", scheduleReconnect);
|
|
ws.addEventListener("error", () => {
|
|
status.textContent = "connection error; reconnecting…";
|
|
ws.close();
|
|
});
|
|
}
|
|
|
|
window.addEventListener("beforeunload", stopHeartbeat);
|
|
connect();
|
|
</script>
|
|
</body>
|
|
</html>
|