Extract Modal base class and fix target editor defaults
Add core/modal.js with reusable Modal class that handles open/close, body locking, backdrop close, dirty checking, error display, and a static stack for ESC key management. Migrate all 13 modals across 8 feature files to use the base class, eliminating ~200 lines of duplicated boilerplate. Replace manual ESC handler list in app.js with Modal.closeTopmost(), fixing 3 modals that were previously unreachable via ESC. Remove 5 unused initialValues variables from state.js. Fix target editor to auto-select first device/source and auto-generate name like the KC editor does. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,9 +21,19 @@ import {
|
||||
} from '../core/state.js';
|
||||
import { API_BASE, getHeaders, fetchWithAuth, escapeHtml, handle401Error } from '../core/api.js';
|
||||
import { t } from '../core/i18n.js';
|
||||
import { setupBackdropClose, lockBody, unlockBody, showToast, showConfirm, openLightbox, openFullImageLightbox, showOverlaySpinner, hideOverlaySpinner } from '../core/ui.js';
|
||||
import { Modal } from '../core/modal.js';
|
||||
import { showToast, showConfirm, openLightbox, openFullImageLightbox, showOverlaySpinner, hideOverlaySpinner } from '../core/ui.js';
|
||||
import { openDisplayPicker, formatDisplayLabel } from './displays.js';
|
||||
|
||||
// ===== Modal instances =====
|
||||
|
||||
const templateModal = new Modal('template-modal');
|
||||
const testTemplateModal = new Modal('test-template-modal');
|
||||
const streamModal = new Modal('stream-modal');
|
||||
const testStreamModal = new Modal('test-stream-modal');
|
||||
const ppTemplateModal = new Modal('pp-template-modal');
|
||||
const testPPTemplateModal = new Modal('test-pp-template-modal');
|
||||
|
||||
// ===== Capture Templates =====
|
||||
|
||||
async function loadCaptureTemplates() {
|
||||
@@ -55,9 +65,7 @@ export async function showAddTemplateModal() {
|
||||
|
||||
await loadAvailableEngines();
|
||||
|
||||
const modal = document.getElementById('template-modal');
|
||||
modal.style.display = 'flex';
|
||||
setupBackdropClose(modal, closeTemplateModal);
|
||||
templateModal.open();
|
||||
}
|
||||
|
||||
export async function editTemplate(templateId) {
|
||||
@@ -83,9 +91,7 @@ export async function editTemplate(templateId) {
|
||||
if (testResults) testResults.style.display = 'none';
|
||||
document.getElementById('template-error').style.display = 'none';
|
||||
|
||||
const modal = document.getElementById('template-modal');
|
||||
modal.style.display = 'flex';
|
||||
setupBackdropClose(modal, closeTemplateModal);
|
||||
templateModal.open();
|
||||
} catch (error) {
|
||||
console.error('Error loading template:', error);
|
||||
showToast(t('templates.error.load') + ': ' + error.message, 'error');
|
||||
@@ -93,7 +99,7 @@ export async function editTemplate(templateId) {
|
||||
}
|
||||
|
||||
export function closeTemplateModal() {
|
||||
document.getElementById('template-modal').style.display = 'none';
|
||||
templateModal.forceClose();
|
||||
setCurrentEditingTemplateId(null);
|
||||
}
|
||||
|
||||
@@ -125,13 +131,11 @@ export async function showTestTemplateModal(templateId) {
|
||||
await loadDisplaysForTest();
|
||||
restoreCaptureDuration();
|
||||
|
||||
const modal = document.getElementById('test-template-modal');
|
||||
modal.style.display = 'flex';
|
||||
setupBackdropClose(modal, closeTestTemplateModal);
|
||||
testTemplateModal.open();
|
||||
}
|
||||
|
||||
export function closeTestTemplateModal() {
|
||||
document.getElementById('test-template-modal').style.display = 'none';
|
||||
testTemplateModal.forceClose();
|
||||
window.currentTestingTemplate = null;
|
||||
}
|
||||
|
||||
@@ -707,10 +711,7 @@ export async function showAddStreamModal(presetType) {
|
||||
|
||||
await populateStreamModalDropdowns();
|
||||
|
||||
const modal = document.getElementById('stream-modal');
|
||||
modal.style.display = 'flex';
|
||||
lockBody();
|
||||
setupBackdropClose(modal, closeStreamModal);
|
||||
streamModal.open();
|
||||
}
|
||||
|
||||
export async function editStream(streamId) {
|
||||
@@ -754,10 +755,7 @@ export async function editStream(streamId) {
|
||||
if (stream.image_source) validateStaticImage();
|
||||
}
|
||||
|
||||
const modal = document.getElementById('stream-modal');
|
||||
modal.style.display = 'flex';
|
||||
lockBody();
|
||||
setupBackdropClose(modal, closeStreamModal);
|
||||
streamModal.open();
|
||||
} catch (error) {
|
||||
console.error('Error loading stream:', error);
|
||||
showToast(t('streams.error.load') + ': ' + error.message, 'error');
|
||||
@@ -896,9 +894,8 @@ export async function deleteStream(streamId) {
|
||||
}
|
||||
|
||||
export function closeStreamModal() {
|
||||
document.getElementById('stream-modal').style.display = 'none';
|
||||
streamModal.forceClose();
|
||||
document.getElementById('stream-type').disabled = false;
|
||||
unlockBody();
|
||||
}
|
||||
|
||||
async function validateStaticImage() {
|
||||
@@ -956,15 +953,11 @@ export async function showTestStreamModal(streamId) {
|
||||
set_currentTestStreamId(streamId);
|
||||
restoreStreamTestDuration();
|
||||
|
||||
const modal = document.getElementById('test-stream-modal');
|
||||
modal.style.display = 'flex';
|
||||
lockBody();
|
||||
setupBackdropClose(modal, closeTestStreamModal);
|
||||
testStreamModal.open();
|
||||
}
|
||||
|
||||
export function closeTestStreamModal() {
|
||||
document.getElementById('test-stream-modal').style.display = 'none';
|
||||
unlockBody();
|
||||
testStreamModal.forceClose();
|
||||
set_currentTestStreamId(null);
|
||||
}
|
||||
|
||||
@@ -1032,15 +1025,11 @@ export async function showTestPPTemplateModal(templateId) {
|
||||
select.value = lastStream;
|
||||
}
|
||||
|
||||
const modal = document.getElementById('test-pp-template-modal');
|
||||
modal.style.display = 'flex';
|
||||
lockBody();
|
||||
setupBackdropClose(modal, closeTestPPTemplateModal);
|
||||
testPPTemplateModal.open();
|
||||
}
|
||||
|
||||
export function closeTestPPTemplateModal() {
|
||||
document.getElementById('test-pp-template-modal').style.display = 'none';
|
||||
unlockBody();
|
||||
testPPTemplateModal.forceClose();
|
||||
set_currentTestPPTemplateId(null);
|
||||
}
|
||||
|
||||
@@ -1296,10 +1285,7 @@ export async function showAddPPTemplateModal() {
|
||||
_populateFilterSelect();
|
||||
renderModalFilterList();
|
||||
|
||||
const modal = document.getElementById('pp-template-modal');
|
||||
modal.style.display = 'flex';
|
||||
lockBody();
|
||||
setupBackdropClose(modal, closePPTemplateModal);
|
||||
ppTemplateModal.open();
|
||||
}
|
||||
|
||||
export async function editPPTemplate(templateId) {
|
||||
@@ -1324,10 +1310,7 @@ export async function editPPTemplate(templateId) {
|
||||
_populateFilterSelect();
|
||||
renderModalFilterList();
|
||||
|
||||
const modal = document.getElementById('pp-template-modal');
|
||||
modal.style.display = 'flex';
|
||||
lockBody();
|
||||
setupBackdropClose(modal, closePPTemplateModal);
|
||||
ppTemplateModal.open();
|
||||
} catch (error) {
|
||||
console.error('Error loading PP template:', error);
|
||||
showToast(t('postprocessing.error.load') + ': ' + error.message, 'error');
|
||||
@@ -1386,9 +1369,8 @@ export async function deletePPTemplate(templateId) {
|
||||
}
|
||||
|
||||
export function closePPTemplateModal() {
|
||||
document.getElementById('pp-template-modal').style.display = 'none';
|
||||
ppTemplateModal.forceClose();
|
||||
set_modalFilters([]);
|
||||
unlockBody();
|
||||
}
|
||||
|
||||
// Exported helpers used by other modules
|
||||
|
||||
Reference in New Issue
Block a user