Files
Kettenoeler/Software/data_src/static/js/websocket.js
2025-08-12 14:21:53 +02:00

322 lines
8.8 KiB
JavaScript

var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
var statusMapping;
var staticMapping;
var overlay;
document.addEventListener("DOMContentLoaded", function () {
// Ihr JavaScript-Code hier, einschließlich der onLoad-Funktion
overlay = document.getElementById("overlay");
onLoad();
});
function initWebSocket() {
console.log("Trying to open a WebSocket connection...");
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage; // <-- add this line
}
function initButtons() {
var elements = document.getElementsByClassName("btn-wsevent");
if (elements.length > 0) {
for (var i = 0; i < elements.length; i++) {
let element = elements[i];
element.addEventListener("click", sendButton);
}
}
}
function initSettingInputs() {
var elements = document.getElementsByClassName("set-wsevent");
if (elements.length > 0) {
for (var i = 0; i < elements.length; i++) {
let element = elements[i];
element.addEventListener("change", function () {
websocket_sendevent("set-" + element.id, element.value);
});
}
}
}
function onOpen(event) {
console.log("Connection opened");
}
function onClose(event) {
console.log("Connection closed");
setTimeout(initWebSocket, 1000);
overlay.style.display = "flex";
}
function sendButton(event) {
var targetElement = event.target;
if (
targetElement.classList.contains("confirm") &&
window.confirm("Sicher?") == false
)
return;
websocket_sendevent("btn-" + targetElement.id, targetElement.value);
}
function onMessage(event) {
var data = event.data;
if (data.startsWith("NOTIFY:")) {
var notify_data = data.slice(7).split(";")[1];
var notify_type = data.slice(7).split(";")[0];
showNotification(notify_data, notify_type);
} else if (data.startsWith("DEBUG:")) {
var addtext = data.slice(6);
var livedebug_out = document.getElementById("livedebug-out");
livedebug_out.value += addtext;
livedebug_out.scrollTop = livedebug_out.scrollHeight;
do_resize(livedebug_out);
} else if (data.startsWith("DTC:")) {
const dtcs = data.slice(4);
const dtcArray = dtcs.trim() !== "" ? dtcs.split(";").filter(Boolean) : [];
processDTCNotifications(dtcArray);
fillDTCTable(dtcArray);
} else if (data.startsWith("MAPPING_STATUS:")) {
const data_sliced = data.slice(15);
statusMapping = createMapping(data_sliced);
} else if (data.startsWith("MAPPING_STATIC:")) {
const data_sliced = data.slice(15);
staticMapping = createMapping(data_sliced);
console.log(staticMapping);
} else if (data.startsWith("STATUS:")) {
const data_sliced = data.slice(7);
const result = processDataString(data_sliced, statusMapping);
fillValuesToHTML(result);
} else if (data.startsWith("STATIC:")) {
const data_sliced = data.slice(7);
const result = processDataString(data_sliced, staticMapping);
fillValuesToHTML(result);
overlay.style.display = "none";
}
}
function createMapping(mappingString) {
return mappingString
.split(";")
.map((s) => s.trim())
.filter((s) => s !== "");
}
function processDataString(dataString, mapping) {
const valuesArray = dataString.split(";");
const dataObject = {};
valuesArray.forEach((value, index) => {
const variable = mapping[index];
if (variable) {
dataObject[variable] = value.trim();
}
});
return dataObject;
}
function onLoad(event) {
initWebSocket();
initButtons();
initSettingInputs();
overlay.style.display = "flex";
}
function websocket_sendevent(element_id, element_value) {
websocket.send(element_id + ":" + element_value);
}
function do_resize(textbox) {
var maxrows = 15;
var minrows = 3;
var txt = textbox.value;
var cols = textbox.cols;
var arraytxt = txt.split("\n");
var rows = arraytxt.length;
for (i = 0; i < arraytxt.length; i++)
rows += parseInt(arraytxt[i].length / cols);
if (rows > maxrows) textbox.rows = maxrows;
else if (rows < minrows) textbox.rows = minrows;
else textbox.rows = rows;
}
// --- Globale Puffer für Select-Handling ---
const selectDesiredValue = Object.create(null); // keyBase -> desired value ("speedsource" -> "GPS")
const selectOptionsReady = Object.create(null); // keyBase -> true/false
function splitCsv(s) {
return (s || "")
.split(",")
.map((x) => x.trim())
.filter(Boolean);
}
function hasOption(selectEl, value) {
for (let i = 0; i < selectEl.options.length; i++) {
if (selectEl.options[i].value === value) return true;
}
return false;
}
function addOption(selectEl, value, selectIt = false) {
const o = document.createElement("option");
o.value = value;
o.textContent = value;
selectEl.appendChild(o);
if (selectIt) {
selectEl.value = value;
}
}
function populateSelect(selectId, options, currentValue) {
const sel = document.getElementById(selectId);
if (!sel) return;
// 1) komplett ersetzen
sel.innerHTML = "";
options.forEach((opt) => addOption(sel, opt, false));
// 2) Zielwert bestimmen (currentValue > bereits gepuffert > vorhandener Wert > erste Option)
const wanted =
(currentValue && currentValue.length ? currentValue : null) ??
selectDesiredValue[selectId] ??
sel.value ??
(options[0] || "");
// 3) Falls gewünschte Option fehlt, hinzufügen
if (wanted && !hasOption(sel, wanted)) addOption(sel, wanted, false);
// 4) Setzen
sel.value = wanted;
// 5) Markieren: Optionen sind ready
selectOptionsReady[selectId] = true;
// Verbrauchte Wunschwerte löschen
delete selectDesiredValue[selectId];
}
// Robust: setzt den Wert; wenn Option fehlt, füge sie hinzu
function setDropdownValue(selectElement, value) {
if (!value) return;
if (!hasOption(selectElement, value)) {
addOption(selectElement, value, false);
}
selectElement.value = value;
}
// Core: schreibt Werte in DOM, erkennt *-options und füllt Selects
function fillValuesToHTML(dataset) {
for (const key in dataset) {
const val = dataset[key];
// A) Optionen-Feld? (z.B. "speedsource-options")
if (key.endsWith("-options")) {
const base = key.slice(0, -"-options".length); // "speedsource"
const selectId = base; // ID = keyBase
populateSelect(
selectId,
splitCsv(val),
selectDesiredValue[selectId] || undefined
);
continue; // fertig mit diesem key
}
// B) Normales Feld
const key_prefixed = "data-" + key;
const elements = document.getElementsByClassName(key_prefixed);
if (elements.length === 0) continue;
for (let i = 0; i < elements.length; i++) {
const el = elements[i];
// Checkbox?
if (el.type === "checkbox") {
el.checked = val == 1;
continue;
}
// Select?
if (el.tagName === "SELECT") {
const selectId = el.id || key; // ID hat Vorrang, sonst key
// Wenn die Optionen für dieses Select noch NICHT bereit sind, Wunschwert puffern
if (!selectOptionsReady[selectId]) {
selectDesiredValue[selectId] = val;
// Sicherheitsnetz: falls doch schon Optionen existieren, sofort setzen
setDropdownValue(el, val);
} else {
// Optionen sind ready -> ganz normal setzen (ggf. Option ergänzen)
setDropdownValue(el, val);
}
continue;
}
// Progress-Bar?
if (el.classList.contains("progress-bar")) {
updateProgressBar(el, val);
continue;
}
// Hideable-Section?
if (el.classList.contains("hideable")) {
el.style.display = val == 0 ? "none" : "";
continue;
}
// Input/Textarea?
if ("value" in el) {
el.value = val;
continue;
}
// Fallback: content nodes (td, span, div)
el.textContent = val;
}
}
}
// Funktion zum Aktualisieren der Fortschrittsleiste
function updateProgressBar(progressBar, value) {
// Wert in das aria-valuenow-Attribut einfügen
progressBar.setAttribute("aria-valuenow", value);
// Breite des Fortschrittsbalkens und inneren Text aktualisieren
progressBar.style.width = value + "%";
progressBar.textContent = value + "%";
}
function showNotification(message, type) {
// Erstellen Sie ein Bootstrap-Alert-Element
var alertElement = $(
'<div class="alert alert-' +
type +
' alert-dismissible fade show notification" role="alert">' +
"<strong>" +
message +
"</strong>" +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
'<span aria-hidden="true">&times;</span>' +
"</button>" +
"</div>"
);
// Fügen Sie das Alert-Element dem Container hinzu
$("#notification-container").append(alertElement);
// Nach 5 Sekunden das Alert-Element ausblenden
setTimeout(function () {
alertElement.alert("close");
}, 5000);
}