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:
@@ -5,14 +5,33 @@
|
||||
import {
|
||||
kcTestAutoRefresh, setKcTestAutoRefresh,
|
||||
kcTestTargetId, setKcTestTargetId,
|
||||
kcEditorInitialValues, setKcEditorInitialValues,
|
||||
_kcNameManuallyEdited, set_kcNameManuallyEdited,
|
||||
kcWebSockets,
|
||||
PATTERN_RECT_BORDERS,
|
||||
} from '../core/state.js';
|
||||
import { API_BASE, getHeaders, fetchWithAuth, escapeHtml, handle401Error } from '../core/api.js';
|
||||
import { t } from '../core/i18n.js';
|
||||
import { lockBody, unlockBody, showToast, showConfirm, setupBackdropClose } from '../core/ui.js';
|
||||
import { lockBody, showToast, showConfirm } from '../core/ui.js';
|
||||
import { Modal } from '../core/modal.js';
|
||||
|
||||
class KCEditorModal extends Modal {
|
||||
constructor() {
|
||||
super('kc-editor-modal');
|
||||
}
|
||||
|
||||
snapshotValues() {
|
||||
return {
|
||||
name: document.getElementById('kc-editor-name').value,
|
||||
source: document.getElementById('kc-editor-source').value,
|
||||
fps: document.getElementById('kc-editor-fps').value,
|
||||
interpolation: document.getElementById('kc-editor-interpolation').value,
|
||||
smoothing: document.getElementById('kc-editor-smoothing').value,
|
||||
patternTemplateId: document.getElementById('kc-editor-pattern-template').value,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const kcEditorModal = new KCEditorModal();
|
||||
|
||||
export function createKCTargetCard(target, sourceMap, patternTemplateMap) {
|
||||
const state = target.state || {};
|
||||
@@ -391,19 +410,8 @@ export async function showKCEditor(targetId = null) {
|
||||
patSelect.onchange = () => _autoGenerateKCName();
|
||||
if (!targetId) _autoGenerateKCName();
|
||||
|
||||
setKcEditorInitialValues({
|
||||
name: document.getElementById('kc-editor-name').value,
|
||||
source: sourceSelect.value,
|
||||
fps: document.getElementById('kc-editor-fps').value,
|
||||
interpolation: document.getElementById('kc-editor-interpolation').value,
|
||||
smoothing: document.getElementById('kc-editor-smoothing').value,
|
||||
patternTemplateId: patSelect.value,
|
||||
});
|
||||
|
||||
const modal = document.getElementById('kc-editor-modal');
|
||||
modal.style.display = 'flex';
|
||||
lockBody();
|
||||
setupBackdropClose(modal, closeKCEditorModal);
|
||||
kcEditorModal.snapshot();
|
||||
kcEditorModal.open();
|
||||
|
||||
document.getElementById('kc-editor-error').style.display = 'none';
|
||||
setTimeout(() => document.getElementById('kc-editor-name').focus(), 100);
|
||||
@@ -414,29 +422,15 @@ export async function showKCEditor(targetId = null) {
|
||||
}
|
||||
|
||||
export function isKCEditorDirty() {
|
||||
return (
|
||||
document.getElementById('kc-editor-name').value !== kcEditorInitialValues.name ||
|
||||
document.getElementById('kc-editor-source').value !== kcEditorInitialValues.source ||
|
||||
document.getElementById('kc-editor-fps').value !== kcEditorInitialValues.fps ||
|
||||
document.getElementById('kc-editor-interpolation').value !== kcEditorInitialValues.interpolation ||
|
||||
document.getElementById('kc-editor-smoothing').value !== kcEditorInitialValues.smoothing ||
|
||||
document.getElementById('kc-editor-pattern-template').value !== kcEditorInitialValues.patternTemplateId
|
||||
);
|
||||
return kcEditorModal.isDirty();
|
||||
}
|
||||
|
||||
export async function closeKCEditorModal() {
|
||||
if (isKCEditorDirty()) {
|
||||
const confirmed = await showConfirm(t('modal.discard_changes'));
|
||||
if (!confirmed) return;
|
||||
}
|
||||
forceCloseKCEditorModal();
|
||||
await kcEditorModal.close();
|
||||
}
|
||||
|
||||
export function forceCloseKCEditorModal() {
|
||||
document.getElementById('kc-editor-modal').style.display = 'none';
|
||||
document.getElementById('kc-editor-error').style.display = 'none';
|
||||
unlockBody();
|
||||
setKcEditorInitialValues({});
|
||||
kcEditorModal.forceClose();
|
||||
}
|
||||
|
||||
export async function saveKCEditor() {
|
||||
@@ -447,17 +441,14 @@ export async function saveKCEditor() {
|
||||
const interpolation = document.getElementById('kc-editor-interpolation').value;
|
||||
const smoothing = parseFloat(document.getElementById('kc-editor-smoothing').value);
|
||||
const patternTemplateId = document.getElementById('kc-editor-pattern-template').value;
|
||||
const errorEl = document.getElementById('kc-editor-error');
|
||||
|
||||
if (!name) {
|
||||
errorEl.textContent = t('kc.error.required');
|
||||
errorEl.style.display = 'block';
|
||||
kcEditorModal.showError(t('kc.error.required'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!patternTemplateId) {
|
||||
errorEl.textContent = t('kc.error.no_pattern');
|
||||
errorEl.style.display = 'block';
|
||||
kcEditorModal.showError(t('kc.error.no_pattern'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -497,13 +488,12 @@ export async function saveKCEditor() {
|
||||
}
|
||||
|
||||
showToast(targetId ? t('kc.updated') : t('kc.created'), 'success');
|
||||
forceCloseKCEditorModal();
|
||||
kcEditorModal.forceClose();
|
||||
// Use window.* to avoid circular import with targets.js
|
||||
if (typeof window.loadTargetsTab === 'function') window.loadTargetsTab();
|
||||
} catch (error) {
|
||||
console.error('Error saving KC target:', error);
|
||||
errorEl.textContent = error.message;
|
||||
errorEl.style.display = 'block';
|
||||
kcEditorModal.showError(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user