feat(b07): 횡단 장 안내선 보이기 / 숨기기 단추 — 점선 작도 영역 + 붉은 넘침 틀 · 숨김이면 넘침 토스트 없음(180-3)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
/* 180-3 B07 안내선 보이기 / 숨기기 단추 헬퍼 — `…_UI_GuideToggle.ts` 를 Node 로 돌려 JSON 한 벌로.
|
||||
* 공용 단추(`ui_template_elements`)는 진짜 · 화면 그릇만 흉내(helper_153 꼴).
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
||||
|
||||
const ROOT = path.join(__dirname, "..", "..");
|
||||
const cache = new Map();
|
||||
|
||||
class FakeNode {
|
||||
constructor(tag) {
|
||||
this.tagName = tag.toUpperCase();
|
||||
this.children = [];
|
||||
this.dataset = {};
|
||||
this.attrs = {};
|
||||
this.listeners = {};
|
||||
this._text = "";
|
||||
this._classes = new Set();
|
||||
this.disabled = false;
|
||||
this.title = "";
|
||||
const self = this;
|
||||
this.classList = {
|
||||
add: (...names) => names.forEach((n) => self._classes.add(n)),
|
||||
contains: (name) => self._classes.has(name),
|
||||
};
|
||||
}
|
||||
set className(value) {
|
||||
this._classes = new Set(String(value).split(/\s+/).filter(Boolean));
|
||||
}
|
||||
get className() {
|
||||
return [...this._classes].join(" ");
|
||||
}
|
||||
set textContent(value) {
|
||||
this._text = String(value);
|
||||
this.children = [];
|
||||
}
|
||||
get textContent() {
|
||||
return this._text + this.children.map((c) => c.textContent).join("");
|
||||
}
|
||||
setAttribute(key, value) {
|
||||
this.attrs[key] = String(value);
|
||||
}
|
||||
append(...kids) {
|
||||
kids.forEach((k) => this.children.push(k));
|
||||
}
|
||||
addEventListener(type, handler) {
|
||||
(this.listeners[type] ||= []).push(handler);
|
||||
}
|
||||
click() {
|
||||
if (!this.disabled) (this.listeners.click || []).forEach((handler) => handler({}));
|
||||
}
|
||||
}
|
||||
globalThis.document = { createElement: (tag) => new FakeNode(tag) };
|
||||
|
||||
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) => {
|
||||
if (request === "@ui/ui_template_elements")
|
||||
return loadTs(path.join(ROOT, "ui_template", "ui_template_elements.ts"));
|
||||
if (request.startsWith(".")) {
|
||||
const target = path.join(path.dirname(full), `${request}.ts`);
|
||||
return fs.existsSync(target) ? loadTs(target) : {};
|
||||
}
|
||||
return {};
|
||||
};
|
||||
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
|
||||
cache.set(full, box.exports);
|
||||
return box.exports;
|
||||
}
|
||||
|
||||
const { buildGuideToggle, guideShown } = loadTs(
|
||||
path.join(ROOT, "B07_DesignDetail", "B07_DesignDetail_UI_GuideToggle.ts"),
|
||||
);
|
||||
|
||||
const sent = [];
|
||||
const button = buildGuideToggle((visible) => sent.push(visible));
|
||||
const view = () => ({
|
||||
text: button.textContent,
|
||||
cls: button.className,
|
||||
pressed: button.attrs["aria-pressed"],
|
||||
shown: guideShown(),
|
||||
});
|
||||
const out = { first: view() };
|
||||
button.click();
|
||||
out.hidden = view();
|
||||
button.click();
|
||||
out.again = view();
|
||||
button.click();
|
||||
out.last = view();
|
||||
// 화면을 다시 세워 새 단추를 만들어도 숨김 유지(모듈 값)
|
||||
const rebuilt = buildGuideToggle((visible) => sent.push(visible));
|
||||
out.rebuilt = { text: rebuilt.textContent, pressed: rebuilt.attrs["aria-pressed"] };
|
||||
out.sent = sent;
|
||||
process.stdout.write(JSON.stringify(out));
|
||||
@@ -0,0 +1,76 @@
|
||||
"""180-3 B07 횡단 장 안내선 보이기 / 숨기기 단추.
|
||||
|
||||
- 끄는 것 = 점선 작도 영역 + 붉은 넘침 틀(화면 전용) · 인쇄 칸선 · 도면 개체는 그대로
|
||||
- 단추 = 배치 칸 줄 · ghost sm · 글 「안내선 숨기기」 ↔ 「안내선 보이기」 · 상태는 모듈 값(저장 안 함)
|
||||
- 숨김이면 넘침 토스트도 안 띄움 · 메시지 한 줄(`aislo:b08:guide-visible`) · cad_host `setGuideVisible`
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
ROOT = Path(HERE).parents[1]
|
||||
B07 = ROOT / "B07_DesignDetail"
|
||||
|
||||
|
||||
def _read(path: Path) -> str:
|
||||
return path.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_단추_글_누름_상태_이어짐():
|
||||
proc = subprocess.run(
|
||||
["node", os.path.join(HERE, "helper_180_3_b07_guide_toggle.cjs")],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
timeout=60,
|
||||
)
|
||||
assert proc.returncode == 0, proc.stderr
|
||||
out = json.loads(proc.stdout)
|
||||
assert out["first"] == {
|
||||
"text": "안내선 숨기기",
|
||||
"cls": "ui-btn ui-btn--ghost ui-btn--sm",
|
||||
"pressed": "false",
|
||||
"shown": True,
|
||||
}
|
||||
assert out["hidden"]["text"] == "안내선 보이기" and out["hidden"]["pressed"] == "true"
|
||||
assert out["hidden"]["shown"] is False
|
||||
assert out["again"]["text"] == "안내선 숨기기" and out["again"]["shown"] is True
|
||||
assert out["last"]["shown"] is False
|
||||
assert out["sent"] == [False, True, False] # CAD 에 알린 값
|
||||
# 화면을 다시 세워 새 단추를 만들어도 숨김 유지
|
||||
assert out["rebuilt"] == {"text": "안내선 보이기", "pressed": "true"}
|
||||
|
||||
|
||||
def test_메시지_짝_호스트_CAD():
|
||||
host = _read(ROOT / "ui_template" / "cad_host" / "cad_host.ts")
|
||||
bridge = _read(B07 / "openwebcad" / "src" / "integration" / "aislo-drawing-bridge.ts")
|
||||
guide = _read(B07 / "openwebcad" / "src" / "integration" / "guide-area.ts")
|
||||
name = "aislo:b08:guide-visible"
|
||||
assert f'"{name}"' in host and f"'{name}'" in bridge # 짝 메시지 이름 같음
|
||||
assert "setGuideVisible: (visible) => postAfterLoad(" in host
|
||||
assert "setGuideVisible: (visible: boolean) => void;" in host
|
||||
assert "return setGuideVisible(guideMessage.visible);" in bridge
|
||||
assert "if (!guide || !guideVisible) return;" in guide # 그리기 거름
|
||||
assert "!guideVisible) return;" in guide # 끌기 집기도 거름
|
||||
# 싣기(setGuide)가 보임 값을 건드리지 않음
|
||||
body = guide[
|
||||
guide.index("export function setGuide(") : guide.index("export function setGuideArea")
|
||||
]
|
||||
assert "guideVisible" not in body
|
||||
|
||||
|
||||
def test_페이지_잇기_토스트_거름_장만():
|
||||
page = _read(B07 / "B07_DesignDetail_UI_Page.ts")
|
||||
assert "if (guideShown() && guide?.marks?.length) {" in page # 숨김 = 넘침 토스트 없음
|
||||
assert "cad.setGuideVisible(visible)" in page
|
||||
assert "if (!guideShown()) cad.setGuideVisible(false);" in page # 다시 세운 화면에 이어 줌
|
||||
assert "controls.append(guideToggle);" in page # 배치 칸 줄 끝
|
||||
assert "guideToggle.disabled = !isCrossSheet(drawing);" in page # 장만
|
||||
# 단추는 인쇄 칸선(도각 층) · 도면 개체를 건드리지 않음 — 파이썬 쪽 변경 없음
|
||||
assert not re.search(
|
||||
r"guide.?visible", _read(B07 / "B07_DesignDetail_Engine_Cad_Sheet.py"), re.I
|
||||
)
|
||||
Reference in New Issue
Block a user