diff --git a/server/src/wled_controller/static/js/features/value-sources.js b/server/src/wled_controller/static/js/features/value-sources.js index fe4762f..a6c3a3d 100644 --- a/server/src/wled_controller/static/js/features/value-sources.js +++ b/server/src/wled_controller/static/js/features/value-sources.js @@ -64,6 +64,30 @@ class ValueSourceModal extends Modal { const valueSourceModal = new ValueSourceModal(); +/* ── Name auto-generation ────────────────────────────────────── */ + +let _vsNameManuallyEdited = false; + +function _autoGenerateVSName() { + if (_vsNameManuallyEdited) return; + if (document.getElementById('value-source-id').value) return; + const type = document.getElementById('value-source-type').value; + const typeLabel = t(`value_source.type.${type}`); + let detail = ''; + if (type === 'animated') { + const wf = document.getElementById('value-source-waveform').value; + detail = t(`value_source.waveform.${wf}`); + } else if (type === 'audio') { + const mode = document.getElementById('value-source-mode').value; + detail = t(`value_source.mode.${mode}`); + } else if (type === 'adaptive_scene') { + const sel = document.getElementById('value-source-picture-source'); + const name = sel?.selectedOptions[0]?.textContent?.trim(); + if (name) detail = name; + } + document.getElementById('value-source-name').value = detail ? `${typeLabel} · ${detail}` : typeLabel; +} + /* ── Icon-grid type selector ──────────────────────────────────── */ const VS_TYPE_KEYS = ['static', 'animated', 'audio', 'adaptive_time', 'adaptive_scene']; @@ -132,19 +156,23 @@ function _ensureVSTypeIconSelect() { // ── Modal ───────────────────────────────────────────────────── export async function showValueSourceModal(editData) { - const isEdit = !!editData; + const hasId = editData?.id; + const isEdit = !!hasId; const titleKey = isEdit ? 'value_source.edit' : 'value_source.add'; - const titleIcon = isEdit ? getValueSourceIcon(editData.source_type) : getValueSourceIcon('static'); + const titleIcon = editData ? getValueSourceIcon(editData.source_type) : getValueSourceIcon('static'); document.getElementById('value-source-modal-title').innerHTML = `${titleIcon} ${t(titleKey)}`; document.getElementById('value-source-id').value = isEdit ? editData.id : ''; document.getElementById('value-source-error').style.display = 'none'; + _vsNameManuallyEdited = !!(isEdit || editData); + document.getElementById('value-source-name').oninput = () => { _vsNameManuallyEdited = true; }; + _ensureVSTypeIconSelect(); const typeSelect = document.getElementById('value-source-type'); document.getElementById('value-source-type-group').style.display = isEdit ? 'none' : ''; - if (isEdit) { + if (editData) { document.getElementById('value-source-name').value = editData.name || ''; document.getElementById('value-source-description').value = editData.description || ''; typeSelect.value = editData.source_type || 'static'; @@ -205,8 +233,14 @@ export async function showValueSourceModal(editData) { _setSlider('value-source-scene-smoothing', 0.3); _setSlider('value-source-adaptive-min-value', 0); _setSlider('value-source-adaptive-max-value', 1); + _autoGenerateVSName(); } + // Wire up auto-name triggers + document.getElementById('value-source-waveform').onchange = () => _autoGenerateVSName(); + document.getElementById('value-source-mode').onchange = () => _autoGenerateVSName(); + document.getElementById('value-source-picture-source').onchange = () => _autoGenerateVSName(); + valueSourceModal.open(); valueSourceModal.snapshot(); } @@ -240,6 +274,8 @@ export function onValueSourceTypeChange() { if (type === 'adaptive_scene') { _populatePictureSourceDropdown(''); } + + _autoGenerateVSName(); } // ── Save ──────────────────────────────────────────────────────