revert(802-1): 801-1 wip 옛 나무 위 고침 걷음 — 요구 664 수식 문서로 다시 짬

- 걷음: 43784a4c0 의 옛 수식 나무 위 고침(서버 · 화면 · css) = 그 앞 판으로 되돌림
- 남김: master_equation_sign.py · ui_template_equation_text.ts · ui_template_equation_edit.ts(다시 쓸 조각 · 지금 안 부름) · text 는 `입력글` 을 제 타입에
- 지움: test_801_1_equation_inline.py — 걷은 옛 나무 고침을 재는 시험

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-07 17:55:58 +09:00
co-authored by Claude Opus 5.5
parent 6c7618c54a
commit 2376e70fbb
11 changed files with 100 additions and 456 deletions
-14
View File
@@ -44,23 +44,9 @@ def _typed(eq: dict, row: dict) -> dict:
for line in eq.get("줄") or []:
if line.get("식"):
line["입력글"] = me.keyboard_of(fx.to_name(str(line["식"]), row), row)
_atoms(line.get("이름식"), lambda raw: me.keyboard_of(fx.to_name(raw, row), row))
return eq
def _atoms(tree, word) -> None:
"""식 속 표 찾기 · 요소 · 로직 부름 마디 `입력글` = 키보드 글(801 그 자리 고침 · 블록 속 나무 빼고)."""
if isinstance(tree, dict):
if tree.get("식") and (tree.get("꼴") == "블록" or tree.get("갈래") in ("찾기", "요소")):
tree["입력글"] = word(str(tree["식"]))
for k, v in tree.items():
if k != "나무":
_atoms(v, word)
elif isinstance(tree, list):
for v in tree:
_atoms(v, word)
def export_row(whole, row: dict, inputs: dict | None = None) -> dict:
"""로직 줄(정본 · 사본) → 수식 — 마스터에 그 줄을 얹어 셈."""
eq = meq.export(me.swap(whole, row), str(row.get("키")), _given(inputs))
@@ -4,9 +4,7 @@
* 그림 = 공통 수식 부품(`ui_template_equation*.ts`) · 서버 나무 = `POST /api/m01/logic/equation`(796-1)
* 위 = 옵션 가로(도구줄 + 값 칸 · 바꾸면 다시 셈) · 합계 · 고침 도구(시스템 관리자만)
* 배치(800-2) = 왼쪽 수식 영역(줄 구분 없이 식이 이어짐 + 소계 표) · 오른쪽 변수 정의 영역(고른 옵션 갈래의 변수만 · 값 · 단위 · DB 열쇠 없음)
* 고침(801) = 보이는 조판 식 그 자리에서(`ui_template_equation_edit` · 칠 때마다 `/equation/preview` 검사 · 틀리면 그 자리 빨강 + 까닭)
* · 값 식 숫자 = 그 변수 값(`valueEdit` — 입력 = 옵션 값 · 중간 = 그 줄 식 · 수 · 표 찾기 · 요소 = 이 식의 그 자리 수)
* · 기호를 누르면 정의 줄이 열림(이름 · 기호 · 첨자 · 계산 변수는 연결 바꿈)
* 고침(800-3) = 수식 영역의 식 칸을 눌러 그 자리에서(공용 `sheet_formula_cell` · 칠 때마다 `/equation/preview` 검사 · 틀리면 그 자리 빨강 + 까닭)
* · 새 기호를 쓰면 정의 영역에 그 기호 줄이 생겨 연결 지정(`_EquationDefs` · 고침 `연결`) · 이름 · 기호 · 첨자 고침 · 지움도 정의 줄에서
* · 고친 목록(`edits`)은 캐시(sessionStorage)에 쌓고 [저장] 한 번에 `/equation/save`(개정 확인)
* 계산 자리 = 서버 한 벌(③) — 화면은 고침 목록만 보내고 서버가 다시 셈한 나무를 다시 그림(옛 요청 끊음)
@@ -28,6 +26,7 @@ import {
type EqNode,
type EqTree,
} from "@ui/ui_template_equation";
import { lineId } from "@ui/ui_template_equation_line";
import {
el,
hideLoadingOverlay,
@@ -39,8 +38,7 @@ import { createInputField } from "@ui/ui_template_input";
import { currentLanguageIndex } from "@ui/ui_template_locale";
import { createText } from "@ui/ui_template_text";
import { createToolbar } from "@ui/ui_template_toolbar";
import type { FormulaVerdict } from "../A00_Common/sheet_formula_cell";
import { editEq } from "@ui/ui_template_equation_edit";
import { createFormulaCell, type FormulaVerdict } from "../A00_Common/sheet_formula_cell";
import { createValueControl } from "../M02_MasterTemplete/M02_Labor_Values";
import type { ItemInput } from "../M02_MasterTemplete/M02_MasterTemplete_Api_Fetch";
import { ApiError, type LogicRow } from "./M01_MasterData_UI_Logic_Api";
@@ -52,13 +50,7 @@ import {
} from "./M01_MasterData_UI_LogicLab_EquationDefs";
import { openAddDialog } from "./M01_MasterData_UI_LogicLab_EquationVar";
import { saveRevised } from "./M01_MasterData_UI_LogicLab_Revise";
import {
formulaEdit,
inputsOf,
unknownOf,
valueEdit,
type EqEdit,
} from "./logic/M01_Logic_Equation_Model";
import { formulaEdit, inputsOf, unknownOf, type EqEdit } from "./logic/M01_Logic_Equation_Model";
import "./M01_MasterData_UI_LogicLab_Equation.css";
const TEXT = {
@@ -78,8 +70,8 @@ const TEXT = {
Options: ["옵션", "Options"],
Wait: ["수식을 불러오는 중", "Loading equation"],
Hint: [
"식을 눌러 그 자리 고침(+ − × ÷ / ( ) _ ^ · Enter 넣음 · Esc 버림) · 기호 = 연결 · 숫자 = 값",
"Click a formula to edit in place · symbol = link · number = value",
"식을 눌러 바로 고침 · 키보드 + − × ÷ / ( )",
"Click a formula to edit · keyboard + − × ÷ / ( )",
],
Apply: ["연결 적용 · 식 넣기", "Apply links and formula"],
Leave: ["저장 안 한 수식 고침 {n} 건 — 버리고 나감?", "Discard {n} unsaved equation edits?"],
@@ -179,7 +171,6 @@ export function createLabEquation(opt: LabEquationOptions) {
let before: Record<string, unknown> | null = null;
let why = "";
let editingLine: string | null = null;
let editAt: { x: number; y: number } | null = null;
let defEditing: string | null = null;
let pending: PendingLink | null = null;
let defsBox: HTMLElement = el("div");
@@ -187,6 +178,7 @@ export function createLabEquation(opt: LabEquationOptions) {
let timer = 0;
let paintedBlocked = false;
const open = new Set<string>();
const drafts = new Map<string, string>();
const canEdit = (): boolean => opt.admin && !opt.blocked();
const page = opt.page;
const vals = (): Record<string, string> => page?.values() ?? inputs;
@@ -415,6 +407,7 @@ export function createLabEquation(opt: LabEquationOptions) {
if (missing) return;
const bad = await commit([...list, formulaEdit(p.line, p.text)]);
if (bad.length) return [...p.rows.values()].forEach((d) => d.say(bad.join(" · ")));
drafts.delete(lineId(p.line));
[pending, editingLine] = [null, null];
paint();
}
@@ -440,66 +433,43 @@ export function createLabEquation(opt: LabEquationOptions) {
};
};
/** 수식 영역 — 그린 식 그 자리 고침 · 칠 때마다 미리 셈 · Enter = 고침 목록에 굳힘 */
function editor(line: EqLine, _id: string, host: HTMLElement): void {
const say = el("span", { className: "ui-eq__bad" });
host.closest(".ui-eq__name")?.after(say);
/** 수식 영역의 식 칸 자리에 들어가는 식 칸 — 바꾸면 미리 셈 · 되면 고침 목록에 굳힘 */
function editor(line: EqLine, id: string): HTMLElement {
const shown = line.입력글 ?? line.식;
const close = (): void => {
[editingLine, pending] = [null, null];
paint();
};
const show = (ok: boolean, list: string[]): void => {
host.dataset.bad = ok ? "" : "1";
say.className = ok ? "ui-eq__note" : "ui-eq__bad";
say.textContent = list.join(" · ");
};
let mine: AbortController | null = null;
editEq(host, {
at: editAt,
onInput: (text) => {
mine?.abort();
const me = (mine = new AbortController());
check(line)(text, me.signal)
.then((v) => me === mine && show(v.되나, (v.되나 ? v.알림 : v.까닭) ?? []))
.catch(() => undefined);
const cell = createFormulaCell({
key: id,
spot: id,
shown,
origin: shown,
drafts,
check: check(line),
put: (text) => {
if (text === null) return pending ? undefined : close();
void commit([formulaEdit(line, text)]).then((bad) => {
if (bad.length) showToast(bad.join(" · "), "error");
else close();
});
},
onCommit: (text) => {
if (pending) return void applyPending();
void commit([formulaEdit(line, text)]).then((bad) =>
bad.length ? show(false, bad) : close(),
);
},
onCancel: () => (pending ? undefined : close()),
className: "m01-eq__fx",
});
const input = cell.querySelector("input");
// 안 바꾸고 다른 데를 누르면 닫음 · 바꾼 글이 있거나 연결 지정 중이면 그대로
cell.addEventListener("focusout", () =>
window.setTimeout(() => {
if (editingLine === id && !pending && !cell.contains(document.activeElement)) {
if ((input?.value.trim() ?? shown) === shown) close();
}
}, 120),
);
queueMicrotask(() => input?.focus());
return cell;
}
/** 값 숫자 고침 — 입력 = 옵션 값 · 그 밖 = 고침 목록 */
function onValue(line: EqLine, leaf: EqNode, text: string): void {
const got = valueEdit(line, leaf, text);
if (typeof got === "string") return showToast(got, "error");
if ("input" in got) {
if (page) return page.setValue(got.input, text);
inputs[got.input] = text;
drawOptions();
return askAgain();
}
void commit(got.edits).then((bad) => bad.length && showToast(bad.join(" · "), "error"));
}
/** 기호를 누름 — 정의 줄로 · 고칠 수 있으면 그 줄 고침 열림 */
function showVar(node: EqNode): void {
const sign = defSign({
기호: node.기호 || node.열쇠 || "",
위: typeof node.위 === "string" ? node.위 : "",
아래: typeof node.아래 === "string" ? node.아래 : "",
});
const def = eq?.정의?.find((d) => defSign(d) === sign);
if (canEdit() && def?.고침 && defEditing !== sign) {
defEditing = sign;
drawDefs();
}
flashEqDef(defsBox, node);
}
const showDef = (node: EqNode): void => flashEqDef(defsBox, node);
// ── 그림 ──────────────────────────────────────────────────────────
function drawBar(): void {
@@ -559,16 +529,15 @@ export function createLabEquation(opt: LabEquationOptions) {
path: "",
open,
resultUnit: eq.결과단위,
onVar: showVar, // 기호 = 정의 줄(연결) · 그 밖 식 자리 = 그 자리 고침
onVar: edit ? undefined : showDef, // 고칠 수 있으면 식 어디를 눌러도 그 자리 고침(변수 칩 포함)
editing: editingLine,
onEdit: edit
? (_line, id, at) => {
[editingLine, editAt] = [id, at];
? (_line, id) => {
editingLine = id;
paint();
}
: undefined,
editor: edit ? editor : undefined,
onValue: edit ? onValue : undefined,
after: (line) => (line.갈래 === "호표" ? (sum?.inline.get(line.열쇠) ?? null) : null),
}),
...(sum ? [sum.tail] : []), // 799-1 · 800-4 묶음 소계 · 끝수 · 합계
@@ -607,6 +576,7 @@ export function createLabEquation(opt: LabEquationOptions) {
async function discard(): Promise<void> {
edits = [];
[editingLine, defEditing, pending] = [null, null, null];
drafts.clear();
persist();
await refresh();
drawOptions();
@@ -625,6 +595,7 @@ export function createLabEquation(opt: LabEquationOptions) {
inputs = {};
edits = page ? page.edits() : (loadCache()[nextKey] ?? []);
open.clear();
drafts.clear();
paint();
drawOptions();
void refresh().then(drawOptions);
@@ -2,12 +2,10 @@
* M01_MasterData/logic/M01_Logic_Equation_Model.ts
* 수식 탭 계산(796-2 · 화면 · fetch 없음) — 줄 → 고침 자리 · 식 칸 아이콘 끼움 · 옵션 값 꼴 · 변수 고침 요청.
* 서버 고침 꼴 = `master_equation_edit.py` 머리(할일 식 · 더함 · 지움 · 변수 · 표시) — 여기서는 요청 목록만 만듦
* 값 숫자 고침(801 · `valueEdit`) = 입력 → 옵션 값 · 중간 → 그 줄 식 = 그 수 · 수 · 표 찾기 · 요소 → 이 줄 식의 그 자리 = 그 수
* 셈 · 검사는 서버 한 벌(③ 서버 단독) — 브라우저는 모양만
* ========================================================================== */
import type { EqLine, EqNode } from "@ui/ui_template_equation";
import { textOf } from "@ui/ui_template_equation_text";
import type { EqLine } from "@ui/ui_template_equation";
export interface EqEdit {
할일: "식" | "더함" | "지움" | "변수" | "표시" | "연결";
@@ -123,17 +121,3 @@ export function unknownOf(reasons: string[]): string[] {
}
return [];
}
/** 값 식 숫자 고침 → 옵션 값(입력) | 고침 목록 | 까닭 글 */
export function valueEdit(
line: EqLine,
leaf: EqNode,
text: string,
): { input: string } | { edits: EqEdit[] } | string {
if (!/^-?\d+(\.\d+)?$/.test(text)) return "값은 수로 적을 것";
if (leaf.꼴 === "변수" && leaf.갈래 === "입력") return { input: leaf.열쇠 ?? "" };
if (leaf.꼴 === "변수" && leaf.갈래 === "중간")
return { edits: [{ 할일: "식", 자리: `중간:${leaf.열쇠 ?? ""}`, 식: text }] };
const tree = line.갈래 === "호표" ? line.이름식?.우 : line.이름식; // 호표 식 = 수량 쪽
return { edits: [formulaEdit(line, textOf(tree, new Map([[leaf, text]])))] };
}