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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user