/* ============================================================================= * formula_doc_options.ts * 수식 문서 옵션 가로(PLAN 802-3 · 802-4b-2 · 요구 655 「옵션 선택은 상단에 수평」) — 선택 · 입력 기호마다 칸 하나 * 값 = 화면 값(`given`) › 문서 값 · 고침은 부른 쪽 `set`(M01 = 화면 값만 · M02 사본 = 문서 값) · `lock` = 읽기만 * 목록이 모두 기계 원문번호(`0101-0007`)면 글 = 「이름 규격 (원문번호)」(요구 692-2 · 값은 그대로 · 이름은 한 번 받아 둠) * `view` 있음 + 기계 목록 = 곁에 [조회](827-1 · 기계 창 읽기 전용 · 고른 기계) * ========================================================================== */ import { createButton } from "@ui/ui_template_button"; import { createInputField, createSelectField } from "@ui/ui_template_input"; import { varId, type DocVar, type FormulaDoc } from "../common_util/common_util_formula_doc"; import { varUnit } from "../common_util/common_util_line_stack_unit"; import { cfMachineNames, cfMachineOff } from "../M02_MasterTemplete/DataFlow/M02_DF_Api"; import { mt } from "../M02_MasterTemplete/M02_MyMachine_Text"; import { ft } from "./formula_doc_text"; const MACHINE = /^\d{4}-\d{4}$/; let names: Record = {}; let off = new Set(); // 842-2 끈 기계 원문번호 const machineInfo = (): Promise> => Promise.all([cfMachineNames(), cfMachineOff()]).then( ([got, gone]) => ((off = new Set(gone)), got), ); /** 고르기 글 — 기계 원문번호는 이름 · 규격을 앞에 · 끈 기계는 「· 비활성 기계」(842-2) */ export const optionText = (x: string, known: Record = names): string => known[x] ? `${known[x]} (${x})${off.has(x) ? ` · ${ft("Machine_Off")}` : ""}` : x; /** 고르기 목록 — 끈 기계 뺌(지금 고른 값은 남김 · 842-2) */ export const liveOptions = (list: string[], now: string): string[] => list.filter((x) => x === now || !off.has(x)); /** 목록이 모두 원문번호(빈 칸 빼고)면 이름을 받아 `redraw`(글만 다시) — 수식 탭 옵션 · 단가산출 상세 옵션 */ export function nameMachines(list: string[], redraw: () => void): void { const codes = list.filter(Boolean); if (codes.length && codes.every((x) => MACHINE.test(x)) && codes.some((x) => !(x in names))) void machineInfo().then((got) => { names = got; redraw(); }); } let asked = false; /** 글 값이 기계 원문번호면 「이름 규격 (원문번호)」(838-3 · 요구 859) — 이름이 아직 없으면 한 번 받아 `redraw` · 아니면 null */ export function machineText(x: unknown, redraw: () => void): string | null { if (typeof x !== "string" || !MACHINE.test(x)) return null; if (!(x in names) && !asked) { asked = true; void machineInfo().then((got) => { names = { ...names, ...got }; redraw(); }); } return optionText(x); } export function buildOptions( doc: FormulaDoc | null, given: Record, lock: boolean, set: (key: string, v: DocVar, value: unknown) => void, view?: (code: string) => void, ): HTMLElement[] { const out: HTMLElement[] = []; for (const v of doc?.변수 ?? []) { const kind = v.연결?.갈래; const k = v.열쇠; if (!k || (kind !== "선택" && kind !== "입력")) continue; const label = v.이름 || varId(v); const now = k in given ? given[k] : v.연결?.값; if (kind === "선택") { const list = (v.연결?.목록 ?? []).map(String); const items = () => liveOptions(list, String(now ?? "")).map((x) => ({ value: x, text: optionText(x) })); const f = createSelectField({ label, options: items(), value: String(now ?? ""), compact: true, size: 28, disabled: lock, onChange: (x) => set(k, v, x), }); f.root.dataset.option = k; nameMachines(list, () => f.setOptions(items(), f.select.value)); out.push(f.root); const codes = list.filter(Boolean); if (view && codes.length && codes.every((x) => MACHINE.test(x))) { const b = createButton({ label: mt("Win_View"), variant: "ghost", size: 28, iconStart: "search", onClick: () => view(f.select.value), }); b.dataset.optionView = k; out.push(b); } } else { const f = createInputField({ label, value: now === undefined || now === null ? "" : String(now), compact: true, size: 28, unit: varUnit(v) || undefined, // 845-2 단위 규칙 한 벌 }); f.input.disabled = lock; f.input.addEventListener("change", () => { const t = f.input.value.trim(); const n = Number(t.replace(/,/g, "")); set(k, v, t !== "" && Number.isFinite(n) ? n : t); }); f.root.dataset.option = k; out.push(f.root); } } return out; }