Add incremental card reconciliation to prevent full DOM rebuild on auto-refresh

CardSection now diffs cards by key attributes instead of rebuilding innerHTML,
preserving DOM elements, filter input focus, scroll position, and Chart.js
instances across the 2s targets tab auto-refresh cycle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 00:58:38 +03:00
parent 166ec351b1
commit 27720e51aa
4 changed files with 209 additions and 54 deletions

View File

@@ -667,18 +667,18 @@ function renderPictureSourcesList(streams) {
if (tab.key === 'raw') {
panelContent =
csRawStreams.render(rawStreams.map(renderStreamCard).join(''), rawStreams.length) +
csRawTemplates.render(_cachedCaptureTemplates.map(renderCaptureTemplateCard).join(''), _cachedCaptureTemplates.length);
csRawStreams.render(rawStreams.map(s => ({ key: s.id, html: renderStreamCard(s) }))) +
csRawTemplates.render(_cachedCaptureTemplates.map(t => ({ key: t.id, html: renderCaptureTemplateCard(t) })));
} else if (tab.key === 'processed') {
panelContent =
csProcStreams.render(processedStreams.map(renderStreamCard).join(''), processedStreams.length) +
csProcTemplates.render(_cachedPPTemplates.map(renderPPTemplateCard).join(''), _cachedPPTemplates.length);
csProcStreams.render(processedStreams.map(s => ({ key: s.id, html: renderStreamCard(s) }))) +
csProcTemplates.render(_cachedPPTemplates.map(t => ({ key: t.id, html: renderPPTemplateCard(t) })));
} else if (tab.key === 'audio') {
panelContent =
csAudioMulti.render(multichannelSources.map(renderAudioSourceCard).join(''), multichannelSources.length) +
csAudioMono.render(monoSources.map(renderAudioSourceCard).join(''), monoSources.length);
csAudioMulti.render(multichannelSources.map(s => ({ key: s.id, html: renderAudioSourceCard(s) }))) +
csAudioMono.render(monoSources.map(s => ({ key: s.id, html: renderAudioSourceCard(s) })));
} else {
panelContent = csStaticStreams.render(staticImageStreams.map(renderStreamCard).join(''), staticImageStreams.length);
panelContent = csStaticStreams.render(staticImageStreams.map(s => ({ key: s.id, html: renderStreamCard(s) })));
}
return `<div class="stream-tab-panel${tab.key === activeTab ? ' active' : ''}" id="stream-tab-${tab.key}">${panelContent}</div>`;