Add dirty check to all remaining editor modals
Subclass Modal with snapshotValues() for: value source editor, audio source editor, add device, profile editor, capture template, stream editor, and PP template modals. Close/cancel now triggers discard confirmation when form has unsaved changes. Document the convention in CLAUDE.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -45,11 +45,72 @@ document.addEventListener('languageChanged', () => { if (apiKey) loadPictureSour
|
||||
|
||||
// ===== Modal instances =====
|
||||
|
||||
const templateModal = new Modal('template-modal');
|
||||
class CaptureTemplateModal extends Modal {
|
||||
constructor() { super('template-modal'); }
|
||||
|
||||
snapshotValues() {
|
||||
const vals = {
|
||||
name: document.getElementById('template-name').value,
|
||||
description: document.getElementById('template-description').value,
|
||||
engine: document.getElementById('template-engine').value,
|
||||
};
|
||||
document.querySelectorAll('[data-config-key]').forEach(field => {
|
||||
vals['cfg_' + field.dataset.configKey] = field.value;
|
||||
});
|
||||
return vals;
|
||||
}
|
||||
|
||||
onForceClose() {
|
||||
setCurrentEditingTemplateId(null);
|
||||
set_templateNameManuallyEdited(false);
|
||||
}
|
||||
}
|
||||
|
||||
class StreamEditorModal extends Modal {
|
||||
constructor() { super('stream-modal'); }
|
||||
|
||||
snapshotValues() {
|
||||
return {
|
||||
name: document.getElementById('stream-name').value,
|
||||
description: document.getElementById('stream-description').value,
|
||||
type: document.getElementById('stream-type').value,
|
||||
displayIndex: document.getElementById('stream-display-index').value,
|
||||
captureTemplate: document.getElementById('stream-capture-template').value,
|
||||
targetFps: document.getElementById('stream-target-fps').value,
|
||||
source: document.getElementById('stream-source').value,
|
||||
ppTemplate: document.getElementById('stream-pp-template').value,
|
||||
imageSource: document.getElementById('stream-image-source').value,
|
||||
};
|
||||
}
|
||||
|
||||
onForceClose() {
|
||||
document.getElementById('stream-type').disabled = false;
|
||||
set_streamNameManuallyEdited(false);
|
||||
}
|
||||
}
|
||||
|
||||
class PPTemplateEditorModal extends Modal {
|
||||
constructor() { super('pp-template-modal'); }
|
||||
|
||||
snapshotValues() {
|
||||
return {
|
||||
name: document.getElementById('pp-template-name').value,
|
||||
description: document.getElementById('pp-template-description').value,
|
||||
filters: JSON.stringify(_modalFilters.map(fi => ({ filter_id: fi.filter_id, options: fi.options }))),
|
||||
};
|
||||
}
|
||||
|
||||
onForceClose() {
|
||||
set_modalFilters([]);
|
||||
set_ppTemplateNameManuallyEdited(false);
|
||||
}
|
||||
}
|
||||
|
||||
const templateModal = new CaptureTemplateModal();
|
||||
const testTemplateModal = new Modal('test-template-modal');
|
||||
const streamModal = new Modal('stream-modal');
|
||||
const streamModal = new StreamEditorModal();
|
||||
const testStreamModal = new Modal('test-stream-modal');
|
||||
const ppTemplateModal = new Modal('pp-template-modal');
|
||||
const ppTemplateModal = new PPTemplateEditorModal();
|
||||
const testPPTemplateModal = new Modal('test-pp-template-modal');
|
||||
|
||||
// ===== Capture Templates =====
|
||||
@@ -94,6 +155,7 @@ export async function showAddTemplateModal(cloneData = null) {
|
||||
}
|
||||
|
||||
templateModal.open();
|
||||
templateModal.snapshot();
|
||||
}
|
||||
|
||||
export async function editTemplate(templateId) {
|
||||
@@ -120,16 +182,15 @@ export async function editTemplate(templateId) {
|
||||
document.getElementById('template-error').style.display = 'none';
|
||||
|
||||
templateModal.open();
|
||||
templateModal.snapshot();
|
||||
} catch (error) {
|
||||
console.error('Error loading template:', error);
|
||||
showToast(t('templates.error.load') + ': ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
export function closeTemplateModal() {
|
||||
templateModal.forceClose();
|
||||
setCurrentEditingTemplateId(null);
|
||||
set_templateNameManuallyEdited(false);
|
||||
export async function closeTemplateModal() {
|
||||
await templateModal.close();
|
||||
}
|
||||
|
||||
function updateCaptureDuration(value) {
|
||||
@@ -419,7 +480,7 @@ export async function saveTemplate() {
|
||||
}
|
||||
|
||||
showToast(templateId ? t('templates.updated') : t('templates.created'), 'success');
|
||||
closeTemplateModal();
|
||||
templateModal.forceClose();
|
||||
await loadCaptureTemplates();
|
||||
} catch (error) {
|
||||
console.error('Error saving template:', error);
|
||||
@@ -793,6 +854,7 @@ export async function showAddStreamModal(presetType, cloneData = null) {
|
||||
}
|
||||
|
||||
streamModal.open();
|
||||
streamModal.snapshot();
|
||||
}
|
||||
|
||||
export async function editStream(streamId) {
|
||||
@@ -837,6 +899,7 @@ export async function editStream(streamId) {
|
||||
}
|
||||
|
||||
streamModal.open();
|
||||
streamModal.snapshot();
|
||||
} catch (error) {
|
||||
console.error('Error loading stream:', error);
|
||||
showToast(t('streams.error.load') + ': ' + error.message, 'error');
|
||||
@@ -996,7 +1059,7 @@ export async function saveStream() {
|
||||
}
|
||||
|
||||
showToast(streamId ? t('streams.updated') : t('streams.created'), 'success');
|
||||
closeStreamModal();
|
||||
streamModal.forceClose();
|
||||
await loadPictureSources();
|
||||
} catch (error) {
|
||||
console.error('Error saving stream:', error);
|
||||
@@ -1023,10 +1086,8 @@ export async function deleteStream(streamId) {
|
||||
}
|
||||
}
|
||||
|
||||
export function closeStreamModal() {
|
||||
streamModal.forceClose();
|
||||
document.getElementById('stream-type').disabled = false;
|
||||
set_streamNameManuallyEdited(false);
|
||||
export async function closeStreamModal() {
|
||||
await streamModal.close();
|
||||
}
|
||||
|
||||
async function validateStaticImage() {
|
||||
@@ -1448,6 +1509,7 @@ export async function showAddPPTemplateModal(cloneData = null) {
|
||||
}
|
||||
|
||||
ppTemplateModal.open();
|
||||
ppTemplateModal.snapshot();
|
||||
}
|
||||
|
||||
export async function editPPTemplate(templateId) {
|
||||
@@ -1473,6 +1535,7 @@ export async function editPPTemplate(templateId) {
|
||||
renderModalFilterList();
|
||||
|
||||
ppTemplateModal.open();
|
||||
ppTemplateModal.snapshot();
|
||||
} catch (error) {
|
||||
console.error('Error loading PP template:', error);
|
||||
showToast(t('postprocessing.error.load') + ': ' + error.message, 'error');
|
||||
@@ -1503,7 +1566,7 @@ export async function savePPTemplate() {
|
||||
}
|
||||
|
||||
showToast(templateId ? t('postprocessing.updated') : t('postprocessing.created'), 'success');
|
||||
closePPTemplateModal();
|
||||
ppTemplateModal.forceClose();
|
||||
await loadPPTemplates();
|
||||
} catch (error) {
|
||||
console.error('Error saving PP template:', error);
|
||||
@@ -1571,10 +1634,8 @@ export async function deletePPTemplate(templateId) {
|
||||
}
|
||||
}
|
||||
|
||||
export function closePPTemplateModal() {
|
||||
ppTemplateModal.forceClose();
|
||||
set_modalFilters([]);
|
||||
set_ppTemplateNameManuallyEdited(false);
|
||||
export async function closePPTemplateModal() {
|
||||
await ppTemplateModal.close();
|
||||
}
|
||||
|
||||
// Exported helpers used by other modules
|
||||
|
||||
Reference in New Issue
Block a user