diff --git a/measurement.html b/measurement.html index a80bc50..31c5594 100644 --- a/measurement.html +++ b/measurement.html @@ -74,44 +74,50 @@ oneditprepare: function() { const node = this; - // === Mode selector — TOP-LEVEL hierarchy === - // The Input Mode drives whether analog-pipeline fields or the - // digital channels editor are shown. Initialize the from the saved node.mode. Legacy + // nodes (saved before the mode field existed) fall back to + // 'analog' so they keep behaving exactly like before. + const initialMode = (node.mode === 'digital' || node.mode === 'analog') ? node.mode : 'analog'; + if (modeSelect) modeSelect.value = initialMode; - modeSelect.addEventListener('change', (e) => applyMode(e.target.value)); - applyMode(initialMode); - - // === Channels JSON live validation (digital only) === - const channelsArea = document.getElementById('node-input-channels'); - const channelsHint = document.getElementById('channels-validation'); + // Populate the channels textarea from the saved node.channels + // (stored as a raw JSON string; parsing happens server-side). if (channelsArea && typeof node.channels === 'string') { channelsArea.value = node.channels; } + function validateChannelsJson() { if (!channelsHint) return; - if (modeSelect.value !== 'digital') { channelsHint.textContent = ''; return; } - const raw = (channelsArea.value || '').trim(); + if (!modeSelect || modeSelect.value !== 'digital') { + channelsHint.textContent = ''; + return; + } + const raw = (channelsArea && channelsArea.value || '').trim(); if (!raw || raw === '[]') { channelsHint.innerHTML = 'Digital mode with no channels — no measurements will be emitted.'; return; @@ -120,7 +126,7 @@ const parsed = JSON.parse(raw); if (!Array.isArray(parsed)) throw new Error('must be an array'); const missing = parsed - .map((c, i) => (c && c.key && c.type ? null : `entry ${i}: missing key or type`)) + .map((c, i) => (c && c.key && c.type ? null : 'entry ' + i + ': missing key or type')) .filter(Boolean); if (missing.length) { channelsHint.innerHTML = '' + missing.join('; ') + ''; @@ -131,17 +137,24 @@ channelsHint.innerHTML = 'Invalid JSON: ' + e.message + ''; } } - if (channelsArea) channelsArea.addEventListener('input', validateChannelsJson); - // === Asset / logger / position placeholders (dynamic menus) === - const waitForMenuData = () => { - if (window.EVOLV?.nodes?.measurement?.initEditor) { - window.EVOLV.nodes.measurement.initEditor(node); - } else { - setTimeout(waitForMenuData, 50); + function applyMode(mode) { + const isDigital = mode === 'digital'; + if (analogBlock) analogBlock.style.display = isDigital ? 'none' : 'block'; + if (digitalBlock) digitalBlock.style.display = isDigital ? 'block' : 'none'; + if (modeHint) { + modeHint.textContent = isDigital + ? 'msg.payload must be an OBJECT, e.g. {"temperature": 22.5, "humidity": 45}. Define each key below.' + : 'msg.payload must be a NUMBER (or numeric string). Configure scaling/smoothing below.'; } - }; - waitForMenuData(); + validateChannelsJson(); + } + + if (modeSelect) modeSelect.addEventListener('change', (e) => applyMode(e.target.value)); + if (channelsArea) channelsArea.addEventListener('input', validateChannelsJson); + try { applyMode(initialMode); } catch (e) { + console.error('measurement: applyMode failed', e); + } // === Smoothing method dropdown (analog only) === const smoothMethodSelect = document.getElementById('node-input-smooth_method');