open-grid 0.4.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/OpenGrid-C6SK6VeK.cjs +90 -0
  2. package/dist/OpenGrid-C6SK6VeK.cjs.map +1 -0
  3. package/dist/OpenGrid-D7EJOVi1.js +4864 -0
  4. package/dist/OpenGrid-D7EJOVi1.js.map +1 -0
  5. package/dist/open-grid-react.cjs +1 -1
  6. package/dist/open-grid-react.js +1 -1
  7. package/dist/open-grid-vue.cjs +1 -1
  8. package/dist/open-grid-vue.js +1 -1
  9. package/dist/open-grid.cjs +1 -1
  10. package/dist/open-grid.js +2 -2
  11. package/dist/types/core/CellEditManager.d.ts +2 -3
  12. package/dist/types/core/CellEventHandler.d.ts +4 -5
  13. package/dist/types/core/CellTypeRegistry.d.ts +1 -2
  14. package/dist/types/core/ColumnLayout.d.ts +1 -2
  15. package/dist/types/core/ContextMenu.d.ts +1 -2
  16. package/dist/types/core/CrossGridRegistry.d.ts +1 -2
  17. package/dist/types/core/DataLayer.d.ts +4 -2
  18. package/dist/types/core/ExportManager.d.ts +4 -3
  19. package/dist/types/core/FilterPanel.d.ts +1 -2
  20. package/dist/types/core/FilterSelect.d.ts +1 -2
  21. package/dist/types/core/FindBarManager.d.ts +4 -5
  22. package/dist/types/core/FooterManager.d.ts +2 -1
  23. package/dist/types/core/FormulaEngine.d.ts +1 -2
  24. package/dist/types/core/GridRenderer.d.ts +3 -2
  25. package/dist/types/core/GridShuttle.d.ts +1 -2
  26. package/dist/types/core/GroupEngine.d.ts +7 -4
  27. package/dist/types/core/GroupTreeManager.d.ts +6 -3
  28. package/dist/types/core/KeyboardManager.d.ts +4 -5
  29. package/dist/types/core/OpenGrid.d.ts +27 -4
  30. package/dist/types/core/OverrideKernel.d.ts +70 -0
  31. package/dist/types/core/PivotEngine.d.ts +1 -2
  32. package/dist/types/core/RowManager.d.ts +0 -1
  33. package/dist/types/core/SortFilterManager.d.ts +5 -6
  34. package/dist/types/core/TriggerManager.d.ts +1 -2
  35. package/dist/types/core/WorksheetManager.d.ts +1 -2
  36. package/dist/types/core/editors/CellEditor.d.ts +2 -3
  37. package/dist/types/core/editors/DateEditor.d.ts +2 -3
  38. package/dist/types/core/editors/SelectEditor.d.ts +2 -3
  39. package/dist/types/core/renderers/CellRenderer.d.ts +4 -4
  40. package/dist/types/core/types.d.ts +58 -0
  41. package/dist/types/index.d.ts +1 -1
  42. package/dist/types/react/OpenGrid.d.ts +3 -3
  43. package/dist/types/vue/types.d.ts +1 -2
  44. package/package.json +99 -99
  45. package/dist/OpenGrid-ClmeIJYR.cjs +0 -88
  46. package/dist/OpenGrid-ClmeIJYR.cjs.map +0 -1
  47. package/dist/OpenGrid-doS5aFVl.js +0 -4669
  48. package/dist/OpenGrid-doS5aFVl.js.map +0 -1
