Files
Aislo/resources/tester/helper_359_2_late_actions.cjs
T
eomsangdonandClaude Opus 5.5 4f4cc22c36 fix(가이드): 좌측 패널 [?] 늦게 붙인 단추 줄에도 자리 — E03 · E04 · E06 · E07(요구 359-2 · 360-2)
- 까닭 = 패널을 세운 뒤 단추 줄을 붙이는 화면은 쪼갬 · [?] [<] [>] 자리를 못 찾음
- 고침 = 공용 좌측 패널이 단추 줄이 붙는 때를 지켜보다 한 번 쪼갬 · 붙으면 지켜보기 끊음
- 시험 = 늦게 붙인 줄 · 먼저 붙인 줄 [?] 한 벌(새) · 280-2 헬퍼 대역에 538-3 고침 모듈 더함(낡음)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:46:24 +09:00

142 lines
4.1 KiB
JavaScript

/* 요구 359-2 · 360-2 — 좌측 패널 [?] 자리. `ui_template_overlay.ts` 를 트랜스파일해 가짜 DOM 위에서
* 액션 줄을 ① 패널 세우기 전(E05 꼴) ② 세운 뒤(E03 · E04 · E06 · E07 꼴)에 붙여 쪼갬 · [?] 를 JSON 한 벌로 냄.
*/
const path = require("path");
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
const ROOT = path.join(__dirname, "..", "..");
class FakeNode {
constructor(tag) {
this.tagName = tag;
this.children = [];
this.parent = null;
this.style = {};
this._classes = new Set();
const self = this;
this.classList = {
add: (...n) => n.forEach((x) => self._classes.add(x)),
remove: (...n) => n.forEach((x) => self._classes.delete(x)),
toggle: (n, f) =>
(f === undefined ? !self._classes.has(n) : !!f)
? self._classes.add(n)
: self._classes.delete(n),
contains: (n) => self._classes.has(n),
};
}
set className(v) {
this._classes = new Set(String(v).split(/\s+/).filter(Boolean));
}
get className() {
return [...this._classes].join(" ");
}
get parentElement() {
return this.parent;
}
get firstChild() {
return this.children[0] ?? null;
}
get childElementCount() {
return this.children.length;
}
_adopt(kid) {
if (kid.parent) kid.parent.children = kid.parent.children.filter((c) => c !== kid);
kid.parent = this;
return kid;
}
append(...kids) {
kids.forEach((k) => this.children.push(this._adopt(k)));
mutated();
}
prepend(...kids) {
this.children.unshift(...kids.map((k) => this._adopt(k)));
mutated();
}
setAttribute() {}
addEventListener() {}
querySelector(selector) {
const cls = selector.slice(1);
let hit = null;
const walk = (n) =>
n.children.forEach((k) => {
if (!hit && k._classes.has(cls)) hit = k;
if (!hit) walk(k);
});
walk(this);
return hit;
}
}
// 진짜 MutationObserver 처럼 바뀐 뒤 한꺼번에 — `flush()` 가 부름(지켜보는 것만 · 끊으면 안 부름)
const observers = new Set();
let dirty = false;
function mutated() {
dirty = true;
}
function flush() {
while (dirty) {
dirty = false;
[...observers].forEach((o) => o.cb());
}
}
globalThis.MutationObserver = class {
constructor(cb) {
this.cb = cb;
}
observe() {
observers.add(this);
}
disconnect() {
observers.delete(this);
}
};
globalThis.document = { createElement: (tag) => new FakeNode(tag) };
globalThis.window = { innerWidth: 1600 };
const { loadTs } = makeLoader({
root: ROOT,
stubs: {
"./ui_template_locale": { t: (key) => key },
"./ui_template_help": {
placeHelpButton: (actions) => {
const button = new FakeNode("button");
button.className = "ui-help-btn";
actions.prepend(button);
},
},
"./ui_template_overlay_drag": { makePanelDraggable: () => ({ refresh() {} }) },
"/b_workflow_nav": { fetchWorkflowState: async () => ({}) },
"/b_page_state": { readByKey: () => null, writeByKey: () => undefined },
"/device_context": { SIZE_BREAKS: { expanded: 840 } },
},
});
const overlay = loadTs(path.join(ROOT, "ui_template", "ui_template_overlay.ts"));
function mount(late) {
const panel = new FakeNode("div");
const actions = new FakeNode("div");
actions.className = "ui-sidebar-actions";
panel.append(new FakeNode("p"));
if (!late) panel.append(actions);
const { root } = overlay.createWorkflowOverlays({
title: "t",
optionsContent: panel,
showProjectName: false,
});
const before = !!actions.querySelector(".ui-help-btn");
if (late) panel.append(actions);
flush();
const body = root.querySelector(".ui-workflow-overlay__body");
return {
before,
help: actions.querySelector(".ui-help-btn") ? 1 : 0,
split: body.classList.contains("ui-sidebar-split"),
scroll: !!panel.querySelector(".ui-sidebar-scroll"),
lastIsActions: panel.children[panel.children.length - 1] === actions,
watching: observers.size,
};
}
const early = mount(false);
const late = mount(true);
process.stdout.write(JSON.stringify({ early, late }));