Introduces a new Value Source entity that produces a scalar float (0.0-1.0) for dynamic brightness modulation. Three subtypes: Static (constant), Animated (sine/triangle/square/sawtooth waveform), and Audio-reactive (RMS/peak/beat from mono audio source). Value sources can be optionally attached to LED targets to control brightness each frame. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
414 lines
12 KiB
JavaScript
414 lines
12 KiB
JavaScript
/**
|
|
* Entry point — imports all modules, registers globals, initializes app.
|
|
*/
|
|
|
|
// Layer 0: state
|
|
import { apiKey, setApiKey, refreshInterval } from './core/state.js';
|
|
import { Modal } from './core/modal.js';
|
|
|
|
// Layer 1: api, i18n
|
|
import { loadServerInfo, loadDisplays, configureApiKey } from './core/api.js';
|
|
import { t, initLocale, changeLocale } from './core/i18n.js';
|
|
|
|
// Layer 2: ui
|
|
import {
|
|
toggleHint, lockBody, unlockBody, closeLightbox,
|
|
showToast, showConfirm, closeConfirmModal,
|
|
openFullImageLightbox, showOverlaySpinner, hideOverlaySpinner,
|
|
} from './core/ui.js';
|
|
|
|
// Layer 3: displays, tutorials
|
|
import {
|
|
openDisplayPicker, closeDisplayPicker, selectDisplay, formatDisplayLabel,
|
|
} from './features/displays.js';
|
|
import {
|
|
startCalibrationTutorial, startDeviceTutorial,
|
|
closeTutorial, tutorialNext, tutorialPrev,
|
|
} from './features/tutorials.js';
|
|
|
|
// Layer 4: devices, dashboard, streams, kc-targets, pattern-templates, profiles
|
|
import {
|
|
showSettings, closeDeviceSettingsModal, forceCloseDeviceSettingsModal,
|
|
saveDeviceSettings, updateBrightnessLabel, saveCardBrightness,
|
|
turnOffDevice, removeDevice, loadDevices,
|
|
updateSettingsBaudFpsHint,
|
|
} from './features/devices.js';
|
|
import {
|
|
loadDashboard, stopUptimeTimer,
|
|
dashboardToggleProfile, dashboardStartTarget, dashboardStopTarget, dashboardStopAll,
|
|
toggleDashboardSection, changeDashboardPollInterval,
|
|
} from './features/dashboard.js';
|
|
import { startEventsWS, stopEventsWS } from './core/events-ws.js';
|
|
import {
|
|
startPerfPolling, stopPerfPolling,
|
|
} from './features/perf-charts.js';
|
|
import {
|
|
loadPictureSources, switchStreamTab,
|
|
showAddTemplateModal, editTemplate, closeTemplateModal, saveTemplate, deleteTemplate,
|
|
showTestTemplateModal, closeTestTemplateModal, onEngineChange, runTemplateTest,
|
|
showAddStreamModal, editStream, closeStreamModal, saveStream, deleteStream,
|
|
onStreamTypeChange, onStreamDisplaySelected, onTestDisplaySelected,
|
|
showTestStreamModal, closeTestStreamModal, updateStreamTestDuration, runStreamTest,
|
|
showTestPPTemplateModal, closeTestPPTemplateModal, updatePPTestDuration, runPPTemplateTest,
|
|
showAddPPTemplateModal, editPPTemplate, closePPTemplateModal, savePPTemplate, deletePPTemplate,
|
|
addFilterFromSelect, toggleFilterExpand, removeFilter, moveFilter, updateFilterOption,
|
|
renderModalFilterList, updateCaptureDuration,
|
|
cloneStream, cloneCaptureTemplate, clonePPTemplate,
|
|
} from './features/streams.js';
|
|
import {
|
|
createKCTargetCard, testKCTarget, toggleKCTestAutoRefresh,
|
|
showKCEditor, closeKCEditorModal, forceCloseKCEditorModal, saveKCEditor,
|
|
deleteKCTarget, disconnectAllKCWebSockets,
|
|
updateKCBrightnessLabel, saveKCBrightness,
|
|
cloneKCTarget,
|
|
} from './features/kc-targets.js';
|
|
import {
|
|
createPatternTemplateCard,
|
|
showPatternTemplateEditor, closePatternTemplateModal, forceClosePatternTemplateModal,
|
|
savePatternTemplate, deletePatternTemplate,
|
|
renderPatternRectList, selectPatternRect, updatePatternRect,
|
|
addPatternRect, deleteSelectedPatternRect, removePatternRect,
|
|
capturePatternBackground,
|
|
clonePatternTemplate,
|
|
} from './features/pattern-templates.js';
|
|
import {
|
|
loadProfiles, openProfileEditor, closeProfileEditorModal,
|
|
saveProfileEditor, addProfileCondition,
|
|
toggleProfileEnabled, toggleProfileTargets, deleteProfile,
|
|
} from './features/profiles.js';
|
|
|
|
// Layer 5: device-discovery, targets
|
|
import {
|
|
onDeviceTypeChanged, updateBaudFpsHint, onSerialPortFocus,
|
|
showAddDevice, closeAddDeviceModal, scanForDevices, handleAddDevice,
|
|
} from './features/device-discovery.js';
|
|
import {
|
|
loadTargetsTab, loadTargets, switchTargetSubTab,
|
|
showTargetEditor, closeTargetEditorModal, forceCloseTargetEditorModal, saveTargetEditor,
|
|
startTargetProcessing, stopTargetProcessing,
|
|
startTargetOverlay, stopTargetOverlay, deleteTarget,
|
|
cloneTarget,
|
|
} from './features/targets.js';
|
|
|
|
// Layer 5: color-strip sources
|
|
import {
|
|
showCSSEditor, closeCSSEditorModal, forceCSSEditorClose, saveCSSEditor, deleteColorStrip,
|
|
onCSSTypeChange, onEffectTypeChange, onAnimationTypeChange, updateEffectPreview,
|
|
colorCycleAddColor, colorCycleRemoveColor,
|
|
compositeAddLayer, compositeRemoveLayer,
|
|
mappedAddZone, mappedRemoveZone,
|
|
onAudioVizChange,
|
|
applyGradientPreset,
|
|
cloneColorStrip,
|
|
} from './features/color-strips.js';
|
|
|
|
// Layer 5: audio sources
|
|
import {
|
|
showAudioSourceModal, closeAudioSourceModal, saveAudioSource,
|
|
editAudioSource, deleteAudioSource, onAudioSourceTypeChange,
|
|
} from './features/audio-sources.js';
|
|
|
|
// Layer 5: value sources
|
|
import {
|
|
showValueSourceModal, closeValueSourceModal, saveValueSource,
|
|
editValueSource, deleteValueSource, onValueSourceTypeChange,
|
|
} from './features/value-sources.js';
|
|
|
|
// Layer 5: calibration
|
|
import {
|
|
showCalibration, closeCalibrationModal, forceCloseCalibrationModal, saveCalibration,
|
|
updateOffsetSkipLock, updateCalibrationPreview,
|
|
setStartPosition, toggleEdgeInputs, toggleDirection, toggleTestEdge,
|
|
showCSSCalibration,
|
|
} from './features/calibration.js';
|
|
|
|
// Layer 6: tabs
|
|
import { switchTab, initTabs, startAutoRefresh } from './features/tabs.js';
|
|
|
|
// ─── Register all HTML onclick / onchange / onfocus globals ───
|
|
|
|
Object.assign(window, {
|
|
// core / state (for inline script)
|
|
setApiKey,
|
|
|
|
// core / ui
|
|
toggleHint,
|
|
lockBody,
|
|
unlockBody,
|
|
closeLightbox,
|
|
showToast,
|
|
showConfirm,
|
|
closeConfirmModal,
|
|
openFullImageLightbox,
|
|
showOverlaySpinner,
|
|
hideOverlaySpinner,
|
|
|
|
// core / api + i18n
|
|
t,
|
|
configureApiKey,
|
|
loadServerInfo,
|
|
loadDisplays,
|
|
changeLocale,
|
|
|
|
// displays
|
|
openDisplayPicker,
|
|
closeDisplayPicker,
|
|
selectDisplay,
|
|
formatDisplayLabel,
|
|
|
|
// tutorials
|
|
startCalibrationTutorial,
|
|
startDeviceTutorial,
|
|
closeTutorial,
|
|
tutorialNext,
|
|
tutorialPrev,
|
|
|
|
// devices
|
|
showSettings,
|
|
closeDeviceSettingsModal,
|
|
forceCloseDeviceSettingsModal,
|
|
saveDeviceSettings,
|
|
updateBrightnessLabel,
|
|
saveCardBrightness,
|
|
turnOffDevice,
|
|
removeDevice,
|
|
loadDevices,
|
|
updateSettingsBaudFpsHint,
|
|
|
|
// dashboard
|
|
loadDashboard,
|
|
dashboardToggleProfile,
|
|
dashboardStartTarget,
|
|
dashboardStopTarget,
|
|
dashboardStopAll,
|
|
toggleDashboardSection,
|
|
changeDashboardPollInterval,
|
|
stopUptimeTimer,
|
|
startPerfPolling,
|
|
stopPerfPolling,
|
|
|
|
// streams / capture templates / PP templates
|
|
loadPictureSources,
|
|
switchStreamTab,
|
|
showAddTemplateModal,
|
|
editTemplate,
|
|
closeTemplateModal,
|
|
saveTemplate,
|
|
deleteTemplate,
|
|
showTestTemplateModal,
|
|
closeTestTemplateModal,
|
|
onEngineChange,
|
|
runTemplateTest,
|
|
updateCaptureDuration,
|
|
showAddStreamModal,
|
|
editStream,
|
|
closeStreamModal,
|
|
saveStream,
|
|
deleteStream,
|
|
onStreamTypeChange,
|
|
onStreamDisplaySelected,
|
|
onTestDisplaySelected,
|
|
showTestStreamModal,
|
|
closeTestStreamModal,
|
|
updateStreamTestDuration,
|
|
runStreamTest,
|
|
showTestPPTemplateModal,
|
|
closeTestPPTemplateModal,
|
|
updatePPTestDuration,
|
|
runPPTemplateTest,
|
|
showAddPPTemplateModal,
|
|
editPPTemplate,
|
|
closePPTemplateModal,
|
|
savePPTemplate,
|
|
deletePPTemplate,
|
|
addFilterFromSelect,
|
|
toggleFilterExpand,
|
|
removeFilter,
|
|
moveFilter,
|
|
updateFilterOption,
|
|
renderModalFilterList,
|
|
cloneStream,
|
|
cloneCaptureTemplate,
|
|
clonePPTemplate,
|
|
|
|
// kc-targets
|
|
createKCTargetCard,
|
|
testKCTarget,
|
|
toggleKCTestAutoRefresh,
|
|
showKCEditor,
|
|
closeKCEditorModal,
|
|
forceCloseKCEditorModal,
|
|
saveKCEditor,
|
|
deleteKCTarget,
|
|
disconnectAllKCWebSockets,
|
|
updateKCBrightnessLabel,
|
|
saveKCBrightness,
|
|
cloneKCTarget,
|
|
|
|
// pattern-templates
|
|
createPatternTemplateCard,
|
|
showPatternTemplateEditor,
|
|
closePatternTemplateModal,
|
|
forceClosePatternTemplateModal,
|
|
savePatternTemplate,
|
|
deletePatternTemplate,
|
|
renderPatternRectList,
|
|
selectPatternRect,
|
|
updatePatternRect,
|
|
addPatternRect,
|
|
deleteSelectedPatternRect,
|
|
removePatternRect,
|
|
capturePatternBackground,
|
|
clonePatternTemplate,
|
|
|
|
// profiles
|
|
loadProfiles,
|
|
openProfileEditor,
|
|
closeProfileEditorModal,
|
|
saveProfileEditor,
|
|
addProfileCondition,
|
|
toggleProfileEnabled,
|
|
toggleProfileTargets,
|
|
deleteProfile,
|
|
|
|
// device-discovery
|
|
onDeviceTypeChanged,
|
|
updateBaudFpsHint,
|
|
onSerialPortFocus,
|
|
showAddDevice,
|
|
closeAddDeviceModal,
|
|
scanForDevices,
|
|
handleAddDevice,
|
|
|
|
// targets
|
|
loadTargetsTab,
|
|
loadTargets,
|
|
switchTargetSubTab,
|
|
showTargetEditor,
|
|
closeTargetEditorModal,
|
|
forceCloseTargetEditorModal,
|
|
saveTargetEditor,
|
|
startTargetProcessing,
|
|
stopTargetProcessing,
|
|
startTargetOverlay,
|
|
stopTargetOverlay,
|
|
deleteTarget,
|
|
cloneTarget,
|
|
|
|
// color-strip sources
|
|
showCSSEditor,
|
|
closeCSSEditorModal,
|
|
forceCSSEditorClose,
|
|
saveCSSEditor,
|
|
deleteColorStrip,
|
|
onCSSTypeChange,
|
|
onEffectTypeChange,
|
|
onAnimationTypeChange,
|
|
updateEffectPreview,
|
|
colorCycleAddColor,
|
|
colorCycleRemoveColor,
|
|
compositeAddLayer,
|
|
compositeRemoveLayer,
|
|
mappedAddZone,
|
|
mappedRemoveZone,
|
|
onAudioVizChange,
|
|
applyGradientPreset,
|
|
cloneColorStrip,
|
|
|
|
// audio sources
|
|
showAudioSourceModal,
|
|
closeAudioSourceModal,
|
|
saveAudioSource,
|
|
editAudioSource,
|
|
deleteAudioSource,
|
|
onAudioSourceTypeChange,
|
|
|
|
// value sources
|
|
showValueSourceModal,
|
|
closeValueSourceModal,
|
|
saveValueSource,
|
|
editValueSource,
|
|
deleteValueSource,
|
|
onValueSourceTypeChange,
|
|
|
|
// calibration
|
|
showCalibration,
|
|
closeCalibrationModal,
|
|
forceCloseCalibrationModal,
|
|
saveCalibration,
|
|
updateOffsetSkipLock,
|
|
updateCalibrationPreview,
|
|
setStartPosition,
|
|
toggleEdgeInputs,
|
|
toggleDirection,
|
|
toggleTestEdge,
|
|
showCSSCalibration,
|
|
|
|
// tabs
|
|
switchTab,
|
|
startAutoRefresh,
|
|
});
|
|
|
|
// ─── Global Escape key handler ───
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') {
|
|
// Close in order: overlay lightboxes first, then modals via stack
|
|
if (document.getElementById('display-picker-lightbox').classList.contains('active')) {
|
|
closeDisplayPicker();
|
|
} else if (document.getElementById('image-lightbox').classList.contains('active')) {
|
|
closeLightbox();
|
|
} else {
|
|
Modal.closeTopmost();
|
|
}
|
|
}
|
|
});
|
|
|
|
// ─── Cleanup on page unload ───
|
|
|
|
window.addEventListener('beforeunload', () => {
|
|
if (refreshInterval) {
|
|
clearInterval(refreshInterval);
|
|
}
|
|
stopEventsWS();
|
|
disconnectAllKCWebSockets();
|
|
});
|
|
|
|
// ─── Initialization ───
|
|
|
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
// Load API key from localStorage before anything that triggers API calls
|
|
setApiKey(localStorage.getItem('wled_api_key'));
|
|
|
|
// Initialize locale (dispatches languageChanged which may trigger API calls)
|
|
await initLocale();
|
|
|
|
// Restore active tab before showing content to avoid visible jump
|
|
initTabs();
|
|
|
|
// Show content now that translations are loaded and tabs are set
|
|
document.body.style.visibility = 'visible';
|
|
|
|
// Setup form handler
|
|
document.getElementById('add-device-form').addEventListener('submit', handleAddDevice);
|
|
|
|
// Show modal if no API key is stored
|
|
if (!apiKey) {
|
|
setTimeout(() => {
|
|
if (typeof window.showApiKeyModal === 'function') {
|
|
window.showApiKeyModal(null, true);
|
|
}
|
|
}, 100);
|
|
return;
|
|
}
|
|
|
|
// User is logged in, load data
|
|
loadServerInfo();
|
|
loadDisplays();
|
|
loadTargetsTab();
|
|
|
|
// Start global events WebSocket and auto-refresh
|
|
startEventsWS();
|
|
startAutoRefresh();
|
|
});
|