- mountRouteEditor(parent, host, …) — 덮개 · 전체 화면 · 닫기 걷음 · 이력 · 키 듣기 = host 보임 · 숨김 · 떠남 · 칸 크기 = ResizeObserver - [취소] → [반영 전으로](이력 처음으로 · 되돌리기로 다시 살림) · [확인] → [노선 반영] · 대기 막 = 화면 전체(노선 재탐색) - [노선 반영] 끝 = 초안 · 결과 · 옛 노선 · 종단면 캐시 비움 → remountRoute(location.reload 없앰) - R 라벨 = 칸 안 절대 위치 · 오른쪽 횡단 미리보기 = 접는 칸 · [3D] 단추 = 평면 머리 도구줄 - 새 _RouteEdit_UndoOwner(누른 판 기억) · 종단도 Ctrl+Z 줄이 물음 - 시험: test_345_3_route_body 5 · 칸 · 겉틀 시험 고쳐 씀 · 관련 411 통과(옛 3 실패 그대로) · typecheck 통과 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VmC34fsxxbweEG3RUjs3Mn
92 lines
3.4 KiB
JavaScript
92 lines
3.4 KiB
JavaScript
/* 345-3 Ctrl+Z · Y 한 판만 헬퍼 — `_RouteEdit_History`(평면 이력 단추 · 단축키)와 `_RouteEdit_UndoOwner` 를
|
|
* 트랜스파일해 가짜 창(window)에서 돌림. 종단도 쪽 듣는 자리는 `_Profile_Panel_Tools` 와 같은 꼴
|
|
* (`undoOwner() === "plan"` 이면 안 받음)로 흉내. 결과는 JSON 한 벌(표준출력).
|
|
*/
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
const listeners = {};
|
|
global.window = {
|
|
addEventListener: (type, fn) => (listeners[type] ??= new Set()).add(fn),
|
|
removeEventListener: (type, fn) => listeners[type]?.delete(fn),
|
|
};
|
|
const fire = (type, event) => [...(listeners[type] ?? [])].forEach((fn) => fn(event));
|
|
|
|
const cache = new Map();
|
|
function loadTs(file) {
|
|
const full = path.resolve(file);
|
|
if (cache.has(full)) return cache.get(full);
|
|
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
cache.set(full, box.exports);
|
|
const localRequire = (request) =>
|
|
request.startsWith(".")
|
|
? loadTs(`${path.resolve(path.dirname(full), request)}.ts`)
|
|
: require(request);
|
|
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
|
|
return box.exports;
|
|
}
|
|
|
|
const page = path.join(ROOT, "B05_Profile");
|
|
const { bindHistoryControls } = loadTs(path.join(page, "B05_Profile_UI_RouteEdit_History.ts"));
|
|
const { undoOwner } = loadTs(path.join(page, "B05_Profile_UI_RouteEdit_UndoOwner.ts"));
|
|
|
|
const button = () => ({ disabled: false, addEventListener: () => undefined });
|
|
const buttons = { '[data-act="undo"]': button(), '[data-act="redo"]': button() };
|
|
const overlay = { querySelector: (sel) => buttons[sel] };
|
|
const plan = [];
|
|
const history = {
|
|
undo: () => (plan.push("undo"), { tag: "u" }),
|
|
redo: () => (plan.push("redo"), { tag: "r" }),
|
|
canUndo: () => true,
|
|
canRedo: () => true,
|
|
};
|
|
const controls = bindHistoryControls({
|
|
overlay,
|
|
getHistory: () => history,
|
|
restore: () => undefined,
|
|
});
|
|
|
|
// 종단도 듣는 자리 흉내 — `_Profile_Panel_Tools` 의 Ctrl+Z 줄과 같은 거름.
|
|
const profile = [];
|
|
window.addEventListener("keydown", (event) => {
|
|
if (!(event.ctrlKey && event.key === "z")) return;
|
|
if (undoOwner() === "plan") return;
|
|
profile.push(event.shiftKey ? "redo" : "undo");
|
|
});
|
|
|
|
const key = (k, shift = false) =>
|
|
fire("keydown", { ctrlKey: true, key: k, code: "", shiftKey: shift, preventDefault() {} });
|
|
const press = (cls) =>
|
|
fire("pointerdown", { target: { closest: (sel) => (sel === `.${cls}` ? {} : null) } });
|
|
const snap = () => ({ plan: [...plan], profile: [...profile], owner: undoOwner() });
|
|
|
|
const out = {};
|
|
key("z"); // 듣기 전 — 종단도만
|
|
out.beforeListen = snap();
|
|
controls.listen(true);
|
|
key("z"); // 아직 아무 판도 안 만짐 — 종단도
|
|
out.untouched = snap();
|
|
press("b05-routeedit");
|
|
key("z");
|
|
key("y");
|
|
out.afterPlanPress = snap();
|
|
press("b05-route-profile");
|
|
key("z");
|
|
out.afterProfilePress = snap();
|
|
press("b05-routeedit");
|
|
controls.listen(false); // 보기 숨김 — 평면 이력은 안 들음
|
|
key("z");
|
|
out.hidden = snap();
|
|
controls.listen(true);
|
|
key("z", true); // 다시 보임 · 마지막에 만진 판 = 평면 · Shift+Z = 다시하기
|
|
out.shown = snap();
|
|
controls.dispose();
|
|
key("z");
|
|
out.disposed = snap();
|
|
console.log(JSON.stringify(out));
|