- 관 측점 열쇠 갈림(세션 pipe-s1 ↔ 계산 줄 pipe:p35100) = 415-1 로 풀림 · B06 연 길은 초안 카드 조절 그대로(화면) - B05 만 연 길(새로고침 · 조정창 맵 없음) · 세월 · BOX · 연동 칸은 안 옮겨짐 → 갈아끼움 알림 뒤 Station_Keys 가 ROUTE_CARRY_STATES(측점 열쇠 칸 빼고) 세션 칸을 바로 새 자리로 · 조정창 맵이 옮긴 칸은 그대로(Swap_Bus afterAnySwap) - 시험: test_415 누가거리 조절 · 노선 바뀜 대조 = 417 넘김 규칙(사면 쉬프트 · 소단 깊이 넘김) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ
58 lines
2.3 KiB
TypeScript
58 lines
2.3 KiB
TypeScript
/* =============================================================================
|
|
* B06_Section_Swap_Bus.ts
|
|
* 상세 갈아끼움 알림판(PLAN 346-2) — 측점 수가 바뀌어 `Section_Store` 가 상세 객체를 갈아끼우면 여기로 알림.
|
|
* 가져오는 것 없음 — 세션 조작값 맵(`_UI_Page_Link_Session`) · 암 경계 저장소(`_UI_Page_Persist`)가 모듈을 읽을 때
|
|
* 붙어도 `Section_Store` 와 돌고 도는 가져오기가 안 생김.
|
|
* ========================================================================== */
|
|
|
|
import type { SectionDetailResponse } from "./B06_Section_Api_Types";
|
|
|
|
/** 새 상세 · 이어 받은 측점의 누가거리 옮김(옛 0.01 m 글 → 새 글 · 조작값 맵을 옮길 때). */
|
|
export type DetailListener = (
|
|
detail: SectionDetailResponse,
|
|
moves: ReadonlyMap<string, string>,
|
|
) => void;
|
|
|
|
const anyListeners = new Set<DetailListener>();
|
|
|
|
/** 어느 노선이든 상세가 갈아끼워지면 부름(조정창 값 · 암 경계 옮김 · 다시 그림) — 돌려준 함수로 끊음. */
|
|
export function onAnySwap(fn: DetailListener): () => void {
|
|
anyListeners.add(fn);
|
|
return () => anyListeners.delete(fn);
|
|
}
|
|
|
|
/** 알림 한 번 동안 조정창 맵이 옮긴 세션 칸(열쇠 글) — 뒤 차례(`afterAnySwap`)는 그 칸을 다시 안 옮김(415-3). */
|
|
const moved = new Set<string>();
|
|
const afterListeners = new Set<
|
|
(
|
|
detail: SectionDetailResponse,
|
|
moves: ReadonlyMap<string, string>,
|
|
owned: ReadonlySet<string>,
|
|
) => void
|
|
>();
|
|
|
|
/** 조정창 맵이 세션 칸을 옮겼다고 적음(`_UI_Page_Link_Session`). */
|
|
export function markMovedStates(keys: Iterable<string>): void {
|
|
for (const key of keys) moved.add(key);
|
|
}
|
|
|
|
/** 갈아끼움 알림이 다 돈 뒤 부름 — `owned` = 그 사이 조정창 맵이 옮긴 세션 칸. */
|
|
export function afterAnySwap(
|
|
fn: (
|
|
detail: SectionDetailResponse,
|
|
moves: ReadonlyMap<string, string>,
|
|
owned: ReadonlySet<string>,
|
|
) => void,
|
|
): () => void {
|
|
afterListeners.add(fn);
|
|
return () => afterListeners.delete(fn);
|
|
}
|
|
|
|
/** 갈아끼운 쪽(`Section_Store`)이 부름. */
|
|
export function emitSwap(detail: SectionDetailResponse, moves: ReadonlyMap<string, string>): void {
|
|
moved.clear();
|
|
anyListeners.forEach((fn) => fn(detail, moves));
|
|
const owned = new Set(moved);
|
|
afterListeners.forEach((fn) => fn(detail, moves, owned));
|
|
}
|