/* ============================================================================= * M01_MasterData_UI_LogicLab_Formula.ts * 「텍스트 수식」 컨테이너 — 서버(`POST /text`)가 준 줄을 그대로 찍음(화면에서 다시 계산하지 않음) * 두 칸 — 왼쪽 = 변수 이름 식(`이름글`) · 오른쪽 = 값이 들어간 식(`글`) · 줄은 `짝` 번호로 같은 높이 * 한쪽에 올리거나 누르면 같은 줄이 밝아짐 · 비목 제목 · 소계 · 끝수 한 마디 · 까닭 있는 줄은 옅게 * ========================================================================== */ import { el } from "@ui/ui_template_elements"; import type { TextAnswer } from "./M01_MasterData_UI_Logic_Api"; import { formatNumber } from "./M01_MasterData_UI_Logic_Edit"; import { tx } from "./M01_MasterData_UI_Logic_Text"; import { tl } from "./M01_MasterData_UI_LogicLab_Text"; import "./M01_MasterData_UI_LogicLab_Formula.css"; export interface FormulaContext { text: TextAnswer | null; } const muted = (text: string): HTMLElement => el("p", { className: "m01-logic__muted", text }); export function buildFormula(host: HTMLElement, ctx: FormulaContext): void { const text = ctx.text; if (!text) { host.replaceChildren(muted(tl("Formula_Slot"))); return; } if (!text.ok) { host.replaceChildren( el("div", { className: "m01-logic__reasons", children: [el("strong", { text: tx("Calc_Stopped") }), el("div", { text: text.reason })], }), ); return; } const heads = el("div", { className: "m01lab-fx__head", children: [ el("strong", { text: tl("Formula_Left") }), el("strong", { text: tl("Formula_Right") }), ], }); const rows: HTMLElement[] = []; const light = (pair: string, on: boolean): void => rows.forEach((r) => r.dataset.pair === pair && r.classList.toggle("is-on", on)); const blocks = text.groups.flatMap((g) => [ el("h4", { className: "m01lab__group m01lab-fx__wide", text: g.비목 }), ...g.줄.map((line, i) => { const pair = String(line.짝 ?? `${g.비목}${i}`); const row = el("div", { className: `m01lab-fx__row m01lab__text${line.까닭 ? " m01lab__text--off" : ""}`, attrs: { "data-text-line": line.이름, "data-pair": pair }, children: [ el("div", { className: "m01lab-fx__cell", text: line.이름글 ?? line.이름 }), el("div", { className: "m01lab-fx__cell", children: [ el("div", { text: `${line.이름} : ${line.글}` }), ...(line.까닭 ? [el("div", { className: "m01-logic__muted", text: line.까닭 })] : []), ], }), ], }); row.addEventListener("mouseenter", () => light(pair, true)); row.addEventListener("mouseleave", () => light(pair, false)); row.addEventListener("click", () => { const pinned = row.classList.toggle("is-pin"); rows.forEach((r) => r !== row && r.classList.remove("is-pin")); if (!pinned) row.classList.remove("is-pin"); }); rows.push(row); return row; }), el("p", { className: "m01lab__subtotal-text m01lab-fx__wide", attrs: { "data-text-sub": String(g.소계) }, text: `${g.비목} ${tl("Subtotal")} ${formatNumber(g.소계)}${g.끝수 ? ` (${g.끝수})` : ""}`, }), ]); blocks.unshift(heads); blocks.push( el("p", { className: "m01lab__total m01lab-fx__wide", attrs: { "data-text-sum": String(text.계) }, text: `${tl("Total")} ${formatNumber(text.계)}`, }), ); host.replaceChildren(el("div", { className: "m01lab-fx", children: blocks })); }