Merge remote-tracking branch 'origin/sub_laptop_2' into main_laptop_1
This commit is contained in:
@@ -26,7 +26,9 @@ function loadTs(file) {
|
||||
}
|
||||
|
||||
const free = loadTs(path.join(ROOT, "A00_Common", "design", "logic", "design_profile_free.ts"));
|
||||
const align = loadTs(path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_Profile_Alignment.ts"));
|
||||
const align = loadTs(
|
||||
path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_Profile_Alignment.ts"),
|
||||
);
|
||||
|
||||
// 전체 측점 폴리라인(20m 간격 · 0~200m) — 계획고 = 지반고, 마디마다 기울기가 다르다.
|
||||
const stations = Array.from({ length: 11 }, (_, i) => i * 20);
|
||||
@@ -124,14 +126,23 @@ out.snapOutside = free.snapStation(stations, 190, [40, 160]);
|
||||
out.radiiKeys = Object.keys(next.curve_radii).sort();
|
||||
const built = align.buildAlignment(base, next);
|
||||
const pvi = (s) => built.pvi.find((n) => Math.abs(n.chainage_m - s) < 1e-6).elevation_m;
|
||||
out.pvi = { 40: pvi(40), 60: pvi(60), 80: pvi(80), 100: pvi(100), 120: pvi(120), 140: pvi(140), 160: pvi(160) };
|
||||
out.pvi = {
|
||||
40: pvi(40),
|
||||
60: pvi(60),
|
||||
80: pvi(80),
|
||||
100: pvi(100),
|
||||
120: pvi(120),
|
||||
140: pvi(140),
|
||||
160: pvi(160),
|
||||
};
|
||||
out.ground = { 40: z0(40), 160: z0(160) };
|
||||
const g1 = (103.46 - z0(40)) / 40;
|
||||
const g2 = (101.2 - 103.46) / 40;
|
||||
out.expectR80 = Number((20 / Math.abs(g2 - g1)).toFixed(6));
|
||||
out.r80 = next.curve_radii["80.000"];
|
||||
out.curve80L = built.curves.find((c) => Math.abs(c.chainage_m - 80) < 1e-6)?.l_m ?? null;
|
||||
out.outsideUntouched = !("20.000" in next.station_offsets) && !("180.000" in next.station_offsets);
|
||||
out.outsideUntouched =
|
||||
!("20.000" in next.station_offsets) && !("180.000" in next.station_offsets);
|
||||
}
|
||||
|
||||
// ④ Enter = 끝(마지막 점 → 끝 세로선) · 끝 세로선에서 거꾸로 시작.
|
||||
@@ -172,4 +183,62 @@ out.snapOutside = free.snapStation(stations, 190, [40, 160]);
|
||||
out.enterOutsideDrawing = draw.key("Enter");
|
||||
}
|
||||
|
||||
// ⑥ 되돌리기 · 다시하기(367-3) — 점 둘 → ↶ → ↷ → 새 클릭이 ↷ 지움 · apply 안 불림 · 범위까지 거꾸로.
|
||||
{
|
||||
const { draw, log } = harness();
|
||||
out.undoEmpty = { can: draw.canUndo(), backspace: draw.key("Backspace") };
|
||||
draw.click(40, 0, stations);
|
||||
draw.click(40, 0, stations); // 같은 세로선 다시 — 상태 그대로 · 안 쌓임
|
||||
draw.click(160, 0, stations);
|
||||
draw.click(40, 0, stations);
|
||||
draw.click(80, 102, stations);
|
||||
draw.click(120, 103, stations);
|
||||
const dots = () => draw.marks().dots.map((d) => d.chainage_m);
|
||||
draw.undo();
|
||||
out.undo1 = { dots: dots(), canRedo: draw.canRedo() };
|
||||
draw.redo();
|
||||
out.redo1 = { dots: dots(), canRedo: draw.canRedo() };
|
||||
draw.undo();
|
||||
draw.click(100, 104, stations); // 새 클릭 = future 비움
|
||||
out.newClick = { dots: dots(), canRedo: draw.canRedo() };
|
||||
const phases = [];
|
||||
while (draw.canUndo()) {
|
||||
draw.undo();
|
||||
phases.push(`${draw.phase()}:${draw.marks().edges.length}`);
|
||||
}
|
||||
out.undoAll = phases;
|
||||
out.undoApplied = log.applied.length;
|
||||
out.undoClosed = log.closed;
|
||||
draw.redo();
|
||||
draw.redo();
|
||||
out.redoTwice = { phase: draw.phase(), band: draw.marks().band };
|
||||
draw.reset();
|
||||
out.resetClears = { undo: draw.canUndo(), redo: draw.canRedo() };
|
||||
}
|
||||
|
||||
// ⑦ 적용이 막히면(apply = false) 자유지정 열린 채 · 점 그대로.
|
||||
{
|
||||
let tries = 0;
|
||||
const draw = free.createFreeDraw({
|
||||
base: () => base,
|
||||
alignment: () => align.buildAlignment(base, align.emptyEdits()),
|
||||
edits: () => align.emptyEdits(),
|
||||
apply: () => ((tries += 1), false),
|
||||
close: () => (tries += 100),
|
||||
changed: () => undefined,
|
||||
});
|
||||
draw.click(40, 0, stations);
|
||||
draw.click(160, 0, stations);
|
||||
draw.click(40, 0, stations);
|
||||
draw.click(80, 102, stations);
|
||||
draw.key("Enter");
|
||||
draw.click(160, 0, stations);
|
||||
out.blocked = {
|
||||
tries,
|
||||
phase: draw.phase(),
|
||||
dots: draw.marks().dots.length,
|
||||
canUndo: draw.canUndo(),
|
||||
};
|
||||
}
|
||||
|
||||
process.stdout.write(JSON.stringify(out));
|
||||
|
||||
@@ -489,7 +489,8 @@ function makePage() {
|
||||
return app;
|
||||
}
|
||||
function fakeDocument(app) {
|
||||
const doc = { body: new El("BODY") };
|
||||
// 374-1 뜨는 자리 = body(모달 포함) · 원 · 배율 글은 html 바로 아래
|
||||
const doc = { body: app, documentElement: new El("HTML") };
|
||||
doc.createElement = (tag) => new El(tag.toUpperCase());
|
||||
doc.getElementById = (id) => (id === "app" ? app : null);
|
||||
return doc;
|
||||
@@ -515,10 +516,12 @@ function fakeDocument(app) {
|
||||
};
|
||||
const view = m.createLoupeView(win);
|
||||
view.show(500, 400);
|
||||
const root = doc.body.children[0];
|
||||
const label = doc.body.children[1];
|
||||
const root = doc.documentElement.children[0];
|
||||
const label = doc.documentElement.children[1];
|
||||
const stage = root.children[0];
|
||||
const page = stage.children[0];
|
||||
const scaler = stage.children[0]; // 이동 = stage · 배율 = scaler
|
||||
const page = scaler.children[0];
|
||||
const lens = () => `${stage.style.transform} ${scaler.style.transform}`;
|
||||
const copy = page.children[0];
|
||||
const [scroller, offscreen, table, svg, frame, cadBox] = copy.children;
|
||||
const [canvas, blank, input, check] = scroller.children;
|
||||
@@ -529,7 +532,8 @@ function fakeDocument(app) {
|
||||
ariaHidden: root.attrs["aria-hidden"],
|
||||
hidden: root.hidden,
|
||||
rootTransform: root.style.transform,
|
||||
stageTransform: stage.style.transform,
|
||||
stageTransform: lens(),
|
||||
stageMoveOnly: stage.style.transform,
|
||||
pageBox: [page.style.left, page.style.top, page.style.width, page.style.height],
|
||||
isClone: copy.cloned === true && copy !== app,
|
||||
canvasDrawn: canvas.drawn.map((d) => d[0]),
|
||||
@@ -560,19 +564,31 @@ function fakeDocument(app) {
|
||||
hidden: label.hidden,
|
||||
};
|
||||
view.setZoom(3);
|
||||
r.label.zoom3 = [label.textContent, stage.style.transform, root.style.transform];
|
||||
r.label.zoom3 = [label.textContent, lens(), root.style.transform];
|
||||
view.move(500, 790);
|
||||
r.label.bottom = label.style.transform;
|
||||
view.setZoom(2);
|
||||
view.move(500, 400);
|
||||
// 화면이 바뀜 — 0.5 초 뒤 한 번만 다시 뜸
|
||||
// 화면이 바뀜 — 멈춘 뒤 0.5 초에 한 번만 다시 뜸
|
||||
const firstCopy = copy;
|
||||
observers[0].fn();
|
||||
observers[0].fn();
|
||||
win.tick(499);
|
||||
const sameBefore = stage.children[0].children[0] === firstCopy;
|
||||
const sameBefore = scaler.children[0].children[0] === firstCopy;
|
||||
win.tick(1);
|
||||
const recaptured = stage.children[0].children[0] !== firstCopy && stage.children.length === 1;
|
||||
const recaptured = scaler.children[0].children[0] !== firstCopy && scaler.children.length === 1;
|
||||
// 374-1 움직이는 동안 안 뜸 — 바뀜 뒤 움직이면 처음부터 · 멈춘 뒤 0.5 초에 한 번
|
||||
const moving = scaler.children[0].children[0];
|
||||
observers[0].fn();
|
||||
win.tick(300);
|
||||
view.move(520, 400);
|
||||
win.tick(300);
|
||||
view.move(540, 400);
|
||||
win.tick(499);
|
||||
const heldWhileMoving = scaler.children[0].children[0] === moving;
|
||||
win.tick(1);
|
||||
r.debounce = { heldWhileMoving, afterStop: scaler.children[0].children[0] !== moving };
|
||||
view.move(500, 400);
|
||||
view.move(10, 10);
|
||||
const nearEdge = root.style.transform;
|
||||
view.hide();
|
||||
@@ -580,20 +596,21 @@ function fakeDocument(app) {
|
||||
sameBefore,
|
||||
recaptured,
|
||||
nearEdge,
|
||||
stageChildren: stage.children.length,
|
||||
stageChildren: scaler.children.length,
|
||||
hidden: root.hidden,
|
||||
disconnected: observers[0].watching === null,
|
||||
scrollListen: win.calls.some((c) => c.type === "scroll"),
|
||||
};
|
||||
observers[0].fn();
|
||||
win.tick(1000);
|
||||
r.hide.noRecaptureAfterHide = stage.children.length;
|
||||
r.hide.noRecaptureAfterHide = scaler.children.length;
|
||||
r.hide.labelHidden = label.hidden;
|
||||
view.setZoom(4);
|
||||
view.hide();
|
||||
view.show(500, 400);
|
||||
r.hide.reopenLabel = [label.textContent, label.hidden, stage.style.transform];
|
||||
r.hide.reuseRoot = doc.body.children.length;
|
||||
r.hide.reopenLabel = [label.textContent, label.hidden, lens()];
|
||||
r.hide.reuseRoot = doc.documentElement.children.length;
|
||||
r.hide.bodyUntouched = app.children.length; // 원이 body 에 안 붙음
|
||||
}
|
||||
{
|
||||
// 221-2 스크롤 — 스크롤한 뒤 켬 · 켠 채 스크롤(칸 · 문서)
|
||||
@@ -606,8 +623,9 @@ function fakeDocument(app) {
|
||||
disconnect() {}
|
||||
};
|
||||
const view = m.createLoupeView(win);
|
||||
const cloneScroller = () => doc.body.children[0].children[0].children[0].children[0].children[0];
|
||||
const page = () => doc.body.children[0].children[0].children[0];
|
||||
const scaler = () => doc.documentElement.children[0].children[0].children[0];
|
||||
const cloneScroller = () => scaler().children[0].children[0].children[0];
|
||||
const page = () => scaler().children[0];
|
||||
view.show(500, 400);
|
||||
view.hide();
|
||||
scroller.scrollTop = 0; // 0 에서 켬 → 스크롤 칸으로 잡힘
|
||||
|
||||
@@ -23,7 +23,7 @@ const mass = read("B05_Profile", "B05_Profile_UI_Profile_MassHaul.ts");
|
||||
let stored = null;
|
||||
const src = [
|
||||
'const SERIES_BASES = ["cross", "longitudinal"];',
|
||||
'const DEFAULT_VISIBLE = ["cross"];',
|
||||
'const DEFAULT_VISIBLE = ["cross", "balance"];', // 367-1 기본 = 횡단 + 분배
|
||||
block(util, "export function normalizeVisibleBasis("),
|
||||
block(mass, "function readVisible(): Set<string> {"),
|
||||
block(util, "export function computeMassHaulSeries("),
|
||||
|
||||
@@ -115,6 +115,38 @@ def test_Backspace_와_Esc_취소(out):
|
||||
assert out["enterOutsideDrawing"] is False
|
||||
|
||||
|
||||
def test_자유지정_되돌리기_다시하기(out):
|
||||
# 367-3 ⑥ 점 둘 → ↶ → ↷ → 새 클릭이 ↷ 지움 · 큰 이력(apply · close) 안 건드림
|
||||
assert out["undoEmpty"] == {"can": False, "backspace": False}
|
||||
assert out["undo1"] == {"dots": [40, 80], "canRedo": True}
|
||||
assert out["redo1"] == {"dots": [40, 80, 120], "canRedo": False}
|
||||
assert out["newClick"] == {"dots": [40, 80, 100], "canRedo": False}
|
||||
# 한 걸음 = 점 · 시작 · 범위 끝 · 범위 첫 · 같은 세로선 다시 누름은 안 쌓임
|
||||
assert out["undoAll"] == ["drawing:2", "drawing:2", "armed:2", "range:1", "range:0"]
|
||||
assert out["undoApplied"] == 0 and out["undoClosed"] == 0
|
||||
assert out["redoTwice"] == {"phase": "armed", "band": [40, 160]}
|
||||
assert out["resetClears"] == {"undo": False, "redo": False}
|
||||
|
||||
|
||||
def test_적용_막히면_열린_채(out):
|
||||
# 367-3 ⑦ Enter · 끝 세로선 둘 다 apply 시도(2) · close 없음 · 점 그대로
|
||||
assert out["blocked"] == {"tries": 2, "phase": "drawing", "dots": 2, "canUndo": True}
|
||||
|
||||
|
||||
def test_되돌리기_배선_자유지정_먼저():
|
||||
panel = _read("B05_Profile/B05_Profile_UI_Profile_Panel_Tools.ts")
|
||||
assert 'tools.mode() === "free" ? (free.undo(), freeView.redraw()) : inner.undo()' in panel
|
||||
assert 'tools.mode() === "free" ? free.canUndo() : inner.canUndo()' in panel
|
||||
keys = panel[panel.index('isCtrlKey(event, "z") || isCtrlKey(event, "y")') :]
|
||||
free_at = keys.index('if (tools.mode() === "free") {')
|
||||
assert (
|
||||
free_at < keys.index("history.undo()")
|
||||
and "return;" in keys[free_at : keys.index("flushHold();")]
|
||||
)
|
||||
profile = _read("A00_Common/design/design_profile.ts")
|
||||
assert "function applyEdits(next: AlignmentEdits): boolean {" in profile
|
||||
|
||||
|
||||
def test_도구줄_직선화_오른쪽_자유지정():
|
||||
tools = _read("B05_Profile/B05_Profile_UI_Profile_Tools.ts")
|
||||
assert '"자유지정"' in tools
|
||||
@@ -142,6 +174,28 @@ def test_오버레이_점선_빨강_글():
|
||||
assert ".b05-profile-freemark__line.is-over" in css
|
||||
|
||||
|
||||
def _css_rule(css: str, selector: str) -> str:
|
||||
at = css.index(selector + " {")
|
||||
return css[at : css.index("}", at)]
|
||||
|
||||
|
||||
def test_자유지정_녹색_넘음_빨강_띠_보라():
|
||||
# 367-4 선 · 미리 보기 · 점 = --color-success · 넘음 빨강 · 범위 띠 · 경계 보라 그대로
|
||||
css = _read("B05_Profile/B05_Profile_UI_Style_Table.css")
|
||||
assert "stroke: var(--color-success);" in _css_rule(css, ".b05-profile-freemark__line")
|
||||
assert "stroke: var(--color-success);" in _css_rule(css, ".b05-profile-freemark__dot")
|
||||
assert "var(--color-danger" in _css_rule(css, ".b05-profile-freemark__line.is-over")
|
||||
assert "var(--color-danger" in _css_rule(css, ".b05-profile-freemark__grade.is-over")
|
||||
assert "--color-primary" in _css_rule(css, ".b05-profile-freemark__band")
|
||||
assert "--color-primary" in _css_rule(css, ".b05-profile-freemark__edge")
|
||||
# 밝음 · 어두움(명시 · OS 자동) 모두 success · danger 토큰 있음
|
||||
theme = _read("ui_template/ui_template_theme.css")
|
||||
auto = theme[theme.index("@media (prefers-color-scheme: dark)") :]
|
||||
auto = auto[: auto.index("\n}\n")]
|
||||
for block in (_css_rule(theme, ":root"), _css_rule(theme, ':root[data-theme="dark"]'), auto):
|
||||
assert "--color-success:" in block and "--color-danger:" in block
|
||||
|
||||
|
||||
def test_줄_수_늘리지_않음():
|
||||
for relative in (
|
||||
"A00_Common/design/design_profile.ts",
|
||||
|
||||
@@ -162,6 +162,26 @@ def test_바뀌면_0_5초_뒤_다시_뜸_끄면_복제_지움(r):
|
||||
assert h["hidden"] and h["disconnected"] and h["scrollListen"] is False
|
||||
assert h["noRecaptureAfterHide"] == 0
|
||||
assert h["reuseRoot"] == 2 # 원 · 배율 글 하나씩을 다시 씀
|
||||
assert h["bodyUntouched"] == 6 # 원 · 글은 html 바로 아래 — body 복제 · 관찰에 안 걸림(374-1)
|
||||
|
||||
|
||||
def test_움직이는_동안_안_뜸_멈춘_뒤_한_번(r):
|
||||
# 374-1 디바운스 — 바뀜 뒤 계속 움직이면 안 뜸 · 마지막 움직임 0.5 초 뒤 한 번
|
||||
assert r["debounce"] == {"heldWhileMoving": True, "afterStop": True}
|
||||
# 이동 = 바깥 판 translate 만(합성층) · 배율 = 안쪽 상자
|
||||
assert r["capture"]["stageMoveOnly"] == "translate(-820px, -620px)"
|
||||
css = _read("ui_template/ui_template_loupe.css")
|
||||
stage = css[css.index(".ui-loupe__stage {") :]
|
||||
assert "will-change: transform;" in stage[: stage.index("}")]
|
||||
scale = css[css.index(".ui-loupe__scale {") :]
|
||||
assert "transform-origin: 0 0;" in scale[: scale.index("}")]
|
||||
|
||||
|
||||
def test_뜨는_자리_화면_전체_모달_포함():
|
||||
src = _read("ui_template/ui_template_loupe.ts")
|
||||
assert "sourceOf: () => Element | null = () => win.document.body," in src
|
||||
assert "doc.documentElement.append(root, label);" in src
|
||||
assert 'getElementById("app")' not in src
|
||||
|
||||
|
||||
def test_테두리_그림자_토큰():
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
@@ -65,7 +64,5 @@ def test_끌기도_유토_판_안_셈():
|
||||
|
||||
def test_뗀_유토는_노선_전체_세로():
|
||||
mass = (B05 / "B05_Profile_UI_Profile_MassHaul.ts").read_text(encoding="utf-8")
|
||||
assert re.search(
|
||||
r'viewRange: overlay\.classList\.contains\("is-popout"\) \? undefined : params\.axis\.viewRange',
|
||||
mass,
|
||||
)
|
||||
# 367-1 붙음 · 뗌 모두 노선 전체 세로
|
||||
assert "viewRange: undefined," in mass
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""224-1c(PLAN 325-3) 유토곡선 · 배수유역 [창 분할] — 종단 [창 분할]과 같은 양식 · 따로 새 창.
|
||||
|
||||
- 단추 = 두 판 머리줄 맨 앞(유토는 접어도 남는 머리줄 · 354-1) · 글 [창 분할]/[창 결합] · 툴팁에 판 이름.
|
||||
- 단추 = 두 판 머리줄 맨 앞(유토는 펼친 때만 보임 · 367-2) · 글 [창 분할]/[창 결합] · 툴팁에 판 이름.
|
||||
- 창 이름 셋 다름(같으면 앞 창 body 를 덮어 조각이 사라짐).
|
||||
- 뗌 = 새 창 body · 뗀 유토 판 손잡이 · 리사이저는 CSS 로 감춤 · 배수 지도 관찰 rehome.
|
||||
- 붙임(단추 · 새 창 닫힘 · 페이지 떠남) = 제자리 — 종단 열 끝(종단 칸 아래) · 배수 content 끝.
|
||||
|
||||
@@ -48,7 +48,9 @@ def test_Ctrl_Z_는_사진첩_한_줄(out):
|
||||
def test_종단도_Ctrl_Z_줄이_사진첩_하나():
|
||||
tools = _read("B05_Profile/B05_Profile_UI_Profile_Panel_Tools.ts")
|
||||
at = tools.index('if (isCtrlKey(event, "z") || isCtrlKey(event, "y")) {')
|
||||
assert "undoOwner" not in tools and "history.undo()" in tools[at : at + 240]
|
||||
assert (
|
||||
"undoOwner" not in tools and "history.undo()" in tools[at : at + 600]
|
||||
) # 367-3 자유지정 분기 앞에 섬
|
||||
history = _read("B05_Profile/B05_Profile_UI_RouteEdit_History.ts")
|
||||
assert '"keydown"' not in history and "onPageHistory" in history
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
- 종단 열(`b05-route-profile__column`) = [종단 칸(bodyWrap), 유토 판] · content 안이라 종단 [창 분할]
|
||||
(`.is-popout > :not(content)` 숨김)에도 같이 감 · B05 · B06 이 같은 `design_profile` 하나.
|
||||
- 유토 판은 흐름 칸(겹침 아님) · 자기 리사이저 높이 · 접으면 머리줄만(손잡이 · [창 분할] 닿음).
|
||||
- 높이 나눔 · 표 쌓기에서 빠짐(표 bottomOffset 없음) · X 동기화는 그대로.
|
||||
- 유토 판은 흐름 칸(겹침 아님) · 자기 리사이저 높이 · 접으면 높이 0 · 손잡이만 매달림 · [창 분할] 숨김(367-2).
|
||||
- 높이 나눔 · 표 쌓기에서 빠짐(표 bottomOffset 없음) · X 동기화 없음(367-1 늘 전체 맞춤).
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -30,7 +30,7 @@ def test_종단_열_아래_자기_칸():
|
||||
assert 'column.className = "b05-route-profile__column";' in overlays
|
||||
assert "column.append(bodyWrap, massHaul.overlay);" in overlays
|
||||
assert "bodyWrap.append(massHaul.overlay" not in overlays
|
||||
assert "massHaul.attachScrollSync(body);" in overlays
|
||||
assert "massHaul.attachScrollSync" not in overlays # 367-1 측점 연계 없앰
|
||||
profile = read("A00_Common/design/design_profile.ts")
|
||||
assert "content.append(column);" in profile
|
||||
assert sum(1 for _ in profile.splitlines()) <= 700
|
||||
@@ -57,6 +57,18 @@ def test_흐름_칸_자기_높이_접으면_머리줄():
|
||||
".b05-profile__masshaul-overlay.is-collapsed:not(.is-popout) > :not(.b05-profile__masshaul-head)",
|
||||
)
|
||||
assert "display: none;" in hide
|
||||
# 367-2 접음 = 높이 0 · 손잡이 판 위 경계에 매달림 · [창 분할] 숨김(뗀 창 [창 결합] 그대로)
|
||||
folded = css_block(css, ".b05-profile__masshaul-overlay.is-collapsed:not(.is-popout)")
|
||||
assert "height: 0;" in folded
|
||||
head = css_block(
|
||||
css,
|
||||
".b05-profile__masshaul-overlay.is-collapsed:not(.is-popout) > .b05-profile__masshaul-head",
|
||||
)
|
||||
assert "top: auto;" in head and "bottom: 100%;" in head
|
||||
assert "display: none;" in css_block(
|
||||
css, ".b05-profile__masshaul-overlay.is-collapsed:not(.is-popout) .b05-subpanel__popout"
|
||||
)
|
||||
assert ".is-popout .b05-subpanel__popout" not in css
|
||||
assert "display: none;" in css_block(
|
||||
css, ".b05-route-profile.is-collapsed .b05-profile__masshaul-overlay"
|
||||
)
|
||||
|
||||
@@ -37,7 +37,7 @@ def test_저장된_종단_범례는_횡단으로(r):
|
||||
assert r["longitudinal"] == ["cross"]
|
||||
assert r["longitudinalBalance"] == ["balance", "cross"]
|
||||
assert r["cross"] == ["cross"]
|
||||
assert r["empty"] == ["cross"] and r["broken"] == ["cross"]
|
||||
assert r["empty"] == ["balance", "cross"] and r["broken"] == ["balance", "cross"]
|
||||
|
||||
|
||||
def test_기준_횡단만_계산(r):
|
||||
|
||||
@@ -4,14 +4,13 @@
|
||||
- 메아리: scroll 은 다음 틀에 옴 → 동기 플래그로 못 막아 한 틀 전 값을 되씀 → 뒤로 튐 →
|
||||
휠 이동이 접힘. 공용 `linkScrollLeft`(Wheel.ts)가 써 넣은 값으로 온 scroll 을 무시.
|
||||
가짜 창(다음 틀 scroll) 재현 — 옛 잇기는 뒤로 튐 · 멈춤, 새 잇기는 4 경우 × 휠 쪽 둘 모두 튐 0.
|
||||
- 유토 스크롤 그리기 = 열림 · 분배 맞춤 아님 · 붙음일 때만 · 한 틀 한 번 · 다시 셈 없음.
|
||||
- 유토곡선 = 늘 전체 맞춤 · 종단과 안 이음(367-1) — 휠 · 잇기 경우는 공용 도우미 시험으로 남김.
|
||||
|
||||
`helper_354_3_scroll_echo.cjs` 가 진짜 휠 · 잇기 TS 를 가짜 창 위에서 돌림.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
@@ -64,24 +63,25 @@ def test_새_잇기는_뒤로_튐_0_끝까지(r, case):
|
||||
assert got["mass"] == (0 if balance else 1200)
|
||||
|
||||
|
||||
def test_유토_표_같은_도우미():
|
||||
for name in ("MassHaul", "TableOverlay"):
|
||||
src = (B05 / f"B05_Profile_UI_Profile_{name}.ts").read_text(encoding="utf-8")
|
||||
assert "linkScrollLeft(main, scroll" in src
|
||||
assert "syncing" not in src
|
||||
|
||||
|
||||
def test_유토_스크롤_그리기는_창_따를_때만_한_틀_한_번():
|
||||
def test_표만_잇기_유토는_안_이음():
|
||||
# 367-1 유토곡선 = 늘 전체 맞춤 · 종단 스크롤과 안 이음
|
||||
table = (B05 / "B05_Profile_UI_Profile_TableOverlay.ts").read_text(encoding="utf-8")
|
||||
assert "linkScrollLeft(main, scroll" in table
|
||||
assert "syncing" not in table
|
||||
mass = (B05 / "B05_Profile_UI_Profile_MassHaul.ts").read_text(encoding="utf-8")
|
||||
body = mass[mass.index("function drawWindow(") :]
|
||||
body = body[: body.index("\n }\n")]
|
||||
assert '!open || fitted || overlay.classList.contains("is-popout") || !lastSeries' in body
|
||||
assert "windowState.frame" in body and "frameOf(overlay" in body
|
||||
assert "draw(lastParams, true)" in body
|
||||
# 다시 셈 없음 · 총괄값 · 범례는 계열이 바뀔 때만
|
||||
assert re.search(r"reuse && lastSeries\s*\? lastSeries", mass)
|
||||
for gone in ("linkScrollLeft", "attachWheelHorizontalScroll", "attachScrollSync", "drawWindow"):
|
||||
assert gone not in mass, gone
|
||||
|
||||
|
||||
def test_유토는_늘_전체_맞춤_스크롤마다_안_그림():
|
||||
mass = (B05 / "B05_Profile_UI_Profile_MassHaul.ts").read_text(encoding="utf-8")
|
||||
assert "hideStations: true," in mass
|
||||
assert "viewRange: undefined," in mass
|
||||
assert "scroll.scrollLeft = 0;" in mass
|
||||
assert "createMassHaulWindowState" not in mass and "scheduleMassHaulSettle" not in mass
|
||||
assert "if (series !== lastSeries) emitSummary(series);" in mass
|
||||
# 다시 그려도 제 자리 — 종단 값으로 되쓰는 것은 처음 · 맞춤 뒤 · 창 옮김 뒤만
|
||||
assert "scroll.scrollLeft = syncedMain.scrollLeft" not in mass
|
||||
render = (B05 / "B05_Profile_UI_Profile_Render.ts").read_text(encoding="utf-8")
|
||||
assert "massHaul.drawWindow({" in render
|
||||
assert "drawWindow" not in render and "massHaulUpdater" not in render
|
||||
css = (B05 / "B05_Profile_UI_Style_MassHaul.css").read_text(encoding="utf-8")
|
||||
block = css[css.index(".b05-profile__masshaul-scroll {") :]
|
||||
assert "overflow-x: hidden;" in block[: block.index("}")]
|
||||
|
||||
Reference in New Issue
Block a user