/* 224-1b 유토 판 「붙어 있음」 판정 — 진짜 높이 나눔(`createHeightCascade`)과 방향키 판정 * (`arrowsBelongToProfile` 본문)을 가짜 DOM 위에서 돌려 JSON 으로 냄. * · 열림 && 뿌리 안 = 자리 차지 · 열림 && 새 창(뿌리 밖) = 자리 0 · 인라인 높이 안 씀 * · 방향키 = 마지막 누름이 종단 뿌리 · 뗀 유토 · 뗀 배수 판 안이면 종단도 몫 */ const fs = require("fs"); const path = require("path"); const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript")); const ROOT = path.join(__dirname, "..", ".."); const read = (...p) => fs.readFileSync(path.join(ROOT, ...p), "utf8"); const transpile = (code) => ts.transpileModule(code, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }, }).outputText; // ---- 가짜 요소(부모 사슬 · contains · closest) ---- function el(className = "") { const node = { className, parent: null, hidden: false, clientHeight: 0, offsetHeight: 0 }; node.style = { height: "", setProperty: (k, v) => (node.style[k] = v), }; node.append = (kid) => ((kid.parent = node), kid); node.contains = (other) => { for (let at = other; at; at = at.parent) if (at === node) return true; return false; }; node.closest = (selector) => { const wanted = selector.split(",").map((s) => s.trim().replace(/^\./, "")); for (let at = node; at; at = at.parent) if (wanted.some((c) => at.className.split(/\s+/).includes(c))) return at; return null; }; return node; } // ---- 진짜 높이 나눔 ---- const heightsExports = {}; new Function( "exports", "require", "window", transpile(read("B05_Profile", "B05_Profile_UI_Profile_Heights.ts")), )( heightsExports, (id) => id.includes("MassHaul") ? { MASSHAUL_MIN_HEIGHT: 160 } : id.includes("TableOverlay") ? { TABLE_OVERLAY_MIN_HEIGHT: 120 } : id.includes("Structures_Marks") ? { STRUCTURE_LANE_HEIGHT_PX: 40 } : { frameOf: () => 0 }, { innerHeight: 900 }, ); function run(docked) { const root = el("b05-route-profile"); root.offsetHeight = 500; const body = root.append(el()); body.clientHeight = 400; const overlay = el("b05-profile__masshaul-overlay"); if (docked) body.append(overlay); else el("popup-body").append(overlay); // 새 창 body const cascade = heightsExports.createHeightCascade({ root, body, massHaul: { overlay, desiredHeight: () => 300, syncHandle() {} }, tableOverlay: { overlay: el(), isOpen: () => false, desiredHeight: () => 0, setBottomOffset() {}, }, isMainDragging: () => false, isSubDragging: () => false, mainDragRef: () => null, isMainDragCooldown: () => true, // 자동 키우기 끔 — 나눔만 봄 hasDetail: () => true, }); const { chartHeight } = cascade.apply(false); return { chartHeight, inline: overlay.style.height }; } // ---- 진짜 방향키 판정 본문 ---- const base = read("B06_Section", "B06_Section_UI_Cross_Panel_Base.ts"); const at = base.indexOf("export function arrowsBelongToProfile"); const fnSrc = base.slice(at, base.indexOf("\n}", at) + 2).replace("export ", ""); const arrows = new Function( `let lastPointer; ${transpile(fnSrc)}; return (p) => ((lastPointer = p), arrowsBelongToProfile());`, )(); const profileRoot = el("b05-route-profile"); const profileChild = profileRoot.append(el("b05-profile__chart")); const massPopped = el("b05-profile__masshaul-overlay is-popout"); const massChild = massPopped.append(el("b05-profile__masshaul-scroll")); const drainPopped = el("b05-drainage is-popout"); const drainChild = drainPopped.append(el("b05-drainage__canvas")); const card = el("b06-cross-card"); process.stdout.write( JSON.stringify({ docked: run(true), popped: run(false), arrows: { profile: arrows(profileChild), mass: arrows(massChild), drainage: arrows(drainChild), card: arrows(card), none: arrows(null), }, }), );