Files
Aislo/B05_Profile/B05_Profile_UI_Drainage_Revet_Choice.ts
T

124 lines
5.5 KiB
TypeScript

/* =============================================================================
* B05_Profile_UI_Drainage_Revet_Choice.ts
* 관 보호공 상자 안 [연동] · [경사] 한 줄(54-30) — 반 폭 단추 둘 · 쓸 수 있는 쪽만 누를 수 있음.
* 값 = 횡단 연동 제어 옛 자리(`revet_link_detached` · `revet_follow_grade` · `design_structure_pipe_calc`) ·
* 고르면 횡단 그림이 바로 따라감. 경사를 끄면(수평) 연동은 풀 수 없음(옛 규칙 그대로).
* ========================================================================== */
import { toggleButton } from "./B05_Profile_UI_Panel_Fields";
import { labeled, numberInput, stepper } from "./B05_Profile_UI_Drainage_Facility_Fields";
import {
pipeExtraCount,
pipeRevetChoice,
setPipeExtraCount,
setPipeRevetChoice,
} from "../A00_Common/design/design_structure_pipe_calc";
const LINK_TITLE = "옆 측점 흙막이와 횡단 자리를 함께 씀 — 끄면 측점마다 따로 잡음";
const LINK_LOCKED = "경사를 끈(수평) 동안은 연동을 풀 수 없음";
const GRADE_TITLE = "종단경사 반영 — 끄면 연장 구간 내내 같은 높이(수평)";
/** 한 줄 — `paint` 가 지금 값 · 쓸 수 있는지를 다시 칠하고 줄을 돌려줌(폼 다시 그림마다). */
export function revetChoiceRow(
chainageOf: () => number | null,
/** 쓴 뒤 — 폼을 다시 그려 유입 · 유출 두 줄을 함께 칠함. */
written: () => void,
): {
paint: (hidden: boolean) => HTMLElement;
} {
const row = document.createElement("div"); // label 이 아님 — 이름표를 눌러 첫 단추가 눌리지 않게
row.className = "b05-route__field";
const caption = document.createElement("span");
caption.textContent = "옵션";
const pair = document.createElement("div");
pair.className = "b05-structure__half-pair";
const write = (kind: "link" | "grade", on: boolean): void =>
void setPipeRevetChoice(chainageOf(), kind, on).then(written);
const link = toggleButton("연동", true, (on) => write("link", on));
const grade = toggleButton("경사", true, (on) => write("grade", on));
grade.title = GRADE_TITLE;
pair.append(link, grade);
row.append(caption, pair);
const set = (button: HTMLButtonElement, value: boolean | null, locked: boolean): void => {
button.disabled = value === null || locked;
button.classList.toggle("is-active", value === true);
button.setAttribute("aria-pressed", String(value === true));
};
function paint(hidden: boolean): HTMLElement {
const now = pipeRevetChoice(chainageOf());
const locked = now?.grade === false;
set(link, now?.linked ?? null, locked);
link.title = locked ? LINK_LOCKED : LINK_TITLE;
set(grade, now?.grade ?? null, false);
row.hidden = hidden;
return row;
}
return { paint };
}
/** 유출 「추가 흙막이(단)」(54-27 · 90-1 배관 · 세월교 · 박스 공용) — 값 = 횡단 조정 단 수(같은 저장 자리) ·
* 흙막이 상자 수가 따라감(폼 `count` 훅 = `pipeExtraCount`). `shown` = 유출 구조 값이 벽인지. */
export function outletTiersRow(
chainageOf: () => number | null,
/** 쓴 뒤 — 지형이 못 세운 단은 횡단 기하가 자름 · 세운 만큼으로 상자를 다시 셈. */
recount: () => void,
shown: (structure: string | undefined) => boolean,
): { paint: (values: Record<string, string>) => HTMLElement } {
const input = numberInput("1", "0");
input.max = "9";
const row = labeled("추가 흙막이(단)", stepper(input, 1, 0));
row.dataset.specItem = "outlet.tiers";
row.querySelectorAll("button").forEach((b, i) => (b.title = `1단 ${i ? "늘리기" : "줄이기"}`));
input.addEventListener("change", () => {
const count = Math.max(0, Math.min(9, Math.round(Number(input.value) || 0)));
void setPipeExtraCount(chainageOf(), count).then(recount);
});
return {
paint: (values) => {
const count = pipeExtraCount(chainageOf());
input.value = count === null ? "" : String(count);
input.disabled = count === null;
row.hidden = !shown(values.structure);
return row;
},
};
}
/** 세월교 · 박스 흙막이 상자 줄(65-2 · 배관과 같은 줄) — 흙막이를 고른 유입 · 유출 · 추가 흙막이 상자마다 한 줄 ·
* 유출 상자엔 「추가 흙막이(단)」(90-1). 명세 폼 `fields` 자리에 그대로 씀. */
export function guardChoiceFields(
chainageOf: () => number | null,
written: () => void,
recount: () => void,
): (c: { id: string }, values: Record<string, string>) => HTMLElement[] {
const sides = {
inlet: revetChoiceRow(chainageOf, written),
outlet: revetChoiceRow(chainageOf, written),
};
const tiers = outletTiersRow(chainageOf, recount, (structure) => structure === "흙막이");
return (c, values) =>
c.id === "soil_add"
? [revetChoiceRow(chainageOf, written).paint(false)]
: c.id === "inlet" || c.id === "outlet"
? [
...(c.id === "outlet" ? [tiers.paint(values)] : []),
sides[c.id].paint(values.structure !== "흙막이"),
]
: [];
}
/** 세월교 · 박스 흙막이 상자 수(90-1) — 유출이 흙막이면 지형이 세운 유출 단 수 · 아니면 0(옛 상자는
* 숨기고 값은 파일에 남김). 명세 폼 `count` 훅 자리. */
export function guardSoilCount(
chainageOf: () => number | null,
outletStructure: () => string | undefined,
): (c: { id: string }) => number | null | undefined {
return (c) =>
c.id !== "soil_add"
? undefined
: outletStructure() === "흙막이"
? pipeExtraCount(chainageOf())
: 0;
}