- 수식 영역 줄 번호 · 구분선 · 줄마다 풀이 걷음 · 오른쪽 변수 정의 영역 부품 ui_template_equation_defs - 식 칸을 눌러 그 자리 고침(줄 선택 · 아이콘 줄 걷음) · 틀린 식 그 자리 빨강 + 까닭 · 미리 셈 - 새 기호 = 정의 영역 맨 위 줄에서 연결(입력 · 표 · 요소 · 로직 · 상수) · 이름 · 기호 · 첨자 고침 · 지움(쓰는 변수 막음) - 낡은 시험 test_796_2_equation_screen 두 건: 아이콘 줄 · 줄 선택 고침 → 바로 고침 꼴로 바꿈(동작 걷음) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
94 lines
4.4 KiB
TypeScript
94 lines
4.4 KiB
TypeScript
/* =============================================================================
|
|
* ui_template_equation_defs.ts
|
|
* 부품 「수식」 넷째 파일(800-2 · 요구 660-2 · 3 · 6) — 오른쪽 「변수 정의 영역」.
|
|
* 한 덩어리 목록 · 같은 기호는 한 줄(서버가 합침) · 줄 = 기호 : 국문 이름 — 연결 설명(입력 · 표 찾기 · 요소 · 로직 · 계산을 사람 말로)
|
|
* 값 · 단위 · DB 열쇠 글은 안 그림(값은 왼쪽 값 식에 있음) · 고른 옵션 갈래의 변수만(서버 `정의`)
|
|
* 상태 = 고침 열린 줄 `data-editing`(줄 아래 `editor` 칸) · 연결 안 한 새 기호 줄 `data-draft`(`drafts` 요소 — 부르는 쪽이 만듦) · 눌러 보인 줄 `data-flash`
|
|
* 쓰는 법 = `createEqDefs(defs, { editing, onEdit, editor, drafts, head })` → 요소 · `flashEqDef(root, node)` = 식의 변수를 눌렀을 때 그 정의 줄로 이동
|
|
* ========================================================================== */
|
|
|
|
import { symbolOf, type EqDef, type EqNode } from "./ui_template_equation";
|
|
|
|
export interface EqDefsOptions {
|
|
/** 고침이 열린 정의의 기호 글(`defSign`) */
|
|
editing?: string | null;
|
|
/** 정의 줄을 누름(없으면 고칠 수 없음 — 고침 가능한 줄만 눌림) */
|
|
onEdit?: (def: EqDef) => void;
|
|
/** 고침이 열린 줄 아래 칸 */
|
|
editor?: (def: EqDef) => HTMLElement;
|
|
/** 연결을 지정할 새 기호 줄들 */
|
|
drafts?: HTMLElement[];
|
|
/** 머리 오른쪽 단추 자리 */
|
|
head?: HTMLElement[];
|
|
}
|
|
|
|
const node = (tag: "div" | "span", className: string, text = ""): HTMLElement => {
|
|
const out = document.createElement(tag);
|
|
out.className = className;
|
|
if (text) out.textContent = text;
|
|
return out;
|
|
};
|
|
|
|
/** 정의의 기호 글(기호 · 아래 · 위) — 줄 이름표 · 식의 변수와 맞대는 열쇠 */
|
|
export const defSign = (d: Pick<EqDef, "기호" | "위" | "아래">): string =>
|
|
`${d.기호}${d.아래 ? `_${d.아래}` : ""}${d.위 ? `^${d.위}` : ""}`;
|
|
|
|
/** 식 변수 마디의 기호 글 — `defSign` 과 같은 꼴 */
|
|
export const nodeSign = (n: Pick<EqNode, "기호" | "열쇠" | "위" | "아래">): string =>
|
|
defSign({
|
|
기호: n.기호 || n.열쇠 || "",
|
|
위: typeof n.위 === "string" ? n.위 : "",
|
|
아래: typeof n.아래 === "string" ? n.아래 : "",
|
|
});
|
|
|
|
function defRow(d: EqDef, o: EqDefsOptions): HTMLElement {
|
|
const sign = defSign(d);
|
|
const row = node("div", "ui-eq__def");
|
|
row.dataset.eqDef = sign;
|
|
row.dataset.kind = d.갈래;
|
|
const main = node("div", "ui-eq__def-main");
|
|
main.append(symbolOf({ 열쇠: d.열쇠, 기호: d.기호, 위: d.위, 아래: d.아래 }));
|
|
if (d.이름 && d.이름 !== d.기호)
|
|
main.append(node("span", "ui-eq__op", ":"), node("span", "ui-eq__def-name", d.이름));
|
|
if (d.안씀) main.append(node("span", "ui-eq__def-tag", "쓰는 식 없음"));
|
|
const links = node("div", "ui-eq__def-links");
|
|
for (const text of d.연결) links.append(node("div", "ui-eq__def-link", text));
|
|
const top = node("div", "ui-eq__def-top", "");
|
|
top.append(main, links);
|
|
if (o.onEdit && d.고침) {
|
|
row.classList.add("is-pick");
|
|
top.title = "눌러서 이름 · 기호 · 첨자 고침 · 지움";
|
|
top.addEventListener("click", () => o.onEdit?.(d));
|
|
}
|
|
row.append(top);
|
|
if (o.editing === sign && o.editor) {
|
|
row.dataset.editing = "1";
|
|
row.append(o.editor(d));
|
|
}
|
|
return row;
|
|
}
|
|
|
|
export function createEqDefs(defs: EqDef[], o: EqDefsOptions = {}): HTMLElement {
|
|
const root = node("div", "ui-eq__defs");
|
|
root.dataset.eqDefs = "";
|
|
const head = node("div", "ui-eq__defs-head");
|
|
head.append(node("span", "ui-eq__defs-title", "변수 정의"), ...(o.head ?? []));
|
|
root.append(head);
|
|
for (const draft of o.drafts ?? []) root.append(draft); // 새 기호는 맨 위 — 식을 고치는 곳 옆에서 바로 보이게
|
|
for (const d of defs) root.append(defRow(d, o));
|
|
if (!defs.length && !o.drafts?.length) root.append(node("div", "ui-eq__def-empty", "—"));
|
|
return root;
|
|
}
|
|
|
|
/** 식의 변수를 눌렀을 때 — 그 정의 줄로 이동 · 잠깐 표시 */
|
|
export function flashEqDef(root: HTMLElement, n: EqNode): void {
|
|
const sign = nodeSign(n);
|
|
const row = [...root.querySelectorAll<HTMLElement>("[data-eq-def]")].find(
|
|
(r) => r.dataset.eqDef === sign,
|
|
);
|
|
if (!row) return;
|
|
row.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
row.dataset.flash = "1";
|
|
window.setTimeout(() => delete row.dataset.flash, 1200);
|
|
}
|