feat(B05·B06): 「구조물 옵션 보이기」에서 끈 옵션을 배수관 · BOX암거 · 세월교 · 기슭막이 하위 폼에서도 가림(21-10 흠 8)
- 시설 폼 칸에 옵션 키 표식(data-option-keys) · 끈 키의 칸은 가림 · 칸이 다 가려진 줄은 줄째 - 키가 여럿인 칸(본체 규격 · 유입구 구조)은 키가 다 꺼졌을 때만 가림 · 독립 기슭막이는 유입 · 유출 채널 키로 넓힘 - 숨긴 칸은 칸 값(제안값 채우기 포함)이 아니라 폼이 받은 옛 값을 저장에 그대로 실음 · 이 폼에는 필수 검사가 없음 - 가리기 코드는 새 파일(_Facility_Hidden)로 분리해 Facility.ts 700줄 아래 유지 - 시험 3개 추가 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TULoa94ZFL26KU6ZqVpjkF
This commit is contained in:
@@ -66,6 +66,20 @@ class FakeNode {
|
||||
(this.listeners.click || []).forEach((h) => h({ target: this }));
|
||||
}
|
||||
scrollIntoView() {}
|
||||
// 시험에 필요한 두 가지 선택자만 — `[data-option-keys]` · `.클래스`
|
||||
querySelectorAll(selector) {
|
||||
const match = selector.startsWith("[")
|
||||
? (n) => n.dataset && n.dataset.optionKeys !== undefined
|
||||
: (n) => n.classList.contains(selector.slice(1));
|
||||
const found = [];
|
||||
const walk = (node) =>
|
||||
node.children.forEach((kid) => {
|
||||
if (kid.classList && match(kid)) found.push(kid);
|
||||
walk(kid);
|
||||
});
|
||||
walk(this);
|
||||
return found;
|
||||
}
|
||||
}
|
||||
globalThis.document = { createElement: (tag) => new FakeNode(tag) };
|
||||
globalThis.Option = function Option(text, value) {
|
||||
@@ -101,6 +115,9 @@ function loadTs(file) {
|
||||
if (STUBS[request]) return STUBS[request];
|
||||
// 화면 공용 부품(@ui/…) — 이 시험이 안 쓰는 것이라 뭘 불러도 아무 일 안 하는 함수로 막아 둠
|
||||
if (request.startsWith("@ui/")) return new Proxy({}, { get: () => () => {} });
|
||||
if (request.startsWith(".") && request.endsWith(".json")) {
|
||||
return JSON.parse(fs.readFileSync(path.join(path.dirname(full), request), "utf8"));
|
||||
}
|
||||
return request.startsWith(".")
|
||||
? loadTs(path.join(path.dirname(full), `${request}.ts`))
|
||||
: require(request);
|
||||
@@ -118,6 +135,8 @@ const { buildSummaryRow } = B05("B05_Profile_UI_Structures_Summary_Row");
|
||||
const { renderStructureList } = B05("B05_Profile_UI_Structures_List");
|
||||
const { renderOptionFields } = B05("B05_Profile_UI_Structures_Panel_Options");
|
||||
const commitModule = B05("B05_Profile_UI_Structures_Panel_Commit");
|
||||
const { createHiddenOptions } = B05("B05_Profile_UI_Drainage_Facility_Hidden");
|
||||
const { labeled } = B05("B05_Profile_UI_Drainage_Facility_Fields");
|
||||
|
||||
const out = {};
|
||||
const A = {
|
||||
@@ -358,6 +377,58 @@ const prev = () => ({
|
||||
summary_item: A,
|
||||
});
|
||||
|
||||
// 시설 폼 끈 옵션 가리기(PLAN 21-10 흠 8)
|
||||
{
|
||||
const tagged = labeled("관종", new FakeNode("select"), "pipe_kind");
|
||||
const multi = labeled("구조", new FakeNode("select"), ["inlet_type", "inlet_structure"]);
|
||||
const plain = labeled("메모", new FakeNode("select"));
|
||||
out.labelTag = [tagged.dataset.optionKeys, multi.dataset.optionKeys, plain.dataset.optionKeys];
|
||||
const root = new FakeNode("div");
|
||||
const rowA = new FakeNode("div");
|
||||
rowA.className = "b05-structure__grid";
|
||||
const kind = labeled("관종", new FakeNode("select"), "pipe_kind");
|
||||
const dia = labeled("관경", new FakeNode("select"), "pipe_diameter_mm");
|
||||
rowA.append(kind, dia);
|
||||
const rowB = new FakeNode("div");
|
||||
rowB.className = "b05-structure__grid";
|
||||
const inlet = labeled("구조", new FakeNode("select"), ["inlet_type", "inlet_structure"]);
|
||||
const free = labeled("메모", new FakeNode("select")); // 표식 없는 칸은 안 가림
|
||||
rowB.append(inlet, free);
|
||||
root.append(rowA, rowB);
|
||||
const hiddenOf = () => ({
|
||||
kind: kind.classList.contains("is-option-hidden"),
|
||||
dia: dia.classList.contains("is-option-hidden"),
|
||||
rowA: rowA.classList.contains("is-option-hidden"),
|
||||
inlet: inlet.classList.contains("is-option-hidden"),
|
||||
free: free.classList.contains("is-option-hidden"),
|
||||
rowB: rowB.classList.contains("is-option-hidden"),
|
||||
});
|
||||
const hidden = createHiddenOptions(root);
|
||||
hidden.set("pipe", ["pipe_kind"]);
|
||||
out.hideOne = hiddenOf();
|
||||
hidden.set("pipe", ["pipe_kind", "pipe_diameter_mm"]);
|
||||
out.hideRow = hiddenOf(); // 줄의 칸이 다 가려지면 줄째
|
||||
hidden.set("pipe", ["inlet_structure"]);
|
||||
out.hideInletPartial = hiddenOf(); // 키가 여럿인 칸은 하나만 꺼지면 그대로
|
||||
hidden.set("pipe", ["inlet_type"]);
|
||||
out.hideInlet = hiddenOf(); // 유입구 「구조」는 inlet_type 을 끄면 함께 가려짐(구조 키 포함)
|
||||
hidden.set("pipe", []);
|
||||
out.showAll = hiddenOf(); // [모두 보임] 뒤 되돌아옴
|
||||
// 숨긴 칸은 폼이 받은 옛 값 그대로 — 칸에서 읽은 값(제안값 채우기 포함)이 아니라
|
||||
hidden.remember({ pipe_kind: "흄관", pipe_diameter_mm: 1000, other: 1 });
|
||||
hidden.set("pipe", ["pipe_kind", "inlet_type"]);
|
||||
const read = { pipe_kind: "VR관", pipe_diameter_mm: 800, inlet_type: "제안", other: 2 };
|
||||
hidden.restore(read);
|
||||
out.restored = read;
|
||||
hidden.remember({}); // 옛 값이 없던 숨긴 칸은 값이 안 실림
|
||||
const read2 = { pipe_kind: "VR관", pipe_diameter_mm: 800 };
|
||||
hidden.restore(read2);
|
||||
out.restoredEmpty = read2;
|
||||
out.revetKeys = [...merge.hiddenFormKeys("revetment", ["form", "height_m", "side"])].sort();
|
||||
out.pipeKeys = [...merge.hiddenFormKeys("pipe", ["inlet_type"])].sort();
|
||||
out.otherKeys = [...merge.hiddenFormKeys("box_culvert", ["form"])].sort();
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const fresh = await saveWith({ previous: null, summary: null, formOptions: { H: 3 } });
|
||||
out.commitNew = { hasKey: "summary_item" in fresh, options: fresh.options };
|
||||
|
||||
@@ -136,3 +136,39 @@ def test_배수유역_화면은_들어올_때_세션_초안_관을_먼저_씀():
|
||||
body = source.split("const loadSaved", 1)[1].split("/**", 1)[0]
|
||||
assert "readPendingPipes(" in body and "computeDetailBasins(" in body
|
||||
assert body.index("readPendingPipes(") < body.index("fetchDetailPipePoints(")
|
||||
|
||||
|
||||
def test_시설_폼_끈_옵션_가리기(out):
|
||||
# 칸 표식 — 키 하나 · 여럿 · 없음
|
||||
assert out["labelTag"] == ["pipe_kind", "inlet_type inlet_structure", None]
|
||||
none = dict(kind=False, dia=False, rowA=False, inlet=False, free=False, rowB=False)
|
||||
assert out["hideOne"] == {**none, "kind": True}
|
||||
# 줄의 칸이 다 가려지면 줄째 · 표식 없는 칸은 그대로
|
||||
assert out["hideRow"] == {**none, "kind": True, "dia": True, "rowA": True}
|
||||
assert out["hideInletPartial"] == none
|
||||
assert out["hideInlet"] == {**none, "inlet": True}
|
||||
assert out["showAll"] == none # [모두 보임] 뒤 되돌아옴
|
||||
|
||||
|
||||
def test_숨긴_칸은_옛_값_그대로_저장에_실림(out):
|
||||
# 칸에서 읽은 값(VR관 · 제안)이 아니라 폼이 받은 옛 값 — 안 숨긴 칸은 칸 값
|
||||
assert out["restored"] == {"pipe_kind": "흄관", "pipe_diameter_mm": 800, "other": 2}
|
||||
# 옛 값이 없던 숨긴 칸은 값이 안 실림(칸의 제안값이 몰래 확정되지 않음)
|
||||
assert out["restoredEmpty"] == {"pipe_diameter_mm": 800}
|
||||
|
||||
|
||||
def test_끈_키를_폼_칸_키로_넓힘(out):
|
||||
# 독립 기슭막이는 유입 · 유출 채널 키로 · 유입구 구조는 inlet_structure 까지
|
||||
assert out["revetKeys"] == sorted(
|
||||
[
|
||||
"form",
|
||||
"height_m",
|
||||
"side",
|
||||
"inlet_revet_form",
|
||||
"outlet_revet_form",
|
||||
"inlet_revet_height_m",
|
||||
"outlet_revet_height_m",
|
||||
]
|
||||
)
|
||||
assert out["pipeKeys"] == ["inlet_structure", "inlet_type"]
|
||||
assert out["otherKeys"] == ["form"]
|
||||
|
||||
Reference in New Issue
Block a user