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 = $( '