connectiopn fix round 2 4
This commit is contained in:
@ -1414,6 +1414,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById("watch-close-btn").addEventListener("click", closeWatchOverlay);
|
document.getElementById("watch-close-btn").addEventListener("click", closeWatchOverlay);
|
||||||
|
// Klick auf den abgedunkelten Hintergrund (nicht auf das Panel selbst)
|
||||||
|
// schliesst die Live-Ansicht ebenfalls.
|
||||||
|
document.getElementById("watch-overlay").addEventListener("click", (ev) => {
|
||||||
|
if (ev.target === ev.currentTarget) closeWatchOverlay();
|
||||||
|
});
|
||||||
|
|
||||||
function watchSession(session) {
|
function watchSession(session) {
|
||||||
closeWatchOverlay();
|
closeWatchOverlay();
|
||||||
@ -1517,6 +1522,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById("rec-close-btn").addEventListener("click", closeRecordingOverlay);
|
document.getElementById("rec-close-btn").addEventListener("click", closeRecordingOverlay);
|
||||||
|
// Klick auf den abgedunkelten Hintergrund (nicht auf das Panel selbst)
|
||||||
|
// schliesst die Wiedergabe ebenfalls.
|
||||||
|
document.getElementById("rec-overlay").addEventListener("click", (ev) => {
|
||||||
|
if (ev.target === ev.currentTarget) closeRecordingOverlay();
|
||||||
|
});
|
||||||
|
|
||||||
function createSshPlayer(entries) {
|
function createSshPlayer(entries) {
|
||||||
const outputEntries = entries.filter((e) => e.dir === "output");
|
const outputEntries = entries.filter((e) => e.dir === "output");
|
||||||
|
|||||||
@ -109,6 +109,8 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById("exit-btn").addEventListener("click", () => {
|
document.getElementById("exit-btn").addEventListener("click", () => {
|
||||||
|
statusEl.textContent = "Sitzung wird beendet ...";
|
||||||
|
statusEl.classList.remove("error");
|
||||||
try { client.disconnect(); } catch (_) { /* bereits getrennt */ }
|
try { client.disconnect(); } catch (_) { /* bereits getrennt */ }
|
||||||
window.close();
|
window.close();
|
||||||
// Siehe terminal.js fuer die ausfuehrliche Begruendung: window.close()
|
// Siehe terminal.js fuer die ausfuehrliche Begruendung: window.close()
|
||||||
|
|||||||
@ -33,8 +33,24 @@
|
|||||||
function b64encode(str) {
|
function b64encode(str) {
|
||||||
return btoa(unescape(encodeURIComponent(str)));
|
return btoa(unescape(encodeURIComponent(str)));
|
||||||
}
|
}
|
||||||
function b64decode(b64) {
|
// Bugfix: NICHT ueber decodeURIComponent(escape(atob(...))) als JS-String
|
||||||
return decodeURIComponent(escape(atob(b64)));
|
// dekodieren. Jedes "output"-Frame entspricht genau einem Chunk aus
|
||||||
|
// process.stdout.read() auf dem Server (app/ssh_proxy/terminal_ws.py) --
|
||||||
|
// ein Mehrbyte-UTF-8-Zeichen (Umlaute, Box-Drawing-Zeichen, Emoji in
|
||||||
|
// Banner/Prompt/htop etc.) kann dabei GENAU AN DER CHUNK-GRENZE
|
||||||
|
// auseinandergerissen werden. decodeURIComponent() wirft dann einen
|
||||||
|
// "URI malformed"-Fehler fuer diesen einen Chunk (siehe
|
||||||
|
// static/js/admin.js::createSshPlayer fuer die noch schwerwiegendere
|
||||||
|
// Auswirkung bei der Wiedergabe -- dort blieb die gesamte Wiedergabe an
|
||||||
|
// genau dieser Stelle haengen). xterm.js' term.write() nimmt daher direkt
|
||||||
|
// die rohen Bytes als Uint8Array entgegen -- xterm.js ist ein echter
|
||||||
|
// Terminal-Emulator mit eigenem, chunk-uebergreifend korrektem
|
||||||
|
// UTF-8-Parser, genau fuer diesen Fall gebaut.
|
||||||
|
function b64decodeBytes(b64) {
|
||||||
|
const bin = atob(b64);
|
||||||
|
const bytes = new Uint8Array(bin.length);
|
||||||
|
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
|
||||||
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Troubleshooting: der Server liefert bei einem Fehlschlag entweder eine
|
// Troubleshooting: der Server liefert bei einem Fehlschlag entweder eine
|
||||||
@ -76,7 +92,7 @@
|
|||||||
ws.addEventListener("message", (ev) => {
|
ws.addEventListener("message", (ev) => {
|
||||||
const msg = JSON.parse(ev.data);
|
const msg = JSON.parse(ev.data);
|
||||||
if (msg.type === "output") {
|
if (msg.type === "output") {
|
||||||
term.write(b64decode(msg.data));
|
term.write(b64decodeBytes(msg.data));
|
||||||
} else if (msg.type === "error") {
|
} else if (msg.type === "error") {
|
||||||
lastErrorMessage = msg.message;
|
lastErrorMessage = msg.message;
|
||||||
statusEl.textContent = "Fehler: " + msg.message;
|
statusEl.textContent = "Fehler: " + msg.message;
|
||||||
@ -107,6 +123,28 @@
|
|||||||
});
|
});
|
||||||
document.addEventListener("fullscreenchange", sendResize);
|
document.addEventListener("fullscreenchange", sendResize);
|
||||||
|
|
||||||
|
document.getElementById("exit-btn").addEventListener("click", () => {
|
||||||
|
// Sofortiges sichtbares Feedback, damit erkennbar ist, dass der Klick
|
||||||
|
// ueberhaupt ankam -- unabhaengig davon, ob window.close() gleich
|
||||||
|
// klappt oder der Fallback (siehe unten) erst nach der Wartezeit greift.
|
||||||
|
statusEl.textContent = "Sitzung wird beendet ...";
|
||||||
|
statusEl.classList.remove("error");
|
||||||
|
try {
|
||||||
|
if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
|
||||||
|
ws.close(1000, "Sitzung durch Benutzer beendet");
|
||||||
|
}
|
||||||
|
} catch (_) { /* bereits getrennt */ }
|
||||||
|
window.close();
|
||||||
|
// window.close() schliesst den Tab nur, wenn er per Skript/Link mit
|
||||||
|
// target="_blank" geoeffnet wurde (siehe dashboard.js) UND noch keine
|
||||||
|
// weitere Navigation darin stattfand -- sonst verweigern Browser das
|
||||||
|
// lautlos, ohne Fehler oder Rueckgabewert. Deshalb IMMER zusaetzlich
|
||||||
|
// nach kurzer Wartezeit zum Dashboard weiterleiten: war das Schliessen
|
||||||
|
// erfolgreich, existiert die Seite dann laengst nicht mehr und der
|
||||||
|
// Timeout laeuft ins Leere; sonst bleibt so ein Weg zurueck.
|
||||||
|
window.setTimeout(() => { window.location.href = "/dashboard"; }, 300);
|
||||||
|
});
|
||||||
|
|
||||||
// --- Dateitransfer-Panel ------------------------------------------------
|
// --- Dateitransfer-Panel ------------------------------------------------
|
||||||
|
|
||||||
const ftOverlay = document.getElementById("ft-overlay");
|
const ftOverlay = document.getElementById("ft-overlay");
|
||||||
@ -123,6 +161,11 @@
|
|||||||
}
|
}
|
||||||
document.getElementById("filetransfer-btn").addEventListener("click", openFt);
|
document.getElementById("filetransfer-btn").addEventListener("click", openFt);
|
||||||
document.getElementById("ft-close-btn").addEventListener("click", closeFt);
|
document.getElementById("ft-close-btn").addEventListener("click", closeFt);
|
||||||
|
// Klick auf den abgedunkelten Hintergrund (nicht auf das Panel selbst)
|
||||||
|
// schliesst das Overlay ebenfalls -- Standardverhalten fuer solche Panels.
|
||||||
|
ftOverlay.addEventListener("click", (ev) => {
|
||||||
|
if (ev.target === ftOverlay) closeFt();
|
||||||
|
});
|
||||||
|
|
||||||
function formatSize(bytes) {
|
function formatSize(bytes) {
|
||||||
if (bytes < 1024) return `${bytes} B`;
|
if (bytes < 1024) return `${bytes} B`;
|
||||||
|
|||||||
Reference in New Issue
Block a user