Files
Aislo/resources/tester/helper_ui_data_table.cjs
T
eomsangdonandClaude Sonnet 5.5 5f8f909b65 fix(731-1): 일위대가표 줄 끝 ⋯ 단추 — 우클릭 · 길게 누름 없이도 위로 · 아래로 · 별칭 · 삭제
- 마우스 우클릭 · 길게 누름 삭제는 개인 · 마스터 층 모두 이미 되었음(재현 0) — 삭제 길이 눈에 안 보이는 것이 까닭
- 공용 표(ui_template_data_table)에 rowMenu 옵션 추가(첫 칸 오른쪽 ⋯ · 누르면 줄 누름 없이 메뉴만) · 일위대가표가 같은 메뉴를 연결
- 지킴 시험 test_ui_data_table 에 rowMenu 한 건

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-02 13:19:34 +09:00

133 lines
4.5 KiB
JavaScript

/* 공용 표(`ui_template/ui_template_data_table.ts`) 단위검증 헬퍼 —
* 트랜스파일해 Node 로 견본 표 HTML 을 만들고 판정할 값을 JSON 으로 냄. */
const fs = require("fs");
const path = require("path");
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
const file = path.join(__dirname, "..", "..", "ui_template", "ui_template_data_table.ts");
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
const req = (p) => (p.endsWith(".css") ? {} : require(p));
new Function("exports", "module", "require", js)(box.exports, box, req);
const m = box.exports;
const src = fs.readFileSync(path.join(__dirname, "fixture_data_table_sample.js"), "utf8");
const sampleDataTable = new Function(src + "; return sampleDataTable;")();
const s = sampleDataTable(66);
const html = m.renderDataTableHtml(s);
const head = html.split("<thead>")[1].split("</thead>")[0];
const headRows = head.split("</tr>").filter(Boolean);
const body = html.split("<tbody>")[1].split("</tbody>")[0];
const bodyRows = body.split("</tr>").filter(Boolean);
const foot = html.split("<tfoot>")[1].split("</tfoot>")[0];
const t0 = process.hrtime.bigint();
const big = m.renderDataTableHtml(sampleDataTable(1000));
const ms = Number(process.hrtime.bigint() - t0) / 1e6;
const one = (c, v) =>
m.formatCell(
v,
c.kind === "number"
? new Intl.NumberFormat("ko-KR", {
minimumFractionDigits: c.decimals ?? 0,
maximumFractionDigits: c.decimals ?? 0,
})
: null,
)[0];
const nc = { key: "a", label: "a", kind: "number", decimals: 2 };
const tc = { key: "b", label: "b" };
console.log(
JSON.stringify({
cols: s.columns.length,
headRows: headRows.length,
firstHeadRow: headRows[0],
secondHeadRow: headRows[1],
bodyRows: bodyRows.length,
firstBodyRow: bodyRows[0],
foot,
frozenCells: (body.match(/class="is-frozen is-edge"/g) || []).length,
bigRows: big.split("<tbody>")[1].split("</tbody>")[0].split("</tr>").length - 1,
bigMs: ms,
fmt: {
thousands: one(nc, 1234567.891),
neg: one(nc, -97.9),
zero: one(nc, 0),
nul: one(nc, null),
undef: one(nc, undefined),
blank: one(nc, ""),
nan: one(nc, NaN),
text: one(tc, "120+18"),
textNum: one(tc, 5),
},
win: (() => {
const b = m
.renderDataTableHtml(sampleDataTable(1000), { from: 61, to: 121, rowH: 25 })
.split("<tbody>")[1]
.split("</tbody>")[0]
.split("</tr>")
.filter(Boolean);
return { n: b.length, top: b[0], second: b[1].slice(0, 20), bottom: b[b.length - 1] };
})(),
opts: m.renderDataTableHtml({
columns: [
{ key: "sta", label: "측점" },
{ key: "c1", label: "메쌓기", group: ["기슭막이"], title: "풍선", className: "is-missing" },
],
rows: [{ sta: "0+0" }],
frozen: 1,
empty: "",
}),
pick: m.renderDataTableHtml({
columns: [{ key: "x", label: "X" }],
rows: [{ x: 1 }, { x: 2 }],
total: { x: 3 },
onRowClick: () => undefined,
}),
escaped: m.renderDataTableHtml({ columns: [{ key: "x", label: "<b>" }], rows: [{ x: "a&<" }] }),
noTotal: m.renderDataTableHtml({ columns: [tc], rows: [] }).includes("<tfoot>"),
rowClass: m.renderDataTableHtml({
columns: [{ key: "x", label: "X" }],
rows: [{ x: "제 1 호표" }, { x: " ㄴ 석공" }],
total: { x: 3 },
rowClass: (i) => (i === 0 ? "is-title" : null),
}),
rowMenu: m.renderDataTableHtml({
columns: [
{ key: "a", label: "A" },
{ key: "b", label: "B" },
],
rows: [
{ a: "제목", b: 1 },
{ a: "줄", b: 2 },
{ a: "줄2", b: 3 },
],
onRowClick: () => undefined,
rowMenu: { show: (i) => i > 0, open: () => undefined },
}),
noRowMenu: m.renderDataTableHtml({
columns: [{ key: "a", label: "A" }],
rows: [{ a: "줄" }],
onRowClick: () => undefined,
}),
scale: m.SCALE,
widths: m.renderDataTableHtml({
columns: [
{ key: "a", label: "A" },
{ key: "b", label: "B", kind: "number" },
{ key: "c", label: "C", width: 120 },
],
rows: [{ a: 1 }],
frozen: 2,
}),
css: fs.readFileSync(
path.join(__dirname, "..", "..", "ui_template", "ui_template_data_table.css"),
"utf8",
),
}),
);