144 lines
4.6 KiB
TypeScript
144 lines
4.6 KiB
TypeScript
import { createIcons, X } from 'lucide';
|
|
import { setEditLock } from './ModalUtils';
|
|
import './modal.css';
|
|
|
|
/**
|
|
* 모든 모달의 공통 기능을 관리하는 베이스 추상 클래스입니다.
|
|
*/
|
|
export abstract class BaseModal {
|
|
protected idPrefix: string;
|
|
protected title: string;
|
|
protected currentAsset: any | null = null;
|
|
protected isEditMode: boolean = false;
|
|
protected currentMode: 'view' | 'edit' | 'add' = 'view';
|
|
protected modalEl: HTMLElement | null = null;
|
|
protected formEl: HTMLFormElement | null = null;
|
|
|
|
constructor(idPrefix: string, title: string) {
|
|
this.idPrefix = idPrefix;
|
|
this.title = title;
|
|
}
|
|
|
|
/**
|
|
* 모달 초기화: HTML 삽입 및 공통 이벤트 바인딩
|
|
*/
|
|
public init(onSave: () => void, closeModalsFn: () => void) {
|
|
// 1. 프레임 HTML 삽입 (자식 클래스에서 정의한 HTML 사용)
|
|
if (!document.getElementById(`${this.idPrefix}-asset-modal`)) {
|
|
document.body.insertAdjacentHTML('beforeend', this.renderFrameHTML());
|
|
}
|
|
|
|
this.modalEl = document.getElementById(`${this.idPrefix}-asset-modal`);
|
|
this.formEl = document.getElementById(`${this.idPrefix}-asset-form`) as HTMLFormElement;
|
|
|
|
// 2. 공통 버튼 이벤트 바인딩 (닫기, 취소 등)
|
|
const btnCloseHeader = document.getElementById(`btn-close-${this.idPrefix}-modal`);
|
|
const btnCancelFooter = document.getElementById(`btn-cancel-${this.idPrefix}-modal`);
|
|
|
|
const closeAction = () => {
|
|
this.close();
|
|
closeModalsFn(); // 전역 모달 상태 해제 콜백
|
|
};
|
|
|
|
btnCloseHeader?.addEventListener('click', closeAction);
|
|
btnCancelFooter?.addEventListener('click', closeAction);
|
|
|
|
// 3. 자식 클래스 전용 초기화 로직 실행
|
|
this.initChildLogic(onSave, closeModalsFn);
|
|
|
|
// 4. 아이콘 초기화
|
|
createIcons({ icons: { X } });
|
|
}
|
|
|
|
/**
|
|
* 모달 열기: 데이터 바인딩 및 모드 설정
|
|
*/
|
|
public open(asset: any, mode: 'view' | 'edit' | 'add' = 'view') {
|
|
this.currentAsset = asset;
|
|
this.currentMode = mode;
|
|
this.isEditMode = (mode === 'add' || mode === 'edit');
|
|
|
|
// 폼 초기화 추가
|
|
if (this.formEl) this.formEl.reset();
|
|
|
|
// fillFormData를 먼저 호출하여 동적 요소들을 생성한 후 잠금 처리
|
|
this.fillFormData(asset);
|
|
this.setEditLockMode(mode);
|
|
|
|
if (this.modalEl) {
|
|
this.modalEl.classList.remove('hidden');
|
|
const content = this.modalEl.querySelector('.modal-content');
|
|
if (content) {
|
|
if (mode === 'view') content.classList.add('is-view-mode');
|
|
else content.classList.remove('is-view-mode');
|
|
}
|
|
}
|
|
|
|
this.onAfterOpen(asset, mode);
|
|
}
|
|
|
|
/**
|
|
* 모달 닫기: 상태 초기화
|
|
*/
|
|
public close() {
|
|
if (this.modalEl) {
|
|
this.modalEl.classList.add('hidden');
|
|
}
|
|
this.isEditMode = false;
|
|
this.currentAsset = null;
|
|
this.onAfterClose();
|
|
}
|
|
|
|
/**
|
|
* 조회/수정 모드에 따른 UI 잠금 및 버튼 제어
|
|
*/
|
|
protected setEditLockMode(mode: 'view' | 'edit' | 'add') {
|
|
setEditLock(`${this.idPrefix}-asset-form`, mode, {
|
|
saveBtnId: `btn-save-${this.idPrefix}-asset`,
|
|
revertBtnId: `btn-revert-${this.idPrefix}-edit`,
|
|
addLogBtnId: `btn-add-${this.idPrefix}-log`
|
|
});
|
|
}
|
|
|
|
// --- 추상 메서드: 자식 클래스에서 구현해야 함 ---
|
|
protected abstract renderFrameHTML(): string;
|
|
protected abstract initChildLogic(onSave: () => void, closeModals: () => void): void;
|
|
protected abstract fillFormData(asset: any): void;
|
|
protected abstract onAfterOpen(asset: any, mode: string): void;
|
|
|
|
// --- 훅(Hook) 메서드: 필요 시 오버라이드 ---
|
|
protected onAfterClose(): void {}
|
|
}
|
|
|
|
/**
|
|
* --- 레거시 호환성을 위한 함수형 익스포트 ---
|
|
* 기존 코드들이 참조하고 있는 함수들을 유지합니다.
|
|
*/
|
|
export function closeModals() {
|
|
const modals = document.querySelectorAll('.modal-overlay');
|
|
modals.forEach(modal => modal.classList.add('hidden'));
|
|
}
|
|
|
|
export function initBaseModal() {
|
|
// ESC 키로 모든 모달 닫기 (위치보기 팝업이 있으면 그것부터 닫음)
|
|
window.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') {
|
|
const picker = document.querySelector('.image-picker-overlay');
|
|
if (picker) {
|
|
picker.remove();
|
|
} else {
|
|
closeModals();
|
|
}
|
|
}
|
|
});
|
|
|
|
return { closeAllModals: closeModals };
|
|
}
|
|
|
|
export function openModal(modalId: string) {
|
|
const modal = document.getElementById(modalId);
|
|
if (modal) {
|
|
modal.classList.remove('hidden');
|
|
}
|
|
}
|