- 280-1 이름 칸 = 고르기(누름 · Enter · Space · 손 커서 · 풍선 · 초점 테두리) · [선택] 단추 지움 · [해제] 그대로 · 본체 · 그룹 · 명세 잇기 같은 줄 부품 - 280-2 모달 제목 「구조물 조합 선택」 · 위 표 열 고름 → 나무 펼쳐 고름 · 카드 · 층 단추 → 위 표 = 그 층 표 · B08 연결 같은 모달 - 280-3 M02 구조물 조합 = 따로 짠 길로 두 고리 정상 · 고침 없음 - 시험 test_280_1_combo_label_pick 새로 · test_224_1 · test_b05_structures_form_summary 새 꼴에 맞춤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VmC34fsxxbweEG3RUjs3Mn
100 lines
3.6 KiB
TypeScript
100 lines
3.6 KiB
TypeScript
/* =============================================================================
|
|
* ui_template_item_picker_table.ts
|
|
* 항목 고르기 모달 상단 표(PLAN 224-1) — M02 「구조물 조합」 페이지 상단의 구조물집계표를 **같은 부품**
|
|
* (`ui_template/sheet` `createSheet` · 줄 글 = `numberLabels` · 숨김 열 = `comboView`)으로 보임.
|
|
* 보기 전용(`readOnly` · 고침은 M02 에서) · 보이는 층(+ 주인)의 표 · 고른 항목의 열이 밝게 골라짐(280-2).
|
|
* 같은 층이면 표는 그대로 두고 열만 옮김 · 층이 바뀌면 그 층 표로 바뀜 · 표에서 열을 고르면 `onColumn`.
|
|
* 표 부품 · 집계표 모듈은 처음 보일 때만 `import()`(B05 · B06 번들에 안 섞임).
|
|
* ========================================================================== */
|
|
|
|
import { el } from "./ui_template_elements";
|
|
import {
|
|
fetchStructureNumbersAt,
|
|
readTemplate,
|
|
} from "../M02_MasterTemplete/M02_MasterTemplete_Api_Fetch";
|
|
import type { PickerLayer } from "./ui_template_item_picker_data";
|
|
import { t } from "./ui_template_locale";
|
|
import type { SheetDoc, SheetHandle } from "./sheet/ui_template_sheet";
|
|
|
|
export interface ComboTable {
|
|
root: HTMLElement;
|
|
/** 보일 층(+ 주인) · 고를 열(빈 글 = 안 고름) — `null` 이면 표를 숨김 */
|
|
show: (at: { layer: PickerLayer; owner: string | null } | null, column: string) => void;
|
|
destroy: () => void;
|
|
}
|
|
|
|
const failed = (error: unknown): string =>
|
|
t("M02_PickerTableFailed").replace(
|
|
"{value}",
|
|
error instanceof Error ? error.message : String(error),
|
|
);
|
|
|
|
/** `onColumn` = 표에서 고른 열 id(누르기 · 방향키) */
|
|
export function createComboTable(onColumn: (colId: string) => void): ComboTable {
|
|
const root = el("div", { className: "ui-item-picker__table", attrs: { hidden: "" } });
|
|
let seq = 0;
|
|
let shownKey: string | null = null;
|
|
let sheet: SheetHandle | null = null;
|
|
/** 가장 나중에 고른 열 — 표를 읽는 사이에 바뀌면 읽은 뒤 이 열을 고름 */
|
|
let column = "";
|
|
|
|
const drop = (): void => {
|
|
sheet?.destroy();
|
|
sheet = null;
|
|
shownKey = null;
|
|
};
|
|
|
|
async function paint(
|
|
layer: PickerLayer,
|
|
owner: string | null,
|
|
key: string,
|
|
mine: number,
|
|
): Promise<void> {
|
|
drop();
|
|
root.replaceChildren(
|
|
el("p", { className: "ui-item-picker__hint", text: t("M02_PickerLoading") }),
|
|
);
|
|
try {
|
|
const [{ createSheet }, struct] = await Promise.all([
|
|
import("./sheet/ui_template_sheet"),
|
|
import("../M02_MasterTemplete/M02_MasterTemplete_Structure"),
|
|
]);
|
|
const [got, numbers] = await Promise.all([
|
|
readTemplate(layer, "table", struct.STRUCTURE_TABLE, null, owner),
|
|
fetchStructureNumbersAt(layer, owner).catch(() => ({})),
|
|
]);
|
|
if (mine !== seq) return;
|
|
sheet = createSheet(root, struct.comboView(got.문서) as SheetDoc, {
|
|
mode: "master",
|
|
readOnly: true,
|
|
lockHead: true,
|
|
combo: {},
|
|
onSelect: (sel) => sel.colId && onColumn(sel.colId),
|
|
...struct.numberLabels(() => numbers),
|
|
});
|
|
shownKey = key;
|
|
sheet.selectColumn(column);
|
|
} catch (error) {
|
|
if (mine === seq)
|
|
root.replaceChildren(el("p", { className: "ui-item-picker__hint", text: failed(error) }));
|
|
}
|
|
}
|
|
|
|
return {
|
|
root,
|
|
show: (at, col) => {
|
|
const mine = ++seq;
|
|
root.hidden = !at;
|
|
if (!at) return;
|
|
column = col;
|
|
const key = `${at.layer}|${at.owner ?? ""}`;
|
|
if (sheet && key === shownKey) return sheet.selectColumn(column);
|
|
void paint(at.layer, at.owner, key, mine);
|
|
},
|
|
destroy: () => {
|
|
seq += 1;
|
|
drop();
|
|
},
|
|
};
|
|
}
|