/* 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));