- Added rulesets manager to handle various data types and updates via HTTP and WebSocket. - Introduced layout store for managing kiosk layouts with caching and server synchronization. - Enhanced dashboard and data routes to support new layout and ruleset features. - Updated kiosk HTML and JavaScript to utilize new layout rendering and data binding. - Removed obsolete map route and integrated map functionality into the new tile renderer. - Improved Telegram commands to reflect changes in data structure and logging. - Refactored weather fetching intervals to prevent multiple instances. - Added SSE stream for real-time layout updates in the kiosk.
99 lines
3.6 KiB
JavaScript
99 lines
3.6 KiB
JavaScript
/**
|
|
* layout-client.js — apre l'EventSource /meb/kiosk/stream del plugin, riceve
|
|
* il layout corrente (e i successivi update), e ridisegna la griglia.
|
|
*
|
|
* Il plugin NON edita: si limita a mostrare. La logica di binding ai dati
|
|
* SignalK (local stream) e' in data-binder.js; il render dei tile e' in
|
|
* tile-renderer.js.
|
|
*/
|
|
(function () {
|
|
const grid = document.getElementById('grid');
|
|
const chip = document.getElementById('statusChip');
|
|
|
|
let activeUnbinds = []; // funzioni di unbind per i tile correnti
|
|
let currentLayout = null;
|
|
|
|
function setStatus(text, isErr = false) {
|
|
chip.textContent = text;
|
|
chip.classList.toggle('err', isErr);
|
|
}
|
|
|
|
function clearGrid() {
|
|
for (const off of activeUnbinds) { try { off(); } catch (_) {} }
|
|
activeUnbinds = [];
|
|
grid.innerHTML = '';
|
|
}
|
|
|
|
function applyLayout(layoutRow) {
|
|
const content = layoutRow?.content;
|
|
if (!content || !Array.isArray(content.tiles)) {
|
|
console.warn('[KIOSK] layout vuoto/non valido');
|
|
return;
|
|
}
|
|
clearGrid();
|
|
currentLayout = layoutRow;
|
|
|
|
// grid CSS variables
|
|
grid.style.setProperty('--cols', String(content.grid?.cols ?? 12));
|
|
grid.style.setProperty('--rows', String(content.grid?.rows ?? 8));
|
|
grid.style.setProperty('--gap', String(content.grid?.gap ?? 4) + 'px');
|
|
|
|
// theme (opzionale)
|
|
if (content.theme === 'light') {
|
|
document.body.style.background = '#f4f5f7';
|
|
document.body.style.color = '#111';
|
|
} else {
|
|
document.body.style.background = '#0b1220';
|
|
document.body.style.color = '#fff';
|
|
}
|
|
|
|
for (const tile of content.tiles) {
|
|
const el = document.createElement('div');
|
|
el.className = `tile tile-${tile.type}`;
|
|
el.style.gridColumn = `${tile.x + 1} / span ${tile.w}`;
|
|
el.style.gridRow = `${tile.y + 1} / span ${tile.h}`;
|
|
grid.appendChild(el);
|
|
|
|
const r = window.tileRenderer.get(tile.type);
|
|
if (!r) { el.innerHTML = `<div class="title">tipo sconosciuto: ${tile.type}</div>`; continue; }
|
|
try {
|
|
r.mount(el, tile);
|
|
const off = r.bind(el, tile, window.dataBinder);
|
|
if (off) activeUnbinds.push(off);
|
|
} catch (err) {
|
|
console.error('[KIOSK] render', tile.id, err);
|
|
el.innerHTML = `<div class="title">errore render ${tile.id}</div>`;
|
|
}
|
|
}
|
|
|
|
setStatus(`v${layoutRow.version || '?'} · ${content.tiles.length} tiles`);
|
|
}
|
|
|
|
// ====== Stream del plugin (SSE) ======
|
|
function openStream() {
|
|
const es = new EventSource('/meb/kiosk/stream');
|
|
es.addEventListener('layout', (ev) => {
|
|
try { applyLayout(JSON.parse(ev.data)); }
|
|
catch (err) { console.warn('[KIOSK] layout parse:', err); }
|
|
});
|
|
es.onerror = () => setStatus('stream disconnesso', true);
|
|
es.onopen = () => setStatus('stream ok');
|
|
}
|
|
|
|
// status connessione SignalK
|
|
if (window.dataBinder) {
|
|
window.dataBinder.onConnState(({ connected }) => {
|
|
if (!connected) setStatus('signalk disconnesso', true);
|
|
else if (currentLayout) setStatus(`v${currentLayout.version || '?'} · live`);
|
|
});
|
|
}
|
|
|
|
// bootstrap: prima fetch one-shot del layout (per non aspettare il primo evento SSE),
|
|
// poi apri lo stream per gli update successivi
|
|
fetch('/meb/kiosk/layout')
|
|
.then(r => r.ok ? r.json() : null)
|
|
.then(l => { if (l) applyLayout(l); })
|
|
.catch(() => {})
|
|
.finally(openStream);
|
|
})();
|