@@ -1,4669 +0,0 @@
1
- class tt {
2
- constructor() {
3
- this.listeners = /* @__PURE__ */ new Map();
4
- }
5
- on(e, t) {
6
- const s = this.listeners.get(e) ?? [];
7
- return s.push({ handler: t, once: !1 }), this.listeners.set(e, s), this;
8
- }
9
- once(e, t) {
10
- const s = this.listeners.get(e) ?? [];
11
- return s.push({ handler: t, once: !0 }), this.listeners.set(e, s), this;
12
- }
13
- off(e, t) {
14
- if (!t)
15
- return this.listeners.delete(e), this;
16
- const s = this.listeners.get(e);
17
- if (s) {
18
- const i = s.filter((n) => n.handler !== t);
19
- i.length === 0 ? this.listeners.delete(e) : this.listeners.set(e, i);
20
- }
21
- return this;
22
- }
23
- emit(e, ...t) {
24
- const s = this.listeners.get(e);
25
- if (!s || s.length === 0) return !1;
26
- const i = [];
27
- for (const n of s)
28
- n.handler(...t), n.once || i.push(n);
29
- return i.length !== s.length && (i.length === 0 ? this.listeners.delete(e) : this.listeners.set(e, i)), !0;
30
- }
31
- removeAllListeners(e) {
32
- return e ? this.listeners.delete(e) : this.listeners.clear(), this;
33
- }
34
- listenerCount(e) {
35
- var t;
36
- return ((t = this.listeners.get(e)) == null ? void 0 : t.length) ?? 0;
37
- }
38
- }
39
- let st = 0;
40
- function ke() {
41
- return `og-r-${++st}`;
42
- }
43
- class it {
44
- constructor(e = "_ogRowId") {
45
- this._data = [], this._original = [], this._meta = /* @__PURE__ */ new Map(), this._displayIndexes = [], this._idMap = /* @__PURE__ */ new Map(), this._findQuery = "", this._findFields = [], this._idField = e;
46
- }
47
- // ─── 데이터 설정 ──────────────────────────────────────
48
- setData(e) {
49
- this._data = e.map((t) => {
50
- const s = ke(), i = { ...t, [this._idField]: s };
51
- return this._meta.set(s, { state: "none", rowId: s }), i;
52
- }), this._original = this._data.map((t) => ({ ...t })), this._rebuildIdMap(), this._displayIndexes = this._data.map((t, s) => s);
53
- }
54
- getData() {
55
- return this._displayIndexes.map((e) => this._data[e]);
56
- }
57
- getOriginalData() {
58
- return [...this._original];
59
- }
60
- getAllData() {
61
- return [...this._data];
62
- }
63
- clearData() {
64
- this._data = [], this._original = [], this._meta.clear(), this._idMap.clear(), this._displayIndexes = [];
65
- }
66
- get rowCount() {
67
- return this._displayIndexes.length;
68
- }
69
- get totalRowCount() {
70
- return this._data.length;
71
- }
72
- // ─── 행 CRUD ──────────────────────────────────────────
73
- addRow(e, t = "last") {
74
- const s = ke(), i = { ...e, [this._idField]: s };
75
- if (this._meta.set(s, { state: "added", rowId: s }), t === "last") {
76
- const n = this._data.push(i) - 1;
77
- this._idMap.set(s, n), this._displayIndexes.push(n);
78
- } else if (t === "first")
79
- this._data.unshift(i), this._rebuildIdMap(), this._displayIndexes.unshift(0);
80
- else {
81
- const n = Math.min(t, this._displayIndexes.length), o = n < this._displayIndexes.length ? this._displayIndexes[n] : this._data.length;
82
- this._data.splice(o, 0, i), this._rebuildIdMap(), this._displayIndexes = this._data.map((l, r) => r);
83
- }
84
- }
85
- removeRow(e) {
86
- const t = this._displayIndexes[e];
87
- if (t === void 0) return;
88
- const s = this._data[t], i = s[this._idField], n = this._meta.get(i);
89
- return (n == null ? void 0 : n.state) === "added" ? (this._data.splice(t, 1), this._meta.delete(i)) : this._meta.set(i, { ...n, state: "removed" }), this._rebuildIdMap(), this._displayIndexes = this._data.map((o, l) => ({ r: o, i: l })).filter(({ r: o }) => {
90
- var l;
91
- return ((l = this._meta.get(o[this._idField])) == null ? void 0 : l.state) !== "removed";
92
- }).map(({ i: o }) => o), s;
93
- }
94
- moveRow(e, t) {
95
- const s = this._displayIndexes[e], i = this._displayIndexes[t];
96
- if (s === void 0 || i === void 0) return;
97
- const [n] = this._data.splice(s, 1), o = s < i ? i - 1 : i;
98
- this._data.splice(o, 0, n), this._rebuildIdMap(), this._displayIndexes = this._data.map((l, r) => ({ r: l, i: r })).filter(({ r: l }) => {
99
- var r;
100
- return ((r = this._meta.get(l[this._idField])) == null ? void 0 : r.state) !== "removed";
101
- }).map(({ i: l }) => l);
102
- }
103
- updateCell(e, t, s) {
104
- const i = this._displayIndexes[e];
105
- if (i === void 0) return !1;
106
- const o = this._data[i][this._idField], l = this._meta.get(o);
107
- return (l == null ? void 0 : l.state) === "none" && this._meta.set(o, {
108
- ...l,
109
- state: "edited",
110
- original: { ...this._original[i] }
111
- }), this._data[i][t] = s, !0;
112
- }
113
- getRowByIndex(e) {
114
- const t = this._displayIndexes[e];
115
- return t !== void 0 ? this._data[t] : void 0;
116
- }
117
- getCellValue(e, t) {
118
- var s;
119
- return (s = this.getRowByIndex(e)) == null ? void 0 : s[t];
120
- }
121
- // ─── 변경 추적 ────────────────────────────────────────
122
- /** 수정된 행만 반환 (추가/삭제 제외) */
123
- getEditedRows() {
124
- return this._data.filter(
125
- (e) => {
126
- var t;
127
- return ((t = this._meta.get(e[this._idField])) == null ? void 0 : t.state) === "edited";
128
- }
129
- );
130
- }
131
- /** 수정된 행만 반환 (하위 호환용 — 신규 코드는 getEditedRows() 사용) */
132
- getChangedRows() {
133
- return this.getEditedRows();
134
- }
135
- getAddedRows() {
136
- return this._data.filter(
137
- (e) => {
138
- var t;
139
- return ((t = this._meta.get(e[this._idField])) == null ? void 0 : t.state) === "added";
140
- }
141
- );
142
- }
143
- getRemovedRows() {
144
- return this._data.filter(
145
- (e) => {
146
- var t;
147
- return ((t = this._meta.get(e[this._idField])) == null ? void 0 : t.state) === "removed";
148
- }
149
- );
150
- }
151
- /**
152
- * 추가/수정/삭제 모든 변경사항을 한 번에 반환.
153
- * edited 행에는 _changedFields 배열도 포함.
154
- */
155
- getChanges() {
156
- const e = [], t = [], s = [];
157
- for (const i of this._data) {
158
- const n = i[this._idField], o = this._meta.get(n), l = (o == null ? void 0 : o.state) ?? "none";
159
- if (l === "added")
160
- e.push({ ...i });
161
- else if (l === "removed")
162
- s.push({ ...i });
163
- else if (l === "edited") {
164
- const r = o.original ?? {}, a = Object.keys(i).filter(
165
- (c) => c !== this._idField && i[c] !== r[c]
166
- );
167
- t.push({ ...i, _changedFields: a });
168
- }
169
- }
170
- return { added: e, edited: t, removed: s };
171
- }
172
- /**
173
- * 수정된 컬럼 정보 반환 — 각 edited 행에 대해 { row, fields, diff } 반환.
174
- * diff: { field, oldValue, newValue }[]
175
- */
176
- getChangedColumns() {
177
- return this._data.filter((e) => {
178
- var t;
179
- return ((t = this._meta.get(e[this._idField])) == null ? void 0 : t.state) === "edited";
180
- }).map((e) => {
181
- var i;
182
- const t = ((i = this._meta.get(e[this._idField])) == null ? void 0 : i.original) ?? {}, s = [];
183
- for (const n of Object.keys(e))
184
- n !== this._idField && e[n] !== t[n] && s.push({ field: n, oldValue: t[n], newValue: e[n] });
185
- return { row: { ...e }, fields: s.map((n) => n.field), diff: s };
186
- });
187
- }
188
- /** rowIndex 행의 원본(수정 전) 데이터 반환. 추가된 행은 undefined. */
189
- getOriginalRow(e) {
190
- const t = this._displayIndexes[e];
191
- if (t === void 0) return;
192
- const s = this._data[t], i = this._meta.get(s[this._idField]);
193
- if (!(!i || i.state === "added"))
194
- return i.state === "edited" && i.original ? { ...i.original } : { ...this._original[t] };
195
- }
196
- getRowsWithState(e) {
197
- return this._data.map((t) => {
198
- var i;
199
- const s = ((i = this._meta.get(t[this._idField])) == null ? void 0 : i.state) ?? "none";
200
- return { ...t, [e]: s };
201
- });
202
- }
203
- getRowState(e) {
204
- var s;
205
- const t = this.getRowByIndex(e);
206
- return t ? ((s = this._meta.get(t[this._idField])) == null ? void 0 : s.state) ?? "none" : "none";
207
- }
208
- // ─── 정렬 ─────────────────────────────────────────────
209
- applySort(e) {
210
- const t = (i) => {
211
- var n, o;
212
- return ((o = this._meta.get((n = this._data[i]) == null ? void 0 : n[this._idField])) == null ? void 0 : o.state) !== "removed";
213
- };
214
- if (e.length === 0) {
215
- this._displayIndexes = this._data.map((i, n) => n).filter(t);
216
- return;
217
- }
218
- const s = this._displayIndexes.filter(t).map((i) => {
219
- const n = this._data[i];
220
- return {
221
- idx: i,
222
- keys: e.map((o) => n[o.field])
223
- };
224
- });
225
- s.sort((i, n) => {
226
- for (let o = 0; o < e.length; o++) {
227
- const l = e[o].dir, r = i.keys[o], a = n.keys[o];
228
- let c = 0;
229
- if (r == null && a == null) c = 0;
230
- else if (r == null) c = -1;
231
- else if (a == null) c = 1;
232
- else if (typeof r == "number" && typeof a == "number") c = r - a;
233
- else {
234
- const h = String(r), u = String(a);
235
- c = h < u ? -1 : h > u ? 1 : 0;
236
- }
237
- if (c !== 0) return l === "asc" ? c : -c;
238
- }
239
- return 0;
240
- }), this._displayIndexes = s.map((i) => i.idx);
241
- }
242
- // ─── 필터 ─────────────────────────────────────────────
243
- applyFilter(e) {
244
- const t = Object.keys(e);
245
- this._displayIndexes = this._data.map((s, i) => ({ r: s, i })).filter(({ r: s }) => {
246
- var i;
247
- if (((i = this._meta.get(s[this._idField])) == null ? void 0 : i.state) === "removed" || t.length > 0 && !t.every((n) => {
248
- const o = s[n];
249
- return e[n].every((l) => nt(o, l));
250
- }))
251
- return !1;
252
- if (this._findQuery && this._findFields.length > 0) {
253
- const n = this._findQuery;
254
- if (!this._findFields.some((l) => {
255
- const r = s[l];
256
- return r != null && String(r).toLowerCase().includes(n);
257
- })) return !1;
258
- }
259
- return !0;
260
- }).map(({ i: s }) => s);
261
- }
262
- /** F3: 찾기 바 전체 컬럼 OR 검색 설정 */
263
- setFindFilter(e, t) {
264
- this._findQuery = e.toLowerCase(), this._findFields = t;
265
- }
266
- // ─── 내부 유틸 ────────────────────────────────────────
267
- _rebuildIdMap() {
268
- this._idMap.clear(), this._data.forEach((e, t) => {
269
- this._idMap.set(e[this._idField], t);
270
- });
271
- }
272
- }
273
- function nt(d, e) {
274
- const t = d, s = e.value;
275
- switch (e.operator) {
276
- case "=":
277
- return t == s;
278
- case "!=":
279
- return t != s;
280
- case ">":
281
- return t > s;
282
- case ">=":
283
- return t >= s;
284
- case "<":
285
- return t < s;
286
- case "<=":
287
- return t <= s;
288
- case "contains":
289
- return String(t).includes(String(s));
290
- case "startsWith":
291
- return String(t).startsWith(String(s));
292
- case "endsWith":
293
- return String(t).endsWith(String(s));
294
- default:
295
- return !0;
296
- }
297
- }
298
- class ot {
299
- constructor(e, t) {
300
- this._totalRows = 0, this._scrollTop = 0, this._viewportHeight = 0, this._rafId = null, this._onScroll = () => {
301
- this._scrollTop = this.container.scrollTop, this._scheduleRender();
302
- }, this.container = e, this.rowHeight = t.rowHeight, this.overscan = t.overscan ?? 5, this.onRender = t.onRender, this.container.addEventListener("scroll", this._onScroll, { passive: !0 });
303
- }
304
- _scheduleRender() {
305
- this._rafId === null && (this._rafId = requestAnimationFrame(() => {
306
- this._rafId = null;
307
- const e = this.getVisibleRange();
308
- this.onRender(e.startIndex, e.endIndex);
309
- }));
310
- }
311
- getVisibleRange() {
312
- const e = Math.ceil(this._viewportHeight / this.rowHeight), t = Math.max(0, Math.floor(this._scrollTop / this.rowHeight) - this.overscan), s = Math.min(
313
- this._totalRows - 1,
314
- t + e + this.overscan * 2
315
- ), i = t * this.rowHeight;
316
- return { startIndex: t, endIndex: s, offsetY: i };
317
- }
318
- setTotalRows(e) {
319
- this._totalRows = e, this._updateSpacerHeight(), this._scheduleRender();
320
- }
321
- setViewportHeight(e) {
322
- this._viewportHeight = e, this._scheduleRender();
323
- }
324
- setRowHeight(e) {
325
- this.rowHeight = e, this._updateSpacerHeight(), this._scheduleRender();
326
- }
327
- scrollToRow(e) {
328
- const t = e * this.rowHeight, s = t + this.rowHeight, i = this._scrollTop + this._viewportHeight;
329
- if (t < this._scrollTop)
330
- this._scrollTop = t, this.container.scrollTop = t;
331
- else if (s > i) {
332
- const n = s - this._viewportHeight;
333
- this._scrollTop = n, this.container.scrollTop = n;
334
- }
335
- }
336
- getTotalHeight() {
337
- return this._totalRows * this.rowHeight;
338
- }
339
- _updateSpacerHeight() {
340
- const e = this.container.querySelector(".og-spacer");
341
- e && (e.style.height = `${this.getTotalHeight()}px`);
342
- }
343
- destroy() {
344
- this.container.removeEventListener("scroll", this._onScroll), this._rafId !== null && cancelAnimationFrame(this._rafId);
345
- }
346
- }
347
- class ce {
348
- constructor(e, t = 0) {
349
- this._flatLeaves = [], this._maxDepth = 1, this._frozenCount = 0, this._columns = e, this._frozenCount = t, this._process();
350
- }
351
- _process() {
352
- const e = [];
353
- let t = 0;
354
- const s = (i, n) => {
355
- for (const o of i)
356
- o.children && o.children.length > 0 ? (s(o.children, n + 1), this._maxDepth = Math.max(this._maxDepth, n + 1)) : e.push({ ...o, _colIndex: t++, _depth: n, _leaf: !0 });
357
- };
358
- this._maxDepth = 1, s(this._columns, 1), this._flatLeaves = e;
359
- }
360
- get leaves() {
361
- return this._flatLeaves;
362
- }
363
- get visibleLeaves() {
364
- return this._flatLeaves.filter((e) => !e.hidden);
365
- }
366
- get headerDepth() {
367
- return this._maxDepth;
368
- }
369
- get frozenCount() {
370
- return this._frozenCount;
371
- }
372
- setFrozen(e) {
373
- this._frozenCount = e;
374
- }
375
- setColumns(e) {
376
- this._columns = e, this._process();
377
- }
378
- hideColumn(e) {
379
- const t = Array.isArray(e) ? e : [e];
380
- this._flatLeaves.forEach((s) => {
381
- t.includes(s.field) && (s.hidden = !0);
382
- });
383
- }
384
- showColumn(e) {
385
- const t = Array.isArray(e) ? e : [e];
386
- this._flatLeaves.forEach((s) => {
387
- t.includes(s.field) && (s.hidden = !1);
388
- });
389
- }
390
- addColumn(e, t = "last") {
391
- t === "last" ? this._columns.push(e) : t === "first" ? this._columns.unshift(e) : this._columns.splice(t, 0, e), this._process();
392
- }
393
- removeColumn(e) {
394
- const t = (s) => s.filter((i) => i.field === e ? !1 : (i.children && (i.children = t(i.children)), !0));
395
- this._columns = t(this._columns), this._process();
396
- }
397
- getColumnByField(e) {
398
- return this._flatLeaves.find((t) => t.field === e);
399
- }
400
- getColumnByIndex(e) {
401
- return this._flatLeaves[e];
402
- }
403
- getColumnIndex(e) {
404
- return this._flatLeaves.findIndex((t) => t.field === e);
405
- }
406
- /** 헤더 렌더링용 셀 계산 */
407
- buildHeaderCells() {
408
- const e = Array.from({ length: this._maxDepth }, () => []);
409
- let t = 0;
410
- const s = (i, n) => {
411
- let o = 0;
412
- for (const l of i)
413
- if (!l.hidden)
414
- if (l.children && l.children.length > 0) {
415
- const r = s(l.children, n + 1);
416
- r > 0 && (e[n - 1].push({
417
- column: l,
418
- colIndex: t,
419
- depth: n,
420
- colSpan: r,
421
- rowSpan: 1
422
- }), o += r);
423
- } else
424
- e[n - 1].push({
425
- column: l,
426
- colIndex: t++,
427
- depth: n,
428
- colSpan: 1,
429
- rowSpan: this._maxDepth - n + 1
430
- }), o++;
431
- return o;
432
- };
433
- return s(this._columns, 1), e;
434
- }
435
- /** 각 리프 컬럼의 계산된 너비 배열 반환 */
436
- computeWidths(e, t = 100) {
437
- const s = this.visibleLeaves, i = s.filter((r) => r.flex), n = s.filter((r) => !r.flex && r.width).reduce((r, a) => r + a.width, 0), o = i.reduce((r, a) => r + (a.flex ?? 1), 0), l = Math.max(0, e - n);
438
- return s.map((r) => r.flex ? Math.round(r.flex / o * l) : r.width ?? t);
439
- }
440
- }
441
- class rt {
442
- constructor(e, t, s) {
443
- this._field = "", this._outsideHandler = null, this._onApply = t, this._onClear = s, this._el = document.createElement("div"), this._el.className = "og-filter-panel", this._el.style.cssText = `
444
- position:absolute;z-index:1000;min-width:200px;max-width:280px;
445
- background:var(--og-row-bg,#fff);border:1px solid var(--og-border-color,#e0e0e0);
446
- border-radius:4px;box-shadow:0 4px 16px rgba(0,0,0,0.15);
447
- padding:10px;box-sizing:border-box;display:none;font-size:13px;
448
- `, e.appendChild(this._el);
449
- }
450
- open(e, t, s) {
451
- var M;
452
- this._field = e, this._el.innerHTML = "";
453
- const i = document.createElement("div");
454
- i.textContent = "필터", i.style.cssText = "font-weight:600;margin-bottom:8px;color:var(--og-text-color,#333);", this._el.appendChild(i);
455
- const n = document.createElement("div");
456
- n.style.cssText = "display:flex;gap:4px;margin-bottom:6px;";
457
- const o = document.createElement("select");
458
- o.style.cssText = "flex:1;padding:3px 4px;border:1px solid var(--og-border-color,#e0e0e0);border-radius:3px;font-size:12px;";
459
- const l = [
460
- { label: "포함", value: "contains" },
461
- { label: "같음", value: "=" },
462
- { label: "같지 않음", value: "!=" },
463
- { label: "시작", value: "startsWith" },
464
- { label: "끝남", value: "endsWith" },
465
- { label: "보다 큼", value: ">" },
466
- { label: "보다 작음", value: "<" },
467
- { label: "이상", value: ">=" },
468
- { label: "이하", value: "<=" }
469
- ];
470
- for (const f of l) {
471
- const E = document.createElement("option");
472
- E.value = f.value, E.textContent = f.label, o.appendChild(E);
473
- }
474
- s[0] && (o.value = s[0].operator), n.appendChild(o), this._el.appendChild(n);
475
- const r = document.createElement("input");
476
- r.type = "text", r.placeholder = "필터 값 입력...", r.value = ((M = s[0]) == null ? void 0 : M.value) ?? "", r.style.cssText = `
477
- width:100%;padding:4px 6px;border:1px solid var(--og-border-color,#e0e0e0);
478
- border-radius:3px;font-size:12px;box-sizing:border-box;margin-bottom:8px;
479
- outline:none;
480
- `, r.addEventListener("keydown", (f) => {
481
- f.key === "Enter" ? h.click() : f.key === "Escape" && this.close();
482
- }), this._el.appendChild(r);
483
- const a = document.createElement("div");
484
- a.style.cssText = "display:flex;gap:6px;justify-content:flex-end;";
485
- const c = document.createElement("button");
486
- c.textContent = "초기화", c.style.cssText = `
487
- padding:3px 10px;border:1px solid var(--og-border-color,#e0e0e0);
488
- border-radius:3px;background:#fff;cursor:pointer;font-size:12px;color:#666;
489
- `, c.addEventListener("click", () => {
490
- this._onClear(this._field), this.close();
491
- });
492
- const h = document.createElement("button");
493
- h.textContent = "적용", h.style.cssText = `
494
- padding:3px 10px;border:1px solid var(--og-primary,#1976d2);
495
- border-radius:3px;background:var(--og-primary,#1976d2);
496
- color:#fff;cursor:pointer;font-size:12px;
497
- `, h.addEventListener("click", () => {
498
- const f = r.value.trim();
499
- f ? this._onApply(this._field, [{ operator: o.value, value: f }]) : this._onClear(this._field), this.close();
500
- }), a.appendChild(c), a.appendChild(h), this._el.appendChild(a);
501
- const u = t.getBoundingClientRect(), p = this._el.parentElement.getBoundingClientRect();
502
- this._el.style.top = `${u.bottom - p.top + 2}px`, this._el.style.left = `${Math.min(u.left - p.left, p.width - 220)}px`, this._el.style.display = "block", requestAnimationFrame(() => r.focus()), this._outsideHandler && document.removeEventListener("mousedown", this._outsideHandler), this._outsideHandler = (f) => {
503
- !this._el.contains(f.target) && f.target !== t && this.close();
504
- }, setTimeout(() => document.addEventListener("mousedown", this._outsideHandler), 0);
505
- }
506
- close() {
507
- this._el.style.display = "none", this._outsideHandler && (document.removeEventListener("mousedown", this._outsideHandler), this._outsideHandler = null);
508
- }
509
- get isOpen() {
510
- return this._el.style.display !== "none";
511
- }
512
- destroy() {
513
- this.close(), this._el.remove();
514
- }
515
- }
516
- const lt = 10;
517
- function at(d, e = lt) {
518
- const t = Math.pow(10, e);
519
- return Math.round(d * t) / t;
520
- }
521
- class R {
522
- // scale = 소수점 아래 자릿수
523
- constructor(e, t) {
524
- this._c = e, this._s = t < 0 ? 0 : t;
525
- }
526
- // ── 생성 ─────────────────────────────────────────────────
527
- static from(e) {
528
- if (e instanceof R) return e;
529
- if (typeof e == "bigint") return new R(e, 0);
530
- const t = String(e).trim();
531
- if (!t || t === "null" || t === "undefined" || t === "NaN")
532
- return new R(0n, 0);
533
- const s = t.startsWith("-"), i = s ? t.slice(1) : t, n = i.indexOf(".");
534
- let o, l;
535
- if (n === -1)
536
- o = BigInt(i), l = 0;
537
- else {
538
- const r = i.slice(n + 1);
539
- o = BigInt(i.slice(0, n) + r), l = r.length;
540
- }
541
- return new R(s ? -o : o, l);
542
- }
543
- static zero() {
544
- return new R(0n, 0);
545
- }
546
- static one() {
547
- return new R(1n, 0);
548
- }
549
- // ── 내부: 두 값의 스케일 정렬 ────────────────────────────
550
- static _align(e, t) {
551
- return e._s === t._s ? [e._c, t._c, e._s] : e._s > t._s ? [e._c, t._c * 10n ** BigInt(e._s - t._s), e._s] : [e._c * 10n ** BigInt(t._s - e._s), t._c, t._s];
552
- }
553
- // ── 사칙연산 ─────────────────────────────────────────────
554
- add(e) {
555
- const [t, s, i] = R._align(this, R.from(e));
556
- return new R(t + s, i);
557
- }
558
- sub(e) {
559
- const [t, s, i] = R._align(this, R.from(e));
560
- return new R(t - s, i);
561
- }
562
- mul(e) {
563
- const t = R.from(e);
564
- return new R(this._c * t._c, this._s + t._s);
565
- }
566
- /**
567
- * 나눗셈. precision = 결과 소수점 자리수 (기본 20).
568
- * 수익 배분처럼 소수 수백 자리가 필요하면 precision을 높인다.
569
- */
570
- div(e, t = 20) {
571
- const s = R.from(e);
572
- if (s._c === 0n) throw new Error("OGDecimal: division by zero");
573
- const n = this._c * 10n ** BigInt(t + s._s) / s._c;
574
- return new R(n, t + this._s);
575
- }
576
- /** 나머지 (정수 나머지와 동일한 개념을 소수에 적용) */
577
- mod(e) {
578
- const t = R.from(e), [s, i, n] = R._align(this, t);
579
- return new R(s % i, n);
580
- }
581
- /** 부호 반전 */
582
- neg() {
583
- return new R(-this._c, this._s);
584
- }
585
- /** 절댓값 */
586
- abs() {
587
- return new R(this._c < 0n ? -this._c : this._c, this._s);
588
- }
589
- // ── 비교 ─────────────────────────────────────────────────
590
- eq(e) {
591
- const [t, s] = R._align(this, R.from(e));
592
- return t === s;
593
- }
594
- gt(e) {
595
- const [t, s] = R._align(this, R.from(e));
596
- return t > s;
597
- }
598
- lt(e) {
599
- const [t, s] = R._align(this, R.from(e));
600
- return t < s;
601
- }
602
- gte(e) {
603
- return !this.lt(e);
604
- }
605
- lte(e) {
606
- return !this.gt(e);
607
- }
608
- isZero() {
609
- return this._c === 0n;
610
- }
611
- isNeg() {
612
- return this._c < 0n;
613
- }
614
- isPos() {
615
- return this._c > 0n;
616
- }
617
- // ── 출력 ─────────────────────────────────────────────────
618
- /**
619
- * 지정 소수점 자리수로 반올림(Half-up) 후 문자열 반환.
620
- * 음원 배분 등 정확한 자리수 표시에 사용.
621
- */
622
- toFixed(e) {
623
- let t = this._c, s = this._s;
624
- if (s < e)
625
- t = t * 10n ** BigInt(e - s);
626
- else if (s > e) {
627
- const c = 10n ** BigInt(s - e), h = c / 2n, u = t < 0n, p = u ? -t : t, M = p % c;
628
- let f = p / c;
629
- M >= h && (f += 1n), t = u ? -f : f;
630
- }
631
- s = e;
632
- const i = t < 0n, o = (i ? -t : t).toString().padStart(e + 1, "0"), l = o.slice(0, o.length - e) || "0", r = e > 0 ? "." + o.slice(o.length - e) : "";
633
- return (i ? "-" : "") + l + r;
634
- }
635
- /** 정규화(후행 0 제거) 후 최소 표현 문자열 반환 */
636
- toString() {
637
- if (this._s === 0) return this._c.toString();
638
- let e = this._c, t = this._s;
639
- for (; t > 0 && e !== 0n && e % 10n === 0n; )
640
- e /= 10n, t--;
641
- return new R(e, t).toFixed(t);
642
- }
643
- /** number로 변환 (정밀도 손실 주의 — 표시 전용) */
644
- toNumber() {
645
- return parseFloat(this.toFixed(20));
646
- }
647
- // ── 집계 정적 메서드 ─────────────────────────────────────
648
- /** 정확한 합산 (내부적으로 BigInt 정수 연산) */
649
- static sum(e) {
650
- return e.reduce((t, s) => t.add(s), R.zero());
651
- }
652
- /** 정확한 평균. precision = 나눗셈 소수점 자리수 */
653
- static avg(e, t = 20) {
654
- return e.length ? R.sum(e).div(e.length, t) : R.zero();
655
- }
656
- /** 배열 최솟값 */
657
- static min(e) {
658
- if (!e.length) throw new Error("OGDecimal.min: empty array");
659
- return e.map(R.from).reduce((t, s) => t.lt(s) ? t : s);
660
- }
661
- /** 배열 최댓값 */
662
- static max(e) {
663
- if (!e.length) throw new Error("OGDecimal.max: empty array");
664
- return e.map(R.from).reduce((t, s) => t.gt(s) ? t : s);
665
- }
666
- }
667
- function Pe(d, e, t = 30) {
668
- return new dt(d, e, t).parse();
669
- }
670
- class dt {
671
- constructor(e, t, s) {
672
- this._ctx = t, this._prec = s, this._pos = 0, this._src = e.trim();
673
- }
674
- parse() {
675
- const e = this._additive();
676
- if (this._skip(), this._pos < this._src.length)
677
- throw new SyntaxError(
678
- `FormulaEngine: 예상치 못한 토큰 '${this._src[this._pos]}' (위치 ${this._pos})`
679
- );
680
- return e;
681
- }
682
- // ── expression layers ──────────────────────────────────
683
- _additive() {
684
- let e = this._multiplicative();
685
- for (this._skip(); this._pos < this._src.length; ) {
686
- const t = this._src[this._pos];
687
- if (t !== "+" && t !== "-") break;
688
- this._pos++, this._skip();
689
- const s = this._multiplicative();
690
- e = t === "+" ? e.add(s) : e.sub(s), this._skip();
691
- }
692
- return e;
693
- }
694
- _multiplicative() {
695
- let e = this._unary();
696
- for (this._skip(); this._pos < this._src.length; ) {
697
- const t = this._src[this._pos];
698
- if (t !== "*" && t !== "/" && t !== "%") break;
699
- this._pos++, this._skip();
700
- const s = this._unary();
701
- t === "*" ? e = e.mul(s) : t === "/" ? e = e.div(s, this._prec) : e = e.mod(s), this._skip();
702
- }
703
- return e;
704
- }
705
- _unary() {
706
- return this._skip(), this._src[this._pos] === "-" ? (this._pos++, this._unary().neg()) : this._primary();
707
- }
708
- _primary() {
709
- this._skip();
710
- const e = this._src[this._pos];
711
- if (e === "(") {
712
- this._pos++;
713
- const t = this._additive();
714
- if (this._skip(), this._src[this._pos] !== ")")
715
- throw new SyntaxError("FormulaEngine: 닫는 괄호 ) 누락");
716
- return this._pos++, t;
717
- }
718
- return e === "[" ? this._fieldRef() : this._literal();
719
- }
720
- // ── 토큰 파싱 ─────────────────────────────────────────
721
- /** [fieldName] → 행 데이터에서 값 추출 */
722
- _fieldRef() {
723
- this._pos++;
724
- const e = this._pos;
725
- for (; this._pos < this._src.length && this._src[this._pos] !== "]"; )
726
- this._pos++;
727
- if (this._pos >= this._src.length)
728
- throw new SyntaxError("FormulaEngine: 닫는 ] 누락");
729
- const t = this._src.slice(e, this._pos);
730
- this._pos++;
731
- const s = this._ctx[t];
732
- if (s == null)
733
- throw new ReferenceError(`FormulaEngine: 필드 '[${t}]'가 행 데이터에 없습니다`);
734
- return R.from(s);
735
- }
736
- /** 숫자 리터럴 파싱 (정수 / 소수 모두) */
737
- _literal() {
738
- const e = this._pos;
739
- for (; this._pos < this._src.length && /[0-9.]/.test(this._src[this._pos]); )
740
- this._pos++;
741
- const t = this._src.slice(e, this._pos);
742
- if (!t)
743
- throw new SyntaxError(
744
- `FormulaEngine: 숫자 또는 [필드]를 기대했지만 '${this._src[this._pos] ?? "EOF"}' 발견 (위치 ${e})`
745
- );
746
- return R.from(t);
747
- }
748
- /** 공백 스킵 */
749
- _skip() {
750
- for (; this._pos < this._src.length && /\s/.test(this._src[this._pos]); )
751
- this._pos++;
752
- }
753
- }
754
- function Me(d, e) {
755
- if (d == null || d === "") return d ?? "";
756
- const t = typeof e == "string" ? { type: e } : e, s = t.char ?? "*";
757
- switch (t.type) {
758
- case "ssn":
759
- return ct(d, s);
760
- case "phone":
761
- case "mobile":
762
- return ht(d, s);
763
- case "email":
764
- return ut(d, s);
765
- case "credit":
766
- return pt(d, s);
767
- case "account":
768
- return gt(d, s, t.visiblePrefix ?? 3, t.visibleSuffix ?? 4);
769
- case "password":
770
- return s.repeat(Math.max(d.length, 6));
771
- case "name":
772
- return _t(d, s);
773
- case "ip":
774
- return ft(d, s);
775
- case "partial":
776
- return se(d, s, t.visiblePrefix ?? 0, t.visibleSuffix ?? 4);
777
- default:
778
- return d;
779
- }
780
- }
781
- function ct(d, e) {
782
- const t = d.replace(/[^0-9]/g, "");
783
- if (t.length < 7) {
784
- const o = d.includes("-") ? "-" : "", l = d.indexOf("-") >= 0 ? d.indexOf("-") : 6;
785
- return d.slice(0, l) + o + e.repeat(Math.max(1, d.length - l - o.length));
786
- }
787
- const s = t.slice(0, 6), i = t[6], n = t.length - 7;
788
- return `${s}-${i}${e.repeat(n)}`;
789
- }
790
- function ht(d, e) {
791
- const t = d.replace(/[^0-9]/g, "");
792
- return t.length === 11 ? `${t.slice(0, 3)}-${e.repeat(4)}-${t.slice(7)}` : t.length === 10 ? t.startsWith("02") ? `${t.slice(0, 2)}-${e.repeat(4)}-${t.slice(6)}` : `${t.slice(0, 3)}-${e.repeat(3)}-${t.slice(6)}` : t.length === 9 ? `${t.slice(0, 2)}-${e.repeat(3)}-${t.slice(5)}` : se(d, e, 3, 4);
793
- }
794
- function ut(d, e) {
795
- const t = d.indexOf("@");
796
- if (t < 0) return se(d, e, 2, 0);
797
- const s = d.slice(0, t), i = d.slice(t), n = Math.min(2, s.length), o = s.slice(0, n), l = Math.max(s.length - n, 3);
798
- return `${o}${e.repeat(l)}${i}`;
799
- }
800
- function pt(d, e) {
801
- const t = d.replace(/[^0-9]/g, "");
802
- if (t.length < 8) return d;
803
- const s = t.slice(0, 4), i = t.slice(-4), n = t.length - 8, o = e.repeat(Math.max(n, 8)), l = [s];
804
- for (let r = 0; r < o.length; r += 4) {
805
- const a = o.slice(r, r + 4);
806
- a && l.push(a);
807
- }
808
- return l.push(i), l.join("-");
809
- }
810
- function gt(d, e, t, s) {
811
- const i = d.replace(/[^0-9]/g, "");
812
- if (i.length <= t + s)
813
- return se(i, e, t, s);
814
- const n = i.slice(0, t), o = i.slice(-s), l = i.length - t - s;
815
- return `${n}-${e.repeat(l)}-${o}`;
816
- }
817
- function _t(d, e) {
818
- const t = d.trim();
819
- return t.length === 0 ? d : t.length === 1 ? e : t.length === 2 ? `${t[0]}${e}` : `${t[0]}${e.repeat(t.length - 2)}${t[t.length - 1]}`;
820
- }
821
- function ft(d, e) {
822
- const t = d.split(".");
823
- if (t.length !== 4) return se(d, e, 3, 0);
824
- const s = (i) => e.repeat(Math.max(i.length, 3));
825
- return `${t[0]}.${t[1]}.${s(t[2])}.${s(t[3])}`;
826
- }
827
- function se(d, e, t, s) {
828
- if (d.length <= t + s) return d;
829
- const i = d.slice(0, t), n = s > 0 ? d.slice(-s) : "", o = d.length - t - s;
830
- return `${i}${e.repeat(o)}${n}`;
831
- }
832
- function je(d) {
833
- const e = d.column;
834
- if (!e.formula) return null;
835
- const t = e.formulaPrecision ?? 30;
836
- try {
837
- let s;
838
- return typeof e.formula == "function" ? s = e.formula(d.row, R) : s = Pe(e.formula, d.row, t), s instanceof R ? e.precision != null ? s.toFixed(e.precision) : s.toString() : typeof s == "string" ? s : e.precision != null ? R.from(s).toFixed(e.precision) : String(s);
839
- } catch (s) {
840
- return console.warn("[OpenGrid] Formula error:", s), "#ERR";
841
- }
842
- }
843
- function mt(d, e, t, s) {
844
- if (d == null || d === "") return "";
845
- let i = Number(d);
846
- if (isNaN(i)) return String(d);
847
- if (t != null && (i = at(i, t)), s)
848
- try {
849
- return new Intl.NumberFormat(void 0, {
850
- style: "currency",
851
- currency: s,
852
- ...t != null ? { minimumFractionDigits: t, maximumFractionDigits: t } : {}
853
- }).format(i);
854
- } catch {
855
- }
856
- if (!e)
857
- return t != null ? i.toFixed(t) : String(i);
858
- const n = e.indexOf(";"), o = n >= 0 ? e.slice(n + 1) : null, l = i < 0 && o != null ? o : n >= 0 ? e.slice(0, n) : e, r = i < 0 && o != null ? Math.abs(i) : i, a = l.match(/[#0][#0,]*(?:\.[#0]+)?/);
859
- if (!a) return String(i);
860
- const c = a[0], h = l.slice(0, a.index), u = l.slice(a.index + c.length), p = c.includes(","), M = c.includes(".") ? c.split(".")[1].length : t ?? 0, f = r.toLocaleString("ko-KR", {
861
- minimumFractionDigits: M,
862
- maximumFractionDigits: M,
863
- useGrouping: p
864
- });
865
- return h + f + u;
866
- }
867
- function Ue(d, e = "yyyy-MM-dd") {
868
- if (!d) return "";
869
- const t = d instanceof Date ? d : new Date(d);
870
- if (isNaN(t.getTime())) return String(d);
871
- const s = t.getFullYear(), i = String(t.getMonth() + 1).padStart(2, "0"), n = String(t.getDate()).padStart(2, "0");
872
- return e.replace("yyyy", String(s)).replace("MM", i).replace("dd", n);
873
- }
874
- function bt(d, e, t) {
875
- const s = Me(d, e.mask), i = document.createElement("span");
876
- i.style.cssText = "display:flex;align-items:center;gap:3px;overflow:hidden;width:100%;box-sizing:border-box;";
877
- const n = document.createElement("span");
878
- n.style.cssText = "flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:monospace;letter-spacing:0.4px;color:var(--og-mask-text,#888);", n.textContent = s;
879
- const o = document.createElement("button");
880
- return o.title = "클릭하면 원문 표시", o.setAttribute("aria-label", "마스킹 해제"), o.innerHTML = '<svg width="13" height="13" viewBox="0 0 16 16" fill="currentColor"><path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8z"/><path d="M8 5.5A2.5 2.5 0 1 0 8 10.5 2.5 2.5 0 0 0 8 5.5zm0 4A1.5 1.5 0 1 1 8 6.5a1.5 1.5 0 0 1 0 3z" fill="#fff"/></svg>', o.style.cssText = "flex-shrink:0;background:none;border:none;cursor:pointer;color:#c0c0c0;padding:1px 2px;line-height:0;border-radius:3px;display:flex;align-items:center;", o.addEventListener("mouseover", () => {
881
- o.style.color = "var(--og-primary,#1976d2)", o.style.background = "rgba(25,118,210,0.08)";
882
- }), o.addEventListener("mouseout", () => {
883
- o.style.color = "#c0c0c0", o.style.background = "none";
884
- }), o.addEventListener("click", (l) => {
885
- l.stopPropagation(), n.textContent = d, n.style.fontFamily = "", n.style.letterSpacing = "", n.style.color = "", o.remove(), (e._maskRevealedRows ?? (e._maskRevealedRows = /* @__PURE__ */ new Set())).add(t);
886
- }), i.appendChild(n), i.appendChild(o), i;
887
- }
888
- class he {
889
- render(e) {
890
- var r;
891
- const t = document.createElement("span");
892
- t.className = "og-cell-text";
893
- const s = je(e);
894
- if (s !== null)
895
- return t.textContent = s, t.style.cssText = "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;", t;
896
- const { value: i, column: n, rowIndex: o } = e;
897
- let l;
898
- if (n.valueMap && i != null && n.valueMap[i] ? l = n.valueMap[i] : l = i == null ? "" : String(i), n.mask) {
899
- const a = n._maskRevealed === !0, c = ((r = n._maskRevealedRows) == null ? void 0 : r.has(o)) === !0;
900
- if (!a && !c)
901
- return bt(l, n, o);
902
- }
903
- return t.textContent = l, t.style.cssText = "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;", t;
904
- }
905
- }
906
- class yt {
907
- constructor(e = [], t) {
908
- this._opts = e.map(
909
- (s) => typeof s == "string" ? { label: s, value: s } : { label: s.label ?? s.text ?? String(s.value ?? ""), value: s.value }
910
- ), this._fn = t ?? null;
911
- }
912
- render(e) {
913
- const t = document.createElement("span");
914
- t.className = "og-cell-text", t.style.cssText = "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;";
915
- const s = e.value;
916
- if (s == null || s === "") return t;
917
- const i = String(s), o = (this._fn ? this._fn(e.row, e.rowIndex).map((l) => typeof l == "string" ? { label: l, value: l } : { label: l.label ?? l.text ?? String(l.value ?? ""), value: l.value }) : this._opts).find((l) => String(l.value) === i);
918
- return t.textContent = o ? o.label : i, t;
919
- }
920
- }
921
- class ue {
922
- render(e) {
923
- const t = document.createElement("span");
924
- t.className = "og-cell-number";
925
- const s = je(e);
926
- return s !== null ? (t.textContent = s, t.style.cssText = "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;width:100%;text-align:right;", t) : (t.textContent = mt(e.value, e.column.format ?? "#,##0", e.column.precision, e.column.currency), t.style.cssText = "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;width:100%;text-align:right;", t);
927
- }
928
- }
929
- class pe {
930
- render(e) {
931
- const t = document.createElement("span");
932
- return t.className = "og-cell-date", t.textContent = Ue(e.value, e.column.format), t.style.cssText = "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;", t;
933
- }
934
- }
935
- class ge {
936
- render(e) {
937
- const t = document.createElement("span");
938
- t.className = "og-cell-checkbox", t.style.cssText = "display:flex;align-items:center;justify-content:center;height:100%;";
939
- const s = document.createElement("input");
940
- return s.type = "checkbox", s.checked = !!e.value, s.disabled = !0, s.style.cssText += "cursor:pointer;pointer-events:none;", t.appendChild(s), t;
941
- }
942
- }
943
- class Le {
944
- constructor(e) {
945
- this.def = e;
946
- }
947
- render(e) {
948
- var n, o, l;
949
- const t = document.createElement("span");
950
- t.style.cssText = "display:flex;align-items:center;justify-content:center;height:100%;";
951
- const s = document.createElement("button");
952
- s.className = `og-cell-btn${(n = this.def) != null && n.buttonClass ? " " + this.def.buttonClass : ""}`;
953
- const i = (o = this.def) == null ? void 0 : o.label;
954
- return typeof i == "function" ? s.textContent = i(e.value, e.row) : s.textContent = i ?? String(e.value ?? "btn"), s.style.cssText = `
955
- padding:2px 10px;border:1px solid var(--og-primary,#1976d2);
956
- border-radius:4px;background:var(--og-row-bg,#fff);color:var(--og-primary,#1976d2);
957
- cursor:pointer;font-size:12px;white-space:nowrap;transition:background 0.12s;
958
- ${((l = this.def) == null ? void 0 : l.style) ?? ""}
959
- `, s.addEventListener("mouseover", () => s.style.background = "var(--og-primary-light,#e3f2fd)"), s.addEventListener("mouseout", () => s.style.background = "var(--og-row-bg,#fff)"), t.appendChild(s), t;
960
- }
961
- }
962
- class Se {
963
- constructor(e, t) {
964
- this.colorMap = e, this.labelMap = t;
965
- }
966
- render(e) {
967
- var l, r, a;
968
- const t = document.createElement("span");
969
- t.style.cssText = "display:flex;align-items:center;height:100%;";
970
- const s = document.createElement("span"), i = e.value == null ? "" : String(e.value), n = ((l = this.labelMap) == null ? void 0 : l[i]) ?? ((r = e.column.valueMap) == null ? void 0 : r[i]) ?? i;
971
- s.textContent = n;
972
- const o = ((a = this.colorMap) == null ? void 0 : a[i]) ?? "#666";
973
- return s.style.cssText = `
974
- display:inline-block;padding:2px 8px;border-radius:12px;font-size:11px;
975
- background:${o}22;color:${o};border:1px solid ${o}66;
976
- white-space:nowrap;
977
- `, t.appendChild(s), t;
978
- }
979
- }
980
- class Fe {
981
- constructor(e, t) {
982
- this.hrefFn = e, this.target = t;
983
- }
984
- render(e) {
985
- const t = document.createElement("a");
986
- return t.className = "og-cell-link", t.textContent = e.value == null ? "" : String(e.value), t.href = this.hrefFn ? this.hrefFn(e.value, e.row) : "#", this.target && (t.target = this.target), t.style.cssText = "color:var(--og-primary,#1976d2);text-decoration:underline;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;", this.hrefFn || t.addEventListener("click", (s) => s.preventDefault()), t;
987
- }
988
- }
989
- class wt {
990
- constructor(e) {
991
- this.templateFn = e;
992
- }
993
- render(e) {
994
- const t = document.createElement("div");
995
- return t.className = "og-cell-template", t.style.cssText = "display:flex;align-items:center;height:100%;overflow:hidden;", t.innerHTML = this.templateFn(e.value, e.row, e.rowIndex), t;
996
- }
997
- }
998
- class vt {
999
- constructor(e) {
1000
- this.def = e;
1001
- }
1002
- render(e) {
1003
- var a, c, h, u, p;
1004
- const t = document.createElement("span");
1005
- t.style.cssText = "display:flex;align-items:center;justify-content:center;height:100%;";
1006
- const s = document.createElement("img"), i = (a = this.def) != null && a.srcFn ? this.def.srcFn(e.value, e.row) : String(e.value ?? "");
1007
- s.src = i;
1008
- const n = ((c = this.def) == null ? void 0 : c.width) ?? 28, o = ((h = this.def) == null ? void 0 : h.height) ?? 28, l = ((u = this.def) == null ? void 0 : u.radius) ?? 4;
1009
- s.style.cssText = `width:${n}px;height:${o}px;object-fit:cover;border-radius:${l}px;display:block;`;
1010
- const r = (p = this.def) == null ? void 0 : p.alt;
1011
- return s.alt = typeof r == "function" ? r(e.value, e.row) : r ?? "", s.onerror = () => {
1012
- s.style.display = "none";
1013
- }, t.appendChild(s), t;
1014
- }
1015
- }
1016
- class xt {
1017
- constructor(e) {
1018
- this.def = e;
1019
- }
1020
- render(e) {
1021
- var a, c, h, u;
1022
- const t = document.createElement("span");
1023
- t.style.cssText = "display:flex;align-items:center;gap:5px;width:100%;padding:0 4px;box-sizing:border-box;";
1024
- const s = ((a = this.def) == null ? void 0 : a.max) ?? 100, i = Number(e.value) || 0, n = Math.min(100, Math.max(0, i / s * 100)), o = (c = this.def) != null && c.colorFn ? this.def.colorFn(i) : ((h = this.def) == null ? void 0 : h.color) ?? "var(--og-primary,#1976d2)", l = document.createElement("div");
1025
- l.className = "og-progress-track", l.style.cssText = "flex:1;height:10px;background:#e0e0e0;border-radius:5px;overflow:hidden;";
1026
- const r = document.createElement("div");
1027
- if (r.className = "og-progress-fill", r.style.cssText = `width:${n}%;height:100%;background:${o};border-radius:5px;`, l.appendChild(r), t.appendChild(l), ((u = this.def) == null ? void 0 : u.showLabel) !== !1) {
1028
- const p = document.createElement("span");
1029
- p.style.cssText = "font-size:11px;color:#666;white-space:nowrap;min-width:28px;text-align:right;", p.textContent = `${Math.round(n)}%`, t.appendChild(p);
1030
- }
1031
- return t;
1032
- }
1033
- }
1034
- class Ct {
1035
- constructor(e) {
1036
- this.def = e;
1037
- }
1038
- render(e) {
1039
- var c, h, u, p;
1040
- const t = document.createElement("span");
1041
- t.style.cssText = "display:flex;align-items:center;justify-content:center;height:100%;";
1042
- const s = Array.isArray(e.value) ? e.value.map(Number) : [];
1043
- if (!s.length)
1044
- return t.textContent = "-", t;
1045
- const i = ((c = this.def) == null ? void 0 : c.width) ?? 80, n = ((h = this.def) == null ? void 0 : h.height) ?? 22, o = ((u = this.def) == null ? void 0 : u.color) ?? "#1976d2", l = ((p = this.def) == null ? void 0 : p.chartType) ?? "bar", r = document.createElement("canvas");
1046
- r.width = i, r.height = n, r.style.cssText = "display:block;";
1047
- const a = r.getContext("2d");
1048
- if (a) {
1049
- const M = Math.max(...s, 1), f = Math.min(...s, 0), E = M - f || 1, x = s.length;
1050
- if (l === "bar") {
1051
- const g = i / x;
1052
- s.forEach((w, L) => {
1053
- const v = (w - f) / E * (n - 2);
1054
- a.fillStyle = o, a.fillRect(L * g + 1, n - v - 1, g - 2, v);
1055
- });
1056
- } else {
1057
- const g = s.map((w, L) => ({
1058
- x: L / (x - 1 || 1) * i,
1059
- y: n - (w - f) / E * (n - 4) - 2
1060
- }));
1061
- l === "area" && (a.fillStyle = o + "33", a.beginPath(), a.moveTo(g[0].x, n), g.forEach((w) => a.lineTo(w.x, w.y)), a.lineTo(g[g.length - 1].x, n), a.closePath(), a.fill()), a.strokeStyle = o, a.lineWidth = 1.5, a.beginPath(), g.forEach((w, L) => L === 0 ? a.moveTo(w.x, w.y) : a.lineTo(w.x, w.y)), a.stroke();
1062
- }
1063
- }
1064
- return t.appendChild(r), t;
1065
- }
1066
- }
1067
- class Te {
1068
- render(e) {
1069
- const t = document.createElement("span");
1070
- t.style.cssText = "display:flex;align-items:center;justify-content:center;height:100%;";
1071
- const s = !!e.value, i = document.createElement("span");
1072
- i.className = "og-switch" + (s ? " og-switch--on" : ""), i.style.cssText = `display:inline-block;width:34px;height:18px;border-radius:9px;
1073
- background:${s ? "var(--og-primary,#1976d2)" : "#bdbdbd"};
1074
- position:relative;transition:background 0.2s;cursor:pointer;flex-shrink:0;pointer-events:none;`;
1075
- const n = document.createElement("span");
1076
- return n.style.cssText = `position:absolute;top:2px;left:${s ? "16px" : "2px"};
1077
- width:14px;height:14px;border-radius:50%;background:#fff;
1078
- transition:left 0.2s;box-shadow:0 1px 3px rgba(0,0,0,0.3);`, i.appendChild(n), t.appendChild(i), t;
1079
- }
1080
- }
1081
- class Mt {
1082
- constructor(e) {
1083
- this.def = e;
1084
- }
1085
- render(e) {
1086
- var o, l;
1087
- const t = document.createElement("span");
1088
- t.style.cssText = "display:flex;align-items:center;gap:1px;height:100%;";
1089
- const s = ((o = this.def) == null ? void 0 : o.max) ?? 5, i = Math.round(Number(e.value) || 0), n = ((l = this.def) == null ? void 0 : l.color) ?? "#ffa000";
1090
- for (let r = 1; r <= s; r++) {
1091
- const a = document.createElement("span");
1092
- a.textContent = "★", a.style.cssText = `font-size:14px;color:${r <= i ? n : "#e0e0e0"};line-height:1;`, t.appendChild(a);
1093
- }
1094
- return t;
1095
- }
1096
- }
1097
- class _e {
1098
- render(e) {
1099
- const t = document.createElement("span");
1100
- t.style.cssText = "display:flex;align-items:center;justify-content:center;height:100%;pointer-events:none;";
1101
- const s = document.createElement("input");
1102
- return s.type = "radio", s.checked = !!e.value, s.setAttribute("aria-checked", e.value ? "true" : "false"), s.setAttribute("aria-label", e.column.header ?? "선택"), e.column.group && (s.name = `og-radio-${e.rowIndex}-${e.column.group}`), s.style.cssText = "width:14px;height:14px;cursor:pointer;accent-color:var(--og-primary,#1976d2);", t.appendChild(s), t;
1103
- }
1104
- }
1105
- class fe {
1106
- render(e) {
1107
- const t = document.createElement("span");
1108
- if (t.style.cssText = "display:flex;align-items:center;justify-content:center;height:100%;overflow:hidden;", !e.value) return t;
1109
- const s = document.createElement("img");
1110
- return s.src = String(e.value), s.alt = e.column.alt ?? e.column.field, s.style.cssText = "max-width:100%;max-height:100%;object-fit:contain;display:block;", s.setAttribute("role", "img"), t.appendChild(s), t;
1111
- }
1112
- }
1113
- function Rt(d) {
1114
- const e = document.createElement("div");
1115
- return e.innerHTML = d, e.querySelectorAll("script,iframe,object,embed").forEach((t) => t.remove()), e.querySelectorAll("*").forEach((t) => {
1116
- for (const s of [...t.attributes])
1117
- s.name.startsWith("on") && t.removeAttribute(s.name);
1118
- if (t.tagName === "A") {
1119
- const s = t.getAttribute("href") ?? "";
1120
- /^javascript:/i.test(s) && t.removeAttribute("href");
1121
- }
1122
- }), e.innerHTML;
1123
- }
1124
- class me {
1125
- render(e) {
1126
- const t = document.createElement("span");
1127
- t.style.cssText = "display:block;overflow:hidden;width:100%;";
1128
- const s = e.column.sanitize !== !1, i = String(e.value ?? "");
1129
- return t.innerHTML = s ? Rt(i) : i, t;
1130
- }
1131
- }
1132
- const Et = [
1133
- "212222",
1134
- "222122",
1135
- "222221",
1136
- "121223",
1137
- "121322",
1138
- "131222",
1139
- "122213",
1140
- "122312",
1141
- // 0-7
1142
- "132212",
1143
- "221213",
1144
- "221312",
1145
- "231212",
1146
- "112232",
1147
- "122132",
1148
- "122231",
1149
- "113222",
1150
- // 8-15
1151
- "123122",
1152
- "123221",
1153
- "223211",
1154
- "221132",
1155
- "221231",
1156
- "213212",
1157
- "223112",
1158
- "312131",
1159
- // 16-23
1160
- "311222",
1161
- "321122",
1162
- "321221",
1163
- "312212",
1164
- "322112",
1165
- "322211",
1166
- "212123",
1167
- "212321",
1168
- // 24-31
1169
- "232121",
1170
- "111323",
1171
- "131123",
1172
- "131321",
1173
- "112313",
1174
- "132113",
1175
- "132311",
1176
- "211313",
1177
- // 32-39
1178
- "231113",
1179
- "231311",
1180
- "112133",
1181
- "112331",
1182
- "132131",
1183
- "113123",
1184
- "113321",
1185
- "133121",
1186
- // 40-47
1187
- "313121",
1188
- "211331",
1189
- "231131",
1190
- "213113",
1191
- "213311",
1192
- "213131",
1193
- "311123",
1194
- "311321",
1195
- // 48-55
1196
- "331121",
1197
- "312113",
1198
- "312311",
1199
- "332111",
1200
- "314111",
1201
- "221411",
1202
- "431111",
1203
- "111224",
1204
- // 56-63
1205
- "111422",
1206
- "121124",
1207
- "121421",
1208
- "141122",
1209
- "141221",
1210
- "112214",
1211
- "112412",
1212
- "122114",
1213
- // 64-71
1214
- "122411",
1215
- "142112",
1216
- "142211",
1217
- "241211",
1218
- "221114",
1219
- "413111",
1220
- "241112",
1221
- "134111",
1222
- // 72-79
1223
- "111242",
1224
- "121142",
1225
- "121241",
1226
- "114212",
1227
- "124112",
1228
- "124211",
1229
- "411212",
1230
- "421112",
1231
- // 80-87
1232
- "421211",
1233
- "212141",
1234
- "214121",
1235
- "412121",
1236
- "111143",
1237
- "111341",
1238
- "131141",
1239
- "114113",
1240
- // 88-95
1241
- "114311",
1242
- "411113",
1243
- "411311",
1244
- "113141",
1245
- "114131",
1246
- "311141",
1247
- "411131",
1248
- "211412",
1249
- // 96-103
1250
- "211214",
1251
- "211232"
1252
- // 104 (Start B), 105 (Start C)
1253
- ], kt = "2331112";
1254
- function De(d) {
1255
- let e = "", t = !0;
1256
- for (const s of d)
1257
- e += (t ? "1" : "0").repeat(+s), t = !t;
1258
- return e;
1259
- }
1260
- function Lt(d) {
1261
- const e = [104];
1262
- for (const s of d) {
1263
- const i = s.charCodeAt(0) - 32;
1264
- i >= 0 && i <= 94 && e.push(i);
1265
- }
1266
- let t = 104;
1267
- for (let s = 1; s < e.length; s++) t += e[s] * s;
1268
- return e.push(t % 103), e.map((s) => De(Et[s])).join("") + De(kt) + "11";
1269
- }
1270
- class be {
1271
- render(e) {
1272
- const t = String(e.value ?? ""), s = e.column.barcodeHeight ?? 28, i = document.createElement("div");
1273
- i.style.cssText = "display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;overflow:hidden;gap:1px;", i.setAttribute("role", "img"), i.setAttribute("aria-label", `바코드: ${t}`), i.innerHTML = St(t, s);
1274
- const n = document.createElement("span");
1275
- return n.textContent = t, n.style.cssText = "font-size:9px;font-family:monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;", i.appendChild(n), i;
1276
- }
1277
- }
1278
- function St(d, e) {
1279
- if (!d) return "";
1280
- const t = Lt(d), s = 1.4, i = 6, n = t.length * s + i * 2, o = [];
1281
- let l = 0, r = i;
1282
- for (; l < t.length; )
1283
- if (t[l] === "1") {
1284
- let a = 0;
1285
- for (; l + a < t.length && t[l + a] === "1"; ) a++;
1286
- o.push(`<rect x="${r.toFixed(2)}" y="0" width="${(a * s).toFixed(2)}" height="${e}"/>`), r += a * s, l += a;
1287
- } else
1288
- r += s, l++;
1289
- return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${n.toFixed(2)} ${e}" width="${n.toFixed(2)}" height="${e}" style="display:block" aria-hidden="true"><g fill="currentColor">${o.join("")}</g></svg>`;
1290
- }
1291
- function Ft(d) {
1292
- const e = d.renderer;
1293
- if (!e)
1294
- switch (d.type) {
1295
- case "number":
1296
- return new ue();
1297
- case "date":
1298
- return new pe();
1299
- case "boolean":
1300
- return new ge();
1301
- case "radio":
1302
- return new _e();
1303
- case "img":
1304
- return new fe();
1305
- case "html":
1306
- return new me();
1307
- case "barcode":
1308
- return new be();
1309
- case "select":
1310
- return new yt(d.options ?? [], d.optionsFn);
1311
- default:
1312
- return new he();
1313
- }
1314
- if (typeof e == "string")
1315
- switch (e) {
1316
- case "number":
1317
- return new ue();
1318
- case "date":
1319
- return new pe();
1320
- case "checkbox":
1321
- return new ge();
1322
- case "button":
1323
- return new Le();
1324
- case "link":
1325
- return new Fe();
1326
- case "badge":
1327
- return new Se();
1328
- case "switch":
1329
- return new Te();
1330
- case "radio":
1331
- return new _e();
1332
- case "img":
1333
- return new fe();
1334
- case "html":
1335
- return new me();
1336
- case "barcode":
1337
- return new be();
1338
- default:
1339
- return new he();
1340
- }
1341
- switch (e.type) {
1342
- case "button":
1343
- return new Le(e);
1344
- case "checkbox":
1345
- return new ge();
1346
- case "link":
1347
- return new Fe(e.hrefFn, e.target);
1348
- case "template":
1349
- return new wt(e.templateFn);
1350
- case "badge":
1351
- return new Se(e.colorMap, e.labelMap ?? e.valueMap);
1352
- case "image":
1353
- return new vt(e);
1354
- case "progress":
1355
- return new xt(e);
1356
- case "sparkline":
1357
- return new Ct(e);
1358
- case "switch":
1359
- return new Te();
1360
- case "rating":
1361
- return new Mt(e);
1362
- case "number":
1363
- return new ue();
1364
- case "date":
1365
- return new pe();
1366
- case "radio":
1367
- return new _e();
1368
- case "img":
1369
- return new fe();
1370
- case "html":
1371
- return new me();
1372
- case "barcode":
1373
- return new be();
1374
- default:
1375
- return new he();
1376
- }
1377
- }
1378
- class Tt {
1379
- constructor(e, t, s) {
1380
- this._cellMap = /* @__PURE__ */ new Map(), this._root = e, this._opts = t, this._cbs = s, this._header = D("div", "og-header"), this._header.style.cssText = "flex-shrink:0;overflow-x:auto;overflow-y:hidden;border:0;border-bottom:1px solid var(--og-border-color,#e0e0e0);scrollbar-width:none;", this._bodyWrap = D("div", "og-body-wrapper"), this._bodyWrap.style.cssText = "flex:1;overflow:auto;position:relative;", this._bodyWrap.style.setProperty("--scrollbar-size", "8px"), this._body = D("div", "og-body"), this._body.style.cssText = "position:relative;", this._bodyWrap.appendChild(this._body), e.appendChild(this._header), e.appendChild(this._bodyWrap), this._bodyWrap.addEventListener("scroll", () => {
1381
- this._header.scrollLeft = this._bodyWrap.scrollLeft;
1382
- }, { passive: !0 });
1383
- }
1384
- get bodyWrapper() {
1385
- return this._bodyWrap;
1386
- }
1387
- updateSize(e, t) {
1388
- this._bodyWrap.style.height = `${e - t}px`;
1389
- }
1390
- renderHeader(e, t, s, i, n) {
1391
- var p, M;
1392
- this._header.innerHTML = "";
1393
- const o = n._frozenCount ?? 0;
1394
- let l = 0;
1395
- n.stateColumn && (l += 24), n.draggable && (l += 18), n.rowNumber && (l += 44), n.checkColumn && (l += 36);
1396
- const r = l + t.reduce((f, E, x) => f + (s[x] ?? n.defaultColumnWidth), 0);
1397
- this._header.style.background = "var(--og-header-bg,#f5f5f5)";
1398
- const a = D("table", "og-header-table");
1399
- a.setAttribute("role", "presentation"), a.style.cssText = `table-layout:fixed;border-collapse:collapse;border-spacing:0;margin:0;width:${r}px;background:var(--og-header-bg,#f5f5f5);`;
1400
- const c = e.length;
1401
- let h = 0;
1402
- const u = (f, E, x, g = "") => {
1403
- const w = D("th", `og-header-cell og-extra-col ${g}`);
1404
- w.setAttribute("rowspan", String(c)), w.textContent = x, Ae(w, {
1405
- width: `${E}px`,
1406
- minWidth: `${E}px`,
1407
- textAlign: "center",
1408
- borderRight: "1px solid var(--og-border-color,#e0e0e0)",
1409
- borderBottom: "1px solid var(--og-border-color,#e0e0e0)",
1410
- // host isolation: extra 컬럼 th 도 호스트 th{} 침범 차단 (border/line-height)
1411
- borderTop: "0",
1412
- borderLeft: "0",
1413
- lineHeight: "normal",
1414
- verticalAlign: "middle",
1415
- padding: "0",
1416
- fontSize: "11px",
1417
- color: "#999",
1418
- userSelect: "none",
1419
- boxSizing: "border-box",
1420
- background: "var(--og-header-bg,#f5f5f5)"
1421
- }), o > 0 && (w.style.position = "sticky", w.style.left = `${h}px`, w.style.zIndex = "4"), h += E, f.appendChild(w);
1422
- };
1423
- for (let f = 0; f < e.length; f++) {
1424
- const E = D("tr", "og-header-row");
1425
- if (E.style.height = `${n.headerHeight}px`, f === 0 && (n.stateColumn && u(E, 24, ""), n.draggable && u(E, 18, ""), n.rowNumber && u(E, 44, "No"), n.checkColumn)) {
1426
- const x = D("th", "og-header-cell og-extra-col");
1427
- x.setAttribute("rowspan", String(c)), x.style.cssText = "width:36px;min-width:36px;text-align:center;border-right:1px solid var(--og-border-color,#e0e0e0);border-bottom:1px solid var(--og-border-color,#e0e0e0);border-top:0;border-left:0;line-height:normal;vertical-align:middle;background:var(--og-header-bg,#f5f5f5);box-sizing:border-box;", o > 0 && (x.style.position = "sticky", x.style.left = `${h}px`, x.style.zIndex = "4"), h += 36;
1428
- const g = document.createElement("input");
1429
- g.type = "checkbox", g.setAttribute("aria-label", "전체 행 선택"), g.style.cssText = "width:16px;height:16px;", g.addEventListener("change", () => this._cbs.onAllCheck(g.checked)), x.appendChild(g), E.appendChild(x);
1430
- }
1431
- for (const x of e[f] ?? []) {
1432
- const g = D("th", "og-header-cell"), w = x.column;
1433
- x.colSpan > 1 && (g.colSpan = x.colSpan), x.rowSpan > 1 && (g.rowSpan = x.rowSpan);
1434
- const L = x.colSpan === 1 ? t.findIndex((_) => _.field === w.field) : -1;
1435
- if (x.colSpan === 1) {
1436
- const _ = L >= 0 ? s[L] ?? n.defaultColumnWidth : w.width ?? n.defaultColumnWidth;
1437
- g.style.width = `${_}px`, g.style.minWidth = `${_}px`;
1438
- }
1439
- const v = i.find((_) => _.field === w.field), C = w.sortable !== !1 && n.sortable && x.colSpan === 1;
1440
- if (g.setAttribute("role", "columnheader"), g.setAttribute("scope", "col"), C && (g.setAttribute("aria-sort", v ? v.dir === "asc" ? "ascending" : "descending" : "none"), g.tabIndex = L === 0 ? 0 : -1, g.addEventListener("keydown", (_) => {
1441
- if (_.key === "Enter" || _.key === " ")
1442
- _.preventDefault(), this._cbs.onHeaderClick(w.field, _.shiftKey);
1443
- else if (_.key === "ArrowRight") {
1444
- _.preventDefault();
1445
- const b = g.nextElementSibling;
1446
- (b == null ? void 0 : b.tagName) === "TH" && b.focus();
1447
- } else if (_.key === "ArrowLeft") {
1448
- _.preventDefault();
1449
- const b = g.previousElementSibling;
1450
- (b == null ? void 0 : b.tagName) === "TH" && b.focus();
1451
- }
1452
- })), L >= 0 && L < o) {
1453
- let _ = 0;
1454
- n.stateColumn && (_ += 24), n.draggable && (_ += 18), n.rowNumber && (_ += 44), n.checkColumn && (_ += 36);
1455
- for (let b = 0; b < L; b++) _ += s[b] ?? n.defaultColumnWidth;
1456
- g.classList.add("og-frozen"), L === o - 1 && g.classList.add("og-frozen-last"), g.style.left = `${_}px`;
1457
- }
1458
- Ae(g, {
1459
- padding: "4px 8px",
1460
- boxSizing: "border-box",
1461
- // host isolation: 헤더 <th> 의 모든 시각 속성을 인라인으로 고정한다.
1462
- // 임베드 호스트(WordPress 등)가 `.entry-content th`/`.fn-post-content th`(특이도 0,2,1)로
1463
- // 배경·글자·라인높이·보더·폰트크기를 덮어써도 인라인(최고 우선순위)이 이긴다.
1464
- // (var 참조라 setTheme 시 자동 반영. text-align/padding 은 그리드 의도값 유지)
1465
- background: "var(--og-header-bg)",
1466
- color: "var(--og-header-color)",
1467
- lineHeight: "normal",
1468
- verticalAlign: "middle",
1469
- fontSize: "var(--og-font-size)",
1470
- textAlign: w.headerAlign ?? "center",
1471
- borderTop: "0",
1472
- borderLeft: "0",
1473
- borderRight: "1px solid var(--og-border-color,#e0e0e0)",
1474
- borderBottom: "1px solid var(--og-border-color,#e0e0e0)",
1475
- userSelect: "none",
1476
- cursor: C ? "pointer" : "default",
1477
- whiteSpace: "nowrap",
1478
- overflow: "hidden",
1479
- textOverflow: "ellipsis",
1480
- position: "relative"
1481
- }), g.title = (typeof w.tooltip == "string" ? w.tooltip : w.header ?? w.field) ?? "";
1482
- const F = D("span");
1483
- if (F.textContent = w.header ?? w.field, F.style.cssText = "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;", g.appendChild(F), v) {
1484
- g.classList.add("og-sorted");
1485
- const _ = D("span", "og-sort-icon");
1486
- _.textContent = v.dir === "asc" ? " ↑" : " ↓", g.appendChild(_);
1487
- }
1488
- if (w.filterable !== !1 && n.filterable && x.colSpan === 1) {
1489
- const _ = D("span", "og-filter-icon"), b = ((M = (p = n._activeFilters) == null ? void 0 : p[w.field]) == null ? void 0 : M.length) > 0;
1490
- _.textContent = b ? "⊿" : "▿", _.title = "필터", _.style.cssText = "margin-left:3px;cursor:pointer;font-size:10px;opacity:0.6;", b && _.classList.add("og-filter-icon--active"), _.addEventListener("click", (T) => {
1491
- T.stopPropagation(), this._cbs.onFilterIconClick(w.field, _);
1492
- }), g.appendChild(_);
1493
- }
1494
- if (w.resizable !== !1) {
1495
- const _ = D("div", "og-resize-handle");
1496
- _.style.cssText = "position:absolute;right:0;top:0;bottom:0;width:4px;cursor:col-resize;z-index:1;", g.appendChild(_);
1497
- const b = L;
1498
- Dt(_, g, (T) => {
1499
- b >= 0 && this._cbs.onColResize(b, T);
1500
- });
1501
- }
1502
- n.columnReorder && L >= 0 && x.colSpan === 1 && (g.draggable = !0, g.addEventListener("dragstart", (_) => {
1503
- var b;
1504
- this._cbs.onColDragStart(L), g.classList.add("og-col-dragging"), (b = _.dataTransfer) == null || b.setData("text/plain", String(L));
1505
- }), g.addEventListener("dragend", () => {
1506
- g.classList.remove("og-col-dragging"), this._header.querySelectorAll(".og-col-drop-over").forEach((_) => _.classList.remove("og-col-drop-over"));
1507
- }), g.addEventListener("dragover", (_) => {
1508
- _.preventDefault();
1509
- const b = this._cbs.getColDragIdx();
1510
- b !== null && b !== L && (this._header.querySelectorAll(".og-col-drop-over").forEach((T) => T.classList.remove("og-col-drop-over")), g.classList.add("og-col-drop-over"));
1511
- }), g.addEventListener("dragleave", () => {
1512
- g.classList.remove("og-col-drop-over");
1513
- }), g.addEventListener("drop", (_) => {
1514
- _.preventDefault(), g.classList.remove("og-col-drop-over"), this._cbs.onColDrop(L);
1515
- })), C && g.addEventListener("click", (_) => {
1516
- _.target.classList.contains("og-resize-handle") || this._cbs.onHeaderClick(w.field, _.shiftKey);
1517
- }), E.appendChild(g);
1518
- }
1519
- a.appendChild(E);
1520
- }
1521
- this._header.appendChild(a);
1522
- }
1523
- renderBody(e, t, s, i, n, o, l, r, a, c, h = null, u, p, M = {}, f) {
1524
- var w, L;
1525
- Object.keys(M).length && (o = { ...o, ...M }), this._body.innerHTML = "", this._cellMap.clear();
1526
- const E = o.autoHeight === !0;
1527
- this._body.classList.toggle("og-autoheight", E), this._body.style.height = E ? "" : `${r}px`;
1528
- const x = o._frozenCount ?? 0;
1529
- {
1530
- let v = 0;
1531
- o.stateColumn && (v += 24), o.draggable && (v += 18), o.rowNumber && (v += 44), o.checkColumn && (v += 36);
1532
- const C = v + i.reduce((F, K, _) => F + (n[_] ?? o.defaultColumnWidth), 0);
1533
- this._body.style.minWidth = `${C}px`;
1534
- }
1535
- if (t < e) return;
1536
- const g = document.createDocumentFragment();
1537
- for (let v = e; v <= t; v++) {
1538
- const C = h ? h[v] : null, F = C && C._isGroup === !0, K = C && C._isTree === !0;
1539
- if (F) {
1540
- const m = C, S = `__${m._groupField}:${m._groupValue}`, z = D("div", "og-group-row"), ie = l + (v - e) * o.rowHeight;
1541
- z.style.cssText = [
1542
- E ? "" : `top:${ie}px;height:${o.rowHeight}px;`,
1543
- "display:flex;align-items:stretch;cursor:pointer;",
1544
- `padding-left:${4 + m._depth * 12}px;`,
1545
- "background:var(--og-header-bg,#f5f5f5);",
1546
- // host isolation: border:0 선행 (WP :where([style*=border-color]) 의 3px 강제 차단)
1547
- "border:0;border-bottom:1px solid var(--og-border-color,#e0e0e0);"
1548
- ].join(""), z.setAttribute("role", "row"), z.setAttribute("aria-expanded", m._expanded ? "true" : "false"), z.setAttribute("aria-rowindex", String(v + 1)), z.setAttribute("aria-level", String(m._depth + 1));
1549
- let P = 0;
1550
- if (o.stateColumn && (P += 24), o.draggable && (P += 18), o.rowNumber && (P += 44), o.checkColumn && (P += 36), P > 0) {
1551
- const y = D("div", "og-group-state-cell");
1552
- y.style.cssText = [
1553
- `width:${P}px;min-width:${P}px;flex-shrink:0;`,
1554
- "display:flex;align-items:center;justify-content:center;",
1555
- "font-size:10px;font-weight:700;gap:2px;",
1556
- "border-right:1px solid var(--og-border-color,#e0e0e0);"
1557
- ].join("");
1558
- const I = m._states ?? { added: 0, edited: 0, removed: 0 };
1559
- if (I.added > 0) {
1560
- const H = D("span");
1561
- H.textContent = `+${I.added}`, H.style.cssText = "color:var(--og-row-added-bg,#2e7d32);background:#e8f5e9;padding:1px 3px;border-radius:3px;", y.appendChild(H);
1562
- }
1563
- if (I.edited > 0) {
1564
- const H = D("span");
1565
- H.textContent = `M${I.edited}`, H.style.cssText = "color:#e65100;background:#fff8e1;padding:1px 3px;border-radius:3px;", y.appendChild(H);
1566
- }
1567
- if (I.removed > 0) {
1568
- const H = D("span");
1569
- H.textContent = `D${I.removed}`, H.style.cssText = "color:var(--og-row-removed-bg,#c62828);background:#ffebee;padding:1px 3px;border-radius:3px;", y.appendChild(H);
1570
- }
1571
- z.appendChild(y);
1572
- }
1573
- let O = !1;
1574
- for (let y = 0; y < i.length; y++) {
1575
- const I = i[y], H = n[y] ?? o.defaultColumnWidth, ne = m._summaryFmt !== void 0 && I.field in (m._summaryFmt ?? {}), B = D("div", "og-group-cell");
1576
- if (B.style.cssText = [
1577
- `width:${H}px;min-width:${H}px;flex-shrink:0;`,
1578
- "padding:2px 8px;box-sizing:border-box;overflow:hidden;",
1579
- "border-right:1px solid var(--og-border-color,#e0e0e0);",
1580
- "display:flex;align-items:center;",
1581
- "white-space:nowrap;text-overflow:ellipsis;"
1582
- ].join(""), ne) {
1583
- const j = m._summaryFmt[I.field];
1584
- B.textContent = j !== "" ? j : "-", B.style.justifyContent = "flex-end", B.style.color = "var(--og-primary,#1976d2)", B.style.fontWeight = "600";
1585
- } else if (!O) {
1586
- O = !0;
1587
- const j = D("span", "og-group-arrow");
1588
- j.textContent = m._expanded ? "▾ " : "▸ ", j.style.cssText = "color:var(--og-primary,#1976d2);margin-right:4px;flex-shrink:0;", B.appendChild(j);
1589
- const U = D("span", "og-group-label");
1590
- U.textContent = `${m._groupLabel} (${m._childCount}건)`, U.style.cssText = "overflow:hidden;text-overflow:ellipsis;font-weight:600;", B.appendChild(U), B.style.gap = "0";
1591
- }
1592
- z.appendChild(B);
1593
- }
1594
- z.addEventListener("click", () => u == null ? void 0 : u(S)), g.appendChild(z);
1595
- continue;
1596
- }
1597
- const _ = K ? C : null, b = _ ? _.data : h ? C : s.getRowByIndex(v);
1598
- if (!b) continue;
1599
- const T = K || F ? "none" : s.getRowState(v), $ = D("div", "og-row");
1600
- if ($.setAttribute("role", "row"), $.setAttribute("aria-rowindex", String(v + 1)), !E) {
1601
- const m = l + (v - e) * o.rowHeight;
1602
- $.style.top = `${m}px`, $.style.height = `${o.rowHeight}px`;
1603
- }
1604
- let A = v % 2 === 0 ? "var(--og-row-bg,#fff)" : "var(--og-row-alt-bg,#fafafa)";
1605
- $.style.background = A, T === "added" && $.classList.add("og-state-added"), T === "edited" && $.classList.add("og-state-edited"), T === "removed" && $.classList.add("og-state-removed"), a.has(v) && $.classList.add("og-selected"), $.setAttribute("aria-selected", a.has(v) ? "true" : "false"), T === "added" && (A = "var(--og-row-added-bg,#e8f5e9)"), T === "edited" && (A = "var(--og-row-edited-bg,#fff8e1)"), T === "removed" && (A = "var(--og-row-removed-bg,#ffebee)"), a.has(v) && (A = "var(--og-row-selected-bg,#bbdefb)");
1606
- const ae = v;
1607
- $.addEventListener("click", (m) => {
1608
- this._cbs.onCellClick(ae, -1, m);
1609
- });
1610
- const de = /* @__PURE__ */ new Map();
1611
- let V = 0;
1612
- if (o.stateColumn) {
1613
- const m = D("div", "og-cell og-col-state"), S = { added: "✚", edited: "✎", removed: "✖", none: "" }, z = { added: "#2e7d32", edited: "#bf360c", removed: "#c62828", none: "" };
1614
- m.textContent = S[T] ?? "", m.style.color = z[T] ?? "", m.title = T, x > 0 && (m.style.position = "sticky", m.style.left = `${V}px`, m.style.zIndex = "2", m.style.background = A), V += 24, $.appendChild(m);
1615
- }
1616
- const Q = this._cbs.getDndManager();
1617
- if (o.draggable && Q) {
1618
- const m = Q.attachHandle($, v, o._totalRows ?? t + 1);
1619
- x > 0 && (m.style.position = "sticky", m.style.left = `${V}px`, m.style.zIndex = "2", m.style.background = A), V += 18, $.appendChild(m);
1620
- }
1621
- if (o.rowNumber) {
1622
- const m = D("div", "og-cell og-col-rownum");
1623
- m.textContent = String(v + 1), x > 0 && (m.style.position = "sticky", m.style.left = `${V}px`, m.style.zIndex = "2", m.style.background = A), V += 44, $.appendChild(m);
1624
- }
1625
- if (o.checkColumn) {
1626
- const m = D("div", "og-cell og-col-check"), S = document.createElement("input");
1627
- S.type = "checkbox", S.checked = c.has(v), S.setAttribute("aria-label", `${v + 1}행 선택`), S.addEventListener("click", (z) => z.stopPropagation()), S.addEventListener("change", (z) => {
1628
- z.stopPropagation(), this._cbs.onRowCheck(v, S.checked);
1629
- }), m.appendChild(S), x > 0 && (m.style.position = "sticky", m.style.left = `${V}px`, m.style.zIndex = "2", m.style.background = A), V += 36, $.appendChild(m);
1630
- }
1631
- for (let m = 0; m < i.length; m++) {
1632
- const S = i[m], z = n[m] ?? o.defaultColumnWidth, ie = o.editable && S.editable !== !1, P = m === 0, O = f && !f.isEmpty ? f.getInfo(v, m) : null;
1633
- if (O != null && O.hidden) {
1634
- const k = D("div", "og-cell og-cell--merge-ph");
1635
- k.style.cssText = `width:${z}px;min-width:${z}px;flex-shrink:0;visibility:hidden;box-sizing:border-box;`, $.appendChild(k);
1636
- continue;
1637
- }
1638
- const y = D("div", "og-cell");
1639
- y.setAttribute("role", "gridcell"), y.setAttribute("aria-colindex", String(m + 1));
1640
- const I = (O == null ? void 0 : O.rowSpan) ?? 1, H = (O == null ? void 0 : O.colSpan) ?? 1, ne = I > 1 ? I * o.rowHeight : o.rowHeight;
1641
- let B = z;
1642
- if (H > 1)
1643
- for (let k = 1; k < H; k++)
1644
- B += n[m + k] ?? o.defaultColumnWidth;
1645
- const j = m < x;
1646
- let U = 0;
1647
- if (j) {
1648
- o.stateColumn && (U += 24), o.draggable && (U += 18), o.rowNumber && (U += 44), o.checkColumn && (U += 36);
1649
- for (let k = 0; k < m; k++) U += n[k] ?? o.defaultColumnWidth;
1650
- y.classList.add("og-frozen-cell"), m === x - 1 && y.classList.add("og-frozen-last");
1651
- }
1652
- y.style.width = `${B}px`, y.style.minWidth = `${B}px`, y.style.maxWidth = `${B}px`, I > 1 && (y.style.height = `${ne}px`), j && (y.style.background = A), _ && P && (y.style.padding = "0"), y.style.overflow = "hidden", I > 1 ? (y.style.height = `${ne}px`, y.style.position = "absolute", y.style.zIndex = "3", y.style.background = A && A !== "inherit" ? A : "var(--og-row-bg, #fff)", y.style.borderTop = "0", y.style.borderLeft = "0", y.style.borderBottom = "1px solid var(--og-border-color, #e0e0e0)") : j && (y.style.position = "sticky", y.style.left = `${U}px`, y.style.zIndex = "1"), S.type === "number" || S.align === "right" ? y.classList.add("og-cell--right") : S.align === "center" && y.classList.add("og-cell--center"), ie && y.classList.add("og-cell--editable"), S.wrap && y.classList.add("og-cell--wrap"), ie || y.setAttribute("aria-readonly", "true"), H > 1 && y.setAttribute("aria-colspan", String(H)), I > 1 && y.setAttribute("aria-rowspan", String(I)), ((w = o._focusCell) == null ? void 0 : w.ri) === v && ((L = o._focusCell) == null ? void 0 : L.ci) === m && (y.classList.add("og-cell-focused"), y.tabIndex = -1);
1653
- const Z = b ? b[S.field] : null;
1654
- y.setAttribute("aria-label", `${S.header}: ${Z == null ? "" : String(Z)}`), S.tooltip != null ? y.title = typeof S.tooltip == "function" ? String(S.tooltip(Z, b) ?? "") : String(S.tooltip) : o.tooltips && Z != null && Z !== "" && (y.title = String(Z));
1655
- let Ee = y;
1656
- if (_ && P) {
1657
- const k = D("div", "og-tree-cell"), G = _._ancestorHasMore ?? [];
1658
- for (let N = 0; N < _._depth; N++) {
1659
- const q = D("span", "og-tree-guide");
1660
- G[N] && q.classList.add("og-tree-guide--line"), k.appendChild(q);
1661
- }
1662
- if (_._depth > 0) {
1663
- const N = D("span", "og-tree-connector");
1664
- N.classList.add(
1665
- _._isLastChild ? "og-tree-connector--last" : "og-tree-connector--mid"
1666
- ), k.appendChild(N);
1667
- }
1668
- const oe = D("span", "og-tree-toggle-wrap");
1669
- if (!_._hasChildren) {
1670
- const N = D("span", "og-tree-leaf-dot");
1671
- oe.appendChild(N);
1672
- }
1673
- k.appendChild(oe);
1674
- const W = document.createElement("i");
1675
- if (_._hasChildren) {
1676
- const N = $e(S.treeNodeIcon, b, !0, _._expanded);
1677
- W.className = _._expanded ? `${N} og-tree-node-icon og-tree-node-icon--branch og-tree-node-icon--open og-tree-node-icon--toggle` : `${N} og-tree-node-icon og-tree-node-icon--branch og-tree-node-icon--toggle`, W.setAttribute("role", "button"), W.setAttribute("tabindex", "0"), W.setAttribute("aria-expanded", _._expanded ? "true" : "false"), W.setAttribute("aria-label", _._expanded ? "접기" : "펼치기"), W.addEventListener("click", (q) => {
1678
- q.stopPropagation(), p == null || p(_._treeId);
1679
- }), W.addEventListener("keydown", (q) => {
1680
- (q.key === "Enter" || q.key === " ") && (q.preventDefault(), q.stopPropagation(), p == null || p(_._treeId));
1681
- });
1682
- } else {
1683
- const N = $e(S.treeNodeIcon, b, !1, !1);
1684
- W.setAttribute("aria-hidden", "true"), W.className = `${N} og-tree-node-icon og-tree-node-icon--leaf`;
1685
- }
1686
- k.appendChild(W), y.appendChild(k), Ee = k;
1687
- }
1688
- if (S.cellStyle) {
1689
- const k = b[S.field], G = typeof S.cellStyle == "function" ? S.cellStyle(k, b, v) : S.cellStyle;
1690
- Object.assign(y.style, G);
1691
- }
1692
- const et = Ft(S).render({
1693
- value: b[S.field],
1694
- row: b,
1695
- rowIndex: v,
1696
- column: S,
1697
- colIndex: m,
1698
- isSelected: a.has(v),
1699
- rowState: T
1700
- });
1701
- Ee.appendChild(et);
1702
- const X = v, Y = m;
1703
- if (y.addEventListener("click", (k) => {
1704
- k.stopPropagation(), this._cbs.onCellClick(X, Y, k);
1705
- }), y.addEventListener("dblclick", (k) => {
1706
- k.stopPropagation(), this._cbs.onCellDblClick(X, Y, k);
1707
- }), y.addEventListener("mouseover", (k) => {
1708
- k.stopPropagation(), this._cbs.onCellMouseOver(X, Y, k);
1709
- }), y.addEventListener("mouseout", (k) => {
1710
- k.stopPropagation(), this._cbs.onCellMouseOut(X, Y, k);
1711
- }), y.addEventListener("mousedown", (k) => {
1712
- k.stopPropagation(), this._cbs.onCellMouseDown(X, Y, k);
1713
- }), y.addEventListener("mouseup", (k) => {
1714
- k.stopPropagation(), this._cbs.onCellMouseUp(X, Y, k);
1715
- }), y.addEventListener("mousemove", (k) => {
1716
- k.stopPropagation(), this._cbs.onCellMouseMove(X, Y, k);
1717
- }), de.set(m, y), I > 1) {
1718
- const k = document.createElement("div");
1719
- k.style.cssText = [
1720
- `width:${z}px;min-width:${z}px;height:${o.rowHeight}px;`,
1721
- "flex-shrink:0;box-sizing:border-box;",
1722
- "border-right:1px solid var(--og-border-color,#e0e0e0);"
1723
- ].join(""), $.appendChild(k);
1724
- let G = 0;
1725
- o.stateColumn && (G += 24), o.draggable && (G += 18), o.rowNumber && (G += 44), o.checkColumn && (G += 36);
1726
- for (let W = 0; W < m; W++) G += n[W] ?? o.defaultColumnWidth;
1727
- const oe = l + (v - e) * o.rowHeight;
1728
- y.style.left = `${G}px`, y.style.top = `${oe}px`, g.appendChild(y);
1729
- } else
1730
- $.appendChild(y);
1731
- }
1732
- this._cellMap.set(v, de), g.appendChild($);
1733
- }
1734
- if (s.rowCount === 0) {
1735
- const v = D("div", "og-empty-message");
1736
- v.textContent = "데이터가 없습니다.", v.style.cssText = "width:100%;", g.appendChild(v);
1737
- }
1738
- this._body.appendChild(g);
1739
- }
1740
- getCellEl(e, t) {
1741
- var s;
1742
- return (s = this._cellMap.get(e)) == null ? void 0 : s.get(t);
1743
- }
1744
- destroy() {
1745
- this._root.innerHTML = "";
1746
- }
1747
- }
1748
- function $e(d, e, t, s) {
1749
- let i;
1750
- return d ? typeof d == "function" ? i = d(e, t, s) : t ? i = s ? d.branchOpen ?? "bi-folder2-open" : d.branch ?? "bi-folder2" : i = d.leaf ?? "bi-file-earmark" : i = t ? s ? "bi-folder2-open" : "bi-folder2" : "bi-file-earmark", i.startsWith("bi ") ? i : `bi ${i}`;
1751
- }
1752
- function D(d, e) {
1753
- const t = document.createElement(d);
1754
- return e && (t.className = e), t;
1755
- }
1756
- function Ae(d, e) {
1757
- Object.assign(d.style, e);
1758
- }
1759
- function ze(d, e, t = "text/plain;charset=utf-8") {
1760
- const s = new Blob([d], { type: t }), i = URL.createObjectURL(s), n = document.createElement("a");
1761
- n.href = i, n.download = e, n.click(), URL.revokeObjectURL(i);
1762
- }
1763
- function Dt(d, e, t) {
1764
- let s = 0, i = 0;
1765
- d.addEventListener("mousedown", (n) => {
1766
- n.stopPropagation(), n.preventDefault(), s = n.clientX, i = e.offsetWidth;
1767
- const o = (r) => {
1768
- const a = Math.max(40, i + r.clientX - s);
1769
- e.style.width = `${a}px`, e.style.minWidth = `${a}px`;
1770
- }, l = (r) => {
1771
- document.removeEventListener("mousemove", o), document.removeEventListener("mouseup", l), t(Math.max(40, i + r.clientX - s));
1772
- };
1773
- document.addEventListener("mousemove", o), document.addEventListener("mouseup", l);
1774
- });
1775
- }
1776
- class $t {
1777
- constructor(e) {
1778
- this._selectedRows = /* @__PURE__ */ new Set(), this._checkedRows = /* @__PURE__ */ new Set(), this._data = e;
1779
- }
1780
- // ─── Read-only 접근 ───────────────────────────────────────
1781
- get selectedRows() {
1782
- return this._selectedRows;
1783
- }
1784
- get checkedRows() {
1785
- return this._checkedRows;
1786
- }
1787
- // ─── 선택 변경 ───────────────────────────────────────────
1788
- selectSingle(e) {
1789
- this._selectedRows.clear(), this._selectedRows.add(e);
1790
- }
1791
- selectToggle(e) {
1792
- this._selectedRows.has(e) ? this._selectedRows.delete(e) : this._selectedRows.add(e);
1793
- }
1794
- clearSelection() {
1795
- this._selectedRows.clear();
1796
- }
1797
- // ─── 체크 변경 ───────────────────────────────────────────
1798
- check(e, t) {
1799
- t ? this._checkedRows.add(e) : this._checkedRows.delete(e);
1800
- }
1801
- checkAll(e, t) {
1802
- if (e)
1803
- for (let s = 0; s < t; s++) this._checkedRows.add(s);
1804
- else
1805
- this._checkedRows.clear();
1806
- }
1807
- checkByValue(e, t) {
1808
- for (let s = 0; s < this._data.rowCount; s++)
1809
- t.includes(this._data.getCellValue(s, e)) && this._checkedRows.add(s);
1810
- }
1811
- uncheckAll() {
1812
- this._checkedRows.clear();
1813
- }
1814
- checkById(e) {
1815
- }
1816
- addCheckById(e) {
1817
- }
1818
- uncheckById(e) {
1819
- }
1820
- // ─── 선택 쿼리 API ───────────────────────────────────────
1821
- getSelections() {
1822
- return [...this._selectedRows].map((e) => this._data.getRowByIndex(e)).filter(Boolean);
1823
- }
1824
- getChecked() {
1825
- return [...this._checkedRows].map((e) => ({
1826
- row: this._data.getRowByIndex(e),
1827
- rowIndex: e
1828
- }));
1829
- }
1830
- getAllChecked() {
1831
- return this.getChecked().map((e) => e.row);
1832
- }
1833
- getActiveRow() {
1834
- return this._selectedRows.size > 0 ? [...this._selectedRows][0] : -1;
1835
- }
1836
- activate(e) {
1837
- this._selectedRows.clear(), this._selectedRows.add(e);
1838
- }
1839
- deselect() {
1840
- this._selectedRows.clear();
1841
- }
1842
- // ─── 전체 초기화 (setData / clearData 시) ────────────────
1843
- reset() {
1844
- this._selectedRows.clear(), this._checkedRows.clear();
1845
- }
1846
- }
1847
- class ye {
1848
- constructor() {
1849
- this._onKeyDown = (e) => {
1850
- e.stopPropagation(), e.key === "Enter" ? (e.preventDefault(), this._onCommit(this.input.value)) : e.key === "Escape" && this._onCancel();
1851
- }, this._onBlur = () => {
1852
- this._onCommit(this.input.value);
1853
- };
1854
- }
1855
- mount(e, t, s, i) {
1856
- this._container = e, this._onCommit = s, this._onCancel = i, e.setAttribute("aria-haspopup", "dialog"), e.setAttribute("aria-expanded", "true"), this.input = document.createElement("input"), this.input.type = "date", this.input.className = "og-cell-input", this.input.setAttribute("aria-label", t.column.header ?? "날짜 선택");
1857
- const n = t.value;
1858
- if (n) {
1859
- const o = n instanceof Date ? n : new Date(n);
1860
- isNaN(o.getTime()) || (this.input.value = Ue(o, "yyyy-MM-dd"));
1861
- }
1862
- this.input.addEventListener("keydown", this._onKeyDown), this.input.addEventListener("blur", this._onBlur), e.appendChild(this.input);
1863
- }
1864
- getValue() {
1865
- var e;
1866
- return (e = this.input) == null ? void 0 : e.value;
1867
- }
1868
- focus() {
1869
- var e;
1870
- (e = this.input) == null || e.focus();
1871
- }
1872
- destroy() {
1873
- var e, t, s;
1874
- (e = this._container) == null || e.setAttribute("aria-expanded", "false"), (t = this.input) == null || t.removeEventListener("keydown", this._onKeyDown), (s = this.input) == null || s.removeEventListener("blur", this._onBlur);
1875
- }
1876
- }
1877
- function He(d) {
1878
- return d.map((e) => typeof e == "string" ? { label: e, value: e } : { label: e.label ?? e.text ?? String(e.value ?? ""), value: e.value });
1879
- }
1880
- class we {
1881
- constructor(e = [], t) {
1882
- this._options = He(e), this._optionsFn = t ?? null;
1883
- }
1884
- mount(e, t, s, i) {
1885
- this._container = e, this._onCommit = s, this._onCancel = i, e.setAttribute("aria-haspopup", "listbox"), e.setAttribute("aria-expanded", "true"), this.select = document.createElement("select"), this.select.className = "og-cell-select", this.select.setAttribute("aria-label", t.column.header ?? "선택");
1886
- const n = this._optionsFn ? He(this._optionsFn(t.row, t.rowIndex)) : this._options;
1887
- for (const l of n) {
1888
- const r = document.createElement("option");
1889
- r.value = String(l.value), r.textContent = l.label, this.select.appendChild(r);
1890
- }
1891
- const o = t.value == null ? "" : String(t.value);
1892
- n.some((l) => String(l.value) === o) && (this.select.value = o), this.select.addEventListener("change", () => s(this.select.value)), this.select.addEventListener("blur", () => s(this.select.value)), this.select.addEventListener("keydown", (l) => {
1893
- l.key === "Escape" && i();
1894
- }), e.appendChild(this.select);
1895
- }
1896
- getValue() {
1897
- var e;
1898
- return (e = this.select) == null ? void 0 : e.value;
1899
- }
1900
- focus() {
1901
- var e;
1902
- (e = this.select) == null || e.focus();
1903
- }
1904
- destroy() {
1905
- var e;
1906
- (e = this._container) == null || e.setAttribute("aria-expanded", "false");
1907
- }
1908
- }
1909
- class ve {
1910
- constructor() {
1911
- this._onKeyDown = (e) => {
1912
- e.stopPropagation(), e.key === "Enter" || e.key === "Tab" ? (e.preventDefault(), this._onCommit(this.input.value)) : e.key === "Escape" && this._onCancel();
1913
- }, this._onBlur = () => {
1914
- this._onCommit(this.input.value);
1915
- };
1916
- }
1917
- mount(e, t, s, i) {
1918
- this._onCommit = s, this._onCancel = i, this.input = document.createElement("input"), this.input.type = "text", this.input.value = t.value == null ? "" : String(t.value), this.input.style.cssText = `
1919
- width:100%;height:100%;border:none;outline:none;padding:0 8px;
1920
- font-size:var(--og-font-size,13px);font-family:var(--og-font-family,sans-serif);
1921
- background:var(--og-row-bg,#fff);box-sizing:border-box;
1922
- `, this.input.addEventListener("keydown", this._onKeyDown), this.input.addEventListener("blur", this._onBlur), e.appendChild(this.input);
1923
- }
1924
- getValue() {
1925
- var e;
1926
- return (e = this.input) == null ? void 0 : e.value;
1927
- }
1928
- focus() {
1929
- var e, t;
1930
- (e = this.input) == null || e.focus(), (t = this.input) == null || t.select();
1931
- }
1932
- destroy() {
1933
- var e, t;
1934
- (e = this.input) == null || e.removeEventListener("keydown", this._onKeyDown), (t = this.input) == null || t.removeEventListener("blur", this._onBlur);
1935
- }
1936
- }
1937
- class xe {
1938
- constructor(e) {
1939
- this._onKeyDown = (t) => {
1940
- t.stopPropagation(), t.key === "Enter" || t.key === "Tab" ? (t.preventDefault(), this._commit()) : t.key === "Escape" && this._onCancel();
1941
- }, this._onBlur = () => {
1942
- this._commit();
1943
- }, this.min = e == null ? void 0 : e.min, this.max = e == null ? void 0 : e.max, this.step = e == null ? void 0 : e.step;
1944
- }
1945
- mount(e, t, s, i) {
1946
- this._onCommit = s, this._onCancel = i, this.input = document.createElement("input"), this.input.type = "number", this.input.value = t.value == null ? "" : String(t.value), this.min != null && (this.input.min = String(this.min)), this.max != null && (this.input.max = String(this.max)), this.step != null && (this.input.step = String(this.step)), this.input.style.cssText = `
1947
- width:100%;height:100%;border:none;outline:none;padding:0 8px;
1948
- font-size:var(--og-font-size,13px);text-align:right;
1949
- background:var(--og-row-bg,#fff);box-sizing:border-box;
1950
- `, this.input.addEventListener("keydown", this._onKeyDown), this.input.addEventListener("blur", this._onBlur), e.appendChild(this.input);
1951
- }
1952
- _commit() {
1953
- const e = this.input.value === "" ? null : Number(this.input.value);
1954
- this._onCommit(e);
1955
- }
1956
- getValue() {
1957
- var e, t;
1958
- return ((e = this.input) == null ? void 0 : e.value) === "" ? null : Number((t = this.input) == null ? void 0 : t.value);
1959
- }
1960
- focus() {
1961
- var e, t;
1962
- (e = this.input) == null || e.focus(), (t = this.input) == null || t.select();
1963
- }
1964
- destroy() {
1965
- var e, t;
1966
- (e = this.input) == null || e.removeEventListener("keydown", this._onKeyDown), (t = this.input) == null || t.removeEventListener("blur", this._onBlur);
1967
- }
1968
- }
1969
- class Ce {
1970
- mount(e, t, s, i) {
1971
- this._onCommit = s, e.style.cssText += "display:flex;align-items:center;justify-content:center;", this.chk = document.createElement("input"), this.chk.type = "checkbox", this.chk.checked = !!t.value, this.chk.style.cursor = "pointer", this.chk.addEventListener("change", () => s(this.chk.checked)), e.appendChild(this.chk);
1972
- }
1973
- getValue() {
1974
- var e;
1975
- return (e = this.chk) == null ? void 0 : e.checked;
1976
- }
1977
- focus() {
1978
- var e;
1979
- (e = this.chk) == null || e.focus();
1980
- }
1981
- destroy() {
1982
- }
1983
- }
1984
- function Ie(d) {
1985
- const e = d.editor;
1986
- if (!e)
1987
- switch (d.type) {
1988
- case "number":
1989
- return new xe();
1990
- case "date":
1991
- return new ye();
1992
- case "boolean":
1993
- return new Ce();
1994
- case "select":
1995
- return new we(d.options ?? [], d.optionsFn);
1996
- default:
1997
- return new ve();
1998
- }
1999
- if (typeof e == "string")
2000
- switch (e) {
2001
- case "number":
2002
- return new xe();
2003
- case "date":
2004
- return new ye();
2005
- case "select":
2006
- return new we(d.options ?? [], d.optionsFn);
2007
- case "checkbox":
2008
- return new Ce();
2009
- default:
2010
- return new ve();
2011
- }
2012
- switch (e.type) {
2013
- case "number": {
2014
- const t = {};
2015
- return e.min != null && (t.min = e.min), e.max != null && (t.max = e.max), e.step != null && (t.step = e.step), new xe(t);
2016
- }
2017
- case "date":
2018
- return new ye();
2019
- case "select":
2020
- return new we(e.options ?? [], d.optionsFn);
2021
- case "checkbox":
2022
- return new Ce();
2023
- default:
2024
- return new ve();
2025
- }
2026
- }
2027
- function te(d) {
2028
- const e = typeof d.renderer == "string" ? d.renderer : d.renderer && typeof d.renderer == "object" ? d.renderer.type : "";
2029
- return d.type === "boolean" || d.type === "checkbox" || e === "checkbox" || e === "switch";
2030
- }
2031
- class At {
2032
- constructor(e) {
2033
- this._activeEditor = null, this._editCell = null, this._focusCell = null, this._dragColIdx = null, this._d = e;
2034
- }
2035
- // ─── 상태 접근자 ─────────────────────────────────────────
2036
- get activeEditor() {
2037
- return this._activeEditor;
2038
- }
2039
- get editCell() {
2040
- return this._editCell;
2041
- }
2042
- get focusCell() {
2043
- return this._focusCell;
2044
- }
2045
- get dragColIdx() {
2046
- return this._dragColIdx;
2047
- }
2048
- set dragColIdx(e) {
2049
- this._dragColIdx = e;
2050
- }
2051
- // ─── 포커스 셀 ───────────────────────────────────────────
2052
- setFocusCell(e, t) {
2053
- this._focusCell = { ri: e, ci: t }, this._d.scrollToRow(e), this._d.doRender();
2054
- const s = this._d.getVisibleLeaves()[t], i = this._d.data.getRowByIndex(e);
2055
- if (s && i) {
2056
- const n = i[s.field];
2057
- this._d.announce(
2058
- `${e + 1}행 ${t + 1}열, ${s.header}: ${n == null ? "빈 값" : String(n)}`
2059
- );
2060
- }
2061
- }
2062
- clearFocusCell() {
2063
- this._focusCell = null;
2064
- }
2065
- // ─── 편집 시작 (키보드) ──────────────────────────────────
2066
- startEditByKey(e, t) {
2067
- var a, c, h;
2068
- const s = this._d.getVisibleLeaves()[t];
2069
- if (!s) return;
2070
- if (te(s)) {
2071
- const u = this._d.getOptions();
2072
- if (s.editable !== !1 && (s.editable !== void 0 || u.editable)) {
2073
- const M = this._d.data.getRowByIndex(e);
2074
- M && this._d.writeCell(e, s.field, !M[s.field]);
2075
- }
2076
- return;
2077
- }
2078
- const i = this._d.data.getRowByIndex(e);
2079
- if (s.editable === !1 || typeof s.editable == "function" && !s.editable(i, e)) return;
2080
- this.commitEdit();
2081
- const n = (a = this._d.getRenderer()) == null ? void 0 : a.getCellEl(e, t);
2082
- if (!n) return;
2083
- n.innerHTML = "";
2084
- const o = Ie(s);
2085
- this._activeEditor = o, this._editCell = { ri: e, ci: t };
2086
- const l = {
2087
- type: "editStart",
2088
- rowIndex: e,
2089
- columnIndex: t,
2090
- field: s.field,
2091
- oldValue: i == null ? void 0 : i[s.field],
2092
- newValue: i == null ? void 0 : i[s.field],
2093
- row: i,
2094
- column: s
2095
- };
2096
- this._d.emit("editStart", l), (h = (c = this._d.getOptions()).onEditStart) == null || h.call(c, l), n.classList.add("og-editing");
2097
- const r = {
2098
- value: i == null ? void 0 : i[s.field],
2099
- row: i,
2100
- rowIndex: e,
2101
- column: s,
2102
- colIndex: t,
2103
- isSelected: !0,
2104
- rowState: "none"
2105
- };
2106
- o.mount(
2107
- n,
2108
- r,
2109
- (u) => this.commitEditWithValue(e, t, u),
2110
- () => this.cancelEdit()
2111
- ), requestAnimationFrame(() => o.focus());
2112
- }
2113
- // ─── 편집 시작 (마우스) ──────────────────────────────────
2114
- startEdit(e, t, s) {
2115
- var h, u;
2116
- const i = this._d.getOptions();
2117
- if (!i.editable) return;
2118
- const n = this._d.getVisibleLeaves()[t];
2119
- if (!n || te(n)) return;
2120
- const o = this._d.data.getRowByIndex(e);
2121
- if (n.editable === !1 || typeof n.editable == "function" && !n.editable(o, e) || !n.editable && !i.editable) return;
2122
- this.commitEdit();
2123
- const l = (h = this._d.getRenderer()) == null ? void 0 : h.getCellEl(e, t);
2124
- if (!l) return;
2125
- l.innerHTML = "";
2126
- const r = Ie(n);
2127
- this._activeEditor = r, this._editCell = { ri: e, ci: t };
2128
- const a = {
2129
- type: "editStart",
2130
- rowIndex: e,
2131
- columnIndex: t,
2132
- field: n.field,
2133
- oldValue: o == null ? void 0 : o[n.field],
2134
- newValue: o == null ? void 0 : o[n.field],
2135
- row: o,
2136
- column: n
2137
- };
2138
- this._d.emit("editStart", a), (u = i.onEditStart) == null || u.call(i, a), l.classList.add("og-editing");
2139
- const c = {
2140
- value: o == null ? void 0 : o[n.field],
2141
- row: o,
2142
- rowIndex: e,
2143
- column: n,
2144
- colIndex: t,
2145
- isSelected: !0,
2146
- rowState: "none"
2147
- };
2148
- r.mount(
2149
- l,
2150
- c,
2151
- (p) => this.commitEditWithValue(e, t, p),
2152
- () => this.cancelEdit()
2153
- ), requestAnimationFrame(() => r.focus());
2154
- }
2155
- // ─── 편집 종료 ───────────────────────────────────────────
2156
- commitEdit() {
2157
- if (!this._activeEditor || !this._editCell) return;
2158
- const e = this._activeEditor.getValue(), { ri: t, ci: s } = this._editCell;
2159
- this._finishEdit(t, s, e, !1);
2160
- }
2161
- commitEditWithValue(e, t, s) {
2162
- this._finishEdit(e, t, s, !1);
2163
- }
2164
- cancelEdit() {
2165
- if (!this._editCell) return;
2166
- const { ri: e, ci: t } = this._editCell;
2167
- this._finishEdit(e, t, void 0, !0);
2168
- }
2169
- _finishEdit(e, t, s, i) {
2170
- var l, r, a;
2171
- if (!this._activeEditor) return;
2172
- const n = this._d.getVisibleLeaves()[t], o = (l = this._d.getRenderer()) == null ? void 0 : l.getCellEl(e, t);
2173
- if (o && (this._activeEditor.destroy(), o.classList.remove("og-editing")), this._activeEditor = null, this._editCell = null, !i && n) {
2174
- const c = this._d.data.getCellValue(e, n.field);
2175
- if (s !== c) {
2176
- this._d.data.updateCell(e, n.field, s);
2177
- const h = this._d.data.getRowByIndex(e), u = this._d.getOptions(), p = {
2178
- type: "editEnd",
2179
- rowIndex: e,
2180
- columnIndex: t,
2181
- field: n.field,
2182
- oldValue: c,
2183
- newValue: s,
2184
- row: h,
2185
- column: n
2186
- };
2187
- this._d.emit("editEnd", p), (r = u.onEditEnd) == null || r.call(u, p), this._d.emit("dataChange", this._d.data.getData()), (a = u.onDataChange) == null || a.call(u, this._d.data.getData());
2188
- }
2189
- }
2190
- this._d.doRender(), requestAnimationFrame(() => this._d.getContainer().focus({ preventScroll: !0 }));
2191
- }
2192
- }
2193
- class zt {
2194
- constructor(e, t, s, i, n) {
2195
- this._selects = /* @__PURE__ */ new Map(), this._selected = {}, this._config = t, this._onFilter = s, this._onReset = i, this._el = document.createElement("fieldset"), this._el.className = "og-filter-select";
2196
- const o = document.createElement("legend");
2197
- o.className = "og-filter-select-legend", o.textContent = t.legend ?? "필터", this._el.appendChild(o);
2198
- const l = document.createElement("div");
2199
- l.className = "og-filter-select-row";
2200
- for (const a of t.columns) {
2201
- const c = `og-fsel-${a.field}`, h = document.createElement("div");
2202
- h.className = "og-filter-select-group";
2203
- const u = document.createElement("label");
2204
- u.htmlFor = c, u.textContent = a.label, u.className = "og-filter-select-label";
2205
- const p = document.createElement("select");
2206
- p.id = c, p.className = "og-filter-select-sel", p.setAttribute("aria-label", a.label), n && p.setAttribute("aria-controls", n), a.dependsOn ? this._fill(p, [], !1) : this._fill(p, this._resolve(a, ""), !0), p.addEventListener("change", () => this._onChange(a.field, p.value)), h.appendChild(u), h.appendChild(p), l.appendChild(h), this._selects.set(a.field, p);
2207
- }
2208
- const r = document.createElement("button");
2209
- r.type = "button", r.textContent = "초기화", r.className = "og-filter-select-reset", r.setAttribute("aria-label", "필터 초기화"), r.addEventListener("click", () => this._reset()), this._el.appendChild(l), this._el.appendChild(r), e.insertBefore(this._el, e.firstChild);
2210
- }
2211
- // ─── 옵션 해결 ────────────────────────────────────────
2212
- /**
2213
- * 컬럼의 옵션 목록을 계산한다.
2214
- *
2215
- * @param col 대상 컬럼 정의
2216
- * @param parentValue 부모 선택값 (캐스케이딩 필터에 사용)
2217
- */
2218
- _resolve(e, t) {
2219
- if (e.options) return e.options;
2220
- let s = e.data ?? [];
2221
- e.dependsOn && e.dependsOnKey && t && (s = s.filter(
2222
- (o) => String(o[e.dependsOnKey] ?? "") === t
2223
- ));
2224
- const i = e.valueKey ?? "value", n = e.textKey ?? i;
2225
- return s.map((o) => ({
2226
- value: String(o[i] ?? ""),
2227
- text: String(o[n] ?? o[i] ?? "")
2228
- }));
2229
- }
2230
- // ─── select DOM 채우기 ────────────────────────────────
2231
- _fill(e, t, s) {
2232
- e.innerHTML = "";
2233
- const i = document.createElement("option");
2234
- i.value = "", i.textContent = "전체", e.appendChild(i);
2235
- for (const n of t) {
2236
- const o = document.createElement("option");
2237
- o.value = n.value, o.textContent = n.text, e.appendChild(o);
2238
- }
2239
- e.disabled = !s;
2240
- }
2241
- // ─── 선택 변경 처리 ───────────────────────────────────
2242
- _onChange(e, t) {
2243
- const s = this._config.columns.find((n) => n.field === e), i = s.filterKey ?? s.field;
2244
- t ? (this._selected[e] = t, this._onFilter(i, [{ operator: "=", value: t }])) : (delete this._selected[e], this._onReset(i)), this._cascade(e);
2245
- }
2246
- /**
2247
- * 부모 컬럼 변경 후 자식 컬럼 옵션을 재계산한다 (재귀).
2248
- */
2249
- _cascade(e) {
2250
- const t = this._selected[e] ?? "";
2251
- for (const s of this._config.columns) {
2252
- if (s.dependsOn !== e) continue;
2253
- const i = this._selects.get(s.field);
2254
- if (!i) continue;
2255
- const n = s.filterKey ?? s.field;
2256
- t ? (this._fill(i, this._resolve(s, t), !0), i.value = "", delete this._selected[s.field], this._onReset(n)) : (this._fill(i, [], !1), delete this._selected[s.field], this._onReset(n), this._cascade(s.field));
2257
- }
2258
- }
2259
- // ─── 전체 초기화 ──────────────────────────────────────
2260
- _reset() {
2261
- this._selected = {};
2262
- for (const e of this._config.columns) {
2263
- const t = this._selects.get(e.field), s = e.filterKey ?? e.field;
2264
- t && (e.dependsOn ? this._fill(t, [], !1) : (t.value = "", t.disabled = !1), this._onReset(s));
2265
- }
2266
- }
2267
- // ─── 공개 API ─────────────────────────────────────────
2268
- reset() {
2269
- this._reset();
2270
- }
2271
- destroy() {
2272
- this._el.remove();
2273
- }
2274
- }
2275
- class Ht {
2276
- constructor(e, t, s) {
2277
- this._page = 1, this._totalRows = 0, this._pageSize = t, this._onChange = s, this._el = document.createElement("div"), this._el.className = "og-pagination", this._el.style.cssText = `
2278
- display:flex;align-items:center;justify-content:center;gap:4px;
2279
- padding:6px 8px;border-top:1px solid var(--og-border-color,#e0e0e0);
2280
- background:var(--og-header-bg,#f5f5f5);flex-shrink:0;user-select:none;
2281
- font-size:12px;color:var(--og-text-color,#333);
2282
- `, e.appendChild(this._el), this._render();
2283
- }
2284
- get page() {
2285
- return this._page;
2286
- }
2287
- get pageSize() {
2288
- return this._pageSize;
2289
- }
2290
- get totalPages() {
2291
- return Math.max(1, Math.ceil(this._totalRows / this._pageSize));
2292
- }
2293
- /** 전체 행 수 갱신 → 현재 페이지 유효성 검사 후 재렌더 */
2294
- setTotalRows(e) {
2295
- this._totalRows = e, this._page > this.totalPages && (this._page = this.totalPages), this._render();
2296
- }
2297
- setPageSize(e) {
2298
- this._pageSize = e, this._page = 1, this._render(), this._emit();
2299
- }
2300
- goTo(e) {
2301
- const t = Math.max(1, Math.min(e, this.totalPages));
2302
- t !== this._page && (this._page = t, this._render(), this._emit());
2303
- }
2304
- /** 현재 페이지의 [startIndex, endIndex] 반환 (DataLayer 인덱스 기준) */
2305
- getRange() {
2306
- const e = (this._page - 1) * this._pageSize, t = Math.min(e + this._pageSize - 1, this._totalRows - 1);
2307
- return { start: e, end: t };
2308
- }
2309
- _emit() {
2310
- this._onChange({
2311
- page: this._page,
2312
- pageSize: this._pageSize,
2313
- totalRows: this._totalRows,
2314
- totalPages: this.totalPages
2315
- });
2316
- }
2317
- _render() {
2318
- this._el.innerHTML = "";
2319
- const e = this.totalPages, t = document.createElement("span");
2320
- t.style.cssText = "display:flex;align-items:center;gap:3px;margin-right:8px;";
2321
- const s = document.createElement("span");
2322
- s.textContent = "행/페이지:", s.style.color = "#888";
2323
- const i = document.createElement("select");
2324
- i.style.cssText = "padding:2px 4px;border:1px solid var(--og-border-color,#e0e0e0);border-radius:3px;font-size:11px;cursor:pointer;";
2325
- for (const c of [10, 20, 50, 100, 200]) {
2326
- const h = document.createElement("option");
2327
- h.value = String(c), h.textContent = String(c), c === this._pageSize && (h.selected = !0), i.appendChild(h);
2328
- }
2329
- i.addEventListener("change", () => this.setPageSize(Number(i.value))), t.appendChild(s), t.appendChild(i), this._el.appendChild(t);
2330
- const n = document.createElement("span"), { start: o, end: l } = this.getRange();
2331
- n.textContent = this._totalRows > 0 ? `${o + 1}–${l + 1} / ${this._totalRows}건` : "0건", n.style.cssText = "margin-right:8px;color:#888;", this._el.appendChild(n);
2332
- const r = (c, h, u) => {
2333
- const p = document.createElement("button");
2334
- return p.textContent = c, p.disabled = u, p.style.cssText = `
2335
- min-width:28px;height:24px;padding:0 6px;
2336
- border:1px solid var(--og-border-color,#e0e0e0);border-radius:3px;
2337
- background:${u ? "#f5f5f5" : "#fff"};
2338
- color:${u ? "#bbb" : "var(--og-text-color,#333)"};
2339
- cursor:${u ? "default" : "pointer"};font-size:12px;
2340
- `, u || p.addEventListener("click", () => this.goTo(h)), p;
2341
- };
2342
- this._el.appendChild(r("«", 1, this._page === 1)), this._el.appendChild(r("‹", this._page - 1, this._page === 1));
2343
- const a = It(this._page, e);
2344
- for (const c of a)
2345
- if (c === -1) {
2346
- const h = document.createElement("span");
2347
- h.textContent = "…", h.style.padding = "0 3px", this._el.appendChild(h);
2348
- } else {
2349
- const h = r(String(c), c, c === this._page);
2350
- c === this._page && (h.style.background = "var(--og-primary,#1976d2)", h.style.color = "#fff", h.style.borderColor = "var(--og-primary,#1976d2)"), this._el.appendChild(h);
2351
- }
2352
- this._el.appendChild(r("›", this._page + 1, this._page === e)), this._el.appendChild(r("»", e, this._page === e));
2353
- }
2354
- destroy() {
2355
- this._el.remove();
2356
- }
2357
- }
2358
- function It(d, e) {
2359
- if (e <= 7) return Array.from({ length: e }, (s, i) => i + 1);
2360
- const t = [1];
2361
- d > 3 && t.push(-1);
2362
- for (let s = Math.max(2, d - 1); s <= Math.min(e - 1, d + 1); s++)
2363
- t.push(s);
2364
- return d < e - 2 && t.push(-1), t.push(e), t;
2365
- }
2366
- class Bt {
2367
- // grab 지점의 상단 오프셋
2368
- constructor(e, t, s, i) {
2369
- this._dx = t - e.left, this._dy = s - e.top;
2370
- const n = document.createElement("div");
2371
- n.className = "og-drag-ghost", n.style.cssText = `position:fixed;left:0;top:0;width:${e.width}px;height:${Math.min(e.height, 40)}px;transform:translate(${e.left}px,${e.top}px);background:rgba(25,118,210,0.12);border:2px dashed #1976d2;box-sizing:border-box;pointer-events:none;z-index:10000;border-radius:3px;opacity:0.92;display:flex;align-items:center;padding-left:10px;font-size:12px;color:#1565c0;font-weight:600;white-space:nowrap;overflow:hidden;`, i > 1 && (n.textContent = `${i}개 행 이동`), document.body.appendChild(n), this._el = n;
2372
- }
2373
- /** 커서 위치로 이동 (grab 오프셋 유지) */
2374
- move(e, t) {
2375
- this._el.style.transform = `translate(${e - this._dx}px,${t - this._dy}px)`;
2376
- }
2377
- destroy() {
2378
- this._el.remove();
2379
- }
2380
- }
2381
- class Be {
2382
- constructor(e = "#1976d2") {
2383
- const t = document.createElement("div");
2384
- t.className = "og-drop-indicator", t.style.cssText = "position:absolute;left:0;right:0;display:none;align-items:center;pointer-events:none;z-index:9998;transform:translateY(-50%);";
2385
- const s = (n) => {
2386
- const o = document.createElement("div"), l = n === "left" ? `border-left:7px solid ${e}` : `border-right:7px solid ${e}`;
2387
- return o.style.cssText = `width:0;height:0;flex-shrink:0;border-top:5px solid transparent;border-bottom:5px solid transparent;${l};`, o;
2388
- }, i = document.createElement("div");
2389
- i.style.cssText = `flex:1;height:3px;background:${e};border-radius:2px;box-shadow:0 0 0 1px rgba(255,255,255,0.7);`, t.append(s("left"), i, s("right")), this._el = t;
2390
- }
2391
- /** parent(그리드 바디) 안의 top(행 경계) 위치에 표시 */
2392
- showIn(e, t) {
2393
- this._el.parentElement !== e && (this._el.remove(), e.appendChild(this._el)), this._el.style.display = "flex", this._el.style.top = `${t}px`;
2394
- }
2395
- hide() {
2396
- this._el.style.display = "none";
2397
- }
2398
- destroy() {
2399
- this._el.remove();
2400
- }
2401
- }
2402
- const We = (d, e, t) => Math.max(e, Math.min(t, d));
2403
- class Wt {
2404
- // 다른 그리드 드롭
2405
- constructor(e, t, s, i = null, n = () => 1) {
2406
- this._bodyEl = e, this._rowHeight = t, this._onDrop = s, this._cross = i, this._getDragCount = n, this._drag = null, this._selfIndicator = new Be("#1976d2"), this._crossIndicator = new Be("#2e7d32"), this._onMouseMove = this._onMouseMove.bind(this), this._onMouseUp = this._onMouseUp.bind(this);
2407
- }
2408
- /** 행 엘리먼트에 드래그 핸들 삽입 */
2409
- attachHandle(e, t, s) {
2410
- const i = document.createElement("div");
2411
- return i.className = "og-drag-handle", i.innerHTML = "⠿", i.style.cssText = `
2412
- width:18px;min-width:18px;height:100%;
2413
- display:flex;align-items:center;justify-content:center;
2414
- cursor:grab;font-size:14px;color:#bbb;flex-shrink:0;
2415
- user-select:none;border-right:1px solid var(--og-border-color,#e0e0e0);
2416
- `, i.addEventListener("mousedown", (n) => {
2417
- n.preventDefault(), n.stopPropagation(), this._startDrag(n, e, t, s);
2418
- }), i;
2419
- }
2420
- _startDrag(e, t, s, i) {
2421
- const n = t.getBoundingClientRect(), o = this._getDragCount(s);
2422
- this._drag = {
2423
- fromIndex: s,
2424
- bodyEl: this._bodyEl,
2425
- rowHeight: this._rowHeight,
2426
- totalRows: i,
2427
- ghost: new Bt(n, e.clientX, e.clientY, o),
2428
- currentTarget: s,
2429
- crossTarget: null
2430
- }, document.addEventListener("mousemove", this._onMouseMove, !0), document.addEventListener("mouseup", this._onMouseUp, !0);
2431
- }
2432
- _onMouseMove(e) {
2433
- if (!this._drag) return;
2434
- const t = this._drag;
2435
- if (t.ghost.move(e.clientX, e.clientY), this._cross) {
2436
- const n = this._cross.resolveTarget(e.clientX, e.clientY);
2437
- if (n && n.bodyEl !== t.bodyEl) {
2438
- const o = n.bodyEl.getBoundingClientRect(), l = e.clientY - o.top + n.bodyEl.scrollTop, r = We(Math.round(l / n.rowHeight), 0, n.totalRows);
2439
- t.crossTarget = { bodyEl: n.bodyEl, index: r }, this._selfIndicator.hide(), this._crossIndicator.showIn(n.bodyEl, r * n.rowHeight);
2440
- return;
2441
- }
2442
- }
2443
- t.crossTarget = null, this._crossIndicator.hide();
2444
- const s = t.bodyEl.getBoundingClientRect(), i = e.clientY - s.top + t.bodyEl.scrollTop;
2445
- t.currentTarget = We(Math.round(i / t.rowHeight), 0, t.totalRows - 1), this._selfIndicator.showIn(t.bodyEl, t.currentTarget * t.rowHeight);
2446
- }
2447
- _onMouseUp(e) {
2448
- if (document.removeEventListener("mousemove", this._onMouseMove, !0), document.removeEventListener("mouseup", this._onMouseUp, !0), !this._drag) return;
2449
- const { fromIndex: t, currentTarget: s, ghost: i, crossTarget: n } = this._drag;
2450
- this._drag = null, i.destroy(), this._selfIndicator.hide(), this._crossIndicator.hide(), n && this._cross ? this._cross.onCrossDrop(t, n.bodyEl, n.index) : t !== s && this._onDrop(t, s);
2451
- }
2452
- destroy() {
2453
- var e;
2454
- document.removeEventListener("mousemove", this._onMouseMove, !0), document.removeEventListener("mouseup", this._onMouseUp, !0), (e = this._drag) == null || e.ghost.destroy(), this._selfIndicator.destroy(), this._crossIndicator.destroy(), this._drag = null;
2455
- }
2456
- }
2457
- class J {
2458
- constructor() {
2459
- this._map = /* @__PURE__ */ new Map();
2460
- }
2461
- static _key(e, t) {
2462
- return `${e}:${t}`;
2463
- }
2464
- /** 수동 병합 정의 목록으로 맵 구성 */
2465
- applyMergeCells(e) {
2466
- this._map.clear();
2467
- for (const t of e) {
2468
- const s = Math.max(1, t.rowSpan ?? 1), i = Math.max(1, t.colSpan ?? 1);
2469
- this._map.set(J._key(t.row, t.col), {
2470
- rowSpan: s,
2471
- colSpan: i,
2472
- hidden: !1
2473
- });
2474
- for (let n = 0; n < s; n++)
2475
- for (let o = 0; o < i; o++)
2476
- n === 0 && o === 0 || this._map.set(J._key(t.row + n, t.col + o), {
2477
- rowSpan: 1,
2478
- colSpan: 1,
2479
- hidden: !0
2480
- });
2481
- }
2482
- }
2483
- /**
2484
- * 자동 병합: 지정 컬럼 인덱스 목록에 대해 연속 같은 값을 rowSpan으로 병합.
2485
- * data: 현재 표시 순서의 행 배열, colIndexes: 자동병합할 leaf 컬럼 인덱스
2486
- * fields: colIndexes[i] 에 대응하는 field 이름
2487
- */
2488
- applyAutoMerge(e, t, s) {
2489
- var i, n;
2490
- this._map.clear();
2491
- for (let o = 0; o < t.length; o++) {
2492
- const l = t[o], r = s[o];
2493
- let a = 0;
2494
- for (let c = 1; c <= e.length; c++) {
2495
- const h = (i = e[c - 1]) == null ? void 0 : i[r], u = c < e.length ? (n = e[c]) == null ? void 0 : n[r] : void 0;
2496
- if (c === e.length || u !== h) {
2497
- const p = c - a;
2498
- if (p > 1) {
2499
- this._map.set(J._key(a, l), {
2500
- rowSpan: p,
2501
- colSpan: 1,
2502
- hidden: !1
2503
- });
2504
- for (let M = a + 1; M < c; M++)
2505
- this._map.set(J._key(M, l), {
2506
- rowSpan: 1,
2507
- colSpan: 1,
2508
- hidden: !0
2509
- });
2510
- }
2511
- a = c;
2512
- }
2513
- }
2514
- }
2515
- }
2516
- /** 셀 병합 정보 조회. 없으면 null */
2517
- getInfo(e, t) {
2518
- return this._map.get(J._key(e, t)) ?? null;
2519
- }
2520
- /** 병합 맵 초기화 */
2521
- clear() {
2522
- this._map.clear();
2523
- }
2524
- get isEmpty() {
2525
- return this._map.size === 0;
2526
- }
2527
- }
2528
- const Nt = [
2529
- { id: "sort-asc", label: "오름차순 정렬", icon: "↑", action: "sortAsc" },
2530
- { id: "sort-desc", label: "내림차순 정렬", icon: "↓", action: "sortDesc" },
2531
- { type: "divider" },
2532
- { id: "find", label: "찾기", icon: "🔍", action: "find" },
2533
- { type: "divider" },
2534
- { id: "excel", label: "Excel로 저장", icon: "📊", action: "excel" },
2535
- { id: "csv", label: "CSV로 저장", icon: "📄", action: "csv" },
2536
- { id: "print", label: "인쇄", icon: "🖨", action: "print" }
2537
- ];
2538
- class Ot {
2539
- /**
2540
- * @param _anchor 그리드 컨테이너 엘리먼트 — CSS 변수 상속 기준점
2541
- * @param _actions 기본 액션 핸들러 (OpenGrid에서 주입)
2542
- */
2543
- constructor(e, t) {
2544
- this._anchor = e, this._actions = t, this._el = null, this._docClick = null, this._docKey = null, this._docScroll = null, this._docMouseMove = null, this._focusIdx = -1;
2545
- }
2546
- open(e, t) {
2547
- this.close();
2548
- const s = t ?? Nt, i = document.createElement("div");
2549
- i.className = "og-context-menu", i.setAttribute("role", "menu");
2550
- for (const l of s) {
2551
- if (l.type === "divider") {
2552
- const c = document.createElement("div");
2553
- c.className = "og-cm-divider", c.setAttribute("role", "separator"), i.appendChild(c);
2554
- continue;
2555
- }
2556
- const r = document.createElement("button");
2557
- if (r.className = "og-cm-item", r.setAttribute("role", "menuitem"), r.setAttribute("tabindex", "-1"), l.disabled && (r.classList.add("og-cm-disabled"), r.setAttribute("aria-disabled", "true")), l.icon) {
2558
- const c = document.createElement("span");
2559
- if (c.className = "og-cm-icon", /^[a-zA-Z][\w-]*(\s+[\w-]+)+$/.test(l.icon.trim())) {
2560
- const h = document.createElement("i");
2561
- h.className = l.icon, c.appendChild(h);
2562
- } else
2563
- c.textContent = l.icon;
2564
- c.setAttribute("aria-hidden", "true"), r.appendChild(c);
2565
- }
2566
- const a = document.createElement("span");
2567
- a.className = "og-cm-label", a.textContent = l.label ?? "", r.appendChild(a), r.addEventListener("click", (c) => {
2568
- c.stopPropagation(), l.disabled || this._runAction(l), this.close();
2569
- }), i.appendChild(r);
2570
- }
2571
- const n = this._anchor.closest("[data-og-theme]"), o = n == null ? void 0 : n.getAttribute("data-og-theme");
2572
- o && i.setAttribute("data-og-theme", o), document.body.appendChild(i), this._el = i, this._docMouseMove = (l) => {
2573
- if (!this._el) return;
2574
- const r = this._el.getBoundingClientRect();
2575
- (l.clientX < r.left - 4 || l.clientX > r.right + 4 || l.clientY < r.top - 4 || l.clientY > r.bottom + 4) && this.close();
2576
- }, this._position(i, e.clientX, e.clientY, () => {
2577
- this._el === i && document.addEventListener("mousemove", this._docMouseMove, { capture: !0, passive: !0 });
2578
- }), this._docClick = (l) => {
2579
- i.contains(l.target) || this.close();
2580
- }, this._docKey = (l) => {
2581
- if (l.key === "Escape") {
2582
- this.close();
2583
- return;
2584
- }
2585
- if (l.key === "ArrowDown") {
2586
- l.preventDefault(), this._moveFocus(1);
2587
- return;
2588
- }
2589
- if (l.key === "ArrowUp") {
2590
- l.preventDefault(), this._moveFocus(-1);
2591
- return;
2592
- }
2593
- if (l.key === "Enter") {
2594
- const r = i.querySelector(".og-cm-item:focus");
2595
- r == null || r.click();
2596
- }
2597
- }, this._docScroll = () => this.close(), setTimeout(() => {
2598
- document.addEventListener("click", this._docClick), document.addEventListener("keydown", this._docKey), window.addEventListener("scroll", this._docScroll, { passive: !0 });
2599
- }, 0), this._focusIdx = -1, this._moveFocus(1);
2600
- }
2601
- close() {
2602
- var e;
2603
- (e = this._el) == null || e.remove(), this._el = null, this._docClick && document.removeEventListener("click", this._docClick), this._docKey && document.removeEventListener("keydown", this._docKey), this._docScroll && window.removeEventListener("scroll", this._docScroll), this._docMouseMove && document.removeEventListener("mousemove", this._docMouseMove, { capture: !0 }), this._docClick = this._docKey = this._docScroll = this._docMouseMove = null, this._focusIdx = -1;
2604
- }
2605
- destroy() {
2606
- this.close();
2607
- }
2608
- // ── 위치 결정 ─────────────────────────────────────────────
2609
- _position(e, t, s, i) {
2610
- e.style.cssText = "position:fixed;visibility:hidden;left:0;top:0;", requestAnimationFrame(() => {
2611
- const { width: n, height: o } = e.getBoundingClientRect(), l = window.innerWidth, r = window.innerHeight, a = t + n > l ? Math.max(0, t - n) : t, c = s + o > r ? Math.max(0, s - o) : s;
2612
- e.style.cssText = `position:fixed;left:${a}px;top:${c}px;z-index:9999;`, i == null || i();
2613
- });
2614
- }
2615
- // ── 키보드 포커스 이동 ────────────────────────────────────
2616
- _moveFocus(e) {
2617
- var s;
2618
- if (!this._el) return;
2619
- const t = Array.from(
2620
- this._el.querySelectorAll(".og-cm-item:not(.og-cm-disabled)")
2621
- );
2622
- t.length && (this._focusIdx = (this._focusIdx + e + t.length) % t.length, (s = t[this._focusIdx]) == null || s.focus());
2623
- }
2624
- // ── 액션 실행 ─────────────────────────────────────────────
2625
- _runAction(e) {
2626
- if (typeof e.action == "function") {
2627
- e.action();
2628
- return;
2629
- }
2630
- switch (e.action) {
2631
- case "sortAsc":
2632
- this._actions.onSortAsc();
2633
- break;
2634
- case "sortDesc":
2635
- this._actions.onSortDesc();
2636
- break;
2637
- case "find":
2638
- this._actions.onFind();
2639
- break;
2640
- case "excel":
2641
- this._actions.onExcel();
2642
- break;
2643
- case "csv":
2644
- this._actions.onCsv();
2645
- break;
2646
- case "print":
2647
- this._actions.onPrint();
2648
- break;
2649
- }
2650
- }
2651
- }
2652
- class Ne {
2653
- constructor(e, t) {
2654
- this._sheets = /* @__PURE__ */ new Map(), this._active = "", this._onSwitch = t, this._tabBar = this._buildTabBar(e);
2655
- }
2656
- // ── 시트 CRUD ────────────────────────────────────────────
2657
- add(e, t = [], s = []) {
2658
- if (this._sheets.has(e))
2659
- throw new Error(`WorksheetManager: 시트 '${e}'이 이미 존재합니다`);
2660
- this._sheets.set(e, { name: e, columns: t, data: s }), this._renderTabs(), this._sheets.size === 1 && this.switch(e);
2661
- }
2662
- remove(e) {
2663
- if (!this._sheets.has(e)) return;
2664
- if (this._sheets.size === 1)
2665
- throw new Error("WorksheetManager: 마지막 시트는 삭제할 수 없습니다");
2666
- const t = this._active === e;
2667
- this._sheets.delete(e), this._renderTabs(), t && this.switch(this._sheets.keys().next().value);
2668
- }
2669
- rename(e, t) {
2670
- if (!this._sheets.has(e)) return;
2671
- if (this._sheets.has(t))
2672
- throw new Error(`WorksheetManager: 시트 '${t}'이 이미 존재합니다`);
2673
- this._sheets.get(e);
2674
- const s = Array.from(this._sheets.entries()).map(
2675
- ([i, n]) => i === e ? [t, { ...n, name: t }] : [i, n]
2676
- );
2677
- this._sheets = new Map(s), this._active === e && (this._active = t), this._renderTabs();
2678
- }
2679
- switch(e) {
2680
- const t = this._sheets.get(e);
2681
- if (!t) throw new Error(`WorksheetManager: 시트 '${e}'을 찾을 수 없습니다`);
2682
- this._active = e, this._renderTabs(), this._onSwitch(e, t);
2683
- }
2684
- get(e) {
2685
- return this._sheets.get(e);
2686
- }
2687
- getNames() {
2688
- return Array.from(this._sheets.keys());
2689
- }
2690
- getActive() {
2691
- return this._active;
2692
- }
2693
- /** 현재 활성 시트의 data를 갱신 (그리드 편집 동기화용) */
2694
- syncData(e, t) {
2695
- const s = this._sheets.get(e);
2696
- s && (s.data = t);
2697
- }
2698
- destroy() {
2699
- this._tabBar.remove();
2700
- }
2701
- // ── 탭 UI ────────────────────────────────────────────────
2702
- _buildTabBar(e) {
2703
- const t = document.createElement("div");
2704
- return t.className = "og-sheet-tabs", e.appendChild(t), t;
2705
- }
2706
- _renderTabs() {
2707
- this._tabBar.innerHTML = "";
2708
- for (const t of this._sheets.keys()) {
2709
- const s = document.createElement("button");
2710
- s.className = "og-sheet-tab", s.textContent = t, s.setAttribute("role", "tab"), s.setAttribute("aria-selected", t === this._active ? "true" : "false"), t === this._active && s.classList.add("og-sheet-tab--active"), s.addEventListener("click", () => {
2711
- t !== this._active && this.switch(t);
2712
- }), s.addEventListener("dblclick", () => this._startRename(s, t)), this._tabBar.appendChild(s);
2713
- }
2714
- const e = document.createElement("button");
2715
- e.className = "og-sheet-add", e.textContent = "+", e.setAttribute("aria-label", "새 워크시트 추가"), e.addEventListener("click", () => {
2716
- const t = `Sheet${this._sheets.size + 1}`;
2717
- this.add(t, [], []), this.switch(t);
2718
- }), this._tabBar.appendChild(e);
2719
- }
2720
- /** 탭 더블클릭 → input으로 전환해 이름 변경 */
2721
- _startRename(e, t) {
2722
- const s = document.createElement("input");
2723
- s.className = "og-sheet-tab-rename", s.value = t, e.replaceWith(s), s.focus(), s.select();
2724
- const i = () => {
2725
- const n = s.value.trim() || t;
2726
- try {
2727
- n !== t ? this.rename(t, n) : this._renderTabs();
2728
- } catch {
2729
- this._renderTabs();
2730
- }
2731
- };
2732
- s.addEventListener("blur", i), s.addEventListener("keydown", (n) => {
2733
- n.key === "Enter" && s.blur(), n.key === "Escape" && (s.value = t, s.blur());
2734
- });
2735
- }
2736
- }
2737
- class Kt {
2738
- constructor(e) {
2739
- this._d = e;
2740
- }
2741
- _readCssVar(e) {
2742
- return getComputedStyle(this._d.getContainer()).getPropertyValue(e).trim();
2743
- }
2744
- _hexToXlsxRgb(e) {
2745
- const t = e.trim(), s = t.match(/^rgba?\(\s*(\d+),\s*(\d+),\s*(\d+)/i);
2746
- if (s)
2747
- return [s[1], s[2], s[3]].map((n) => parseInt(n).toString(16).padStart(2, "0")).join("").toUpperCase();
2748
- const i = t.replace("#", "").toUpperCase();
2749
- return i.length === 3 ? i[0] + i[0] + i[1] + i[1] + i[2] + i[2] : i.length === 6 ? i : "";
2750
- }
2751
- exportExcel(e) {
2752
- const t = typeof e == "string" ? { filename: e } : e ?? {};
2753
- let s = t.filename ?? "export";
2754
- s.toLowerCase().endsWith(".xlsx") || (s += ".xlsx");
2755
- const i = t.sheetName ?? (this._d.getOptions().ariaLabel || "Sheet1"), n = this._d.getData(), o = this._d.getColLayout().visibleLeaves.filter((r) => {
2756
- var a;
2757
- return !((a = t.exceptFields) != null && a.includes(r.field));
2758
- }), l = t.includeHeader !== !1;
2759
- import("./xlsx.min-Wavxcamn.js").then((r) => r.x).then(({ utils: r, writeFile: a }) => {
2760
- var _;
2761
- const c = [];
2762
- l && c.push(o.map((b) => b.header));
2763
- for (const b of n)
2764
- c.push(o.map((T) => {
2765
- const $ = b[T.field];
2766
- if (t.maskOnExport && T.mask && this._d.getMaskEnabled(T.field))
2767
- return Me($ == null ? "" : String($), T.mask);
2768
- const A = $;
2769
- return A == null || A === "" ? "" : T.type === "number" && typeof A == "number" ? A : typeof A == "boolean" ? A ? "✓" : "" : typeof A == "object" ? "" : String(A);
2770
- }));
2771
- const h = r.aoa_to_sheet(c), u = this._d.getColWidths(), p = this._d.getColLayout();
2772
- h["!cols"] = o.map((b) => ({
2773
- wpx: u[p.getColumnIndex(b.field)] ?? 100
2774
- })), h["!rows"] = c.map((b, T) => ({ hpx: T === 0 && l ? 22 : 19 }));
2775
- const M = t.styleMode ?? "theme";
2776
- let f = "1565C0", E = "FFFFFF", x = "FFFFFF", g = "EEF2FF", w = "212121", L = "BDBDBD", v = 10;
2777
- if (M === "theme") {
2778
- const b = ($) => this._hexToXlsxRgb($);
2779
- f = b(this._readCssVar("--og-header-bg")) || f, E = b(this._readCssVar("--og-header-color")) || E, x = b(this._readCssVar("--og-row-bg")) || x, g = b(this._readCssVar("--og-row-alt-bg")) || g, w = b(this._readCssVar("--og-row-color")) || w, L = b(this._readCssVar("--og-border-color")) || L;
2780
- const T = this._readCssVar("--og-font-size");
2781
- T && (v = Math.max(8, Math.round(parseFloat(T) * 0.75)));
2782
- }
2783
- const C = M === "none", F = {
2784
- hdrFont: C ? {} : { bold: !0, color: { rgb: E }, sz: v, name: "맑은 고딕" },
2785
- dataFont: C ? {} : { sz: v, color: { rgb: w }, name: "맑은 고딕" },
2786
- hdrFill: C ? {} : { patternType: "solid", fgColor: { rgb: f } },
2787
- evenFill: C ? {} : { patternType: "solid", fgColor: { rgb: x } },
2788
- oddFill: C ? {} : { patternType: "solid", fgColor: { rgb: g } },
2789
- hdrBorder: C ? {} : {
2790
- top: { style: "medium", color: { rgb: f } },
2791
- bottom: { style: "medium", color: { rgb: f } },
2792
- left: { style: "thin", color: { rgb: f } },
2793
- right: { style: "thin", color: { rgb: f } }
2794
- },
2795
- dataBorder: C ? {} : {
2796
- top: { style: "thin", color: { rgb: L } },
2797
- bottom: { style: "thin", color: { rgb: L } },
2798
- left: { style: "thin", color: { rgb: L } },
2799
- right: { style: "thin", color: { rgb: L } }
2800
- }
2801
- };
2802
- c.forEach((b, T) => {
2803
- const $ = l && T === 0, ae = (l ? T - 1 : T) % 2 === 0;
2804
- b.forEach((de, V) => {
2805
- const Q = r.encode_cell({ r: T, c: V });
2806
- h[Q] || (h[Q] = { t: "s", v: "" });
2807
- const m = o[V], S = m.type === "number" || m.align === "right", z = $ ? "center" : S ? "right" : m.align ?? "left";
2808
- h[Q].s = {
2809
- font: $ ? F.hdrFont : F.dataFont,
2810
- fill: $ ? F.hdrFill : ae ? F.evenFill : F.oddFill,
2811
- border: $ ? F.hdrBorder : F.dataBorder,
2812
- alignment: { horizontal: z, vertical: "center", wrapText: !1 }
2813
- };
2814
- });
2815
- });
2816
- const K = r.book_new();
2817
- r.book_append_sheet(K, h, i), a(K, s, { cellStyles: !0 }), (_ = t.onAfter) == null || _.call(t, new Blob([]));
2818
- }).catch(() => {
2819
- console.error("Excel 내보내기 실패: xlsx 패키지를 확인하세요.");
2820
- });
2821
- }
2822
- exportCsv(e) {
2823
- const t = typeof e == "string" ? { filename: e } : e ?? {}, s = this._d.getData(), i = this._d.getColLayout().visibleLeaves, n = i.map((r) => `"${r.header}"`).join(","), o = s.map((r) => i.map((a) => {
2824
- const c = r[a.field] ?? "";
2825
- if (t.maskOnExport && a.mask && this._d.getMaskEnabled(a.field))
2826
- return Me(String(c), a.mask);
2827
- const h = c;
2828
- return typeof h == "string" && h.includes(",") ? `"${h}"` : h;
2829
- }).join(",")), l = t.filename ?? "export.csv";
2830
- ze("\uFEFF" + [n, ...o].join(`
2831
- `), l);
2832
- }
2833
- exportJson(e) {
2834
- const t = typeof e == "string" ? e : (e == null ? void 0 : e.filename) ?? "export.json";
2835
- ze(JSON.stringify(this._d.getData(), null, 2), t, "application/json");
2836
- }
2837
- print(e) {
2838
- const t = (e == null ? void 0 : e.title) ?? "OPEN_GRID", s = (e == null ? void 0 : e.footerText) ?? "", i = this._d.getData(), n = this._d.getColLayout().visibleLeaves.filter((h) => {
2839
- var u;
2840
- return !((u = e == null ? void 0 : e.excludeFields) != null && u.includes(h.field));
2841
- }), o = n.map((h) => `<th>${h.header ?? h.field}</th>`).join(""), l = i.map(
2842
- (h) => `<tr>${n.map((u) => `<td>${String(h[u.field] ?? "")}</td>`).join("")}</tr>`
2843
- ).join(""), r = s ? `<div class="og-print-footer">${s}</div>` : "", a = `<!DOCTYPE html>
2844
- <html lang="ko"><head>
2845
- <meta charset="UTF-8"><title>${t}</title>
2846
- <style>
2847
- @page{margin:0;}
2848
- body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;font-size:12px;margin:0;padding:1cm;}
2849
- h2{margin:0 0 10px;font-size:14px;color:#333;}
2850
- p{margin:0 0 8px;font-size:11px;color:#999;}
2851
- table{border-collapse:collapse;width:100%;}
2852
- th,td{border:1px solid #ccc;padding:5px 8px;text-align:left;white-space:nowrap;}
2853
- th{background:#f5f5f5;font-weight:600;color:#333;}
2854
- tr:nth-child(even) td{background:#fafafa;}
2855
- .og-print-footer{position:fixed;bottom:0;left:0;right:0;padding:6px 1cm;font-size:10px;color:#888;border-top:1px solid #e5e7eb;background:#fff;text-align:center;}
2856
- </style>
2857
- </head><body>
2858
- <h2>${t}</h2>
2859
- <p>${i.length}행 × ${n.length}열 · ${(/* @__PURE__ */ new Date()).toLocaleString("ko-KR")}</p>
2860
- <table>
2861
- <thead><tr>${o}</tr></thead>
2862
- <tbody>${l}</tbody>
2863
- </table>
2864
- ${r}
2865
- <script>window.addEventListener('load',()=>{window.print();window.addEventListener('afterprint',()=>window.close());});<\/script>
2866
- </body></html>`, c = window.open("", "_blank", "width=960,height=640");
2867
- c && (c.document.write(a), c.document.close());
2868
- }
2869
- exportSheetsExcel(e) {
2870
- const t = this._d.getWsManager();
2871
- if (!t) {
2872
- this.exportExcel(e ?? "workbook");
2873
- return;
2874
- }
2875
- const s = e ?? "workbook.xlsx";
2876
- import("./xlsx.min-Wavxcamn.js").then((i) => i.x).then(({ utils: i, writeFile: n }) => {
2877
- const o = i.book_new(), l = this._d.getOptions();
2878
- for (const r of t.getNames()) {
2879
- const a = t.get(r), c = a.columns.length ? a.columns : l.columns, h = [c.map((p) => p.header)];
2880
- for (const p of a.data)
2881
- h.push(c.map((M) => {
2882
- const f = p[M.field];
2883
- return f == null ? "" : typeof f == "boolean" ? f ? "✓" : "" : M.type === "number" && typeof f == "number" ? f : String(f);
2884
- }));
2885
- const u = i.aoa_to_sheet(h);
2886
- u["!cols"] = c.map(() => ({ wpx: 100 })), i.book_append_sheet(o, u, r);
2887
- }
2888
- n(o, s.endsWith(".xlsx") ? s : s + ".xlsx", { cellStyles: !0 });
2889
- }).catch(() => console.error("exportSheetsExcel: xlsx 패키지를 확인하세요."));
2890
- }
2891
- }
2892
- class Vt {
2893
- constructor(e) {
2894
- this._d = e;
2895
- }
2896
- fmtNum(e, t) {
2897
- if (!t)
2898
- return Math.round(e).toLocaleString("ko-KR");
2899
- const s = t.match(/[#0][#0,]*(?:\.[#0]+)?|\d+/), i = s ? t.slice(0, s.index) : "", n = s ? t.slice(s.index + s[0].length) : "", o = s ? s[0] : t, l = o.includes("#") || o.includes(","), r = o.match(/\.(\d+)$/), a = r ? parseInt(r[1], 10) : /^\d+$/.test(o) ? parseInt(o, 10) : 0, c = Math.abs(e).toFixed(a), [h = "0", u] = c.split("."), p = l ? h.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : h, M = u !== void 0 ? `${p}.${u}` : p, f = `${i}${M}${n}`;
2900
- return e < 0 ? `-${f}` : f;
2901
- }
2902
- computeValues() {
2903
- const e = this._d.getOptions().footer;
2904
- if (!e || e.length === 0) return [];
2905
- const t = this._d.getData();
2906
- return e.filter((s) => s.field && s.op).map((s) => {
2907
- const i = s.field, n = s.op, o = t.map((h) => h[i]).filter((h) => h != null && h !== "");
2908
- let l = null;
2909
- const r = n.toUpperCase();
2910
- if (r === "SUM")
2911
- l = o.length > 0 ? R.sum(o.map((h) => String(h))) : null;
2912
- else if (r === "AVG")
2913
- l = o.length > 0 ? R.sum(o.map((h) => String(h))).div(R.from(String(o.length))) : null;
2914
- else if (r === "COUNT") {
2915
- const h = o.length;
2916
- return { _field: i, _value: h, _formatted: h.toLocaleString("ko-KR") };
2917
- } else r === "MAX" ? l = o.length > 0 ? R.max(o.map((h) => String(h))) : null : r === "MIN" && (l = o.length > 0 ? R.min(o.map((h) => String(h))) : null);
2918
- if (!l) return { _field: i, _value: null, _formatted: "" };
2919
- const a = l.toNumber(), c = this.fmtNum(a, s.format);
2920
- return { _field: i, _value: a, _formatted: c };
2921
- });
2922
- }
2923
- render() {
2924
- var h;
2925
- const e = this._d.getContainer(), t = e.querySelector(".og-footer-bar");
2926
- t == null || t.remove();
2927
- const s = this._d.getOptions(), i = s.footer;
2928
- if (!i || i.length === 0) return;
2929
- const n = this._d.getColLayout().visibleLeaves, o = this._d.getColWidths() ?? n.map((u) => u.width ?? 100), l = new Map(
2930
- this.computeValues().map((u) => [u._field, u])
2931
- ), r = document.createElement("div");
2932
- r.className = "og-footer-bar", r.style.cssText = [
2933
- "display:flex;align-items:stretch;",
2934
- `min-height:${s.footerHeight}px;`,
2935
- "border-top:2px solid var(--og-primary,#1976d2);",
2936
- "background:var(--og-header-bg,#f5f5f5);",
2937
- "overflow:hidden;flex-shrink:0;font-size:13px;font-weight:600;"
2938
- ].join("");
2939
- let a = 0;
2940
- if (s.stateColumn && (a += 24), s.draggable && (a += 18), s.rowNumber && (a += 44), s.checkColumn && (a += 36), a > 0) {
2941
- const u = document.createElement("div");
2942
- u.style.cssText = `width:${a}px;flex-shrink:0;border-right:1px solid var(--og-border-color,#e0e0e0);`, r.appendChild(u);
2943
- }
2944
- let c = 0;
2945
- for (const u of i) {
2946
- const p = Math.max(1, u.colspan ?? 1);
2947
- let M = 0;
2948
- for (let w = 0; w < p; w++)
2949
- M += o[c + w] ?? 100;
2950
- const f = n[c];
2951
- c += p;
2952
- const E = document.createElement("div");
2953
- E.style.cssText = [
2954
- `width:${M}px;min-width:${M}px;flex-shrink:0;`,
2955
- "padding:4px 8px;box-sizing:border-box;overflow:hidden;",
2956
- "border-right:1px solid var(--og-border-color,#e0e0e0);",
2957
- "white-space:nowrap;text-overflow:ellipsis;"
2958
- ].join("");
2959
- const x = u.field, g = x ? l.get(x) : null;
2960
- if (g) {
2961
- const w = g._formatted ?? String(g._value ?? ""), L = u.label ? `${u.label}: ` : "";
2962
- E.textContent = L + w, E.title = `${((h = u.op) == null ? void 0 : h.toUpperCase()) ?? ""} = ${w}`, E.style.color = "var(--og-primary,#1976d2)", E.style.textAlign = u.align ?? ((f == null ? void 0 : f.type) === "number", "right");
2963
- } else u.label && (E.textContent = u.label, E.style.textAlign = u.align ?? "left", E.style.color = "var(--og-row-color,#212121)");
2964
- r.appendChild(E);
2965
- }
2966
- s.footerPosition === "top" ? e.insertBefore(r, e.firstChild) : e.appendChild(r);
2967
- }
2968
- }
2969
- class Pt {
2970
- constructor(e) {
2971
- this._d = e;
2972
- }
2973
- handleKeyDown(e) {
2974
- const t = this._d.getEditMgr();
2975
- if (t.activeEditor) return;
2976
- this._d.handleCellKeyEvt("cellKeyDown", e);
2977
- const s = this._d.getData(), i = this._d.getColLayout(), n = s.rowCount, o = i.visibleLeaves.length;
2978
- if (n === 0 || o === 0) return;
2979
- if ((e.ctrlKey || e.metaKey) && e.key === "c") {
2980
- e.preventDefault(), this._copyToClipboard();
2981
- return;
2982
- }
2983
- if ((e.ctrlKey || e.metaKey) && e.key === "v") {
2984
- e.preventDefault(), this._pasteFromClipboard();
2985
- return;
2986
- }
2987
- const l = this._d.getOptions();
2988
- if ((e.ctrlKey || e.metaKey) && l.draggable && t.focusCell) {
2989
- if (e.key === "ArrowDown") {
2990
- e.preventDefault();
2991
- const r = t.focusCell.ci !== void 0 ? t.focusCell.ri : 0;
2992
- r < n - 1 && (this._d.handleRowDrop(r, r + 1), this._d.setFocusCell(r + 1, t.focusCell.ci), this._d.announce(`행 ${r + 1}을(를) ${r + 2}번째 위치로 이동`));
2993
- return;
2994
- }
2995
- if (e.key === "ArrowUp") {
2996
- e.preventDefault();
2997
- const r = t.focusCell.ri;
2998
- r > 0 && (this._d.handleRowDrop(r, r - 1), this._d.setFocusCell(r - 1, t.focusCell.ci), this._d.announce(`행 ${r + 1}을(를) ${r}번째 위치로 이동`));
2999
- return;
3000
- }
3001
- }
3002
- switch (e.key) {
3003
- case "ArrowDown": {
3004
- e.preventDefault();
3005
- const r = t.focusCell, a = r ? Math.min(r.ri + 1, n - 1) : 0;
3006
- this._d.setFocusCell(a, (r == null ? void 0 : r.ci) ?? 0);
3007
- break;
3008
- }
3009
- case "ArrowUp": {
3010
- e.preventDefault();
3011
- const r = t.focusCell, a = r ? Math.max(r.ri - 1, 0) : 0;
3012
- this._d.setFocusCell(a, (r == null ? void 0 : r.ci) ?? 0);
3013
- break;
3014
- }
3015
- case "ArrowRight": {
3016
- e.preventDefault();
3017
- const r = t.focusCell;
3018
- if (!r) {
3019
- this._d.setFocusCell(0, 0);
3020
- break;
3021
- }
3022
- r.ci < o - 1 ? this._d.setFocusCell(r.ri, r.ci + 1) : r.ri < n - 1 && this._d.setFocusCell(r.ri + 1, 0);
3023
- break;
3024
- }
3025
- case "ArrowLeft": {
3026
- e.preventDefault();
3027
- const r = t.focusCell;
3028
- if (!r) {
3029
- this._d.setFocusCell(0, 0);
3030
- break;
3031
- }
3032
- r.ci > 0 ? this._d.setFocusCell(r.ri, r.ci - 1) : r.ri > 0 && this._d.setFocusCell(r.ri - 1, o - 1);
3033
- break;
3034
- }
3035
- case "Tab": {
3036
- e.preventDefault();
3037
- const r = t.focusCell;
3038
- if (!r) {
3039
- this._d.setFocusCell(0, 0);
3040
- break;
3041
- }
3042
- e.shiftKey ? r.ci > 0 ? this._d.setFocusCell(r.ri, r.ci - 1) : r.ri > 0 && this._d.setFocusCell(r.ri - 1, o - 1) : r.ci < o - 1 ? this._d.setFocusCell(r.ri, r.ci + 1) : r.ri < n - 1 && this._d.setFocusCell(r.ri + 1, 0);
3043
- break;
3044
- }
3045
- case "Home": {
3046
- if (e.preventDefault(), e.ctrlKey || e.metaKey)
3047
- this._d.setFocusCell(0, 0);
3048
- else {
3049
- const r = t.focusCell;
3050
- this._d.setFocusCell((r == null ? void 0 : r.ri) ?? 0, 0);
3051
- }
3052
- break;
3053
- }
3054
- case "End": {
3055
- if (e.preventDefault(), e.ctrlKey || e.metaKey)
3056
- this._d.setFocusCell(n - 1, o - 1);
3057
- else {
3058
- const r = t.focusCell;
3059
- this._d.setFocusCell((r == null ? void 0 : r.ri) ?? 0, o - 1);
3060
- }
3061
- break;
3062
- }
3063
- case "PageDown": {
3064
- e.preventDefault();
3065
- const r = t.focusCell, a = this._d.getOptions().pageSize ?? 10, c = Math.min(r ? r.ri + a : a - 1, n - 1);
3066
- this._d.setFocusCell(c, (r == null ? void 0 : r.ci) ?? 0);
3067
- break;
3068
- }
3069
- case "PageUp": {
3070
- e.preventDefault();
3071
- const r = t.focusCell, a = this._d.getOptions().pageSize ?? 10, c = r ? Math.max(r.ri - a, 0) : 0;
3072
- this._d.setFocusCell(c, (r == null ? void 0 : r.ci) ?? 0);
3073
- break;
3074
- }
3075
- case " ": {
3076
- if (t.focusCell) {
3077
- e.preventDefault();
3078
- const r = t.focusCell.ri, a = this._d.getRowMgr();
3079
- this._d.getOptions().checkColumn ? (a.check(r, !a.checkedRows.has(r)), this._d.doRender()) : (a.selectToggle(r), this._d.doRender());
3080
- }
3081
- break;
3082
- }
3083
- case "F2":
3084
- case "Enter": {
3085
- t.focusCell && this._d.getOptions().editable && (e.preventDefault(), t.startEditByKey(t.focusCell.ri, t.focusCell.ci));
3086
- break;
3087
- }
3088
- case "Escape": {
3089
- t.clearFocusCell(), this._d.doRender();
3090
- break;
3091
- }
3092
- }
3093
- }
3094
- _copyToClipboard() {
3095
- var o;
3096
- if (!this._d.getOptions().clipboard) return;
3097
- const t = this._d.getEditMgr(), s = this._d.getColLayout(), i = this._d.getData();
3098
- let n = "";
3099
- if (t.focusCell) {
3100
- const { ri: l, ci: r } = t.focusCell, a = s.visibleLeaves[r];
3101
- a && (n = String(i.getCellValue(l, a.field) ?? ""));
3102
- } else if (this._d.getRowMgr().selectedRows.size > 0) {
3103
- const l = s.visibleLeaves;
3104
- n = [...this._d.getRowMgr().selectedRows].sort((a, c) => a - c).map((a) => {
3105
- const c = i.getRowByIndex(a);
3106
- return l.map((h) => String((c == null ? void 0 : c[h.field]) ?? "")).join(" ");
3107
- }).join(`
3108
- `);
3109
- }
3110
- n && ((o = navigator.clipboard) == null || o.writeText(n).catch(() => {
3111
- }));
3112
- }
3113
- _pasteFromClipboard() {
3114
- var s;
3115
- const e = this._d.getOptions();
3116
- if (!e.clipboard || !e.editable) return;
3117
- const t = this._d.getEditMgr();
3118
- t.focusCell && ((s = navigator.clipboard) == null || s.readText().then((i) => {
3119
- if (!i) return;
3120
- const { ri: n, ci: o } = t.focusCell, l = i.split(`
3121
- `), r = this._d.getColLayout().visibleLeaves, a = this._d.getData();
3122
- for (let c = 0; c < l.length; c++) {
3123
- const h = l[c].split(" ");
3124
- for (let u = 0; u < h.length; u++) {
3125
- const p = n + c, M = o + u, f = r[M];
3126
- f && p < a.rowCount && a.updateCell(p, f.field, h[u]);
3127
- }
3128
- }
3129
- this._d.emit("dataChange", a.getData()), this._d.doRender();
3130
- }).catch(() => {
3131
- }));
3132
- }
3133
- }
3134
- class jt {
3135
- constructor(e) {
3136
- this._bar = null, this._input = null, this._count = null, this._filter = "", this._d = e;
3137
- }
3138
- get findFilter() {
3139
- return this._filter;
3140
- }
3141
- init(e) {
3142
- const t = document.createElement("div");
3143
- t.className = "og-find-bar", t.hidden = !0;
3144
- const s = document.createElement("span");
3145
- s.className = "og-find-label", s.textContent = "찾기";
3146
- const i = document.createElement("input");
3147
- i.type = "text", i.className = "og-find-input", i.placeholder = "검색어 입력...", i.setAttribute("aria-label", "그리드 내 검색");
3148
- const n = document.createElement("span");
3149
- n.className = "og-find-count";
3150
- const o = document.createElement("button");
3151
- o.className = "og-find-close", o.textContent = "✕", o.setAttribute("aria-label", "찾기 닫기"), t.appendChild(s), t.appendChild(i), t.appendChild(n), t.appendChild(o), e.insertBefore(t, e.firstChild), i.addEventListener("input", () => {
3152
- this._filter = i.value.trim(), this._apply();
3153
- }), i.addEventListener("keydown", (l) => {
3154
- l.key === "Escape" && this.close();
3155
- }), o.addEventListener("click", () => this.close()), this._bar = t, this._input = i, this._count = n;
3156
- }
3157
- open() {
3158
- this._bar && (this._bar.hidden = !1, this._input.focus(), this._input.select());
3159
- }
3160
- close() {
3161
- this._bar && (this._bar.hidden = !0, this._filter = "", this._input.value = "", this._count && (this._count.textContent = ""), this._apply());
3162
- }
3163
- _apply() {
3164
- var i, n;
3165
- const e = this._d.getData(), t = this._d.getColLayout().visibleLeaves.map((o) => o.field);
3166
- e.setFindFilter(this._filter, t), e.applyFilter(this._d.getFilters());
3167
- const s = e.rowCount;
3168
- (i = this._d.getVs()) == null || i.setTotalRows(s), (n = this._d.getPagination()) == null || n.setTotalRows(s), this._count && (this._count.textContent = this._filter ? `${s}건` : ""), this._d.doRender();
3169
- }
3170
- }
3171
- function Ge(d) {
3172
- return d && d._isGroup === !0;
3173
- }
3174
- function Oe(d, e, t = [], s = /* @__PURE__ */ new Set(), i) {
3175
- return e.length ? qe(d, e, 0, t, s, "", i) : [];
3176
- }
3177
- function qe(d, e, t, s, i, n, o) {
3178
- const l = e[t], r = /* @__PURE__ */ new Map();
3179
- for (const c of d) {
3180
- const h = c[l];
3181
- r.has(h) || r.set(h, []), r.get(h).push(c);
3182
- }
3183
- const a = [];
3184
- for (const [c, h] of r) {
3185
- const u = `${n}__${l}:${c}`, p = i.has(u);
3186
- let M;
3187
- t < e.length - 1 ? M = qe(h, e, t + 1, s, i, u, o) : M = h;
3188
- const { summary: f, summaryFmt: E } = Ut(h, s), x = Gt(h, o);
3189
- a.push({
3190
- _isGroup: !0,
3191
- _groupField: l,
3192
- _groupValue: c,
3193
- _groupLabel: c == null ? "(없음)" : String(c),
3194
- _depth: t,
3195
- _expanded: p,
3196
- _childCount: h.length,
3197
- _summary: f,
3198
- _summaryFmt: E,
3199
- _states: x,
3200
- children: M
3201
- });
3202
- }
3203
- return a;
3204
- }
3205
- function Ut(d, e) {
3206
- const t = {}, s = {};
3207
- for (const i of e) {
3208
- const n = d.map((a) => a[i.field]).filter((a) => a != null && a !== "");
3209
- let o = null;
3210
- const l = i.op.toUpperCase();
3211
- if (l === "SUM")
3212
- o = n.length > 0 ? R.sum(n.map(String)) : null;
3213
- else if (l === "AVG")
3214
- o = n.length > 0 ? R.sum(n.map(String)).div(R.from(String(n.length))) : null;
3215
- else if (l === "COUNT") {
3216
- t[i.field] = d.length, s[i.field] = d.length.toLocaleString("ko-KR");
3217
- continue;
3218
- } else l === "MAX" ? o = n.length > 0 ? R.max(n.map(String)) : null : l === "MIN" && (o = n.length > 0 ? R.min(n.map(String)) : null);
3219
- if (!o) {
3220
- t[i.field] = null, s[i.field] = "";
3221
- continue;
3222
- }
3223
- const r = o.toNumber();
3224
- t[i.field] = r, s[i.field] = qt(r, i.format);
3225
- }
3226
- return { summary: t, summaryFmt: s };
3227
- }
3228
- function Gt(d, e) {
3229
- if (!e) return { added: 0, edited: 0, removed: 0 };
3230
- let t = 0, s = 0, i = 0;
3231
- for (const n of d) {
3232
- const o = e(n);
3233
- o === "added" ? t++ : o === "edited" ? s++ : o === "removed" && i++;
3234
- }
3235
- return { added: t, edited: s, removed: i };
3236
- }
3237
- function qt(d, e) {
3238
- if (e == null)
3239
- return d % 1 === 0 ? d.toLocaleString("ko-KR") : parseFloat(d.toFixed(6)).toLocaleString("ko-KR", {
3240
- minimumFractionDigits: 2,
3241
- maximumFractionDigits: 6
3242
- });
3243
- const t = e.includes("#") || e.includes(","), s = e.match(/\.(\d+)$/), i = s ? parseInt(s[1], 10) : /^\d+$/.test(e) ? parseInt(e, 10) : 0, n = Math.abs(d).toFixed(i), [o = "0", l] = n.split("."), r = t ? o.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : o, a = l !== void 0 ? `${r}.${l}` : r;
3244
- return d < 0 ? `-${a}` : a;
3245
- }
3246
- function Xe(d) {
3247
- const e = [];
3248
- for (const t of d)
3249
- if (e.push(t), t._expanded)
3250
- for (const s of t.children)
3251
- Ge(s) ? e.push(...Xe([s])) : e.push(s);
3252
- return e;
3253
- }
3254
- function Ye(d, e = "") {
3255
- const t = [];
3256
- for (const s of d) {
3257
- const i = `${e}__${s._groupField}:${s._groupValue}`;
3258
- t.push(i);
3259
- const n = s.children.filter((o) => Ge(o));
3260
- n.length && t.push(...Ye(n, i));
3261
- }
3262
- return t;
3263
- }
3264
- function Ke(d, e, t = /* @__PURE__ */ new Set()) {
3265
- const { idField: s, parentIdField: i, expandOnLoad: n = !1 } = e, o = /* @__PURE__ */ new Map(), l = [];
3266
- for (const c of d) {
3267
- const h = c[s], u = {
3268
- _isTree: !0,
3269
- _treeId: h,
3270
- _treeParentId: c[i],
3271
- _depth: 0,
3272
- _expanded: n || t.has(h),
3273
- _hasChildren: !1,
3274
- _childCount: 0,
3275
- _isLastChild: !1,
3276
- _ancestorHasMore: [],
3277
- data: c,
3278
- children: []
3279
- };
3280
- o.set(h, u);
3281
- }
3282
- for (const c of o.values()) {
3283
- const h = c._treeParentId;
3284
- if (h == null || h === "" || !o.has(h))
3285
- l.push(c);
3286
- else {
3287
- const p = o.get(h);
3288
- p.children.push(c), p._hasChildren = !0;
3289
- }
3290
- }
3291
- function r(c, h) {
3292
- for (const u of c)
3293
- u._depth = h, u._childCount = Je(u), r(u.children, h + 1);
3294
- }
3295
- r(l, 0);
3296
- function a(c, h) {
3297
- for (let u = 0; u < c.length; u++) {
3298
- const p = c[u], M = u === c.length - 1;
3299
- p._isLastChild = M, p._ancestorHasMore = h, p.children.length > 0 && a(p.children, [...h, !M]);
3300
- }
3301
- }
3302
- return a(l, []), l;
3303
- }
3304
- function Je(d) {
3305
- let e = d.children.length;
3306
- for (const t of d.children) e += Je(t);
3307
- return e;
3308
- }
3309
- function Qe(d) {
3310
- const e = [];
3311
- for (const t of d)
3312
- e.push(t), t._expanded && t.children.length > 0 && e.push(...Qe(t.children));
3313
- return e;
3314
- }
3315
- function Xt(d, e) {
3316
- d.has(e) ? d.delete(e) : d.add(e);
3317
- }
3318
- function Re(d) {
3319
- const e = [];
3320
- for (const t of d)
3321
- e.push(t._treeId), t.children.length && e.push(...Re(t.children));
3322
- return e;
3323
- }
3324
- class Yt {
3325
- constructor(e) {
3326
- this._groupFields = [], this._groupExpandedKeys = /* @__PURE__ */ new Set(), this._groupFlatRows = [], this._isGroupMode = !1, this._treeRoots = [], this._treeFlatRows = [], this._treeExpandedKeys = /* @__PURE__ */ new Set(), this._isTreeMode = !1, this._d = e;
3327
- }
3328
- // ─── 상태 접근자 ─────────────────────────────────────────
3329
- get isGroupMode() {
3330
- return this._isGroupMode;
3331
- }
3332
- get isTreeMode() {
3333
- return this._isTreeMode;
3334
- }
3335
- get groupFlatRows() {
3336
- return this._groupFlatRows;
3337
- }
3338
- get treeFlatRows() {
3339
- return this._treeFlatRows;
3340
- }
3341
- // ─── 그룹 ─────────────────────────────────────────────────
3342
- groupBy(e) {
3343
- this._groupFields = e, this._groupExpandedKeys.clear(), this._isGroupMode = e.length > 0, this.rebuildGroups();
3344
- }
3345
- clearGroup() {
3346
- var t;
3347
- this._groupFields = [], this._groupExpandedKeys.clear(), this._isGroupMode = !1, this._groupFlatRows = [];
3348
- const e = this._d.getData().length;
3349
- (t = this._d.getVs()) == null || t.setTotalRows(e), this._d.doRender();
3350
- }
3351
- expandAll() {
3352
- if (!this._isGroupMode) return;
3353
- const e = Oe(this._d.getData(), this._groupFields, this._getSummaryDefs());
3354
- Ye(e).forEach((t) => this._groupExpandedKeys.add(t)), this.rebuildGroups();
3355
- }
3356
- collapseAll() {
3357
- this._groupExpandedKeys.clear(), this._isGroupMode && this.rebuildGroups();
3358
- }
3359
- handleGroupToggle(e) {
3360
- this._groupExpandedKeys.has(e) ? this._groupExpandedKeys.delete(e) : this._groupExpandedKeys.add(e), this.rebuildGroups();
3361
- }
3362
- rebuildGroups() {
3363
- var n;
3364
- const e = this._d.getData(), t = this._d.getDataLayer(), s = (o) => {
3365
- const l = e.indexOf(o);
3366
- return l >= 0 ? t.getRowState(l) : "none";
3367
- }, i = Oe(e, this._groupFields, this._getSummaryDefs(), this._groupExpandedKeys, s);
3368
- this._groupFlatRows = Xe(i), (n = this._d.getVs()) == null || n.setTotalRows(this._groupFlatRows.length), this._d.doRenderFull(this._groupFlatRows.length);
3369
- }
3370
- // ─── 트리 ─────────────────────────────────────────────────
3371
- enableTree() {
3372
- this._isTreeMode = !0, this._isGroupMode = !1;
3373
- const e = this._d.getOptions();
3374
- if (e.expandOnLoad) {
3375
- const t = Ke(this._d.getData(), {
3376
- idField: e.treeId,
3377
- parentIdField: e.treeParentId
3378
- });
3379
- Re(t).forEach((s) => this._treeExpandedKeys.add(s));
3380
- }
3381
- this.rebuildTree();
3382
- }
3383
- disableTree() {
3384
- var t;
3385
- this._isTreeMode = !1, this._treeRoots = [], this._treeFlatRows = [], this._treeExpandedKeys.clear();
3386
- const e = this._d.getData().length;
3387
- (t = this._d.getVs()) == null || t.setTotalRows(e), this._d.doRender();
3388
- }
3389
- expandNodes(e, t = !0) {
3390
- const s = Array.isArray(e) ? e : [e];
3391
- for (const i of s)
3392
- t ? this._treeExpandedKeys.add(i) : this._treeExpandedKeys.delete(i);
3393
- this._isTreeMode && this.rebuildTree();
3394
- }
3395
- expandAllNodes() {
3396
- this._isTreeMode && (Re(this._treeRoots).forEach((e) => this._treeExpandedKeys.add(e)), this.rebuildTree());
3397
- }
3398
- collapseAllNodes() {
3399
- this._isTreeMode && (this._treeExpandedKeys.clear(), this.rebuildTree());
3400
- }
3401
- handleTreeToggle(e) {
3402
- Xt(this._treeExpandedKeys, e), this.rebuildTree();
3403
- }
3404
- rebuildTree() {
3405
- var t;
3406
- const e = this._d.getOptions();
3407
- this._treeRoots = Ke(this._d.getData(), {
3408
- idField: e.treeId,
3409
- parentIdField: e.treeParentId,
3410
- expandOnLoad: e.expandOnLoad
3411
- }, this._treeExpandedKeys), this._treeFlatRows = Qe(this._treeRoots), (t = this._d.getVs()) == null || t.setTotalRows(this._treeFlatRows.length), this._d.doRenderFull(this._treeFlatRows.length);
3412
- }
3413
- // ─── 내부 헬퍼 ───────────────────────────────────────────
3414
- _getSummaryDefs() {
3415
- const e = this._d.getOptions().summary;
3416
- if (!e) return [];
3417
- if (e.rows && e.rows.length > 0)
3418
- return e.fields.flatMap(
3419
- (s) => e.rows.map((i) => ({ field: s, op: i.op, format: i.format }))
3420
- );
3421
- const t = Array.isArray(e.ops) ? e.ops : e.ops ? [e.ops] : ["SUM"];
3422
- return e.fields.map((s) => ({ field: s, op: t[0] ?? "SUM", format: e.format }));
3423
- }
3424
- }
3425
- class Jt {
3426
- constructor(e) {
3427
- this._sortList = [], this._filters = {}, this._d = e;
3428
- }
3429
- // ─── 상태 접근자 ─────────────────────────────────────────
3430
- get sortList() {
3431
- return this._sortList;
3432
- }
3433
- get filters() {
3434
- return this._filters;
3435
- }
3436
- // ─── 정렬 ─────────────────────────────────────────────────
3437
- handleSortClick(e, t) {
3438
- var l;
3439
- const s = this._d.getOptions();
3440
- if (!s.sortable) return;
3441
- const i = this._sortList.findIndex((r) => r.field === e);
3442
- if (i >= 0) {
3443
- const r = this._sortList[i];
3444
- r.dir === "asc" ? r.dir = "desc" : this._sortList.splice(i, 1);
3445
- } else
3446
- (!t || !s.multiSort) && (this._sortList = []), this._sortList.push({ field: e, dir: "asc" });
3447
- this._d.getData().applySort(this._sortList), this._d.renderHeader(), this._d.doRender();
3448
- const n = this._sortList.find((r) => r.field === e), o = n ? n.dir === "asc" ? "오름차순" : "내림차순" : "정렬 해제";
3449
- this._d.announce(`${e} ${o} 정렬`), this._d.emit("sortChange", { sortList: this._sortList }), (l = s.onSortChange) == null || l.call(s, { field: e, dir: (n == null ? void 0 : n.dir) ?? "asc", sortList: this._sortList });
3450
- }
3451
- sort(e, t = "asc") {
3452
- if (Array.isArray(e))
3453
- this._sortList = e;
3454
- else {
3455
- const s = this._sortList.findIndex((i) => i.field === e);
3456
- s >= 0 ? this._sortList[s].dir = t : this._sortList = [{ field: e, dir: t }], this._d.getOptions().multiSort || (this._sortList = this._sortList.slice(-1));
3457
- }
3458
- this._d.getData().applySort(this._sortList), this._d.renderHeader(), this._d.doRender(), this._d.emit("sortChange", { sortList: this._sortList });
3459
- }
3460
- resetSort() {
3461
- this._sortList = [], this._d.getData().applySort([]), this._d.renderHeader(), this._d.doRender();
3462
- }
3463
- initSort(e) {
3464
- this._sortList = [...e], this._d.getData().applySort(this._sortList);
3465
- }
3466
- getSortState() {
3467
- return [...this._sortList];
3468
- }
3469
- // ─── 필터 ─────────────────────────────────────────────────
3470
- setFilter(e, t) {
3471
- var s, i;
3472
- this._filters[e] = t, this.applyFilters(), this._d.renderHeader(), this._d.doRender(), this._d.emit("filterChange", { field: e, filterItems: t, allFilters: this._filters }), (i = (s = this._d.getOptions()).onFilterChange) == null || i.call(s, { field: e, filterItems: t, allFilters: this._filters });
3473
- }
3474
- resetFilter(e) {
3475
- e ? delete this._filters[e] : this._filters = {}, this.applyFilters(), this._d.renderHeader(), this._d.doRender();
3476
- }
3477
- getFilterState() {
3478
- return { ...this._filters };
3479
- }
3480
- restoreFilter(e) {
3481
- this._filters = { ...e }, this.applyFilters();
3482
- }
3483
- applyFilters() {
3484
- var s, i;
3485
- const e = this._d.getData();
3486
- e.setFindFilter(this._d.getFindFilter(), this._d.getColLayout().visibleLeaves.map((n) => n.field)), e.applyFilter(this._filters);
3487
- const t = e.rowCount;
3488
- (s = this._d.getVs()) == null || s.setTotalRows(t), (i = this._d.getPagination()) == null || i.setTotalRows(t);
3489
- }
3490
- }
3491
- class Qt {
3492
- constructor(e) {
3493
- this._d = e;
3494
- }
3495
- handleCellClick(e, t, s) {
3496
- var a, c, h, u, p, M, f;
3497
- const i = this._d.getOptions(), n = this._d.getRowMgr(), o = this._d.getEditMgr();
3498
- i.selection === "single" || i.selection === "row" ? n.selectSingle(e) : i.selection === "multiple" && (s.ctrlKey || s.metaKey ? n.selectToggle(e) : n.selectSingle(e));
3499
- const l = this._d.getData().getRowByIndex(e), r = this._d.getColLayout().visibleLeaves[t];
3500
- if (l && r) {
3501
- const E = r.editable !== !1 && (r.editable !== void 0 || i.editable);
3502
- if (te(r) && E) {
3503
- const C = l[r.field];
3504
- this._d.writeCell(e, r.field, !C);
3505
- }
3506
- if (r.type === "radio") {
3507
- const C = r.group;
3508
- for (const F of this._d.getColLayout().visibleLeaves)
3509
- F.type === "radio" && F.field !== r.field && (!C || F.group === C) && this._d.getData().updateCell(e, F.field, !1);
3510
- this._d.writeCell(e, r.field, !0);
3511
- }
3512
- let x = l[r.field];
3513
- if (x === void 0 && r.formula)
3514
- try {
3515
- const C = r.formulaPrecision ?? 30, F = Pe(r.formula, l, C);
3516
- x = F instanceof R ? r.precision != null ? F.toFixed(r.precision) : F.toString() : String(F);
3517
- } catch {
3518
- }
3519
- const g = {
3520
- type: "cellClick",
3521
- rowIndex: e,
3522
- columnIndex: t,
3523
- field: r.field,
3524
- value: x,
3525
- row: l,
3526
- column: r,
3527
- target: s.target,
3528
- originalEvent: s
3529
- };
3530
- this._d.emit("cellClick", g), (a = i.onCellClick) == null || a.call(i, g);
3531
- const w = { type: "rowClick", rowIndex: e, row: l, target: s.target, originalEvent: s };
3532
- this._d.emit("rowClick", w), (c = i.onRowClick) == null || c.call(i, w);
3533
- const L = r.type === "select";
3534
- !(o.activeEditor != null && ((h = o.editCell) == null ? void 0 : h.ri) === e && ((u = o.editCell) == null ? void 0 : u.ci) === t) && (i.editMode === "click" || L) && !te(r) && o.startEdit(e, t, s);
3535
- }
3536
- o.activeEditor && ((p = o.editCell) == null ? void 0 : p.ri) === e && ((M = o.editCell) == null ? void 0 : M.ci) === t || (this._d.doRender(), this._d.emit("selectionChange", {
3537
- rows: n.getSelections(),
3538
- rowIndexes: [...n.selectedRows]
3539
- }), (f = i.onSelectionChange) == null || f.call(i, { rows: n.getSelections(), rowIndexes: [...n.selectedRows], cells: [] }));
3540
- }
3541
- handleCellDblClick(e, t, s) {
3542
- var a, c;
3543
- const i = this._d.getData().getRowByIndex(e), n = this._d.getColLayout().visibleLeaves[t];
3544
- if (!i || !n) return;
3545
- const o = this._d.getOptions(), l = {
3546
- type: "cellDblClick",
3547
- rowIndex: e,
3548
- columnIndex: t,
3549
- field: n.field,
3550
- value: i[n.field],
3551
- row: i,
3552
- column: n,
3553
- target: s.target,
3554
- originalEvent: s
3555
- };
3556
- this._d.emit("cellDblClick", l), (a = o.onCellDblClick) == null || a.call(o, l);
3557
- const r = { type: "rowDblClick", rowIndex: e, row: i, target: s.target, originalEvent: s };
3558
- this._d.emit("rowDblClick", r), (c = o.onRowDblClick) == null || c.call(o, r), o.editMode === "dblclick" && this._d.getEditMgr().startEdit(e, t, s);
3559
- }
3560
- handleCellMouseOver(e, t, s) {
3561
- var a, c;
3562
- const i = this._d.getData().getRowByIndex(e), n = this._d.getColLayout().visibleLeaves[t];
3563
- if (!i || !n) return;
3564
- const o = this._d.getOptions(), l = { type: "cellMouseOver", rowIndex: e, columnIndex: t, field: n.field, value: i[n.field], row: i, column: n, target: s.target, originalEvent: s };
3565
- this._d.emit("cellMouseOver", l), (a = o.onCellMouseOver) == null || a.call(o, l);
3566
- const r = { type: "rowMouseOver", rowIndex: e, row: i, target: s.target, originalEvent: s };
3567
- this._d.emit("rowMouseOver", r), (c = o.onRowMouseOver) == null || c.call(o, r);
3568
- }
3569
- handleCellMouseOut(e, t, s) {
3570
- var a, c;
3571
- const i = this._d.getData().getRowByIndex(e), n = this._d.getColLayout().visibleLeaves[t];
3572
- if (!i || !n) return;
3573
- const o = this._d.getOptions(), l = { type: "cellMouseOut", rowIndex: e, columnIndex: t, field: n.field, value: i[n.field], row: i, column: n, target: s.target, originalEvent: s };
3574
- this._d.emit("cellMouseOut", l), (a = o.onCellMouseOut) == null || a.call(o, l);
3575
- const r = { type: "rowMouseOut", rowIndex: e, row: i, target: s.target, originalEvent: s };
3576
- this._d.emit("rowMouseOut", r), (c = o.onRowMouseOut) == null || c.call(o, r);
3577
- }
3578
- handleCellMouseDown(e, t, s) {
3579
- var a, c;
3580
- const i = this._d.getData().getRowByIndex(e), n = this._d.getColLayout().visibleLeaves[t];
3581
- if (!i || !n) return;
3582
- const o = this._d.getOptions(), l = { type: "cellMouseDown", rowIndex: e, columnIndex: t, field: n.field, value: i[n.field], row: i, column: n, target: s.target, originalEvent: s };
3583
- this._d.emit("cellMouseDown", l), (a = o.onCellMouseDown) == null || a.call(o, l);
3584
- const r = { type: "rowMouseDown", rowIndex: e, row: i, target: s.target, originalEvent: s };
3585
- this._d.emit("rowMouseDown", r), (c = o.onRowMouseDown) == null || c.call(o, r);
3586
- }
3587
- handleCellMouseUp(e, t, s) {
3588
- var a, c;
3589
- const i = this._d.getData().getRowByIndex(e), n = this._d.getColLayout().visibleLeaves[t];
3590
- if (!i || !n) return;
3591
- const o = this._d.getOptions(), l = { type: "cellMouseUp", rowIndex: e, columnIndex: t, field: n.field, value: i[n.field], row: i, column: n, target: s.target, originalEvent: s };
3592
- this._d.emit("cellMouseUp", l), (a = o.onCellMouseUp) == null || a.call(o, l);
3593
- const r = { type: "rowMouseUp", rowIndex: e, row: i, target: s.target, originalEvent: s };
3594
- this._d.emit("rowMouseUp", r), (c = o.onRowMouseUp) == null || c.call(o, r);
3595
- }
3596
- handleCellMouseMove(e, t, s) {
3597
- var a, c;
3598
- const i = this._d.getData().getRowByIndex(e), n = this._d.getColLayout().visibleLeaves[t];
3599
- if (!i || !n) return;
3600
- const o = this._d.getOptions(), l = { type: "cellMouseMove", rowIndex: e, columnIndex: t, field: n.field, value: i[n.field], row: i, column: n, target: s.target, originalEvent: s };
3601
- this._d.emit("cellMouseMove", l), (a = o.onCellMouseMove) == null || a.call(o, l);
3602
- const r = { type: "rowMouseMove", rowIndex: e, row: i, target: s.target, originalEvent: s };
3603
- this._d.emit("rowMouseMove", r), (c = o.onRowMouseMove) == null || c.call(o, r);
3604
- }
3605
- handleCellKeyEvt(e, t) {
3606
- var c, h, u;
3607
- const s = this._d.getEditMgr();
3608
- if (!s.focusCell || s.activeEditor) return;
3609
- const { ri: i, ci: n } = s.focusCell, o = this._d.getData().getRowByIndex(i), l = this._d.getColLayout().visibleLeaves[n];
3610
- if (!o || !l) return;
3611
- const r = this._d.getOptions(), a = { type: e, rowIndex: i, columnIndex: n, field: l.field, value: o[l.field], row: o, column: l, key: t.key, target: this._d.getContainer(), originalEvent: t };
3612
- this._d.emit(e, a), e === "cellKeyDown" ? (c = r.onCellKeyDown) == null || c.call(r, a) : e === "cellKeyUp" ? (h = r.onCellKeyUp) == null || h.call(r, a) : (u = r.onCellKeyPress) == null || u.call(r, a);
3613
- }
3614
- }
3615
- class Zt {
3616
- constructor() {
3617
- this._triggers = /* @__PURE__ */ new Map();
3618
- }
3619
- add(e, t) {
3620
- this._triggers.has(e) || this._triggers.set(e, []), this._triggers.get(e).push(t);
3621
- }
3622
- remove(e, t) {
3623
- const s = this._triggers.get(e);
3624
- if (s) {
3625
- const i = s.indexOf(t);
3626
- i >= 0 && s.splice(i, 1);
3627
- }
3628
- }
3629
- clear(e) {
3630
- e ? this._triggers.delete(e) : this._triggers.clear();
3631
- }
3632
- mkCtx(e, t) {
3633
- let s = !1;
3634
- return {
3635
- operation: e,
3636
- args: t,
3637
- result: void 0,
3638
- extra: {},
3639
- timestamp: Date.now(),
3640
- get cancelled() {
3641
- return s;
3642
- },
3643
- cancel() {
3644
- s = !0;
3645
- }
3646
- };
3647
- }
3648
- exec(e, t) {
3649
- const s = this._triggers.get(e) ?? [];
3650
- for (const i of s)
3651
- if (i(t), t.cancelled) return !1;
3652
- if (e.startsWith("after:")) {
3653
- const i = this._triggers.get("complete") ?? [];
3654
- for (const n of i) n(t);
3655
- }
3656
- return !0;
3657
- }
3658
- }
3659
- const le = "";
3660
- function Ze(d) {
3661
- const e = Object.entries(d).filter(([, t]) => t !== le).map(([t, s]) => ` ${JSON.stringify(t)}: src[${JSON.stringify(s)}],`);
3662
- return `// crossGridMapping 옵션에 이 함수를 그대로 지정하세요.
3663
- function mapRow(src) {
3664
- return {
3665
- ` + e.join(`
3666
- `) + (e.length ? `
3667
- ` : "") + ` };
3668
- }`;
3669
- }
3670
- function es(d) {
3671
- return (e) => {
3672
- const t = {};
3673
- for (const [s, i] of Object.entries(d))
3674
- i !== le && (t[s] = e[i]);
3675
- return t;
3676
- };
3677
- }
3678
- function ts(d, e) {
3679
- if (d.length !== e.length) return !1;
3680
- const t = new Set(e);
3681
- return d.every((s) => t.has(s));
3682
- }
3683
- function ss(d, e) {
3684
- return new Promise((t) => {
3685
- const s = new Set(d.map((C) => C.field)), i = {};
3686
- for (const C of e) i[C.field] = s.has(C.field) ? C.field : le;
3687
- const n = document.createElement("div");
3688
- n.className = "og-mapper-overlay", n.setAttribute("role", "dialog"), n.setAttribute("aria-modal", "true"), n.setAttribute("aria-label", "그리드 필드 매핑"), n.style.cssText = "position:fixed;inset:0;z-index:100000;background:rgba(0,0,0,0.45);display:flex;align-items:center;justify-content:center;font-family:var(--og-font-family,-apple-system,sans-serif);";
3689
- const o = document.createElement("div");
3690
- o.style.cssText = "background:#fff;border-radius:10px;box-shadow:0 12px 40px rgba(0,0,0,0.3);width:min(620px,92vw);max-height:88vh;overflow:auto;color:#222;", n.appendChild(o);
3691
- const l = document.createElement("div");
3692
- l.style.cssText = "padding:18px 20px 8px;", l.innerHTML = '<div style="font-size:16px;font-weight:700;">필드 매핑</div><div style="font-size:12.5px;color:#666;margin-top:4px;line-height:1.5;">두 그리드의 필드 구조가 다릅니다. <b>타깃 필드</b>마다 어떤 <b>소스 필드</b>의 값을 가져올지 지정하세요. 아래 스크립트를 복사해 <code>crossGridMapping</code> 에 baking 하면 다음부터는 이 창 없이 자동 변환됩니다.</div>', o.appendChild(l);
3693
- const r = document.createElement("div");
3694
- r.style.cssText = "padding:6px 20px;";
3695
- const a = '<option value="">(비움)</option>' + d.map(
3696
- (C) => `<option value="${ee(C.field)}">${ee(C.header)} &lt;${ee(C.field)}&gt;</option>`
3697
- ).join("");
3698
- for (const C of e) {
3699
- const F = document.createElement("div");
3700
- F.style.cssText = "display:flex;align-items:center;gap:10px;padding:7px 0;border-bottom:1px solid #f0f0f0;";
3701
- const K = document.createElement("div");
3702
- K.style.cssText = "flex:1;font-size:13px;min-width:0;", K.innerHTML = `<span style="font-weight:600;">${ee(C.header)}</span><span style="color:#999;font-size:11.5px;"> &lt;${ee(C.field)}&gt;</span>`;
3703
- const _ = document.createElement("span");
3704
- _.textContent = "←", _.style.cssText = "color:#888;flex-shrink:0;";
3705
- const b = document.createElement("select");
3706
- b.style.cssText = "flex:1;min-width:0;padding:6px 8px;border:1px solid #ccc;border-radius:6px;font-size:13px;background:#fff;", b.innerHTML = a, b.value = i[C.field] ?? le, b.addEventListener("change", () => {
3707
- i[C.field] = b.value, f();
3708
- }), F.append(K, _, b), r.appendChild(F);
3709
- }
3710
- o.appendChild(r);
3711
- const c = document.createElement("div");
3712
- c.style.cssText = "padding:10px 20px 4px;";
3713
- const h = document.createElement("div");
3714
- h.style.cssText = "display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;", h.innerHTML = '<span style="font-size:12.5px;font-weight:600;color:#444;">생성된 변환 스크립트</span>';
3715
- const u = document.createElement("button");
3716
- u.type = "button", u.textContent = "복사", u.style.cssText = "font-size:12px;padding:4px 10px;border:1px solid #ccc;border-radius:6px;background:#f7f7f7;cursor:pointer;", h.appendChild(u);
3717
- const p = document.createElement("pre");
3718
- p.style.cssText = "margin:0;background:#0d1117;color:#c9d1d9;padding:12px;border-radius:8px;font-family:ui-monospace,Consolas,monospace;font-size:12px;line-height:1.5;overflow:auto;max-height:180px;", c.append(h, p), o.appendChild(c);
3719
- function M() {
3720
- return Ze(i);
3721
- }
3722
- function f() {
3723
- p.textContent = M();
3724
- }
3725
- f(), u.addEventListener("click", () => {
3726
- var F;
3727
- const C = M();
3728
- (F = navigator.clipboard) == null || F.writeText(C).then(
3729
- () => {
3730
- u.textContent = "복사됨!", setTimeout(() => u.textContent = "복사", 1200);
3731
- },
3732
- () => {
3733
- u.textContent = "복사 실패", setTimeout(() => u.textContent = "복사", 1200);
3734
- }
3735
- );
3736
- });
3737
- const E = document.createElement("div");
3738
- E.style.cssText = "display:flex;justify-content:flex-end;gap:8px;padding:14px 20px 18px;";
3739
- const x = document.createElement("button");
3740
- x.type = "button", x.textContent = "취소", x.style.cssText = "font-size:13px;padding:8px 16px;border:1px solid #ccc;border-radius:7px;background:#fff;cursor:pointer;";
3741
- const g = document.createElement("button");
3742
- g.type = "button", g.textContent = "적용 후 이동", g.style.cssText = "font-size:13px;padding:8px 16px;border:0;border-radius:7px;background:#1976d2;color:#fff;cursor:pointer;font-weight:600;", E.append(x, g), o.appendChild(E);
3743
- let w = !1;
3744
- function L(C) {
3745
- w || (w = !0, document.removeEventListener("keydown", v), n.remove(), t(C));
3746
- }
3747
- function v(C) {
3748
- C.key === "Escape" && L(null);
3749
- }
3750
- x.addEventListener("click", () => L(null)), n.addEventListener("mousedown", (C) => {
3751
- C.target === n && L(null);
3752
- }), g.addEventListener("click", () => L({ mapping: { ...i }, script: M() })), document.addEventListener("keydown", v), document.body.appendChild(n), g.focus();
3753
- });
3754
- }
3755
- function ee(d) {
3756
- return String(d).replace(/[&<>"]/g, (e) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[e]);
3757
- }
3758
- class is {
3759
- constructor() {
3760
- this._map = /* @__PURE__ */ new Map();
3761
- }
3762
- register(e, t) {
3763
- this._map.set(e, t);
3764
- }
3765
- unregister(e) {
3766
- this._map.delete(e);
3767
- }
3768
- get(e) {
3769
- return this._map.get(e);
3770
- }
3771
- get size() {
3772
- return this._map.size;
3773
- }
3774
- /** 커서 좌표 아래의 다른(crossGrid 허용) 그리드 반환. 없으면 null */
3775
- resolveAt(e, t, s) {
3776
- const i = document.elementFromPoint(e, t), n = i == null ? void 0 : i.closest(".og-body-wrapper");
3777
- if (!n) return null;
3778
- const o = this._map.get(n);
3779
- return !o || o === s ? null : o;
3780
- }
3781
- }
3782
- const re = new is(), Ve = "_ogRowId";
3783
- class rs extends tt {
3784
- constructor(e, t) {
3785
- var i;
3786
- super(), this._vs = null, this._ro = null, this._renderer = null, this._trigMgr = new Zt(), this._destroyed = !1, this._autoHeightWarned = !1, this._colWidths = [], this._userWidths = /* @__PURE__ */ new Map(), this._filterPanel = null, this._filterSelect = null, this._pagination = null, this._dnd = null, this._mergeEngine = new J(), this._liveRegion = null, this._ctxMenu = null, this._cmHandler = null, this._cmKbdHandler = null, this._wsManager = null;
3787
- const s = typeof e == "string" ? document.querySelector(e) : e;
3788
- if (!s) throw new Error(`OpenGrid: container not found: ${e}`);
3789
- this._container = s, this._options = {
3790
- height: "100%",
3791
- width: "100%",
3792
- rowHeight: 32,
3793
- headerHeight: 34,
3794
- footerHeight: 30,
3795
- autoHeight: !1,
3796
- fillWidth: !1,
3797
- defaultColumnWidth: 100,
3798
- editable: !1,
3799
- editMode: "dblclick",
3800
- history: !0,
3801
- historySize: 100,
3802
- selection: "single",
3803
- clipboard: !0,
3804
- sortable: !0,
3805
- multiSort: !0,
3806
- filterable: !0,
3807
- defaultSort: [],
3808
- frozenColumns: 0,
3809
- frozenRows: 0,
3810
- rowNumber: !1,
3811
- stateColumn: !1,
3812
- checkColumn: !1,
3813
- draggable: !1,
3814
- crossGrid: !1,
3815
- crossGridMapping: "auto",
3816
- mergeCells: !1,
3817
- groupBy: [],
3818
- summary: void 0,
3819
- treeMode: "auto",
3820
- treeId: "id",
3821
- treeParentId: "parentId",
3822
- expandOnLoad: !1,
3823
- pagination: !1,
3824
- pageSize: 50,
3825
- footer: void 0,
3826
- footerPosition: "bottom",
3827
- theme: "default",
3828
- cssVars: {},
3829
- ariaLabel: "OPEN_GRID 데이터 그리드",
3830
- ...t
3831
- }, this._data = new it(Ve), this._rowMgr = new $t(this._data), this._colLayout = new ce(this._options.columns, this._options.frozenColumns), this._editMgr = new At({
3832
- data: this._data,
3833
- colLayout: this._colLayout,
3834
- getRenderer: () => this._renderer,
3835
- getContainer: () => this._container,
3836
- getOptions: () => this._options,
3837
- emit: (n, ...o) => this.emit(n, ...o),
3838
- doRender: () => this._doRender(...this._visRange()),
3839
- announce: (n) => this._announce(n),
3840
- writeCell: (n, o, l) => this.writeCell(n, o, l),
3841
- scrollToRow: (n) => {
3842
- var o;
3843
- return (o = this._vs) == null ? void 0 : o.scrollToRow(n);
3844
- },
3845
- getVisibleLeaves: () => this._colLayout.visibleLeaves
3846
- }), this._exportMgr = new Kt({
3847
- getData: () => this._data.getData(),
3848
- getColLayout: () => this._colLayout,
3849
- getColWidths: () => this._colWidths,
3850
- getOptions: () => this._options,
3851
- getContainer: () => this._container,
3852
- getMaskEnabled: (n) => this.getMaskEnabled(n),
3853
- getWsManager: () => this._wsManager
3854
- }), this._footerMgr = new Vt({
3855
- getData: () => this._data.getData(),
3856
- getColLayout: () => this._colLayout,
3857
- getColWidths: () => this._colWidths,
3858
- getOptions: () => this._options,
3859
- getContainer: () => this._container
3860
- }), this._kbdMgr = new Pt({
3861
- getEditMgr: () => this._editMgr,
3862
- getRowMgr: () => this._rowMgr,
3863
- getData: () => this._data,
3864
- getColLayout: () => this._colLayout,
3865
- getOptions: () => this._options,
3866
- setFocusCell: (n, o) => this._setFocusCell(n, o),
3867
- handleRowDrop: (n, o) => this._handleRowDrop(n, o),
3868
- doRender: () => this._doRender(...this._visRange()),
3869
- announce: (n) => this._announce(n),
3870
- emit: (n, ...o) => this.emit(n, ...o),
3871
- visRange: () => this._visRange(),
3872
- handleCellKeyEvt: (n, o) => this._handleCellKeyEvt(n, o)
3873
- }), this._sfMgr = new Jt({
3874
- getData: () => this._data,
3875
- getColLayout: () => this._colLayout,
3876
- getFindFilter: () => this._findMgr.findFilter,
3877
- getVs: () => this._vs,
3878
- getPagination: () => this._pagination,
3879
- getOptions: () => this._options,
3880
- renderHeader: () => this._renderHeader(),
3881
- doRender: () => this._doRender(...this._visRange()),
3882
- announce: (n) => this._announce(n),
3883
- emit: (n, ...o) => this.emit(n, ...o)
3884
- }), this._findMgr = new jt({
3885
- getColLayout: () => this._colLayout,
3886
- getData: () => this._data,
3887
- getFilters: () => this._sfMgr.filters,
3888
- getVs: () => this._vs,
3889
- getPagination: () => this._pagination,
3890
- doRender: () => this._doRender(...this._visRange())
3891
- }), this._cellEvt = new Qt({
3892
- getData: () => this._data,
3893
- getColLayout: () => this._colLayout,
3894
- getOptions: () => this._options,
3895
- getEditMgr: () => this._editMgr,
3896
- getRowMgr: () => this._rowMgr,
3897
- emit: (n, ...o) => this.emit(n, ...o),
3898
- writeCell: (n, o, l) => this.writeCell(n, o, l),
3899
- doRender: () => this._doRender(...this._visRange()),
3900
- getContainer: () => this._container
3901
- }), this._grpMgr = new Yt({
3902
- getData: () => this._data.getData(),
3903
- getDataLayer: () => this._data,
3904
- getOptions: () => this._options,
3905
- getVs: () => this._vs,
3906
- doRenderFull: (n) => this._doRender(0, n - 1),
3907
- doRender: () => this._doRender(...this._visRange())
3908
- }), this._mount(), this._bindOptionEvents(), (i = this._options.defaultSort) != null && i.length && this._sfMgr.initSort(this._options.defaultSort), requestAnimationFrame(() => {
3909
- var n, o;
3910
- this.emit("ready", this), (o = (n = this._options).onReady) == null || o.call(n, this);
3911
- });
3912
- }
3913
- _mount() {
3914
- var s, i;
3915
- this._container.classList.add("og-container");
3916
- const e = this._options.height, t = this._options.width;
3917
- this._container.style.height = typeof e == "number" ? `${e}px` : String(e), this._container.style.width = typeof t == "number" ? `${t}px` : String(t), this._container.style.display = "flex", this._container.style.flexDirection = "column", this._container.style.overflow = "hidden", this._container.style.boxSizing = "border-box", this._container.style.border = "1px solid var(--og-border-color, #e0e0e0)", this._container.style.fontFamily = "var(--og-font-family, -apple-system, sans-serif)", this._container.style.fontSize = "var(--og-font-size, 13px)", this._container.setAttribute("data-og-theme", this._options.theme);
3918
- for (const [n, o] of Object.entries(this._options.cssVars))
3919
- this._container.style.setProperty(n, o);
3920
- this._renderer = new Tt(this._container, this._options, {
3921
- onHeaderClick: (n, o) => this._handleSortClick(n, o),
3922
- onCellClick: (n, o, l) => this._handleCellClick(n, o, l),
3923
- onCellDblClick: (n, o, l) => this._handleCellDblClick(n, o, l),
3924
- onCellMouseOver: (n, o, l) => this._handleCellMouseOver(n, o, l),
3925
- onCellMouseOut: (n, o, l) => this._handleCellMouseOut(n, o, l),
3926
- onCellMouseDown: (n, o, l) => this._handleCellMouseDown(n, o, l),
3927
- onCellMouseUp: (n, o, l) => this._handleCellMouseUp(n, o, l),
3928
- onCellMouseMove: (n, o, l) => this._handleCellMouseMove(n, o, l),
3929
- onRowCheck: (n, o) => this._handleRowCheck(n, o),
3930
- onAllCheck: (n) => this._handleAllCheck(n),
3931
- onColResize: (n, o) => this._handleColResize(n, o),
3932
- onFilterIconClick: (n, o) => this._handleFilterIconClick(n, o),
3933
- getDndManager: () => this._dnd,
3934
- onColDragStart: (n) => {
3935
- this._editMgr.dragColIdx = n;
3936
- },
3937
- onColDrop: (n) => {
3938
- this._editMgr.dragColIdx !== null && this._editMgr.dragColIdx !== n && this._reorderColumn(this._editMgr.dragColIdx, n), this._editMgr.dragColIdx = null;
3939
- },
3940
- getColDragIdx: () => this._editMgr.dragColIdx
3941
- }), this._filterPanel = new rt(
3942
- this._container,
3943
- (n, o) => this.setFilter(n, o),
3944
- (n) => this.resetFilter(n)
3945
- ), this._container.setAttribute("role", "grid"), this._container.setAttribute("aria-label", this._options.ariaLabel ?? ((s = this._options.cssVars) == null ? void 0 : s["aria-label"]) ?? "OPEN_GRID 데이터 그리드"), this._container.setAttribute("aria-rowcount", "0"), this._container.setAttribute("aria-colcount", String(this._options.columns.filter((n) => !n.hidden).length)), this._liveRegion = document.createElement("div"), this._liveRegion.setAttribute("aria-live", "polite"), this._liveRegion.setAttribute("aria-atomic", "true"), this._liveRegion.className = "og-live-region", this._container.insertAdjacentElement("beforebegin", this._liveRegion), this._container.tabIndex = 0, this._container.addEventListener("keydown", (n) => this._handleKeyDown(n)), this._container.addEventListener("keyup", (n) => this._handleCellKeyEvt("cellKeyUp", n)), this._container.addEventListener("keypress", (n) => this._handleCellKeyEvt("cellKeyPress", n)), this._vs = new ot(this._renderer.bodyWrapper, {
3946
- rowHeight: this._options.rowHeight,
3947
- onRender: (n, o) => this._doRender(n, o)
3948
- }), re.register(this._renderer.bodyWrapper, this), this._options.draggable && (this._dnd = new Wt(
3949
- this._renderer.bodyWrapper,
3950
- this._options.rowHeight,
3951
- (n, o) => this._handleRowDrop(n, o),
3952
- this._options.crossGrid ? {
3953
- resolveTarget: (n, o) => {
3954
- const l = re.resolveAt(n, o, this);
3955
- return !l || !l._options.crossGrid ? null : { bodyEl: l._crossBodyEl(), rowHeight: l._options.rowHeight, totalRows: l._data.rowCount };
3956
- },
3957
- onCrossDrop: (n, o, l) => this._handleCrossGridDrop(n, o, l)
3958
- } : void 0,
3959
- (n) => this._dragRowSet(n).length
3960
- )), this._options.pagination && (this._pagination = new Ht(
3961
- this._container,
3962
- this._options.pageSize,
3963
- (n) => {
3964
- this.emit("pageChange", n), this._doRender(...this._visRange());
3965
- }
3966
- )), this._findMgr.init(this._container), this._initContextMenu(), (i = this._options.worksheets) != null && i.length && this._initWorksheets(), this._ro = new ResizeObserver(() => this._onResize()), this._ro.observe(this._container), this._onResize();
3967
- }
3968
- _initContextMenu() {
3969
- const e = this._options.contextMenu;
3970
- e !== !1 && (this._cmHandler && this._container.removeEventListener("contextmenu", this._cmHandler), this._cmKbdHandler && this._container.removeEventListener("keydown", this._cmKbdHandler), this._cmHandler = this._cmKbdHandler = null, this._ctxMenu = new Ot(this._container, {
3971
- onSortAsc: () => {
3972
- const t = this._colLayout.visibleLeaves[0];
3973
- t && this.orderBy(t.field, "asc");
3974
- },
3975
- onSortDesc: () => {
3976
- const t = this._colLayout.visibleLeaves[0];
3977
- t && this.orderBy(t.field, "desc");
3978
- },
3979
- onFind: () => this._findMgr.open(),
3980
- onExcel: () => this.exportExcel(),
3981
- onCsv: () => this.exportCsv(),
3982
- onPrint: () => this.print()
3983
- }), this._cmHandler = (t) => {
3984
- var l;
3985
- const s = t.target.closest(".og-cell");
3986
- if (!s) return;
3987
- t.preventDefault();
3988
- const i = Number(s.dataset.colIndex ?? -1), n = this._colLayout.visibleLeaves[i];
3989
- n && this._ctxMenu && (this._ctxMenu._actions.onSortAsc = () => this.orderBy(n.field, "asc"), this._ctxMenu._actions.onSortDesc = () => this.orderBy(n.field, "desc"));
3990
- const o = Array.isArray(e) ? e : void 0;
3991
- (l = this._ctxMenu) == null || l.open(t, o);
3992
- }, this._container.addEventListener("contextmenu", this._cmHandler), this._cmKbdHandler = (t) => {
3993
- var s;
3994
- if (t.shiftKey && t.key === "F10") {
3995
- t.preventDefault();
3996
- const i = this._container.getBoundingClientRect(), n = { clientX: i.left + 80, clientY: i.top + 40 };
3997
- (s = this._ctxMenu) == null || s.open(n);
3998
- }
3999
- }, this._container.addEventListener("keydown", this._cmKbdHandler));
4000
- }
4001
- // openContextMenu / closeContextMenu 공개 API
4002
- openContextMenu(e, t) {
4003
- var s;
4004
- (s = this._ctxMenu) == null || s.open(e, t);
4005
- }
4006
- closeContextMenu() {
4007
- var e;
4008
- (e = this._ctxMenu) == null || e.close();
4009
- }
4010
- setFilterSelect(e) {
4011
- var t;
4012
- (t = this._filterSelect) == null || t.destroy(), this._filterSelect = null, e && (this._container.id || (this._container.id = `og-${Math.random().toString(36).slice(2, 7)}`), this._filterSelect = new zt(
4013
- this._container,
4014
- e,
4015
- (s, i) => this.setFilter(s, i),
4016
- (s) => this.resetFilter(s),
4017
- this._container.id
4018
- ));
4019
- }
4020
- // 옵션을 런타임에 바꿀 때 호출 (contextMenu 재초기화, groupBy 재구성 등)
4021
- setOptions(e) {
4022
- var t;
4023
- if (Object.assign(this._options, e), "contextMenu" in e && ((t = this._ctxMenu) == null || t.destroy(), this._ctxMenu = null, this._initContextMenu()), "groupBy" in e || "summary" in e) {
4024
- const s = e.groupBy ?? [];
4025
- s.length > 0 ? this._grpMgr.groupBy(s) : this.clearGroup();
4026
- return;
4027
- }
4028
- this._renderHeader(), this._doRender(...this._visRange());
4029
- }
4030
- /**
4031
- * 컬럼 마스킹 ON/OFF 전환.
4032
- * enabled=true → 마스킹 적용 (기본 상태)
4033
- * enabled=false → 컬럼 전체 마스킹 해제 (원문 표시)
4034
- */
4035
- setMaskEnabled(e, t) {
4036
- var i;
4037
- const s = this._colLayout.getColumnByField(e);
4038
- s && (t ? (s._maskRevealed = !1, (i = s._maskRevealedRows) == null || i.clear()) : s._maskRevealed = !0, this._doRender(...this._visRange()));
4039
- }
4040
- /** 현재 컬럼 마스킹 활성 여부 반환. true=마스킹 중, false=해제됨 */
4041
- getMaskEnabled(e) {
4042
- const t = this._colLayout.getColumnByField(e);
4043
- return t ? t._maskRevealed !== !0 : !1;
4044
- }
4045
- _initWorksheets() {
4046
- const e = this._options.worksheets;
4047
- this._wsManager = new Ne(
4048
- this._container,
4049
- (t, s) => {
4050
- this._data.setData(s.data), this._colLayout = new ce(
4051
- s.columns.length ? s.columns : this._options.columns,
4052
- this._options.frozenColumns
4053
- ), this._doRender(...this._visRange()), this._renderHeader();
4054
- }
4055
- );
4056
- for (const t of e)
4057
- this._wsManager.add(t.name, t.columns ?? this._options.columns, t.data ?? []);
4058
- }
4059
- addWorksheet(e, t, s) {
4060
- this._wsManager || (this._wsManager = new Ne(
4061
- this._container,
4062
- (i, n) => {
4063
- this._data.setData(n.data), this._colLayout = new ce(
4064
- n.columns.length ? n.columns : this._options.columns,
4065
- this._options.frozenColumns
4066
- ), this._doRender(...this._visRange()), this._renderHeader();
4067
- }
4068
- )), this._wsManager.add(e, t ?? this._options.columns, s ?? []);
4069
- }
4070
- removeWorksheet(e) {
4071
- var t;
4072
- (t = this._wsManager) == null || t.remove(e);
4073
- }
4074
- switchWorksheet(e) {
4075
- var t;
4076
- (t = this._wsManager) == null || t.switch(e);
4077
- }
4078
- renameWorksheet(e, t) {
4079
- var s;
4080
- (s = this._wsManager) == null || s.rename(e, t);
4081
- }
4082
- getWorksheet(e) {
4083
- var t;
4084
- return (t = this._wsManager) == null ? void 0 : t.get(e);
4085
- }
4086
- getWorksheetNames() {
4087
- var e;
4088
- return ((e = this._wsManager) == null ? void 0 : e.getNames()) ?? [];
4089
- }
4090
- exportSheetsExcel(e) {
4091
- this._exportMgr.exportSheetsExcel(e);
4092
- }
4093
- _paginationHeight() {
4094
- return this._options.pagination ? 38 : 0;
4095
- }
4096
- _onResize() {
4097
- const { width: e, height: t } = this._container.getBoundingClientRect();
4098
- if (!e) return;
4099
- const s = t - this._options.headerHeight - this._paginationHeight();
4100
- this._renderer.updateSize(t - this._paginationHeight(), this._options.headerHeight), this._vs.setViewportHeight(s), this._recalcWidths(e), this._renderHeader(), this._doRender(...this._visRange());
4101
- }
4102
- _recalcWidths(e) {
4103
- this._colWidths = this._colLayout.computeWidths(
4104
- e - (this._options.stateColumn ? 24 : 0) - (this._options.draggable ? 18 : 0) - (this._options.rowNumber ? 44 : 0) - (this._options.checkColumn ? 36 : 0),
4105
- this._options.defaultColumnWidth
4106
- ), this._userWidths.size && this._colLayout.visibleLeaves.forEach((t, s) => {
4107
- const i = this._userWidths.get(t.field);
4108
- i != null && (this._colWidths[s] = i);
4109
- });
4110
- }
4111
- // 헤더(컬럼 제목 행)를 다시 그린다
4112
- _renderHeader() {
4113
- var e;
4114
- (e = this._renderer) == null || e.renderHeader(
4115
- this._colLayout.buildHeaderCells(),
4116
- this._colLayout.visibleLeaves,
4117
- this._colWidths,
4118
- this._sfMgr.sortList,
4119
- { ...this._options, _activeFilters: this._sfMgr.filters, _frozenCount: this._colLayout.frozenCount }
4120
- );
4121
- }
4122
- _doRender(e, t) {
4123
- var n;
4124
- if (!this._renderer || !this._vs) return;
4125
- const s = this._vs.getVisibleRange(), i = this._options.autoHeight === !0;
4126
- i && ([e, t] = this._visRange(), !this._autoHeightWarned && t - e + 1 > 2e3 && (this._autoHeightWarned = !0, console.warn(
4127
- `[OpenGrid] autoHeight 는 가상 스크롤이 아니라 전 행(${t - e + 1}행)을 렌더합니다. 행이 많으면 고정 rowHeight(가상 스크롤) 사용을 권장합니다.`
4128
- ))), this._renderer.renderBody(
4129
- e,
4130
- t,
4131
- this._data,
4132
- this._colLayout.visibleLeaves,
4133
- this._colWidths,
4134
- this._options,
4135
- i ? 0 : s.offsetY,
4136
- i ? 0 : this._vs.getTotalHeight(),
4137
- this._rowMgr.selectedRows,
4138
- this._rowMgr.checkedRows,
4139
- this._grpMgr.isGroupMode ? this._grpMgr.groupFlatRows : this._grpMgr.isTreeMode ? this._grpMgr.treeFlatRows : null,
4140
- (o) => this._grpMgr.handleGroupToggle(o),
4141
- this._grpMgr.isTreeMode ? (o) => this._grpMgr.handleTreeToggle(o) : void 0,
4142
- { _totalRows: this._data.rowCount, _frozenCount: this._colLayout.frozenCount, _focusCell: this._editMgr.focusCell },
4143
- this._mergeEngine
4144
- ), (n = this._options.footer) != null && n.length && this._renderFooterEl();
4145
- }
4146
- _handleGroupToggle(e) {
4147
- this._grpMgr.handleGroupToggle(e);
4148
- }
4149
- // 현재 화면에 보이는 행 범위를 반환한다
4150
- _visRange() {
4151
- var t;
4152
- if (this._options.pagination && this._pagination) {
4153
- const { start: s, end: i } = this._pagination.getRange();
4154
- return [s, i];
4155
- }
4156
- if (this._options.autoHeight)
4157
- return [0, (this._grpMgr.isGroupMode ? this._grpMgr.groupFlatRows.length : this._grpMgr.isTreeMode ? this._grpMgr.treeFlatRows.length : this._data.rowCount) - 1];
4158
- const e = (t = this._vs) == null ? void 0 : t.getVisibleRange();
4159
- return [(e == null ? void 0 : e.startIndex) ?? 0, Math.min(((e == null ? void 0 : e.endIndex) ?? 30) + this._visCount() + 5, this._data.rowCount - 1)];
4160
- }
4161
- _visCount() {
4162
- const e = this._container.getBoundingClientRect().height;
4163
- return Math.ceil((e - this._options.headerHeight - this._paginationHeight()) / this._options.rowHeight) + 5;
4164
- }
4165
- _handleSortClick(e, t) {
4166
- this._sfMgr.handleSortClick(e, t);
4167
- }
4168
- _isToggleCol(e) {
4169
- return te(e);
4170
- }
4171
- _handleCellClick(e, t, s) {
4172
- this._cellEvt.handleCellClick(e, t, s);
4173
- }
4174
- _handleCellDblClick(e, t, s) {
4175
- this._cellEvt.handleCellDblClick(e, t, s);
4176
- }
4177
- _handleCellMouseOver(e, t, s) {
4178
- this._cellEvt.handleCellMouseOver(e, t, s);
4179
- }
4180
- _handleCellMouseOut(e, t, s) {
4181
- this._cellEvt.handleCellMouseOut(e, t, s);
4182
- }
4183
- _handleCellMouseDown(e, t, s) {
4184
- this._cellEvt.handleCellMouseDown(e, t, s);
4185
- }
4186
- _handleCellMouseUp(e, t, s) {
4187
- this._cellEvt.handleCellMouseUp(e, t, s);
4188
- }
4189
- _handleCellMouseMove(e, t, s) {
4190
- this._cellEvt.handleCellMouseMove(e, t, s);
4191
- }
4192
- _handleCellKeyEvt(e, t) {
4193
- this._cellEvt.handleCellKeyEvt(e, t);
4194
- }
4195
- _handleRowCheck(e, t) {
4196
- this._rowMgr.check(e, t), this._doRender(...this._visRange()), this.emit("rowCheck", { rowIndex: e, checked: t, row: this._data.getRowByIndex(e) });
4197
- }
4198
- _handleFilterIconClick(e, t) {
4199
- var i, n;
4200
- if ((i = this._filterPanel) != null && i.isOpen) {
4201
- this._filterPanel.close();
4202
- return;
4203
- }
4204
- const s = this._sfMgr.filters[e] ?? [];
4205
- (n = this._filterPanel) == null || n.open(e, t, s);
4206
- }
4207
- _handleAllCheck(e) {
4208
- this._rowMgr.checkAll(e, this._data.rowCount), this._doRender(...this._visRange()), this.emit("allCheck", { checked: e });
4209
- }
4210
- _handleRowDrop(e, t) {
4211
- var s, i;
4212
- this._data.moveRow(e, t), this._doRender(...this._visRange()), this.emit("rowDrop", { fromIndex: e, toIndex: t }), (i = (s = this._options).onRowDrop) == null || i.call(s, { fromIndex: e, toIndex: t });
4213
- }
4214
- // ── 크로스그리드 내부 헬퍼 ──
4215
- /** 드래그/셔틀이 참조하는 바디 엘리먼트 (레지스트리 해석용) */
4216
- _crossBodyEl() {
4217
- return this._renderer.bodyWrapper;
4218
- }
4219
- /** fromIndex 를 잡고 드래그할 때 함께 이동할 행 집합 (다중선택에 포함되면 선택 전체) */
4220
- _dragRowSet(e) {
4221
- const t = [...this._rowMgr.selectedRows];
4222
- return t.length > 1 && t.includes(e) ? t.sort((s, i) => s - i) : [e];
4223
- }
4224
- /** 드래그 드롭 어댑터 → 공개 moveRowsTo 로 위임 */
4225
- _handleCrossGridDrop(e, t, s) {
4226
- const i = re.get(t);
4227
- !i || i === this || this.moveRowsTo(i, this._dragRowSet(e), s);
4228
- }
4229
- /**
4230
- * 이 그리드의 행들을 다른 그리드로 이동(move)한다. 드래그·화살표 셔틀 공통 경로.
4231
- * 3단계 이벤트(before→after→complete)와 crossGridMapping(필드 매핑)을 적용한다.
4232
- * @param targetGrid 대상 그리드
4233
- * @param sourceIndexes 이동할 (표시)행 인덱스들
4234
- * @param targetIndex 대상에서 삽입 위치 (생략 시 맨 끝에 추가)
4235
- * @returns 이동 성공 true, 취소/무효 false
4236
- */
4237
- async moveRowsTo(e, t, s) {
4238
- const i = e;
4239
- if (!i || i === this || !t.length) return !1;
4240
- const n = [...new Set(t)].sort((c, h) => c - h), o = s ?? i._data.rowCount;
4241
- let l = n.map((c) => {
4242
- const h = { ...this._data.getRowByIndex(c) };
4243
- return delete h[Ve], h;
4244
- });
4245
- const r = await this._resolveCrossTransform(i);
4246
- if (r === !1) return !1;
4247
- r && (l = l.map((c) => r(c)));
4248
- const a = {
4249
- sourceGrid: this,
4250
- targetGrid: i,
4251
- rows: l,
4252
- sourceIndexes: n,
4253
- targetIndex: o
4254
- };
4255
- return this._fireGridDropBefore(a) === !1 || a.cancel || i._fireGridDropBefore(a) === !1 || a.cancel ? !1 : (l.forEach((c, h) => i.insertRow(c, o + h)), [...n].sort((c, h) => h - c).forEach((c) => this.deleteRow(c)), this._fireGridDropAfter(a), i._fireGridDropAfter(a), this._fireGridDropComplete(a), i._fireGridDropComplete(a), !0);
4256
- }
4257
- /** 체크된 행을 다른 그리드로 이동 (화살표 셔틀용). 체크 없으면 무시. */
4258
- async moveCheckedTo(e) {
4259
- const t = this._rowMgr.getChecked().map((s) => s.rowIndex);
4260
- return t.length ? (this._rowMgr.uncheckAll(), this.moveRowsTo(e, t)) : !1;
4261
- }
4262
- /**
4263
- * 크로스그리드 이동의 행 변환 함수를 결정한다.
4264
- * 반환: null=변환 불필요(그대로) / 함수=변환 적용 / false=매핑 모달 취소(이동 중단)
4265
- */
4266
- async _resolveCrossTransform(e) {
4267
- var l, r;
4268
- const t = this._options.crossGridMapping;
4269
- if (typeof t == "function") return t;
4270
- if (t !== "interactive") return null;
4271
- const s = this._colLayout.visibleLeaves.map((a) => ({ field: a.field, header: a.header })), i = e._colLayout.visibleLeaves.map((a) => ({ field: a.field, header: a.header }));
4272
- if (ts(s.map((a) => a.field), i.map((a) => a.field))) return null;
4273
- const n = await ss(s, i);
4274
- if (!n) return !1;
4275
- const o = {
4276
- sourceGrid: this,
4277
- targetGrid: e,
4278
- mapping: n.mapping,
4279
- script: n.script
4280
- };
4281
- return this.emit("gridDropMapping", o), (r = (l = this._options).onGridDropMapping) == null || r.call(l, o), console.log(`[OpenGrid] cross-grid mapping script:
4282
- ` + Ze(n.mapping)), es(n.mapping);
4283
- }
4284
- _fireGridDropBefore(e) {
4285
- var t, s;
4286
- return this.emit("gridDropBefore", e), (s = (t = this._options).onGridDropBefore) == null ? void 0 : s.call(t, e);
4287
- }
4288
- _fireGridDropAfter(e) {
4289
- var t, s;
4290
- this.emit("gridDropAfter", e), (s = (t = this._options).onGridDropAfter) == null || s.call(t, e);
4291
- }
4292
- _fireGridDropComplete(e) {
4293
- var t, s;
4294
- this.emit("gridDropComplete", e), (s = (t = this._options).onGridDropComplete) == null || s.call(t, e);
4295
- }
4296
- /** 행을 드롭으로 이동할 때 실행된다 */
4297
- /** ???꾩튂 ?대룞 */
4298
- reorderRow(e, t) {
4299
- this._data.moveRow(e, t), this._doRender(...this._visRange());
4300
- }
4301
- _handleColResize(e, t) {
4302
- this._colWidths[e] !== void 0 && (this._colWidths[e] = t);
4303
- const s = this._colLayout.visibleLeaves[e];
4304
- s && this._userWidths.set(s.field, t), this._renderHeader(), this._doRender(...this._visRange());
4305
- }
4306
- _handleKeyDown(e) {
4307
- this._kbdMgr.handleKeyDown(e);
4308
- }
4309
- _setFocusCell(e, t) {
4310
- this._rowMgr.selectSingle(e), this._editMgr.setFocusCell(e, t);
4311
- }
4312
- // 스크린리더에게 텍스트를 읽어준다 (aria-live)
4313
- _announce(e) {
4314
- this._liveRegion && (this._liveRegion.textContent = "", setTimeout(() => {
4315
- this._liveRegion && (this._liveRegion.textContent = e);
4316
- }, 50));
4317
- }
4318
- _bindOptionEvents() {
4319
- this._options.onCellClick && this.on("cellClick", this._options.onCellClick), this._options.onCellDblClick && this.on("cellDblClick", this._options.onCellDblClick), this._options.onRowClick && this.on("rowClick", this._options.onRowClick), this._options.onEditStart && this.on("editStart", this._options.onEditStart), this._options.onEditEnd && this.on("editEnd", this._options.onEditEnd), this._options.onSortChange && this.on("sortChange", this._options.onSortChange), this._options.onFilterChange && this.on("filterChange", this._options.onFilterChange), this._options.onScroll && this.on("scroll", this._options.onScroll), this._options.onDataChange && this.on("dataChange", this._options.onDataChange), this._options.onSelectionChange && this.on("selectionChange", this._options.onSelectionChange), this._options.onRowDblClick && this.on("rowDblClick", this._options.onRowDblClick), this._options.onRowMouseOver && this.on("rowMouseOver", this._options.onRowMouseOver), this._options.onRowMouseOut && this.on("rowMouseOut", this._options.onRowMouseOut), this._options.onRowMouseDown && this.on("rowMouseDown", this._options.onRowMouseDown), this._options.onRowMouseUp && this.on("rowMouseUp", this._options.onRowMouseUp), this._options.onRowMouseMove && this.on("rowMouseMove", this._options.onRowMouseMove), this._options.onCellMouseOver && this.on("cellMouseOver", this._options.onCellMouseOver), this._options.onCellMouseOut && this.on("cellMouseOut", this._options.onCellMouseOut), this._options.onCellMouseDown && this.on("cellMouseDown", this._options.onCellMouseDown), this._options.onCellMouseUp && this.on("cellMouseUp", this._options.onCellMouseUp), this._options.onCellMouseMove && this.on("cellMouseMove", this._options.onCellMouseMove), this._options.onCellKeyDown && this.on("cellKeyDown", this._options.onCellKeyDown), this._options.onCellKeyUp && this.on("cellKeyUp", this._options.onCellKeyUp), this._options.onCellKeyPress && this.on("cellKeyPress", this._options.onCellKeyPress);
4320
- }
4321
- setData(e) {
4322
- var s;
4323
- const t = this._trigMgr.mkCtx("setData", [e]);
4324
- this._trigMgr.exec("before:setData", t) && (this._rowMgr.reset(), this._data.setData(e), this._applyFilters(), this._grpMgr.isTreeMode ? this._grpMgr.rebuildTree() : this._grpMgr.isGroupMode ? this._grpMgr.rebuildGroups() : (s = this._vs) == null || s.setTotalRows(this._data.rowCount), this._container.setAttribute("aria-rowcount", String(this._data.rowCount)), this._container.setAttribute("aria-colcount", String(this._colLayout.visibleLeaves.length)), this._announce(`${this._data.rowCount}행 데이터 로드됨`), this.emit("dataChange", this._data.getData()), t.result = e.length, this._trigMgr.exec("after:setData", t));
4325
- }
4326
- getData() {
4327
- return this._data.getData();
4328
- }
4329
- getSourceRows() {
4330
- return this._data.getOriginalData();
4331
- }
4332
- pushData(e) {
4333
- var i, n;
4334
- const t = [...this._data.getAllData(), ...e];
4335
- this._data.setData(t);
4336
- const s = this._data.rowCount;
4337
- (i = this._vs) == null || i.setTotalRows(s), (n = this._pagination) == null || n.setTotalRows(s);
4338
- }
4339
- prefixData(e) {
4340
- var i, n;
4341
- const t = [...e, ...this._data.getAllData()];
4342
- this._data.setData(t);
4343
- const s = this._data.rowCount;
4344
- (i = this._vs) == null || i.setTotalRows(s), (n = this._pagination) == null || n.setTotalRows(s);
4345
- }
4346
- clearData() {
4347
- var e, t;
4348
- this._rowMgr.reset(), this._data.clearData(), (e = this._vs) == null || e.setTotalRows(0), (t = this._pagination) == null || t.setTotalRows(0), this._doRender(0, -1), this.emit("dataChange", []);
4349
- }
4350
- insertRow(e, t = "last") {
4351
- var o, l, r, a;
4352
- const s = this._trigMgr.mkCtx("insertRow", [e, t]);
4353
- if (!this._trigMgr.exec("before:insertRow", s)) return;
4354
- const i = t === "before" ? 0 : t === "after" ? this._data.rowCount : t;
4355
- this._data.addRow(e, i);
4356
- const n = this._data.rowCount;
4357
- (o = this._vs) == null || o.setTotalRows(n), (l = this._pagination) == null || l.setTotalRows(n), this._doRender(...this._visRange()), this.emit("dataChange", this._data.getData()), (a = (r = this._options).onDataChange) == null || a.call(r, this._data.getData()), s.result = { rowCount: n, item: e }, this._trigMgr.exec("after:insertRow", s);
4358
- }
4359
- pushRow(e) {
4360
- var i, n, o, l;
4361
- (Array.isArray(e) ? e : [e]).forEach((r) => this._data.addRow(r, "last"));
4362
- const s = this._data.rowCount;
4363
- (i = this._vs) == null || i.setTotalRows(s), (n = this._pagination) == null || n.setTotalRows(s), this._doRender(...this._visRange()), this.emit("dataChange", this._data.getData()), (l = (o = this._options).onDataChange) == null || l.call(o, this._data.getData());
4364
- }
4365
- /** @deprecated 하위호환 alias → pushRow */
4366
- appendRows(e) {
4367
- this.pushRow(e);
4368
- }
4369
- unshiftRow(e) {
4370
- var i, n, o, l;
4371
- (Array.isArray(e) ? e : [e]).forEach((r) => this._data.addRow(r, "first"));
4372
- const s = this._data.rowCount;
4373
- (i = this._vs) == null || i.setTotalRows(s), (n = this._pagination) == null || n.setTotalRows(s), this._doRender(...this._visRange()), this.emit("dataChange", this._data.getData()), (l = (o = this._options).onDataChange) == null || l.call(o, this._data.getData());
4374
- }
4375
- /** @deprecated 하위호환 alias → unshiftRow */
4376
- prependRows(e) {
4377
- this.unshiftRow(e);
4378
- }
4379
- deleteRow(e) {
4380
- var o, l, r, a;
4381
- const t = this._trigMgr.mkCtx("deleteRow", [e]), s = Array.isArray(e) ? [...e] : [e];
4382
- if (t.extra = { rows: s.map((c) => this._data.getRowByIndex(c)) }, !this._trigMgr.exec("before:deleteRow", t)) return;
4383
- const i = s.sort((c, h) => h - c);
4384
- i.forEach((c) => this._data.removeRow(c));
4385
- const n = this._data.rowCount;
4386
- (o = this._vs) == null || o.setTotalRows(n), (l = this._pagination) == null || l.setTotalRows(n), this._doRender(...this._visRange()), this.emit("dataChange", this._data.getData()), (a = (r = this._options).onDataChange) == null || a.call(r, this._data.getData()), t.result = { deleted: i.length, rowCount: n }, this._trigMgr.exec("after:deleteRow", t);
4387
- }
4388
- deleteById(e) {
4389
- }
4390
- readCell(e, t) {
4391
- return this._data.getCellValue(e, t);
4392
- }
4393
- getDisplayValue(e, t) {
4394
- const s = this.readCell(e, t);
4395
- return s == null ? "" : String(s);
4396
- }
4397
- writeCell(e, t, s) {
4398
- var c, h, u, p;
4399
- const i = this.readCell(e, t), n = this._trigMgr.mkCtx("writeCell", [e, t, s]);
4400
- if (n.extra = { oldValue: i, rowIndex: e, field: t }, !this._trigMgr.exec("before:writeCell", n)) return;
4401
- this._data.updateCell(e, t, s);
4402
- const o = this._data.getRowByIndex(e), l = this._colLayout.getColumnByField(t), r = this._colLayout.getColumnIndex(t), a = { type: "editEnd", rowIndex: e, columnIndex: r, field: t, oldValue: i, newValue: s, row: o, column: l };
4403
- this.emit("editEnd", a), (h = (c = this._options).onEditEnd) == null || h.call(c, a), this.emit("dataChange", this._data.getData()), (p = (u = this._options).onDataChange) == null || p.call(u, this._data.getData()), this._doRender(...this._visRange()), n.result = { rowIndex: e, field: t, oldValue: i, newValue: s }, this._trigMgr.exec("after:writeCell", n);
4404
- }
4405
- getRowAt(e) {
4406
- return this._data.getRowByIndex(e);
4407
- }
4408
- getChanges() {
4409
- return this._data.getChanges();
4410
- }
4411
- getEditedRows() {
4412
- return this._data.getEditedRows();
4413
- }
4414
- getChangedRows() {
4415
- return this._data.getChangedRows();
4416
- }
4417
- // ?섏쐞 ?명솚
4418
- getChangedColumns() {
4419
- return this._data.getChangedColumns();
4420
- }
4421
- getAddedRows() {
4422
- return this._data.getAddedRows();
4423
- }
4424
- getRemovedRows() {
4425
- return this._data.getRemovedRows();
4426
- }
4427
- getOriginalRow(e) {
4428
- return this._data.getOriginalRow(e);
4429
- }
4430
- getRowsWithState(e) {
4431
- return this._data.getRowsWithState(e);
4432
- }
4433
- undo() {
4434
- }
4435
- redo() {
4436
- }
4437
- clearHistory() {
4438
- }
4439
- getColumnDefs() {
4440
- return this._colLayout.visibleLeaves;
4441
- }
4442
- getAllColumnDefs() {
4443
- return this._colLayout.leaves;
4444
- }
4445
- getColumnCount() {
4446
- return this._colLayout.visibleLeaves.length;
4447
- }
4448
- applyColumns(e) {
4449
- const t = this._trigMgr.mkCtx("applyColumns", [e]);
4450
- this._trigMgr.exec("before:applyColumns", t) && (this._colLayout.setColumns(e), this._recalcWidths(this._container.getBoundingClientRect().width), this._renderHeader(), this._doRender(...this._visRange()), t.result = { columnCount: e.length }, this._trigMgr.exec("after:applyColumns", t));
4451
- }
4452
- insertColumn(e, t) {
4453
- this._colLayout.addColumn(e, t), this._recalcWidths(this._container.getBoundingClientRect().width), this._renderHeader(), this._doRender(...this._visRange());
4454
- }
4455
- deleteColumn(e) {
4456
- this._colLayout.removeColumn(e), this._recalcWidths(this._container.getBoundingClientRect().width), this._renderHeader(), this._doRender(...this._visRange());
4457
- }
4458
- _reorderColumn(e, t) {
4459
- var o, l;
4460
- const s = this._colLayout.visibleLeaves.map((r) => r);
4461
- if (e < 0 || t < 0 || e >= s.length || t >= s.length) return;
4462
- const i = [...this._options.columns], [n] = i.splice(e, 1);
4463
- i.splice(t, 0, n), this._options.columns = i, this.applyColumns(i), (l = (o = this._options).onColumnReorder) == null || l.call(o, { fromIndex: e, toIndex: t, field: n.field ?? "" });
4464
- }
4465
- hideColumn(e) {
4466
- this._colLayout.hideColumn(e), this._recalcWidths(this._container.getBoundingClientRect().width), this._renderHeader(), this._doRender(...this._visRange());
4467
- }
4468
- showColumn(e) {
4469
- this._colLayout.showColumn(e), this._recalcWidths(this._container.getBoundingClientRect().width), this._renderHeader(), this._doRender(...this._visRange());
4470
- }
4471
- getColumnIndex(e) {
4472
- return this._colLayout.getColumnIndex(e);
4473
- }
4474
- getFieldAt(e) {
4475
- var t;
4476
- return ((t = this._colLayout.getColumnByIndex(e)) == null ? void 0 : t.field) ?? "";
4477
- }
4478
- getColValues(e, t = !1) {
4479
- return this._data.getData().map((s) => s[e]);
4480
- }
4481
- getUniqueValues(e, t = !1) {
4482
- return [...new Set(this.getColValues(e, t))];
4483
- }
4484
- setColWidths(e) {
4485
- }
4486
- calcColWidths(e = !1) {
4487
- return [];
4488
- }
4489
- getSelections() {
4490
- return this._rowMgr.getSelections();
4491
- }
4492
- getActiveRow() {
4493
- return this._rowMgr.getActiveRow();
4494
- }
4495
- activate(e) {
4496
- this._rowMgr.activate(e), this._doRender(...this._visRange());
4497
- }
4498
- deselect() {
4499
- this._rowMgr.deselect(), this._doRender(...this._visRange());
4500
- }
4501
- getChecked() {
4502
- return this._rowMgr.getChecked();
4503
- }
4504
- getAllChecked() {
4505
- return this._rowMgr.getAllChecked();
4506
- }
4507
- checkById(e) {
4508
- }
4509
- addCheckById(e) {
4510
- }
4511
- checkByValue(e, t) {
4512
- this._rowMgr.checkByValue(e, t), this._doRender(...this._visRange());
4513
- }
4514
- uncheckById(e) {
4515
- }
4516
- uncheckAll() {
4517
- this._rowMgr.uncheckAll(), this._doRender(...this._visRange());
4518
- }
4519
- orderBy(e, t = "asc") {
4520
- const s = this._trigMgr.mkCtx("orderBy", [e, t]);
4521
- this._trigMgr.exec("before:orderBy", s) && (this._sfMgr.sort(e, t), s.result = { sortList: this._sfMgr.sortList }, this._trigMgr.exec("after:orderBy", s));
4522
- }
4523
- resetOrder() {
4524
- this._sfMgr.resetSort();
4525
- }
4526
- setFilter(e, t) {
4527
- const s = this._trigMgr.mkCtx("setFilter", [e, t]);
4528
- this._trigMgr.exec("before:setFilter", s) && (this._sfMgr.setFilter(e, t), s.result = { field: e, filteredCount: this._data.rowCount }, this._trigMgr.exec("after:setFilter", s));
4529
- }
4530
- resetFilter(e) {
4531
- this._sfMgr.resetFilter(e);
4532
- }
4533
- getFilterState() {
4534
- return this._sfMgr.getFilterState();
4535
- }
4536
- restoreFilter(e) {
4537
- this._sfMgr.restoreFilter(e);
4538
- }
4539
- _applyFilters() {
4540
- this._sfMgr.applyFilters();
4541
- }
4542
- freeze(e) {
4543
- this._colLayout.setFrozen(e), this._renderHeader(), this._doRender(...this._visRange());
4544
- }
4545
- /** ?섎룞 蹂묓빀: [{row, col, rowSpan?, colSpan?}] */
4546
- mergeCells(e) {
4547
- this._mergeEngine.applyMergeCells(e), this._doRender(...this._visRange());
4548
- }
4549
- /** 자동 병합: 지정 필드 컬럼에서 연속 같은 값을 rowSpan으로 묶는다 */
4550
- /** ?먮룞 蹂묓빀: 吏€??field 而щ읆?먯꽌 ?곗냽 媛숈? 媛믪쓣 rowSpan */
4551
- autoMerge(e) {
4552
- const t = this._colLayout.visibleLeaves, s = [], i = [];
4553
- for (const n of e) {
4554
- const o = t.findIndex((l) => l.field === n);
4555
- o >= 0 && (s.push(o), i.push(n));
4556
- }
4557
- this._mergeEngine.applyAutoMerge(this._data.getData(), s, i), this._doRender(...this._visRange());
4558
- }
4559
- /** 蹂묓빀 ?댁젣 */
4560
- clearMerge() {
4561
- this._mergeEngine.clear(), this._doRender(...this._visRange());
4562
- }
4563
- freezeRows(e) {
4564
- }
4565
- groupBy(e) {
4566
- const t = this._trigMgr.mkCtx("groupBy", [e]);
4567
- this._trigMgr.exec("before:groupBy", t) && (this._grpMgr.groupBy(e), t.result = { fields: e }, this._trigMgr.exec("after:groupBy", t));
4568
- }
4569
- clearGroup() {
4570
- this._grpMgr.clearGroup();
4571
- }
4572
- expandAll() {
4573
- this._grpMgr.expandAll();
4574
- }
4575
- collapseAll() {
4576
- this._grpMgr.collapseAll();
4577
- }
4578
- enableTree() {
4579
- this._grpMgr.enableTree();
4580
- }
4581
- disableTree() {
4582
- this._grpMgr.disableTree();
4583
- }
4584
- expandNodes(e, t = !0) {
4585
- this._grpMgr.expandNodes(e, t);
4586
- }
4587
- expandAllNodes() {
4588
- this._grpMgr.expandAllNodes();
4589
- }
4590
- collapseAllNodes() {
4591
- this._grpMgr.collapseAllNodes();
4592
- }
4593
- addTreeRow(e, t, s) {
4594
- }
4595
- exportExcel(e) {
4596
- this._exportMgr.exportExcel(e);
4597
- }
4598
- exportCsv(e) {
4599
- this._exportMgr.exportCsv(e);
4600
- }
4601
- exportJson(e) {
4602
- this._exportMgr.exportJson(e);
4603
- }
4604
- print(e) {
4605
- this._exportMgr.print(e);
4606
- }
4607
- toArray(e = !0) {
4608
- const t = this._data.getData();
4609
- if (e) return t;
4610
- const s = this._colLayout.visibleLeaves;
4611
- return t.map((i) => s.map((n) => i[n.field]));
4612
- }
4613
- jumpToRow(e) {
4614
- var t;
4615
- this._rowMgr.selectSingle(e), (t = this._vs) == null || t.scrollToRow(e), this._doRender(...this._visRange());
4616
- }
4617
- jumpToCol(e) {
4618
- }
4619
- getScrollPos() {
4620
- var e, t;
4621
- return { x: ((e = this._renderer) == null ? void 0 : e.bodyWrapper.scrollLeft) ?? 0, y: ((t = this._renderer) == null ? void 0 : t.bodyWrapper.scrollTop) ?? 0 };
4622
- }
4623
- setFooter(e) {
4624
- this._options.footer = e, this._renderFooterEl();
4625
- }
4626
- getFooterData() {
4627
- return this._footerMgr.computeValues();
4628
- }
4629
- getFooterValue(e) {
4630
- var t;
4631
- return ((t = this._footerMgr.computeValues().find((s) => s._field === e)) == null ? void 0 : t._value) ?? null;
4632
- }
4633
- _renderFooterEl() {
4634
- this._footerMgr.render();
4635
- }
4636
- resize(e, t) {
4637
- e && (this._container.style.width = `${e}px`), t && (this._container.style.height = `${t}px`), this._onResize();
4638
- }
4639
- setTheme(e) {
4640
- this._container.setAttribute("data-og-theme", e);
4641
- }
4642
- setThemeVar(e, t) {
4643
- this._container.style.setProperty(e, t);
4644
- }
4645
- addTrigger(e, t) {
4646
- return this._trigMgr.add(e, t), this;
4647
- }
4648
- removeTrigger(e, t) {
4649
- return this._trigMgr.remove(e, t), this;
4650
- }
4651
- clearTriggers(e) {
4652
- return this._trigMgr.clear(e), this;
4653
- }
4654
- _mkCtx(e, t) {
4655
- return this._trigMgr.mkCtx(e, t);
4656
- }
4657
- _trig(e, t) {
4658
- return this._trigMgr.exec(e, t);
4659
- }
4660
- destroy() {
4661
- var e, t, s, i, n, o, l, r;
4662
- this._destroyed || (this._destroyed = !0, this._renderer && re.unregister(this._renderer.bodyWrapper), this._trigMgr.clear(), (e = this._ro) == null || e.disconnect(), (t = this._vs) == null || t.destroy(), (s = this._filterPanel) == null || s.destroy(), (i = this._dnd) == null || i.destroy(), this._cmHandler && this._container.removeEventListener("contextmenu", this._cmHandler), this._cmKbdHandler && this._container.removeEventListener("keydown", this._cmKbdHandler), this._cmHandler = this._cmKbdHandler = null, (n = this._ctxMenu) == null || n.destroy(), (o = this._wsManager) == null || o.destroy(), (l = this._renderer) == null || l.destroy(), (r = this._liveRegion) == null || r.remove(), this._liveRegion = null, this._container.innerHTML = "", this._container.classList.remove("og-container"), this.removeAllListeners());
4663
- }
4664
- }
4665
- export {
4666
- rs as O,
4667
- Ke as b
4668
- };
4669
- //# sourceMappingURL=OpenGrid-doS5aFVl.js.map