fix(M02): 재검증 흠 넷 — 같은 이름 토스트 · 쓸 수 없는 글자 막기(화면·서버 400) · 저장 안 한 고침 버리기 확인 · 덮어쓰기 확인과 개인·회사 지우기 단추
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0148XFUpPfpiuTjxF1EK9c95
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
* 부품 파일이 없거나 못 읽어도 페이지는 뜸 — 빈 자리 글.
|
||||
* ========================================================================== */
|
||||
|
||||
import { createButton, el, showToast } from "@ui/ui_template_elements";
|
||||
import { createButton, el, showConfirmDialog, showToast } from "@ui/ui_template_elements";
|
||||
import { t as L } from "@ui/ui_template_locale";
|
||||
import {
|
||||
readFilled,
|
||||
@@ -48,6 +48,8 @@ export interface MainHandle {
|
||||
root: HTMLElement;
|
||||
open: (sel: Selection | null) => Promise<void>;
|
||||
current: () => Selection | null;
|
||||
/** 저장 안 한 고침이 있으면 버릴지 물음 — 취소면 false */
|
||||
confirmLeave: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
/** 이 층에서 고칠 수 있나 — 시스템은 관리자만 · 회사는 여기서 못 고침(공식으로 저장으로만) */
|
||||
@@ -75,6 +77,21 @@ export function createMain(isAdmin: boolean, onSaved?: () => void): MainHandle {
|
||||
let loaded: unknown = null;
|
||||
let editor: EditorHandle | null = null;
|
||||
let seq = 0;
|
||||
let dirty = false;
|
||||
|
||||
const guard = (event: BeforeUnloadEvent): void => {
|
||||
if (!root.isConnected) return window.removeEventListener("beforeunload", guard);
|
||||
if (!dirty) return;
|
||||
event.preventDefault();
|
||||
event.returnValue = "";
|
||||
};
|
||||
window.addEventListener("beforeunload", guard);
|
||||
const confirmLeave = async (): Promise<boolean> => {
|
||||
if (!dirty) return true;
|
||||
if (!(await showConfirmDialog(L("M02_DiscardConfirm")))) return false;
|
||||
dirty = false;
|
||||
return true;
|
||||
};
|
||||
|
||||
const showNotice = (nodes: (HTMLElement | string)[]): void => {
|
||||
notice.replaceChildren(...nodes);
|
||||
@@ -102,7 +119,10 @@ export function createMain(isAdmin: boolean, onSaved?: () => void): MainHandle {
|
||||
"createSheet",
|
||||
);
|
||||
if (create) {
|
||||
editor = create(host, doc, { mode: at.layer === "project" ? "project" : "master" });
|
||||
editor = create(host, doc, {
|
||||
mode: at.layer === "project" ? "project" : "master",
|
||||
onChange: () => (dirty = !readOnly),
|
||||
});
|
||||
return;
|
||||
}
|
||||
return empty(L("M02_NoSheet"));
|
||||
@@ -118,6 +138,7 @@ export function createMain(isAdmin: boolean, onSaved?: () => void): MainHandle {
|
||||
name: at.name,
|
||||
layer: at.layer,
|
||||
projectId: at.projectId,
|
||||
onChanged: (d: boolean) => (dirty = d && !readOnly),
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -126,6 +147,7 @@ export function createMain(isAdmin: boolean, onSaved?: () => void): MainHandle {
|
||||
|
||||
async function open(next: Selection | null): Promise<void> {
|
||||
const mine = ++seq;
|
||||
dirty = false;
|
||||
drop();
|
||||
showNotice([]);
|
||||
sel = next;
|
||||
@@ -166,6 +188,7 @@ export function createMain(isAdmin: boolean, onSaved?: () => void): MainHandle {
|
||||
const info = await saveTemplate(at.layer, at.kind, at.name, at.projectId, version, doc);
|
||||
version = info.판;
|
||||
loaded = doc;
|
||||
dirty = false;
|
||||
showNotice([]);
|
||||
showToast(L("M02_Saved"), "success");
|
||||
onSaved?.(); // 좌측 목록의 판을 새 판으로
|
||||
@@ -182,8 +205,10 @@ export function createMain(isAdmin: boolean, onSaved?: () => void): MainHandle {
|
||||
}
|
||||
|
||||
save.addEventListener("click", () => void doSave());
|
||||
reload.addEventListener("click", () => sel && void open(sel));
|
||||
reload.addEventListener("click", async () => {
|
||||
if (sel && (await confirmLeave())) void open(sel);
|
||||
});
|
||||
bar();
|
||||
empty("");
|
||||
return { root, open, current: () => sel };
|
||||
return { root, open, current: () => sel, confirmLeave };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user