fix(829-1): 모바일 찾기 칸 되풀이 다시 그리기 — 늦은 옛 응답 덮어쓰기 막음 · 한글 조합 중 검색 보류 · 키보드로 높이만 바뀐 뒤 줄 수 다시 재기 거름

- 원인 셋: ① 목록 불러오기 응답 순서 가드 없음(Rows · Machine · Tables · 복사 고르기 · 고를 재료 판) → 느린 회선에서 앞 글자 응답이 뒤 글자 목록을 덮음 ② 글자 칸 조합마다 input 이 검색을 걸음 ③ 키보드가 뜨고 닫을 때마다 watchFit 이 줄 수를 다시 재 목록을 다시 받아 그림 · 첫 그림 어림(6)과 잰 값(5) 어긋남으로 한 글자에 두 번 받음
- 공용 고침: ui_template_pager(holdForKeyboard · 직전 잰 줄 수 어림) · device_context(찾기 칸 조합 보류) · M01 Rows · Machine · Tables · Page · Pick · LogicLab_Copy
- 시험: test_709_pager_fit 에 holdForKeyboard 1 건 더함

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-13 22:06:27 +09:00
co-authored by Claude Sonnet 5.5
parent af171f67e9
commit a7c48aae9a
9 changed files with 78 additions and 3 deletions
@@ -93,11 +93,14 @@ function openTablePick(onPick: (table: TableHead) => void): void {
});
let timer: number | undefined;
let seq = 0; // 늦게 온 옛 응답은 버림(829-1)
const run = async (): Promise<void> => {
const mine = ++seq;
const q = search.input.value.trim();
const pages = await Promise.all(
TABLE_GROUPS.map((group) => fetchTables(group, "", "", q, 1, 20)),
);
if (mine !== seq) return;
const hits = pages.flatMap((p) => p.tables);
list.replaceChildren(
...(hits.length
+6 -1
View File
@@ -148,9 +148,13 @@ export function renderMachines(
void load();
};
let ticket = 0; // 늦게 온 옛 응답이 새 목록을 덮지 않게(829-1)
const load = async (): Promise<void> => {
const mine = ++ticket;
try {
data = await fetchRows(file, page, size, q, false, pick.sub, pick.detail, pick.state);
const got = await fetchRows(file, page, size, q, false, pick.sub, pick.detail, pick.state);
if (mine !== ticket) return;
data = got;
saveView(pick.group, { page: data.page });
paint();
void fillHourly(data.rows.map((r) => String(r["키"])));
@@ -172,6 +176,7 @@ export function renderMachines(
const off = onDraftChange(paint);
void load();
return () => {
ticket++;
fit.stop();
off();
};
+3 -1
View File
@@ -216,7 +216,9 @@ function buildPage(): HTMLElement {
search.addEventListener("input", () => {
window.clearTimeout(searchTimer);
searchTimer = window.setTimeout(() => {
query = search.value.trim();
const next = search.value.trim();
if (next === query) return; // 같은 글이면 목록을 다시 받지 않음(829-1)
query = next;
if (current) openFile(current);
}, 300);
});
+3
View File
@@ -96,10 +96,13 @@ export function openPickModal(opt: PickOptions): void {
);
};
let timer: number | undefined;
let seq = 0; // 늦게 온 옛 응답은 버림(829-1)
const run = async (fallback = false): Promise<void> => {
const mine = ++seq;
try {
const q = search.value.trim();
const r = await fetchPick(opt.kind, q);
if (mine !== seq) return;
if (!r.total && fallback && q.includes(" ")) {
search.value = q.split(/\s+/)[0];
return run();
+6 -1
View File
@@ -111,6 +111,7 @@ export function renderRows(
let scrolled = false;
let data: RowsPage | null = null;
let unlinked = false;
let ticket = 0; // 늦게 온 옛 응답이 새 목록을 덮지 않게(829-1)
const paint = (): void => {
if (!data) return;
@@ -270,8 +271,11 @@ export function renderRows(
};
const load = async (): Promise<void> => {
const mine = ++ticket;
try {
data = await fetchRows(file, page, size, q, unlinked, sub, detail, state);
const got = await fetchRows(file, page, size, q, unlinked, sub, detail, state);
if (mine !== ticket) return;
data = got;
for (const [key, name] of Object.entries(data.refs ?? {})) names.set(key, name);
saveView(pick.group, { page: data.page });
paint();
@@ -293,6 +297,7 @@ export function renderRows(
const off = onDraftChange(paint);
void load();
return () => {
ticket++;
fit.stop();
off();
};
@@ -49,10 +49,12 @@ export function renderTables(
let usage = pick.view?.usage ?? "";
let size = guessRows(host, FILTER_H); // 화면 높이로 셈 — 그린 뒤 다시 재서 어긋나면 바로잡음
let at = 0; // 목록을 보고 있는 쪽(0 = 표 하나를 보는 중)
let gen = 0; // 늦게 온 옛 응답이 새 목록을 덮지 않게(829-1)
const list = (page = pick.view?.page ?? 1): void => {
stop();
stop = (): void => {};
at = page;
const mine = ++gen;
void showList(
host,
pick,
@@ -70,6 +72,7 @@ export function renderTables(
saveView(pick.group, { usage, page: 1 });
list(1);
},
() => mine !== gen,
).then(() => fit.ask());
};
const fit = watchFit(
@@ -85,6 +88,7 @@ export function renderTables(
list();
const off = onDraftChange(() => host.querySelector(".m01-master__tables") && markChanged(host));
return () => {
gen++;
fit.stop();
stop();
off();
@@ -109,10 +113,12 @@ async function showList(
goPage: (page: number) => void,
open: (file: string, key: string) => void,
onUsageChange: (usage: string) => void,
stale: () => boolean,
): Promise<void> {
let got: { total: number; tables: TableHead[] };
try {
got = await fetchTables(pick.group, pick.sub, pick.detail, q, page, size, usage);
if (stale()) return;
} catch (error) {
showToast(error instanceof Error ? error.message : L("M01_LoadFailed"), "error");
return;