Loading noctua/web/pages/base.html +1 −0 Original line number Diff line number Diff line Loading @@ -168,6 +168,7 @@ <!-- ── Noctua Web Components ──────────────────────────────── --> <!-- ── Unified WebSocket client ───────────────────────────────────────── --> <script src="{{ url_for('web.static', filename='js/ui-styles.js') }}"></script> <script src="{{ url_for('web.static', filename='js/status-stream.js') }}"></script> <script src="{{ url_for('web.static', filename='js/actions.js') }}"></script> <script src="{{ url_for('web.static', filename='js/ws-client.js') }}"></script> Loading noctua/web/pages/init.html +8 −16 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ {"label": "On", "endpoint": "/telescope/power", "val": true, "method": "PUT"}, {"label": "Off", "endpoint": "/telescope/power", "val": false, "method": "PUT"} ], "extra_flags": True }) }} Loading @@ -28,7 +27,6 @@ {"label": "Unpark", "endpoint": "/telescope/coordinates/movement/unpark", "method": "POST"}, {"label": "Park", "endpoint": "/telescope/coordinates/movement/park", "method": "POST"} ], "extra_flags": True }) }} Loading Loading @@ -65,7 +63,6 @@ "endpoint": "/telescope/error", "method": "DELETE" }], "extra_flags": True, "info_list": [{"label": "detail", "status": "telescope-error-details"}] }) }} Loading @@ -74,15 +71,14 @@ {{ w.widget_input({ "info": "/telescope/coordinates/offset", "inputs": [ {"label": "Zd", "value": 1500}, {"label": "Az", "value": -160} {"label": "Zd", "value": -300}, {"label": "Az", "value": -300} ], "unit": "″", "buttons": [{"label": "Set", "endpoint": "/telescope/coordinates/offset", "method": "PUT"}], "info_list": [ {"label": "alt", "status": "telescope-offset-0"}, {"label": "alt", "status": "telescope-coordinates-offset-0"}, {"label": "az", "status": "telescope-coordinates-offset-1"} ] }) Loading @@ -91,10 +87,12 @@ {{ w.widget_input({ "label": "Rotator", "info": "/telescope/rotator", "inputs": [{"value": 0}], "unit": "°", "buttons": [{"label": "Set", "endpoint": "/telescope/rotator/movement", "method": "POST"}] "buttons": [{"label": "Set", "endpoint": "/telescope/rotator/movement", "method": "POST"}], "info_list": [ {"label": "rot", "status": "telescope-rotator"}, ], }) }} </div> Loading @@ -113,7 +111,6 @@ {"label": "Move", "endpoint": "/dome/position/movement/azimuth", "method": "POST"}, {"label": "Sync", "endpoint": "/dome/position/sync", "method": "PUT"} ], "extra_flags": True, "info_list": [ {"label": "slaved", "status": "dome-position-slaved"}, {"label": "az", "status": "dome-position-azimuth"} Loading @@ -128,7 +125,6 @@ {"label": "Park", "endpoint": "/dome/position/movement/park", "method": "POST"}, {"label": "Stop", "endpoint": "/dome/position/movement", "method": "DELETE"} ], "extra_flags": True }) }} Loading @@ -136,7 +132,6 @@ w.widget_shutter( get_url = "/dome/shutter", move_url = "/dome/shutter/movement", extra_flags = True ) }} </div> Loading @@ -152,7 +147,6 @@ {"label": "On", "endpoint": "/camera/power", "val": true, "method": "PUT"}, {"label": "Off", "endpoint": "/camera/power", "val": false, "method": "PUT"} ], "extra_flags": True }) }} Loading @@ -170,12 +164,12 @@ {{ w.widget_input({ "label": "Temperature", "info": "/camera/cooler/temperature/setpoint", "inputs": [{"value": -10}], "unit": "°C", "buttons": [{"label": "Set", "endpoint": "/camera/cooler/temperature/setpoint", "method": "PUT"}], "info_list": [ {"label": "fan", "status": "camera-settings-fan"}, {"label": "set", "status": "camera-settings-setpoint"}, {"label": "T", "status": "camera-settings-temperature"} ] }) Loading @@ -195,7 +189,6 @@ {'label': "On", 'endpoint': "/telescope/lamp", 'val': true, 'method': "PUT"}, {'label': "Off", 'endpoint': "/telescope/lamp", 'val': false, 'method': "PUT"} ], 'extra_flags': True }) }} {{ w.widget_toggle({ Loading @@ -205,7 +198,6 @@ {'label': "On", 'endpoint': "/dome/light", 'val': true, 'method': "PUT"}, {'label': "Off", 'endpoint': "/dome/light", 'val': false, 'method': "PUT"} ], 'extra_flags': True }) }} </div> </section> Loading noctua/web/pages/macros/widgets.html +3 −5 Original line number Diff line number Diff line Loading @@ -118,8 +118,8 @@ {% if config.info %} <div class="status-container ms-2"> <span class="badge bg-secondary" data-status="{{ config.info.strip('/') | replace('/', '-') }}">Unknown</span> <var class="d-none text-info small" data-status="{{ config.info.strip('/') | replace('/', '-') }}-raw" style="font-style: normal;">null</var> <var class="badge bg-secondary" data-status="{{ config.info.strip('/') | replace('/', '-') }}">Unknown</var> <!-- <var class="d-none text-info small" data-status="{{ config.info.strip('/') | replace('/', '-') }}-raw" style="font-style: normal;">null</var> --> </div> {% endif %} </div> Loading Loading @@ -224,8 +224,7 @@ <div class="col-md-4 d-flex justify-content-between align-items-center"> <label class="col-form-label">Shutter</label> <div class="status-container ms-2"> <span class="badge bg-secondary" data-status="dome-shutter">Unknown</span> <var class="d-none text-info small" data-status="dome-shutter-raw" style="font-style: normal;">null</var> <var class="badge bg-secondary" data-status="dome-shutter">Unknown</var> </div> </div> <div class="col-md-8"> Loading Loading @@ -256,7 +255,6 @@ </div> {% if extra_flags %} <aside class="row"> {{ render_flags(safe_id) }} </aside> {% endif %} </fieldset> Loading noctua/web/pages/webcam.html +9 −11 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ {'label': "On", 'endpoint': "/dome/light", 'val': true, 'method': "PUT"}, {'label': "Off", 'endpoint': "/dome/light", 'val': false, 'method': "PUT"} ], 'extra_flags': True }) }} </div> Loading @@ -42,7 +41,6 @@ {'label': "On", 'endpoint': "/telescope/lamp", 'val': true, 'method': "PUT"}, {'label': "Off", 'endpoint': "/telescope/lamp", 'val': false, 'method': "PUT"} ], 'extra_flags': True }) }} </div> </fieldset> Loading @@ -53,7 +51,7 @@ <aside class="row mt-3 align-items-end g-3"> <!-- Movement Controls --> <div class="col-md-7"> <div class="col"> <label class="form-label small text-muted">Movement (Alt/Az Delta)</label> <div class="input-group input-group-sm"> <input id="webcam-position" class="form-control" type="number" value="20" style="max-width: 80px;"> Loading @@ -67,14 +65,14 @@ </div> </div> <div class="col"> {{ w.widget_toggle({ 'label': "Presets", 'buttons': [ {'label': "Reset", 'endpoint': "/webcam/position", 'val': [15,180], 'method': "PUT"}, {'label': "Look top", 'endpoint': "/webcam/position", 'val': [55,170], 'method': "PUT"} ], 'extra_flags': False }) }} </div> </aside> Loading noctua/web/static/js/status-stream.js +42 −33 Original line number Diff line number Diff line Loading @@ -12,10 +12,8 @@ document.addEventListener('DOMContentLoaded', () => { const subsystem = msg.name.replace('all-', ''); const data = msg.data; // Track state to trigger pulses only on real changes if (!previousState[subsystem]) previousState[subsystem] = {}; // Find elements targeting this subsystem (e.g. data-status="camera-settings-xystart-0") const elements = document.querySelectorAll(`[data-status^="${subsystem}-"]`); elements.forEach(el => { Loading @@ -27,24 +25,21 @@ document.addEventListener('DOMContentLoaded', () => { let arrayIndex = null; let remainingKey = keyWithoutSubsystem; // Isola l'indice dell'array se presente alla fine del data-status (-0 o -1) if (remainingKey.endsWith('-0') || remainingKey.endsWith('-1')) { arrayIndex = parseInt(remainingKey.slice(-1), 10); remainingKey = remainingKey.slice(0, -2); } // Risolve l'endpoint e l'eventuale sotto-proprietà interna let endpoint = ''; let subProperty = ''; if (data[remainingKey] !== undefined) { endpoint = remainingKey; // Es. "coordinates-offset" endpoint = remainingKey; } else { // Altrimenti estrae l'ultima proprietà dal percorso const lastHyphenIdx = remainingKey.lastIndexOf('-'); if (lastHyphenIdx !== -1) { endpoint = remainingKey.substring(0, lastHyphenIdx); // Es. "settings" subProperty = remainingKey.substring(lastHyphenIdx + 1); // Es. "binning" endpoint = remainingKey.substring(0, lastHyphenIdx); subProperty = remainingKey.substring(lastHyphenIdx + 1); } else { endpoint = remainingKey; } Loading @@ -53,27 +48,42 @@ document.addEventListener('DOMContentLoaded', () => { const endpointData = data[endpoint]; if (endpointData === undefined) return; // Handle the standard wrapper {response, raw, error} // Gestione dei badge di errore (confronto atomico dello stato di errore) if (statusKey.endsWith('-error')) { const errors = endpointData.error; const hasErrors = errors && errors.length > 0; const displayValue = hasErrors ? 'ERR' : 'OK'; const prevErrorState = previousState[subsystem][statusKey]; const hasChanged = prevErrorState !== undefined && prevErrorState !== displayValue; previousState[subsystem][statusKey] = displayValue; if (hasChanged) { el.classList.add('pulse-update'); setTimeout(() => el.classList.remove('pulse-update'), 50); } el.textContent = displayValue; el.className = `badge ${hasErrors ? 'bg-danger' : 'bg-success'}`; if (hasErrors) el.setAttribute('title', errors.join(', ')); else el.removeAttribute('title'); return; } let core = (endpointData && typeof endpointData === 'object' && endpointData.response !== undefined) ? endpointData.response : endpointData; let finalValue = core; // Naviga nelle proprietà interne se l'endpoint è un oggetto dizionario if (subProperty && core && typeof core === 'object') { finalValue = core[subProperty]; } else if (subProperty === 'error') { const errs = endpointData.error || (core ? core.error : null); finalValue = Array.isArray(errs) ? errs.join(', ') : (errs || 'None'); } // Applica l'indice dell'array se richiesto if (arrayIndex !== null && Array.isArray(finalValue)) { finalValue = finalValue[arrayIndex]; } // Apply declarative mathematical transforms if specified const transformName = el.dataset.transform; if (transformName && window.noctuaTransforms && typeof window.noctuaTransforms[transformName] === 'function') { try { Loading @@ -85,22 +95,15 @@ document.addEventListener('DOMContentLoaded', () => { } } // Normalization for display let displayValue = (finalValue === null || finalValue === undefined) ? 'N/A' : finalValue; if (typeof displayValue === 'boolean') { displayValue = displayValue ? 'Yes' : 'No'; } // 1. Change detection and Pulse const valStr = displayValue.toString(); if (previousState[subsystem][statusKey] !== undefined && previousState[subsystem][statusKey] !== valStr) { el.classList.add('pulse-update'); setTimeout(() => el.classList.remove('pulse-update'), 50); } previousState[subsystem][statusKey] = valStr; // 2. Update Content // 1. Aggiornamento del Contenuto Testuale if (el.tagName.toLowerCase() === 'input') { if (el.type === 'checkbox') el.checked = (valStr === 'Yes'); else el.value = valStr; Loading @@ -108,16 +111,22 @@ document.addEventListener('DOMContentLoaded', () => { el.textContent = valStr; } // 3. Dynamic Badge Coloring if (el.classList.contains('badge')) { const v = valStr.toLowerCase(); el.classList.remove('bg-success', 'bg-danger', 'bg-secondary', 'bg-warning'); // 2. Applicazione dello stile dinamico if (el.tagName.toLowerCase() === 'var' || el.classList.contains('badge')) { if (typeof applyVarStatusStyles === 'function') { applyVarStatusStyles(el, finalValue); } } // 3. Rilevamento dei Cambiamenti Atomici (FOGLIA) e Animazione Pulse const hasChanged = previousState[subsystem][statusKey] !== undefined && previousState[subsystem][statusKey] !== finalValue; if (['on', 'yes', 'open', 'true'].includes(v)) el.classList.add('bg-success'); else if (['off', 'no', 'closed', 'false'].includes(v)) el.classList.add('bg-danger'); else el.classList.add('bg-secondary'); previousState[subsystem][statusKey] = finalValue; if (subProperty === 'quitting' && v === 'yes') el.classList.replace('bg-success', 'bg-warning'); if (hasChanged) { el.classList.add('pulse-update'); setTimeout(() => el.classList.remove('pulse-update'), 50); } }); }); Loading Loading
noctua/web/pages/base.html +1 −0 Original line number Diff line number Diff line Loading @@ -168,6 +168,7 @@ <!-- ── Noctua Web Components ──────────────────────────────── --> <!-- ── Unified WebSocket client ───────────────────────────────────────── --> <script src="{{ url_for('web.static', filename='js/ui-styles.js') }}"></script> <script src="{{ url_for('web.static', filename='js/status-stream.js') }}"></script> <script src="{{ url_for('web.static', filename='js/actions.js') }}"></script> <script src="{{ url_for('web.static', filename='js/ws-client.js') }}"></script> Loading
noctua/web/pages/init.html +8 −16 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ {"label": "On", "endpoint": "/telescope/power", "val": true, "method": "PUT"}, {"label": "Off", "endpoint": "/telescope/power", "val": false, "method": "PUT"} ], "extra_flags": True }) }} Loading @@ -28,7 +27,6 @@ {"label": "Unpark", "endpoint": "/telescope/coordinates/movement/unpark", "method": "POST"}, {"label": "Park", "endpoint": "/telescope/coordinates/movement/park", "method": "POST"} ], "extra_flags": True }) }} Loading Loading @@ -65,7 +63,6 @@ "endpoint": "/telescope/error", "method": "DELETE" }], "extra_flags": True, "info_list": [{"label": "detail", "status": "telescope-error-details"}] }) }} Loading @@ -74,15 +71,14 @@ {{ w.widget_input({ "info": "/telescope/coordinates/offset", "inputs": [ {"label": "Zd", "value": 1500}, {"label": "Az", "value": -160} {"label": "Zd", "value": -300}, {"label": "Az", "value": -300} ], "unit": "″", "buttons": [{"label": "Set", "endpoint": "/telescope/coordinates/offset", "method": "PUT"}], "info_list": [ {"label": "alt", "status": "telescope-offset-0"}, {"label": "alt", "status": "telescope-coordinates-offset-0"}, {"label": "az", "status": "telescope-coordinates-offset-1"} ] }) Loading @@ -91,10 +87,12 @@ {{ w.widget_input({ "label": "Rotator", "info": "/telescope/rotator", "inputs": [{"value": 0}], "unit": "°", "buttons": [{"label": "Set", "endpoint": "/telescope/rotator/movement", "method": "POST"}] "buttons": [{"label": "Set", "endpoint": "/telescope/rotator/movement", "method": "POST"}], "info_list": [ {"label": "rot", "status": "telescope-rotator"}, ], }) }} </div> Loading @@ -113,7 +111,6 @@ {"label": "Move", "endpoint": "/dome/position/movement/azimuth", "method": "POST"}, {"label": "Sync", "endpoint": "/dome/position/sync", "method": "PUT"} ], "extra_flags": True, "info_list": [ {"label": "slaved", "status": "dome-position-slaved"}, {"label": "az", "status": "dome-position-azimuth"} Loading @@ -128,7 +125,6 @@ {"label": "Park", "endpoint": "/dome/position/movement/park", "method": "POST"}, {"label": "Stop", "endpoint": "/dome/position/movement", "method": "DELETE"} ], "extra_flags": True }) }} Loading @@ -136,7 +132,6 @@ w.widget_shutter( get_url = "/dome/shutter", move_url = "/dome/shutter/movement", extra_flags = True ) }} </div> Loading @@ -152,7 +147,6 @@ {"label": "On", "endpoint": "/camera/power", "val": true, "method": "PUT"}, {"label": "Off", "endpoint": "/camera/power", "val": false, "method": "PUT"} ], "extra_flags": True }) }} Loading @@ -170,12 +164,12 @@ {{ w.widget_input({ "label": "Temperature", "info": "/camera/cooler/temperature/setpoint", "inputs": [{"value": -10}], "unit": "°C", "buttons": [{"label": "Set", "endpoint": "/camera/cooler/temperature/setpoint", "method": "PUT"}], "info_list": [ {"label": "fan", "status": "camera-settings-fan"}, {"label": "set", "status": "camera-settings-setpoint"}, {"label": "T", "status": "camera-settings-temperature"} ] }) Loading @@ -195,7 +189,6 @@ {'label': "On", 'endpoint': "/telescope/lamp", 'val': true, 'method': "PUT"}, {'label': "Off", 'endpoint': "/telescope/lamp", 'val': false, 'method': "PUT"} ], 'extra_flags': True }) }} {{ w.widget_toggle({ Loading @@ -205,7 +198,6 @@ {'label': "On", 'endpoint': "/dome/light", 'val': true, 'method': "PUT"}, {'label': "Off", 'endpoint': "/dome/light", 'val': false, 'method': "PUT"} ], 'extra_flags': True }) }} </div> </section> Loading
noctua/web/pages/macros/widgets.html +3 −5 Original line number Diff line number Diff line Loading @@ -118,8 +118,8 @@ {% if config.info %} <div class="status-container ms-2"> <span class="badge bg-secondary" data-status="{{ config.info.strip('/') | replace('/', '-') }}">Unknown</span> <var class="d-none text-info small" data-status="{{ config.info.strip('/') | replace('/', '-') }}-raw" style="font-style: normal;">null</var> <var class="badge bg-secondary" data-status="{{ config.info.strip('/') | replace('/', '-') }}">Unknown</var> <!-- <var class="d-none text-info small" data-status="{{ config.info.strip('/') | replace('/', '-') }}-raw" style="font-style: normal;">null</var> --> </div> {% endif %} </div> Loading Loading @@ -224,8 +224,7 @@ <div class="col-md-4 d-flex justify-content-between align-items-center"> <label class="col-form-label">Shutter</label> <div class="status-container ms-2"> <span class="badge bg-secondary" data-status="dome-shutter">Unknown</span> <var class="d-none text-info small" data-status="dome-shutter-raw" style="font-style: normal;">null</var> <var class="badge bg-secondary" data-status="dome-shutter">Unknown</var> </div> </div> <div class="col-md-8"> Loading Loading @@ -256,7 +255,6 @@ </div> {% if extra_flags %} <aside class="row"> {{ render_flags(safe_id) }} </aside> {% endif %} </fieldset> Loading
noctua/web/pages/webcam.html +9 −11 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ {'label': "On", 'endpoint': "/dome/light", 'val': true, 'method': "PUT"}, {'label': "Off", 'endpoint': "/dome/light", 'val': false, 'method': "PUT"} ], 'extra_flags': True }) }} </div> Loading @@ -42,7 +41,6 @@ {'label': "On", 'endpoint': "/telescope/lamp", 'val': true, 'method': "PUT"}, {'label': "Off", 'endpoint': "/telescope/lamp", 'val': false, 'method': "PUT"} ], 'extra_flags': True }) }} </div> </fieldset> Loading @@ -53,7 +51,7 @@ <aside class="row mt-3 align-items-end g-3"> <!-- Movement Controls --> <div class="col-md-7"> <div class="col"> <label class="form-label small text-muted">Movement (Alt/Az Delta)</label> <div class="input-group input-group-sm"> <input id="webcam-position" class="form-control" type="number" value="20" style="max-width: 80px;"> Loading @@ -67,14 +65,14 @@ </div> </div> <div class="col"> {{ w.widget_toggle({ 'label': "Presets", 'buttons': [ {'label': "Reset", 'endpoint': "/webcam/position", 'val': [15,180], 'method': "PUT"}, {'label': "Look top", 'endpoint': "/webcam/position", 'val': [55,170], 'method': "PUT"} ], 'extra_flags': False }) }} </div> </aside> Loading
noctua/web/static/js/status-stream.js +42 −33 Original line number Diff line number Diff line Loading @@ -12,10 +12,8 @@ document.addEventListener('DOMContentLoaded', () => { const subsystem = msg.name.replace('all-', ''); const data = msg.data; // Track state to trigger pulses only on real changes if (!previousState[subsystem]) previousState[subsystem] = {}; // Find elements targeting this subsystem (e.g. data-status="camera-settings-xystart-0") const elements = document.querySelectorAll(`[data-status^="${subsystem}-"]`); elements.forEach(el => { Loading @@ -27,24 +25,21 @@ document.addEventListener('DOMContentLoaded', () => { let arrayIndex = null; let remainingKey = keyWithoutSubsystem; // Isola l'indice dell'array se presente alla fine del data-status (-0 o -1) if (remainingKey.endsWith('-0') || remainingKey.endsWith('-1')) { arrayIndex = parseInt(remainingKey.slice(-1), 10); remainingKey = remainingKey.slice(0, -2); } // Risolve l'endpoint e l'eventuale sotto-proprietà interna let endpoint = ''; let subProperty = ''; if (data[remainingKey] !== undefined) { endpoint = remainingKey; // Es. "coordinates-offset" endpoint = remainingKey; } else { // Altrimenti estrae l'ultima proprietà dal percorso const lastHyphenIdx = remainingKey.lastIndexOf('-'); if (lastHyphenIdx !== -1) { endpoint = remainingKey.substring(0, lastHyphenIdx); // Es. "settings" subProperty = remainingKey.substring(lastHyphenIdx + 1); // Es. "binning" endpoint = remainingKey.substring(0, lastHyphenIdx); subProperty = remainingKey.substring(lastHyphenIdx + 1); } else { endpoint = remainingKey; } Loading @@ -53,27 +48,42 @@ document.addEventListener('DOMContentLoaded', () => { const endpointData = data[endpoint]; if (endpointData === undefined) return; // Handle the standard wrapper {response, raw, error} // Gestione dei badge di errore (confronto atomico dello stato di errore) if (statusKey.endsWith('-error')) { const errors = endpointData.error; const hasErrors = errors && errors.length > 0; const displayValue = hasErrors ? 'ERR' : 'OK'; const prevErrorState = previousState[subsystem][statusKey]; const hasChanged = prevErrorState !== undefined && prevErrorState !== displayValue; previousState[subsystem][statusKey] = displayValue; if (hasChanged) { el.classList.add('pulse-update'); setTimeout(() => el.classList.remove('pulse-update'), 50); } el.textContent = displayValue; el.className = `badge ${hasErrors ? 'bg-danger' : 'bg-success'}`; if (hasErrors) el.setAttribute('title', errors.join(', ')); else el.removeAttribute('title'); return; } let core = (endpointData && typeof endpointData === 'object' && endpointData.response !== undefined) ? endpointData.response : endpointData; let finalValue = core; // Naviga nelle proprietà interne se l'endpoint è un oggetto dizionario if (subProperty && core && typeof core === 'object') { finalValue = core[subProperty]; } else if (subProperty === 'error') { const errs = endpointData.error || (core ? core.error : null); finalValue = Array.isArray(errs) ? errs.join(', ') : (errs || 'None'); } // Applica l'indice dell'array se richiesto if (arrayIndex !== null && Array.isArray(finalValue)) { finalValue = finalValue[arrayIndex]; } // Apply declarative mathematical transforms if specified const transformName = el.dataset.transform; if (transformName && window.noctuaTransforms && typeof window.noctuaTransforms[transformName] === 'function') { try { Loading @@ -85,22 +95,15 @@ document.addEventListener('DOMContentLoaded', () => { } } // Normalization for display let displayValue = (finalValue === null || finalValue === undefined) ? 'N/A' : finalValue; if (typeof displayValue === 'boolean') { displayValue = displayValue ? 'Yes' : 'No'; } // 1. Change detection and Pulse const valStr = displayValue.toString(); if (previousState[subsystem][statusKey] !== undefined && previousState[subsystem][statusKey] !== valStr) { el.classList.add('pulse-update'); setTimeout(() => el.classList.remove('pulse-update'), 50); } previousState[subsystem][statusKey] = valStr; // 2. Update Content // 1. Aggiornamento del Contenuto Testuale if (el.tagName.toLowerCase() === 'input') { if (el.type === 'checkbox') el.checked = (valStr === 'Yes'); else el.value = valStr; Loading @@ -108,16 +111,22 @@ document.addEventListener('DOMContentLoaded', () => { el.textContent = valStr; } // 3. Dynamic Badge Coloring if (el.classList.contains('badge')) { const v = valStr.toLowerCase(); el.classList.remove('bg-success', 'bg-danger', 'bg-secondary', 'bg-warning'); // 2. Applicazione dello stile dinamico if (el.tagName.toLowerCase() === 'var' || el.classList.contains('badge')) { if (typeof applyVarStatusStyles === 'function') { applyVarStatusStyles(el, finalValue); } } // 3. Rilevamento dei Cambiamenti Atomici (FOGLIA) e Animazione Pulse const hasChanged = previousState[subsystem][statusKey] !== undefined && previousState[subsystem][statusKey] !== finalValue; if (['on', 'yes', 'open', 'true'].includes(v)) el.classList.add('bg-success'); else if (['off', 'no', 'closed', 'false'].includes(v)) el.classList.add('bg-danger'); else el.classList.add('bg-secondary'); previousState[subsystem][statusKey] = finalValue; if (subProperty === 'quitting' && v === 'yes') el.classList.replace('bg-success', 'bg-warning'); if (hasChanged) { el.classList.add('pulse-update'); setTimeout(() => el.classList.remove('pulse-update'), 50); } }); }); Loading