- Ctrl+Z · Y · 편집기 [되돌리기] · [다시하기] · [반영 전으로] = 페이지 사진첩(_Profile_History) — 평면 · 종단 · 횡단 · 관 · 구조물을 만진 차례 거꾸로 - 편집기 쌓기 · [반영 전으로] 뒤 사진첩 한 걸음(_Draft.watch) · 사진첩이 되쓴 route-draft 는 fromPage 로 편집기 새 걸음(같은 선 옛 걸음의 고정 · 추천 꼬리표째) - 쌓는 줄 없는 조작(횡단 카드 등) = 놓은 뒤 · change 뒤 400 ms 한 번 찍음 · 고름 · 관 id · 종류 캐시 · 구조물 넘김 · b08 · b09 칸은 사진 밖 - 「마지막에 만진 판만」(_RouteEdit_UndoOwner) 지움 · 편집기는 단축키 안 들음 - 시험 test_346_4_one_undo.py · 345-3 시험 · 219-1 헬퍼 새 꼴로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
69 lines
2.6 KiB
JavaScript
69 lines
2.6 KiB
JavaScript
/* 345-3 → 346-4 Ctrl+Z · Y 헬퍼 — 「마지막에 만진 판 하나」(`_RouteEdit_UndoOwner`)는 346-4 한 줄 되돌리기로
|
|
* 없어짐. 평면 이력 단추(`_RouteEdit_History.bindHistoryControls`)가 단축키를 안 듣는지 가짜 창에서 봄 —
|
|
* 단축키는 종단도(`_Profile_Panel_Tools`)가 페이지 사진첩 하나로 받음. 결과는 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 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,
|
|
});
|
|
|
|
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 out = {};
|
|
controls.listen(true);
|
|
press("b05-routeedit");
|
|
key("z");
|
|
key("y");
|
|
key("z", true);
|
|
out.plan = [...plan];
|
|
out.keydownListeners = listeners.keydown?.size ?? 0;
|
|
controls.listen(false);
|
|
controls.dispose();
|
|
console.log(JSON.stringify(out));
|