feat(spreadsheet): D 잇기 — 데이터 메뉴(조건부 서식 · 유효성 · 이름 · 눈금선) · 유효성 검사 · 이름 상자 · 여러 범위
- spreadsheet_data_menu.ts(새) — [↑] [↓] [필터] [데이터 ▾] · 패널 창(sub4 조건부 서식 · 유효성 · 이름 관리) · 눈금선 · 유효성 목록 ▼ · Alt+↓ - spreadsheet_editor.ts — 확정 때 유효성 검사(막음 = 편집 유지 · 경고 = 알림) · 주소 상자에 이름 = 그 범위로 · 새 이름 = 지금 고름에 정의 - spreadsheet_mouse.ts · spreadsheet_selection.ts — Ctrl+누르기 여러 범위 · Shift 는 마지막 범위 - spreadsheet_keys.ts · spreadsheet.ts — 유효성에 막히면 이동 · 시트 바꿈 멈춤 - spreadsheet_extras.ts — 정렬 · 필터를 데이터 메뉴로 옮김 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6KXAabDTenEU7hrDQmCKY
This commit is contained in:
@@ -8,12 +8,14 @@
|
||||
* 수식 입력줄(방향키가 글자 사이를 옮김). F2 가 둘을 바꿈.
|
||||
* ========================================================================== */
|
||||
|
||||
import { el } from "@ui/ui_template_elements";
|
||||
import { el, showToast } from "@ui/ui_template_elements";
|
||||
import { moveFormula } from "./spreadsheet_refshift";
|
||||
import { colName, parseA1, parseRange, rangeToA1, toA1 } from "./spreadsheet_address";
|
||||
import { funcHelp, suggestFunctions, type FuncHelp } from "./spreadsheet_func_help";
|
||||
import { defineName, resolveName } from "./spreadsheet_names";
|
||||
import { tokenize } from "./spreadsheet_parser";
|
||||
import { cellsOf, move, selectCell } from "./spreadsheet_selection";
|
||||
import { checkValue, findValidation } from "./spreadsheet_validation";
|
||||
import type { Cell, CellAddress, CellStyle, Sheet } from "./spreadsheet_types";
|
||||
import type {
|
||||
CellBox,
|
||||
@@ -329,10 +331,12 @@ export function createEditor(ctx: SpreadsheetContext): Editor {
|
||||
focus();
|
||||
}
|
||||
|
||||
function write(cells: CellAddress[], value: string, from: CellAddress): void {
|
||||
if (!st) return;
|
||||
/** 칸에 적음 — 유효성(sub4) 「막음」 을 어기면 안 적고 false(편집 그대로 · 엑셀처럼 다시 치게) */
|
||||
function write(cells: CellAddress[], value: string, from: CellAddress): boolean {
|
||||
if (!st) return true;
|
||||
const sheet = sheetOf(st.sheet);
|
||||
const out: Record<string, Cell | null> = {};
|
||||
const warn = new Set<string>();
|
||||
for (const a of cells) {
|
||||
let v = value;
|
||||
if (v.length > 1 && v[0] === "=" && (a.r !== from.r || a.c !== from.c))
|
||||
@@ -340,21 +344,29 @@ export function createEditor(ctx: SpreadsheetContext): Editor {
|
||||
const key = toA1(a.r, a.c);
|
||||
const next = textToCell(v, sheet.칸[key]);
|
||||
if (next === null && !sheet.칸[key]) continue;
|
||||
const rule = next?.값 !== undefined ? findValidation(sheet, a.r, a.c) : undefined;
|
||||
const check = rule && checkValue(rule, next!.값!);
|
||||
if (check && !check.ok) {
|
||||
if (check.어기면 === "막음") return (showToast(check.메시지, "error"), false);
|
||||
warn.add(check.메시지);
|
||||
}
|
||||
out[key] = next;
|
||||
}
|
||||
for (const m of warn) showToast(m, "warning");
|
||||
if (Object.keys(out).length) ctx.dispatch({ 종류: "칸", 시트: sheet.id, 칸: out });
|
||||
return true;
|
||||
}
|
||||
|
||||
function commit(): void {
|
||||
if (!st) return;
|
||||
const value = text();
|
||||
if (value !== st.original) write([st.at], value, st.at);
|
||||
if (value !== st.original && !write([st.at], value, st.at)) return;
|
||||
end();
|
||||
}
|
||||
|
||||
function commitAll(): void {
|
||||
if (!st) return;
|
||||
write(cellsOf(sheetOf(st.sheet), ctx.selection), text(), st.at);
|
||||
if (!write(cellsOf(sheetOf(st.sheet), ctx.selection), text(), st.at)) return;
|
||||
end();
|
||||
}
|
||||
|
||||
@@ -441,6 +453,19 @@ export function createEditor(ctx: SpreadsheetContext): Editor {
|
||||
focus();
|
||||
});
|
||||
|
||||
/** 이름 상자(sub4) — 있는 이름이면 그 범위로 · 없으면 지금 고름에 이름을 붙임(엑셀) */
|
||||
function nameBox(name: string): void {
|
||||
const hit = resolveName(ctx.book, ctx.selection.시트, name);
|
||||
if (hit) {
|
||||
if (hit.시트 !== ctx.selection.시트) ctx.showSheet(hit.시트);
|
||||
const at = { r: hit.범위.r0, c: hit.범위.c0 };
|
||||
return ctx.select({ 시트: hit.시트, 범위: [hit.범위], 활성: at, 기준: { ...at } }, true);
|
||||
}
|
||||
const why = ctx.readOnly ? null : defineName(ctx, name, ctx.selection.범위[0]);
|
||||
if (why) showToast(why, "error");
|
||||
sync();
|
||||
}
|
||||
|
||||
function goTo(value: string): void {
|
||||
const bang = value.lastIndexOf("!");
|
||||
let sheet = ctx.sheet();
|
||||
@@ -454,7 +479,7 @@ export function createEditor(ctx: SpreadsheetContext): Editor {
|
||||
const body = value.slice(bang + 1).replace(/\$/g, "");
|
||||
const one = parseA1(body);
|
||||
const g = parseRange(body);
|
||||
if (!g) return sync();
|
||||
if (!g) return nameBox(value.trim());
|
||||
if (one) return ctx.select(selectCell(sheet, one.r, one.c), true);
|
||||
const at = { r: g.r0, c: g.c0 };
|
||||
ctx.select({ 시트: sheet.id, 범위: [g], 활성: at, 기준: { ...at } }, true);
|
||||
|
||||
Reference in New Issue
Block a user