Files
wterm/static/index.html
T
wt 36aa1bea2a
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-Make-Without-sqlite3 (push) Successful in 6s
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-CMake-Without-sqlite3 (push) Successful in 9s
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-Meson-Without-sqlite3 (push) Successful in 7s
updated codestyle
2025-11-18 11:48:46 +07:00

196 lines
6.8 KiB
HTML

<!doctype html>
<html>
<head>
<title>Web Terminal</title>
<link rel="stylesheet" href="xterm.css" />
<style>
body {
margin: 0;
padding: 20px;
background-color: #1e1e1e;
color: #fff;
font-family: Arial, sans-serif;
height: 100vh;
display: flex;
flex-direction: column;
}
#terminal-container {
flex: 1;
border: 1px solid #333;
border-radius: 5px;
overflow: hidden;
margin-top: 10px;
}
.status {
padding: 10px;
border-radius: 3px;
font-weight: bold;
margin-bottom: 10px;
}
.connected {
background-color: #2d5a2d;
}
.disconnected {
background-color: #5a2d2d;
}
.connecting {
background-color: #5a5a2d;
}
</style>
</head>
<body>
<h1>Web Terminal</h1>
<div class="status connecting" id="status">Connecting...</div>
<div id="terminal-container"></div>
<script src="xterm.js"></script>
<script src="xterm-addon-fit.js"></script>
<script>
class WebTerminal {
constructor() {
this.terminal = new Terminal({
cursorBlink: true,
theme: {
background: "#000000",
foreground: "#ffffff",
cursor: "#ffffff",
},
});
this.fitAddon = new FitAddon.FitAddon();
this.terminal.loadAddon(this.fitAddon);
this.ws = null;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.reconnectDelay = 3000;
this.init();
}
init() {
const terminalContainer =
document.getElementById("terminal-container");
this.terminal.open(terminalContainer);
this.fitAddon.fit();
this.terminal.writeln("Welcome to Web Terminal");
this.terminal.writeln("Connecting to server...");
this.connect();
// Handle terminal input
this.terminal.onData((data) => {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(data);
}
});
// Handle resize
window.addEventListener("resize", () => {
this.fitAddon.fit();
this.sendResize();
});
// Handle page unload
window.addEventListener("beforeunload", () => {
if (this.ws) {
this.ws.close();
}
});
}
connect() {
this.updateStatus("Connecting...", "connecting");
const protocol =
window.location.protocol === "https:" ? "wss:" : "ws:";
const wsUrl = `${protocol}//${window.location.host}/ws`;
this.ws = new WebSocket(wsUrl);
this.ws.onopen = () => {
console.log("WebSocket connected");
this.reconnectAttempts = 0;
this.updateStatus("Connected", "connected");
this.terminal.clear();
this.sendResize();
};
this.ws.onmessage = (event) => {
if (typeof event.data === "string") {
this.terminal.write(event.data);
} else {
// Handle binary data
const reader = new FileReader();
reader.onload = () => {
const data = new Uint8Array(reader.result);
this.terminal.write(data);
};
reader.readAsArrayBuffer(event.data);
}
};
this.ws.onclose = (event) => {
console.log(
"WebSocket disconnected:",
event.code,
event.reason,
);
this.updateStatus("Disconnected", "disconnected");
if (
this.reconnectAttempts < this.maxReconnectAttempts
) {
this.reconnectAttempts++;
const delay =
this.reconnectDelay * this.reconnectAttempts;
this.terminal.write(
`\r\nConnection lost. Reconnecting in ${delay / 1000}s...\r\n`,
);
setTimeout(() => {
this.connect();
}, delay);
} else {
this.terminal.write(
"\r\nFailed to reconnect. Please refresh the page.\r\n",
);
}
};
this.ws.onerror = (error) => {
console.error("WebSocket error:", error);
this.updateStatus("Connection Error", "disconnected");
};
}
sendResize() {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
const dimensions = this.terminal;
const resizeMsg = {
cols: dimensions.cols,
rows: dimensions.rows,
};
this.ws.send(JSON.stringify(resizeMsg));
}
}
updateStatus(text, className) {
const status = document.getElementById("status");
status.textContent = text;
status.className = `status ${className}`;
}
}
// Initialize terminal when page loads
document.addEventListener("DOMContentLoaded", () => {
new WebTerminal();
});
</script>
</body>
</html>