Merge remote-tracking branch 'origin/sub_laptop_5' into main_laptop_1
This commit is contained in:
@@ -66,6 +66,7 @@ const TEXT = {
|
||||
saveLabel: "저장하고 보내기",
|
||||
failed: "표를 못 만듦 — {value}",
|
||||
noRange: "보낼 범위를 시트에서 먼저 고름",
|
||||
empty: "보낼 칸에 내용이 없음",
|
||||
place: "도면에서 표를 놓을 자리를 누름(Esc = 그만)",
|
||||
noPlace: "이 도면 화면은 표 놓기를 아직 못 함",
|
||||
stale: "면적산출 값이 바뀐 표 {n}개",
|
||||
@@ -129,6 +130,10 @@ export interface AreaToDrawing {
|
||||
onArea: (at: Selection, readOnly: boolean, slot: HTMLElement) => void;
|
||||
/** 도면 상세가 섰음 — 넘겨받은 표 놓기 · 연결표 다름 알림 */
|
||||
onDrawing: (handle: unknown, at: Selection, doc: StructureDoc) => void;
|
||||
/** 보낸 표 놓기 기다리는 중 — 편집 칸 「저장 안 한 고침」 에 듦 */
|
||||
waiting: () => boolean;
|
||||
/** 떠나기로 함(물음 [확인]) — 기다리던 표 버림 */
|
||||
drop: () => void;
|
||||
/** 도면 저장 문서 — 맨 위 `연결표` 를 도면의 표에 맞춤 */
|
||||
withLinks: (doc: StructureDoc) => StructureDoc;
|
||||
}
|
||||
@@ -141,6 +146,8 @@ export function createAreaToDrawing(opt: AreaToDrawingOptions): AreaToDrawing {
|
||||
let fresh = new Map<string, TableLink>();
|
||||
let latest = new Map<string, Record<string, string>>();
|
||||
let shown: string | null = null;
|
||||
/** 보낸 표가 도면에 놓이길 기다림 — 떠날 때 「저장 안 한 고침」 물음(`waiting`) */
|
||||
let waiting = false;
|
||||
|
||||
/** 글자 크기 작은 창 — 보내기면 크기 · 닫으면 null */
|
||||
const askSize = (spec: { 범위: string }): Promise<number | null> =>
|
||||
@@ -183,15 +190,20 @@ export function createAreaToDrawing(opt: AreaToDrawingOptions): AreaToDrawing {
|
||||
if (opt.isDirty()) return; // 저장 실패 — 알림은 저장 길이 띄움
|
||||
}
|
||||
const picked = range;
|
||||
const get = (size: number): Promise<AreaTable | null> =>
|
||||
fetchTable(at.layer, at.name, { 시트: picked.시트, 범위: picked.범위, 글자크기: size }).catch(
|
||||
(error: unknown) => (showToast(fill(TEXT.failed, "value", why(error)), "error"), null),
|
||||
);
|
||||
// 보이는 글이 하나도 없는 범위(빈 칸만)는 크기를 묻기 전에 막음
|
||||
let got = await get(SIZE);
|
||||
if (!got) return;
|
||||
if (!Object.values(got.값 ?? {}).some((v) => String(v ?? "").trim())) {
|
||||
return showToast(TEXT.empty, "error");
|
||||
}
|
||||
const size = await askSize(picked);
|
||||
if (size === null) return;
|
||||
const spec: LinkSpec = { 시트: picked.시트, 범위: picked.범위, 글자크기: size };
|
||||
let got: AreaTable;
|
||||
try {
|
||||
got = await fetchTable(at.layer, at.name, spec);
|
||||
} catch (error) {
|
||||
return showToast(fill(TEXT.failed, "value", why(error)), "error");
|
||||
}
|
||||
if (size !== SIZE) got = await get(size);
|
||||
if (!got) return;
|
||||
pending = { layer: at.layer, column: at.name, got, 글자크기: size };
|
||||
await opt.open({
|
||||
layer: at.layer,
|
||||
@@ -247,7 +259,10 @@ export function createAreaToDrawing(opt: AreaToDrawingOptions): AreaToDrawing {
|
||||
|
||||
return {
|
||||
select: (s) => (range = { 시트: s.시트, 범위: s.범위 }),
|
||||
waiting: () => waiting,
|
||||
drop: () => (waiting = false),
|
||||
onArea: (at, readOnly, slot) => {
|
||||
waiting = false;
|
||||
// 범위는 그대로 — 시트가 처음 고름(A1)을 이 갈고리보다 먼저 알림
|
||||
if (readOnly || at.layer === "project") return;
|
||||
const button = createButton({ label: TEXT.send, variant: "ghost", size: "sm" });
|
||||
@@ -257,6 +272,7 @@ export function createAreaToDrawing(opt: AreaToDrawingOptions): AreaToDrawing {
|
||||
slot.append(button);
|
||||
},
|
||||
onDrawing: (raw, at, doc) => {
|
||||
waiting = false;
|
||||
const handle = raw as TableHandle;
|
||||
shown = `${at.layer}:${at.name}`;
|
||||
range = null; // 면적 상세를 떠남
|
||||
@@ -273,12 +289,14 @@ export function createAreaToDrawing(opt: AreaToDrawingOptions): AreaToDrawing {
|
||||
const style = { ...(표.shapeData.style ?? {}), [LINK]: id };
|
||||
fresh.set(id, { 연결: id, 시트, 범위, 글자크기: give.글자크기, 값 });
|
||||
handle.placeTable({ ...표, shapeData: { ...표.shapeData, style } }, id);
|
||||
waiting = true; // 놓기 전 떠나도 물음(놓으면 도면 고침 · [저장] 때 풂)
|
||||
showToast(TEXT.place, "info");
|
||||
}
|
||||
}
|
||||
void checkStale(handle, at, doc);
|
||||
},
|
||||
withLinks: (doc) => {
|
||||
waiting = false;
|
||||
const old = new Map((doc.연결표 ?? []).map((row) => [row.연결, row]));
|
||||
const rows: TableLink[] = [];
|
||||
for (const e of doc.도면?.entities ?? []) {
|
||||
|
||||
@@ -185,7 +185,7 @@ export function createMain(
|
||||
let seq = 0;
|
||||
let dirty = false;
|
||||
/** 저장 안 한 고침 — 이 화면 + 카드(도면 31-4 · 면적산출 31-3) */
|
||||
const busy = (): boolean => dirty || !!panel?.dirty();
|
||||
const busy = (): boolean => dirty || !!panel?.dirty() || toDrawing.waiting(); // + 놓기 기다리는 표(41)
|
||||
|
||||
const guard = (event: BeforeUnloadEvent): void => {
|
||||
if (!root.isConnected) return window.removeEventListener("beforeunload", guard);
|
||||
@@ -204,6 +204,7 @@ export function createMain(
|
||||
return false;
|
||||
}
|
||||
dirty = false;
|
||||
toDrawing.drop();
|
||||
return true;
|
||||
};
|
||||
setLeaveGuard(confirmLeave); // 머리 메뉴 · 뒤로 가기로 떠날 때도 물음
|
||||
|
||||
@@ -94,6 +94,9 @@ globalThis.fetch = async (url, init) => {
|
||||
const old = { 연결: "T1", 시트: "s1", 범위: "A1:A1", 글자크기: 3, 값: { "s1!A1": "옛" } };
|
||||
const drawing = (ents, links) => ({ 양식: "구조물도면", 종류: "structure", 판: 1, 열: "item1", 도번: "SD-1", 도면: { entities: ents }, ...(links ? { 연결표: links } : {}) });
|
||||
ad.onDrawing(handle, { ...area, kind: "structure" }, drawing([table([["옛"]], { 연결: "T1" })], [old]));
|
||||
const waitPlaced = ad.waiting(); // 놓기 기다림 = 저장 안 한 고침
|
||||
ad.drop();
|
||||
const waitDropped = ad.waiting();
|
||||
await new Promise((r) => setTimeout(r, 20));
|
||||
const notice = notices.at(-1) ?? [];
|
||||
const upd = notice.find((x) => x && x.on);
|
||||
@@ -109,7 +112,14 @@ globalThis.fetch = async (url, init) => {
|
||||
await slot.kids[0].on.click();
|
||||
await new Promise((r) => setTimeout(r, 20));
|
||||
ad.onDrawing(handle, { ...area, kind: "structure", name: "item2" }, drawing([]));
|
||||
console.log(JSON.stringify({ ro, buttons: slot.kids.length, sent, placed, notice: notice.map((x) => (typeof x === "string" ? x : x.label)), saved: saved.연결표, plain: "연결표" in plain, other: placed.length - before }));
|
||||
// 빈 칸만 고른 범위 — 크기를 묻기 전에 막고 알림 · 도면 안 엶
|
||||
now = [["", " "]];
|
||||
const openedBefore = opened.length;
|
||||
ad.select({ 시트: "산출", 칸: "E1", 범위: "E1:F1" });
|
||||
await slot.kids[0].on.click();
|
||||
await new Promise((r) => setTimeout(r, 20));
|
||||
const empty = { opened: opened.length - openedBefore, toast: toasts.at(-1) };
|
||||
console.log(JSON.stringify({ ro, buttons: slot.kids.length, sent, placed, notice: notice.map((x) => (typeof x === "string" ? x : x.label)), saved: saved.연결표, plain: "연결표" in plain, other: placed.length - before, waitPlaced, waitDropped, waitSaved: ad.waiting(), empty }));
|
||||
})();
|
||||
"""
|
||||
|
||||
@@ -163,4 +173,14 @@ def test_다른_열_도면에는_안_놓음(got):
|
||||
|
||||
def test_편집_칸은_갈고리만():
|
||||
main = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_UI_Main.ts").read_text("utf-8")
|
||||
assert main.count("toDrawing.") == 4 # select · onArea · onDrawing · withLinks
|
||||
# select · onArea · onDrawing · withLinks · waiting(저장 안 한 고침) · drop(떠나기 확인)
|
||||
assert main.count("toDrawing.") == 6
|
||||
assert "|| toDrawing.waiting()" in main.split("const busy = ")[1].splitlines()[0]
|
||||
|
||||
|
||||
def test_놓기_기다림은_저장_안_한_고침(got):
|
||||
assert got["waitPlaced"] is True and got["waitDropped"] is False and got["waitSaved"] is False
|
||||
|
||||
|
||||
def test_빈_범위는_막고_알림(got):
|
||||
assert got["empty"] == {"opened": 0, "toast": ["error", "보낼 칸에 내용이 없음"]}
|
||||
|
||||
Reference in New Issue
Block a user