Merge remote-tracking branches 'origin/sub_laptop_3' and 'origin/sub_laptop_7' into sub_laptop_5

This commit is contained in:
2026-10-06 12:40:50 +09:00
18 changed files with 308 additions and 240 deletions
@@ -199,7 +199,6 @@ const built = panel.createDesignPanel(
settings: { nodes: [text("a"), text("b")] },
route: {
plannedRouteButton: text("plan"),
calcNodes: [text("calc")],
selectedNodes: [text("sel")],
bindSelectedRoot: (root) => {
root.hidden = true;
+1 -2
View File
@@ -59,7 +59,7 @@ def results():
def test_보기를_오가도_좌측_패널_단추_구조물_배치는_같은_노드(results):
assert results["sameNodes"] == {"cross": True, "back": True}
# 보기마다 새로 만들지 않는다 — 칸은 처음 보일 때 한 번만 서고 뒤로는 숨김 · 보임만.
assert results["childCount"] == 1 + 5 + 2 # 아래 고정 영역 + 종단 칸 다섯 + 횡단 칸 둘
assert results["childCount"] == 1 + 4 + 2 # 아래 고정 영역 + 종단 칸 넷 + 횡단 칸 둘
def test_구조물_배치는_두_보기_모두_맨_위_같은_DOM(results):
@@ -80,7 +80,6 @@ def test_보기마다_제_칸만_보인다(results):
"구조물 배치",
"페이지 설정",
"계획노선",
"경로 계산 설정",
"선택 포인트 상세 설정",
]
assert views["cross"]["shownTitles"] == ["구조물 배치", "횡단 보기 설정", "표준 횡단면 설정"]
@@ -0,0 +1,83 @@
/* 54-22 — 종단 점 ▲ 누름 멈춤(긴 작업) 재기: B06 은 120ms 디바운스 · 종단도 한 번 · B05 는 실시간 그대로
* 시작 화면: B06(#/b06-section) 또는 B05(#/b05-profile) · 검증 프로젝트 · 로그인
* 부르는 법: 단계마다 한 번씩 — 앞에 `window.__m5422 = "단계";` · 긴 단계는 `void` 로 띄우고
* `sessionStorage.getItem("__5422_out_{단계}")` 로 읽음
* snap → 처음 초안(세션 원문)을 `__5422_orig` 에 남김(이미 있으면 그대로)
* one → 가운데 측점 ▲ 한 번 — 긴 작업 최장 · 합 · 횡단 재계산까지 걸린 때
* hold → 가운데 측점 ▲ 2.5초 길게 — 긴 작업 최장 · 합 · 재계산 횟수
* restore → 처음 초안 원문으로 되돌림 → 그 뒤 orca reload
* 판정: B06 one 최장 ≈200ms 안팎 · hold 합 ≈0.5초 안팎(고치기 전 587 / 2,684ms) ·
* B05 one 재계산 때 = 16ms 디바운스 근처(실시간)
* 쓰는 것: sessionStorage(계획선 초안) — 정본(서버)은 안 씀
*/
(async () => {
const MODE = window.__m5422 || "one";
const w = (ms) => new Promise((r) => setTimeout(r, ms));
const DRAFTS = /^aislo:draft:/;
const out = { mode: MODE, page: location.hash };
const save = () => sessionStorage.setItem(`__5422_out_${MODE}`, JSON.stringify(out));
if (MODE === "snap") {
if (!sessionStorage.getItem("__5422_orig")) {
const orig = Object.fromEntries(
Object.keys(sessionStorage)
.filter((k) => DRAFTS.test(k))
.map((k) => [k, sessionStorage.getItem(k)]),
);
sessionStorage.setItem("__5422_orig", JSON.stringify(orig));
}
out.keys = Object.keys(JSON.parse(sessionStorage.getItem("__5422_orig")));
save();
return JSON.stringify(out);
}
if (MODE === "restore") {
const orig = JSON.parse(sessionStorage.getItem("__5422_orig") || "null");
if (!orig) return "no orig";
for (const k of Object.keys(sessionStorage)) if (DRAFTS.test(k)) sessionStorage.removeItem(k);
for (const [k, v] of Object.entries(orig)) sessionStorage.setItem(k, v);
for (const k of Object.keys(sessionStorage))
if (k.startsWith("__5422")) sessionStorage.removeItem(k);
return JSON.stringify({ restored: Object.keys(orig) });
}
const ups = [...document.querySelectorAll(".b05-profile-edit__btn.is-up")];
const button = ups[Math.floor(ups.length / 2)];
if (!button) {
out.error = "▲ 없음";
save();
return JSON.stringify(out);
}
out.button = button.title.split("\n")[0];
const tasks = [];
const observer = new PerformanceObserver((list) =>
list.getEntries().forEach((e) => tasks.push(Math.round(e.duration))),
);
observer.observe({ type: "longtask" });
// 횡단 재계산이 카드 · 캐시에 닿은 때 — 계획선 초안 말고 다른 캐시 쓰기
const writes = [];
const t0 = performance.now();
const origSet = Storage.prototype.setItem;
Storage.prototype.setItem = function (k, v) {
if (this === sessionStorage && !k.startsWith("__5422"))
writes.push([Math.round(performance.now() - t0), k.replace(/:[0-9a-f-]{36}.*/, "")]);
return origSet.call(this, k, v);
};
// 화면이 바뀐 때(ms) — 누른 뒤 재계산 반영이 닿는 때를 봄(B05 ≈16ms 디바운스 · B06 ≈120ms)
const domAt = new Set();
const mo = new MutationObserver(() => domAt.add(Math.round(performance.now() - t0)));
mo.observe(document.body, { subtree: true, childList: true, characterData: true });
button.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, pointerId: 1 }));
await w(MODE === "hold" ? 2500 : 60);
window.dispatchEvent(new PointerEvent("pointerup", { bubbles: true, pointerId: 1 }));
await w(2500);
Storage.prototype.setItem = origSet;
observer.disconnect();
mo.disconnect();
out.domAt = [...domAt].slice(0, 12);
out.longTasks = tasks;
out.max = tasks.length ? Math.max(...tasks) : 0;
out.sum = tasks.reduce((a, b) => a + b, 0);
out.writes = writes;
save();
return JSON.stringify(out);
})();