@xleddyl/443-components-vue 0.9.2 → 0.10.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.
- package/CATALOG.md +331 -0
- package/README.md +73 -16
- package/dist/components/templates/SettingsModal.vue +35 -14
- package/dist/components/templates/SettingsModal.vue.d.ts +2 -0
- package/dist/composables/useForm.d.ts +10 -0
- package/dist/composables/useForm.mjs +63 -2
- package/dist/grid/DataGrid.vue +90 -13
- package/dist/grid/DataGrid.vue.d.ts +44 -2
- package/dist/grid/cells/LinkCell.vue +8 -7
- package/dist/grid/cells/LinkCell.vue.d.ts +1 -417
- package/dist/grid/data-grid.css +113 -0
- package/dist/grid/index.d.ts +2 -1
- package/dist/grid/index.mjs +3 -1
- package/dist/grid/modules.d.ts +1 -0
- package/dist/grid/modules.mjs +8 -0
- package/dist/grid/spreadsheet.d.ts +52 -0
- package/dist/grid/spreadsheet.mjs +928 -0
- package/dist/grid/tsv.d.ts +3 -0
- package/dist/grid/tsv.mjs +88 -0
- package/dist/grid/types.d.ts +81 -0
- package/dist/locale/de.mjs +10 -1
- package/dist/locale/en.mjs +10 -1
- package/dist/locale/it.mjs +10 -1
- package/dist/locale/types.d.ts +9 -0
- package/dist/styles/templates/settings-modal.css +38 -9
- package/package.json +3 -2
|
@@ -0,0 +1,928 @@
|
|
|
1
|
+
import { computed, ref, shallowRef } from "vue";
|
|
2
|
+
import { isApplePlatform } from "../internal/core/env.mjs";
|
|
3
|
+
import { formatTsv, parseTsv, stringifyCellValue } from "./tsv.mjs";
|
|
4
|
+
const WRITE_SOURCE = "k-spreadsheet";
|
|
5
|
+
const HISTORY_LIMIT = 100;
|
|
6
|
+
const HANDLE_HIT = 10;
|
|
7
|
+
const SELECT_EDITORS = /* @__PURE__ */ new Set(["agSelectCellEditor", "agRichSelectCellEditor"]);
|
|
8
|
+
const ARROWS = {
|
|
9
|
+
ArrowUp: { row: -1, col: 0 },
|
|
10
|
+
ArrowDown: { row: 1, col: 0 },
|
|
11
|
+
ArrowLeft: { row: 0, col: -1 },
|
|
12
|
+
ArrowRight: { row: 0, col: 1 }
|
|
13
|
+
};
|
|
14
|
+
function sameValue(a, b) {
|
|
15
|
+
if (Object.is(a, b)) return true;
|
|
16
|
+
if ((a === null || a === void 0) && (b === null || b === void 0)) return true;
|
|
17
|
+
if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
function clampNumber(value, min, max) {
|
|
21
|
+
return Math.min(Math.max(value, min), max);
|
|
22
|
+
}
|
|
23
|
+
function sameCell(a, b) {
|
|
24
|
+
return a === b || !!a && !!b && a.row === b.row && a.col === b.col;
|
|
25
|
+
}
|
|
26
|
+
function rectOf(a, b) {
|
|
27
|
+
return {
|
|
28
|
+
top: Math.min(a.row, b.row),
|
|
29
|
+
bottom: Math.max(a.row, b.row),
|
|
30
|
+
left: Math.min(a.col, b.col),
|
|
31
|
+
right: Math.max(a.col, b.col)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function rectArea(rect) {
|
|
35
|
+
return rect ? (rect.bottom - rect.top + 1) * (rect.right - rect.left + 1) : 0;
|
|
36
|
+
}
|
|
37
|
+
function isTextInput(target) {
|
|
38
|
+
return target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement || target instanceof HTMLElement && target.isContentEditable;
|
|
39
|
+
}
|
|
40
|
+
function shortcutLetter(event) {
|
|
41
|
+
if (/^[a-z]$/i.test(event.key)) return event.key.toLowerCase();
|
|
42
|
+
return event.code.startsWith("Key") ? event.code.slice(3).toLowerCase() : "";
|
|
43
|
+
}
|
|
44
|
+
function stopEvent(event) {
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
event.stopPropagation();
|
|
47
|
+
}
|
|
48
|
+
function allowedValues(colDef) {
|
|
49
|
+
if (typeof colDef.cellEditor !== "string" || !SELECT_EDITORS.has(colDef.cellEditor)) return null;
|
|
50
|
+
const params = colDef.cellEditorParams;
|
|
51
|
+
return params && typeof params === "object" && Array.isArray(params.values) ? params.values : null;
|
|
52
|
+
}
|
|
53
|
+
export function createGridSpreadsheet(options) {
|
|
54
|
+
let api = null;
|
|
55
|
+
let active = null;
|
|
56
|
+
let anchor = null;
|
|
57
|
+
let corner = null;
|
|
58
|
+
let rect = null;
|
|
59
|
+
let columns = [];
|
|
60
|
+
const columnIndex = /* @__PURE__ */ new Map();
|
|
61
|
+
let drag = null;
|
|
62
|
+
let consumedPointer = false;
|
|
63
|
+
let fillOrigin = null;
|
|
64
|
+
let fillCorners = null;
|
|
65
|
+
const dirty = /* @__PURE__ */ new Map();
|
|
66
|
+
const undoStack = [];
|
|
67
|
+
const redoStack = [];
|
|
68
|
+
const range = shallowRef(null);
|
|
69
|
+
const selectedCellCount = ref(0);
|
|
70
|
+
const dirtyCount = ref(0);
|
|
71
|
+
const canUndo = ref(false);
|
|
72
|
+
const canRedo = ref(false);
|
|
73
|
+
const filling = ref(false);
|
|
74
|
+
function rowCount() {
|
|
75
|
+
return api?.getDisplayedRowCount() ?? 0;
|
|
76
|
+
}
|
|
77
|
+
function nodeAt(row) {
|
|
78
|
+
return api?.getDisplayedRowAtIndex(row) ?? void 0;
|
|
79
|
+
}
|
|
80
|
+
function fieldOf(column) {
|
|
81
|
+
return column.getColDef().field ?? column.getColId();
|
|
82
|
+
}
|
|
83
|
+
function isEditable(node, column) {
|
|
84
|
+
return Boolean(node.data) && !node.group && !node.rowPinned && column.isCellEditable(node);
|
|
85
|
+
}
|
|
86
|
+
function readValue(node, column) {
|
|
87
|
+
return api?.getCellValue({ rowNode: node, colKey: column });
|
|
88
|
+
}
|
|
89
|
+
function isMulti() {
|
|
90
|
+
return rectArea(rect) > 1;
|
|
91
|
+
}
|
|
92
|
+
function cellOf(params) {
|
|
93
|
+
const row = params.node.rowIndex;
|
|
94
|
+
if (params.node.rowPinned || row === null || row === void 0) return null;
|
|
95
|
+
const col = columnIndex.get(params.column.getColId());
|
|
96
|
+
return col === void 0 ? null : { row, col };
|
|
97
|
+
}
|
|
98
|
+
function rangeCell(params) {
|
|
99
|
+
if (!rect || !isMulti()) return null;
|
|
100
|
+
const cell = cellOf(params);
|
|
101
|
+
if (!cell) return null;
|
|
102
|
+
const inside = cell.row >= rect.top && cell.row <= rect.bottom && cell.col >= rect.left && cell.col <= rect.right;
|
|
103
|
+
return inside ? cell : null;
|
|
104
|
+
}
|
|
105
|
+
const classRules = {
|
|
106
|
+
"is-range": (params) => {
|
|
107
|
+
const cell = rangeCell(params);
|
|
108
|
+
return !!cell && !sameCell(cell, active);
|
|
109
|
+
},
|
|
110
|
+
"is-range-top": (params) => rangeCell(params)?.row === rect?.top,
|
|
111
|
+
"is-range-bottom": (params) => rangeCell(params)?.row === rect?.bottom,
|
|
112
|
+
"is-range-left": (params) => rangeCell(params)?.col === rect?.left,
|
|
113
|
+
"is-range-right": (params) => rangeCell(params)?.col === rect?.right,
|
|
114
|
+
"is-active": (params) => !!active && sameCell(cellOf(params), active),
|
|
115
|
+
"is-fill-corner": (params) => {
|
|
116
|
+
if (!rect) return false;
|
|
117
|
+
const cell = cellOf(params);
|
|
118
|
+
return !!cell && cell.row === rect.bottom && cell.col === rect.right;
|
|
119
|
+
},
|
|
120
|
+
"is-dirty": (params) => {
|
|
121
|
+
const id = params.node.id;
|
|
122
|
+
return !!id && dirty.get(id)?.has(params.column.getColId()) === true;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
function refreshArea(areas) {
|
|
126
|
+
if (!api) return;
|
|
127
|
+
const list = areas.filter((area) => area !== null);
|
|
128
|
+
if (!list.length) return;
|
|
129
|
+
const top = Math.min(...list.map((area) => area.top));
|
|
130
|
+
const bottom = Math.max(...list.map((area) => area.bottom));
|
|
131
|
+
const left = Math.min(...list.map((area) => area.left));
|
|
132
|
+
const right = Math.max(...list.map((area) => area.right));
|
|
133
|
+
const rowNodes = api.getRenderedNodes().filter(
|
|
134
|
+
(node) => !node.rowPinned && node.rowIndex !== null && node.rowIndex >= top && node.rowIndex <= bottom
|
|
135
|
+
);
|
|
136
|
+
if (!rowNodes.length) return;
|
|
137
|
+
api.refreshCells({ rowNodes, columns: columns.slice(left, right + 1) });
|
|
138
|
+
}
|
|
139
|
+
function refreshRendered() {
|
|
140
|
+
if (api && !api.isDestroyed()) api.refreshCells();
|
|
141
|
+
}
|
|
142
|
+
function toRange() {
|
|
143
|
+
if (!rect || !active) return null;
|
|
144
|
+
const activeColumn = columns[active.col];
|
|
145
|
+
if (!activeColumn) return null;
|
|
146
|
+
return {
|
|
147
|
+
startRowIndex: rect.top,
|
|
148
|
+
endRowIndex: rect.bottom,
|
|
149
|
+
columns: columns.slice(rect.left, rect.right + 1).map((column) => column.getColId()),
|
|
150
|
+
active: { rowIndex: active.row, colId: activeColumn.getColId() }
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function publish() {
|
|
154
|
+
range.value = toRange();
|
|
155
|
+
selectedCellCount.value = rectArea(rect);
|
|
156
|
+
options.onRange(range.value);
|
|
157
|
+
if (isMulti()) options.onSelect(selectedCellCount.value);
|
|
158
|
+
}
|
|
159
|
+
function focusActive() {
|
|
160
|
+
const column = active ? columns[active.col] : void 0;
|
|
161
|
+
if (api && active && column) api.setFocusedCell(active.row, column);
|
|
162
|
+
}
|
|
163
|
+
function select(nextAnchor, nextCorner, nextActive, focus = false) {
|
|
164
|
+
if (sameCell(anchor, nextAnchor) && sameCell(corner, nextCorner) && sameCell(active, nextActive))
|
|
165
|
+
return;
|
|
166
|
+
const previousRect = rect;
|
|
167
|
+
const previousActive = active;
|
|
168
|
+
anchor = nextAnchor;
|
|
169
|
+
corner = nextCorner;
|
|
170
|
+
active = nextActive;
|
|
171
|
+
rect = rectOf(anchor, corner);
|
|
172
|
+
refreshArea([
|
|
173
|
+
previousRect,
|
|
174
|
+
rect,
|
|
175
|
+
previousActive && rectOf(previousActive, previousActive),
|
|
176
|
+
rectOf(active, active)
|
|
177
|
+
]);
|
|
178
|
+
publish();
|
|
179
|
+
if (focus && !sameCell(previousActive, active)) focusActive();
|
|
180
|
+
}
|
|
181
|
+
function selectRect(target, focus = true) {
|
|
182
|
+
const start = { row: target.top, col: target.left };
|
|
183
|
+
select(start, { row: target.bottom, col: target.right }, start, focus);
|
|
184
|
+
}
|
|
185
|
+
function reset() {
|
|
186
|
+
if (!rect && !active) return;
|
|
187
|
+
const previousRect = rect;
|
|
188
|
+
const previousActive = active;
|
|
189
|
+
active = anchor = corner = rect = null;
|
|
190
|
+
refreshArea([previousRect, previousActive && rectOf(previousActive, previousActive)]);
|
|
191
|
+
publish();
|
|
192
|
+
}
|
|
193
|
+
function clamp() {
|
|
194
|
+
if (!anchor || !corner || !active) return;
|
|
195
|
+
const rows = rowCount();
|
|
196
|
+
const cols = columns.length;
|
|
197
|
+
if (!rows || !cols) return reset();
|
|
198
|
+
const fit = (cell) => ({
|
|
199
|
+
row: Math.min(cell.row, rows - 1),
|
|
200
|
+
col: Math.min(cell.col, cols - 1)
|
|
201
|
+
});
|
|
202
|
+
anchor = fit(anchor);
|
|
203
|
+
corner = fit(corner);
|
|
204
|
+
active = fit(active);
|
|
205
|
+
rect = rectOf(anchor, corner);
|
|
206
|
+
publish();
|
|
207
|
+
}
|
|
208
|
+
function syncColumns() {
|
|
209
|
+
columns = (api?.getAllDisplayedColumns() ?? []).filter(
|
|
210
|
+
(column) => !column.getColId().startsWith("ag-Grid-")
|
|
211
|
+
);
|
|
212
|
+
columnIndex.clear();
|
|
213
|
+
columns.forEach((column, index) => columnIndex.set(column.getColId(), index));
|
|
214
|
+
clamp();
|
|
215
|
+
if (rect || dirty.size) refreshRendered();
|
|
216
|
+
}
|
|
217
|
+
function onModelUpdated() {
|
|
218
|
+
clamp();
|
|
219
|
+
if (rect || dirty.size) refreshRendered();
|
|
220
|
+
}
|
|
221
|
+
function onCellFocused(event) {
|
|
222
|
+
if (!options.enabled() || event.rowPinned || event.rowIndex === null || !event.column) return;
|
|
223
|
+
const colId = typeof event.column === "string" ? event.column : event.column.getColId();
|
|
224
|
+
const col = columnIndex.get(colId);
|
|
225
|
+
if (col === void 0) return;
|
|
226
|
+
const cell = { row: event.rowIndex, col };
|
|
227
|
+
if (sameCell(cell, active)) return;
|
|
228
|
+
select(cell, cell, cell);
|
|
229
|
+
}
|
|
230
|
+
function syncHistory() {
|
|
231
|
+
canUndo.value = undoStack.length > 0;
|
|
232
|
+
canRedo.value = redoStack.length > 0;
|
|
233
|
+
}
|
|
234
|
+
function countDirty() {
|
|
235
|
+
let count = 0;
|
|
236
|
+
for (const row of dirty.values()) count += row.size;
|
|
237
|
+
return count;
|
|
238
|
+
}
|
|
239
|
+
function syncDirty() {
|
|
240
|
+
const count = countDirty();
|
|
241
|
+
if (count === dirtyCount.value) return;
|
|
242
|
+
dirtyCount.value = count;
|
|
243
|
+
options.onDirty(count);
|
|
244
|
+
}
|
|
245
|
+
function trackDirty(changes) {
|
|
246
|
+
for (const change of changes) {
|
|
247
|
+
let row = dirty.get(change.rowId);
|
|
248
|
+
const entry = row?.get(change.colId);
|
|
249
|
+
if (row && entry) {
|
|
250
|
+
if (sameValue(entry.original, change.newValue)) {
|
|
251
|
+
row.delete(change.colId);
|
|
252
|
+
if (!row.size) dirty.delete(change.rowId);
|
|
253
|
+
}
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (!row) {
|
|
257
|
+
row = /* @__PURE__ */ new Map();
|
|
258
|
+
dirty.set(change.rowId, row);
|
|
259
|
+
}
|
|
260
|
+
row.set(change.colId, { field: change.field, original: change.oldValue });
|
|
261
|
+
}
|
|
262
|
+
syncDirty();
|
|
263
|
+
}
|
|
264
|
+
function refreshChanges(changes) {
|
|
265
|
+
if (!api) return;
|
|
266
|
+
const rowNodes = /* @__PURE__ */ new Set();
|
|
267
|
+
const colIds = /* @__PURE__ */ new Set();
|
|
268
|
+
for (const change of changes) {
|
|
269
|
+
const node = api.getRowNode(change.rowId);
|
|
270
|
+
if (node) rowNodes.add(node);
|
|
271
|
+
colIds.add(change.colId);
|
|
272
|
+
}
|
|
273
|
+
if (rowNodes.size) api.refreshCells({ rowNodes: [...rowNodes], columns: [...colIds] });
|
|
274
|
+
}
|
|
275
|
+
function commit(changes, source) {
|
|
276
|
+
if (!changes.length) return;
|
|
277
|
+
if (source !== "undo" && source !== "redo") {
|
|
278
|
+
undoStack.push(changes);
|
|
279
|
+
if (undoStack.length > HISTORY_LIMIT) undoStack.shift();
|
|
280
|
+
redoStack.length = 0;
|
|
281
|
+
}
|
|
282
|
+
syncHistory();
|
|
283
|
+
trackDirty(changes);
|
|
284
|
+
refreshChanges(changes);
|
|
285
|
+
options.onChange({ changes, source });
|
|
286
|
+
}
|
|
287
|
+
function applyWrites(writes, source, checkEditable = true) {
|
|
288
|
+
const changes = [];
|
|
289
|
+
if (!api) return changes;
|
|
290
|
+
for (const { node, column, value } of writes) {
|
|
291
|
+
if (!node.id || checkEditable && !isEditable(node, column)) continue;
|
|
292
|
+
const oldValue = readValue(node, column);
|
|
293
|
+
if (sameValue(oldValue, value)) continue;
|
|
294
|
+
if (!node.setDataValue(column, value, WRITE_SOURCE)) continue;
|
|
295
|
+
const newValue = readValue(node, column);
|
|
296
|
+
if (sameValue(oldValue, newValue)) continue;
|
|
297
|
+
changes.push({
|
|
298
|
+
rowId: node.id,
|
|
299
|
+
colId: column.getColId(),
|
|
300
|
+
field: fieldOf(column),
|
|
301
|
+
oldValue,
|
|
302
|
+
newValue
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
commit(changes, source);
|
|
306
|
+
return changes;
|
|
307
|
+
}
|
|
308
|
+
function reportInvalid(cells, source) {
|
|
309
|
+
if (cells.length) options.onInvalid({ cells, source });
|
|
310
|
+
}
|
|
311
|
+
function invalidCell(node, column, text) {
|
|
312
|
+
return { rowId: node.id ?? "", colId: column.getColId(), field: fieldOf(column), text };
|
|
313
|
+
}
|
|
314
|
+
function context() {
|
|
315
|
+
return api?.getGridOption("context");
|
|
316
|
+
}
|
|
317
|
+
function formatWithColumn(node, column, value) {
|
|
318
|
+
const colDef = column.getColDef();
|
|
319
|
+
const formatter = colDef.valueFormatter;
|
|
320
|
+
if (typeof formatter !== "function" || !api) return stringifyCellValue(value);
|
|
321
|
+
return String(
|
|
322
|
+
formatter({ api, context: context(), value, node, data: node.data, colDef, column }) ?? ""
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
function parseWithColumn(node, column, text) {
|
|
326
|
+
const colDef = column.getColDef();
|
|
327
|
+
const parser = colDef.valueParser;
|
|
328
|
+
if (typeof parser !== "function" || colDef.useValueParserForImport === false || !api)
|
|
329
|
+
return text;
|
|
330
|
+
return parser({
|
|
331
|
+
api,
|
|
332
|
+
context: context(),
|
|
333
|
+
node,
|
|
334
|
+
data: node.data,
|
|
335
|
+
oldValue: readValue(node, column),
|
|
336
|
+
newValue: text,
|
|
337
|
+
colDef,
|
|
338
|
+
column
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
function exportParams(node, column, value) {
|
|
342
|
+
return {
|
|
343
|
+
api,
|
|
344
|
+
context: context(),
|
|
345
|
+
value,
|
|
346
|
+
node,
|
|
347
|
+
column,
|
|
348
|
+
type: "clipboard",
|
|
349
|
+
parseValue: (text) => parseWithColumn(node, column, text),
|
|
350
|
+
formatValue: (input) => formatWithColumn(node, column, input)
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function validate(text, value, colDef) {
|
|
354
|
+
if (!text.trim()) return { value, valid: true };
|
|
355
|
+
if (value === null || value === void 0) return { value, valid: false };
|
|
356
|
+
if (typeof value === "number" && Number.isNaN(value)) return { value, valid: false };
|
|
357
|
+
if (value instanceof Date && Number.isNaN(value.getTime())) return { value, valid: false };
|
|
358
|
+
const allowed = allowedValues(colDef);
|
|
359
|
+
if (!allowed) return { value, valid: true };
|
|
360
|
+
const match = allowed.find((option) => option === value || String(option) === String(value));
|
|
361
|
+
return match === void 0 ? { value, valid: false } : { value: match, valid: true };
|
|
362
|
+
}
|
|
363
|
+
function parseText(node, column, text) {
|
|
364
|
+
const fromClipboard = options.gridOptions()?.processCellFromClipboard;
|
|
365
|
+
if (fromClipboard)
|
|
366
|
+
return { value: fromClipboard(exportParams(node, column, text)), valid: true };
|
|
367
|
+
return validate(text, parseWithColumn(node, column, text), column.getColDef());
|
|
368
|
+
}
|
|
369
|
+
function emptyValue(node, column) {
|
|
370
|
+
if (typeof column.getColDef().valueParser !== "function") return null;
|
|
371
|
+
return parseWithColumn(node, column, "") ?? null;
|
|
372
|
+
}
|
|
373
|
+
function copyText(node, column) {
|
|
374
|
+
const value = readValue(node, column);
|
|
375
|
+
const forClipboard = options.gridOptions()?.processCellForClipboard;
|
|
376
|
+
if (!forClipboard) return stringifyCellValue(value);
|
|
377
|
+
return stringifyCellValue(forClipboard(exportParams(node, column, value)));
|
|
378
|
+
}
|
|
379
|
+
function eachCell(target, visit) {
|
|
380
|
+
for (let row = target.top; row <= target.bottom; row++) {
|
|
381
|
+
const node = nodeAt(row);
|
|
382
|
+
if (!node) continue;
|
|
383
|
+
for (let col = target.left; col <= target.right; col++) {
|
|
384
|
+
const column = columns[col];
|
|
385
|
+
if (column) visit(node, column, { row, col });
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
function getRangeText() {
|
|
390
|
+
if (!rect) return null;
|
|
391
|
+
const rows = [];
|
|
392
|
+
for (let row = rect.top; row <= rect.bottom; row++) {
|
|
393
|
+
const node = nodeAt(row);
|
|
394
|
+
if (!node) continue;
|
|
395
|
+
const cells = [];
|
|
396
|
+
for (let col = rect.left; col <= rect.right; col++) {
|
|
397
|
+
const column = columns[col];
|
|
398
|
+
cells.push(column ? copyText(node, column) : "");
|
|
399
|
+
}
|
|
400
|
+
rows.push(cells);
|
|
401
|
+
}
|
|
402
|
+
return formatTsv(rows);
|
|
403
|
+
}
|
|
404
|
+
function restoreFocus(element) {
|
|
405
|
+
if (element instanceof HTMLElement && element.isConnected)
|
|
406
|
+
element.focus({ preventScroll: true });
|
|
407
|
+
else focusActive();
|
|
408
|
+
}
|
|
409
|
+
function tempArea(host, value = "") {
|
|
410
|
+
const area = document.createElement("textarea");
|
|
411
|
+
area.className = "k-data-grid-clipboard";
|
|
412
|
+
area.tabIndex = -1;
|
|
413
|
+
area.setAttribute("aria-hidden", "true");
|
|
414
|
+
area.value = value;
|
|
415
|
+
host.append(area);
|
|
416
|
+
return area;
|
|
417
|
+
}
|
|
418
|
+
function copyWithElement(text) {
|
|
419
|
+
const host = options.body();
|
|
420
|
+
if (!host) return false;
|
|
421
|
+
const previous = document.activeElement;
|
|
422
|
+
const area = tempArea(host, text);
|
|
423
|
+
area.focus({ preventScroll: true });
|
|
424
|
+
area.select();
|
|
425
|
+
let copied = false;
|
|
426
|
+
try {
|
|
427
|
+
copied = document.execCommand("copy");
|
|
428
|
+
} catch {
|
|
429
|
+
copied = false;
|
|
430
|
+
}
|
|
431
|
+
area.remove();
|
|
432
|
+
restoreFocus(previous);
|
|
433
|
+
return copied;
|
|
434
|
+
}
|
|
435
|
+
async function writeClipboard(text) {
|
|
436
|
+
try {
|
|
437
|
+
await navigator.clipboard.writeText(text);
|
|
438
|
+
return true;
|
|
439
|
+
} catch {
|
|
440
|
+
return copyWithElement(text);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
async function copyRange() {
|
|
444
|
+
const text = getRangeText();
|
|
445
|
+
if (text === null) return null;
|
|
446
|
+
const count = selectedCellCount.value;
|
|
447
|
+
if (!await writeClipboard(text)) return null;
|
|
448
|
+
options.onCopy(text);
|
|
449
|
+
options.notify("copied", count, 0);
|
|
450
|
+
return text;
|
|
451
|
+
}
|
|
452
|
+
function capturePaste() {
|
|
453
|
+
const host = options.body();
|
|
454
|
+
if (!host) return;
|
|
455
|
+
const previous = document.activeElement;
|
|
456
|
+
const area = tempArea(host);
|
|
457
|
+
let done = false;
|
|
458
|
+
const finish = (text) => {
|
|
459
|
+
if (done) return;
|
|
460
|
+
done = true;
|
|
461
|
+
area.remove();
|
|
462
|
+
restoreFocus(previous);
|
|
463
|
+
if (text) paste(text);
|
|
464
|
+
};
|
|
465
|
+
area.addEventListener("paste", (event) => {
|
|
466
|
+
stopEvent(event);
|
|
467
|
+
finish(event.clipboardData?.getData("text/plain") ?? "");
|
|
468
|
+
});
|
|
469
|
+
area.focus({ preventScroll: true });
|
|
470
|
+
setTimeout(() => finish(area.value), 100);
|
|
471
|
+
}
|
|
472
|
+
function paste(text) {
|
|
473
|
+
if (!api || !rect || text === "") return 0;
|
|
474
|
+
const block = parseTsv(text);
|
|
475
|
+
const height = block.length;
|
|
476
|
+
const width = block[0]?.length ?? 0;
|
|
477
|
+
if (!height || !width) return 0;
|
|
478
|
+
const rangeHeight = rect.bottom - rect.top + 1;
|
|
479
|
+
const rangeWidth = rect.right - rect.left + 1;
|
|
480
|
+
const tile = rangeHeight % height === 0 && rangeWidth % width === 0 && (rangeHeight > height || rangeWidth > width);
|
|
481
|
+
const target = tile ? { ...rect } : {
|
|
482
|
+
top: rect.top,
|
|
483
|
+
left: rect.left,
|
|
484
|
+
bottom: Math.min(rect.top + height - 1, rowCount() - 1),
|
|
485
|
+
right: Math.min(rect.left + width - 1, columns.length - 1)
|
|
486
|
+
};
|
|
487
|
+
const writes = [];
|
|
488
|
+
const invalid = [];
|
|
489
|
+
eachCell(target, (node, column, cell) => {
|
|
490
|
+
if (!isEditable(node, column)) return;
|
|
491
|
+
const value = block[(cell.row - target.top) % height]?.[(cell.col - target.left) % width];
|
|
492
|
+
const parsed = parseText(node, column, value ?? "");
|
|
493
|
+
if (parsed.valid) writes.push({ node, column, value: parsed.value });
|
|
494
|
+
else invalid.push(invalidCell(node, column, value ?? ""));
|
|
495
|
+
});
|
|
496
|
+
const changes = applyWrites(writes, "paste");
|
|
497
|
+
reportInvalid(invalid, "paste");
|
|
498
|
+
selectRect(target);
|
|
499
|
+
options.notify("pasted", changes.length, invalid.length);
|
|
500
|
+
return changes.length;
|
|
501
|
+
}
|
|
502
|
+
function fillArea(source, target) {
|
|
503
|
+
const height = source.bottom - source.top + 1;
|
|
504
|
+
const width = source.right - source.left + 1;
|
|
505
|
+
const writes = [];
|
|
506
|
+
const invalid = [];
|
|
507
|
+
eachCell(target, (node, column, cell) => {
|
|
508
|
+
if (!isEditable(node, column)) return;
|
|
509
|
+
const sourceNode = nodeAt(source.top + (cell.row - target.top) % height);
|
|
510
|
+
const sourceColumn = columns[source.left + (cell.col - target.left) % width];
|
|
511
|
+
if (!sourceNode || !sourceColumn) return;
|
|
512
|
+
const value = readValue(sourceNode, sourceColumn);
|
|
513
|
+
if (sourceColumn === column) {
|
|
514
|
+
writes.push({ node, column, value });
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const text = stringifyCellValue(value);
|
|
518
|
+
const parsed = parseText(node, column, text);
|
|
519
|
+
if (parsed.valid) writes.push({ node, column, value: parsed.value });
|
|
520
|
+
else invalid.push(invalidCell(node, column, text));
|
|
521
|
+
});
|
|
522
|
+
const changes = applyWrites(writes, "fill");
|
|
523
|
+
reportInvalid(invalid, "fill");
|
|
524
|
+
options.notify("filled", changes.length, invalid.length);
|
|
525
|
+
return changes.length;
|
|
526
|
+
}
|
|
527
|
+
function fillDown() {
|
|
528
|
+
if (!rect) return 0;
|
|
529
|
+
if (rect.top === rect.bottom) {
|
|
530
|
+
if (rect.top === 0) return 0;
|
|
531
|
+
return fillArea({ ...rect, top: rect.top - 1, bottom: rect.top - 1 }, rect);
|
|
532
|
+
}
|
|
533
|
+
return fillArea({ ...rect, bottom: rect.top }, { ...rect, top: rect.top + 1 });
|
|
534
|
+
}
|
|
535
|
+
function fillRight() {
|
|
536
|
+
if (!rect) return 0;
|
|
537
|
+
if (rect.left === rect.right) {
|
|
538
|
+
if (rect.left === 0) return 0;
|
|
539
|
+
return fillArea({ ...rect, left: rect.left - 1, right: rect.left - 1 }, rect);
|
|
540
|
+
}
|
|
541
|
+
return fillArea({ ...rect, right: rect.left }, { ...rect, left: rect.left + 1 });
|
|
542
|
+
}
|
|
543
|
+
function clearCells() {
|
|
544
|
+
if (!rect) return 0;
|
|
545
|
+
const writes = [];
|
|
546
|
+
eachCell(rect, (node, column) => {
|
|
547
|
+
if (isEditable(node, column))
|
|
548
|
+
writes.push({ node, column, value: emptyValue(node, column) });
|
|
549
|
+
});
|
|
550
|
+
const changes = applyWrites(writes, "clear");
|
|
551
|
+
options.notify("cleared", changes.length, 0);
|
|
552
|
+
return changes.length;
|
|
553
|
+
}
|
|
554
|
+
function setRangeValue(value, settings = {}) {
|
|
555
|
+
if (!rect) return 0;
|
|
556
|
+
const writes = [];
|
|
557
|
+
const invalid = [];
|
|
558
|
+
eachCell(rect, (node, column) => {
|
|
559
|
+
if (!isEditable(node, column)) return;
|
|
560
|
+
if (!settings.parse || typeof value !== "string") {
|
|
561
|
+
writes.push({ node, column, value });
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const parsed = parseText(node, column, value);
|
|
565
|
+
if (parsed.valid) writes.push({ node, column, value: parsed.value });
|
|
566
|
+
else invalid.push(invalidCell(node, column, value));
|
|
567
|
+
});
|
|
568
|
+
const changes = applyWrites(writes, "bulk");
|
|
569
|
+
reportInvalid(invalid, "bulk");
|
|
570
|
+
options.notify("updated", changes.length, invalid.length);
|
|
571
|
+
return changes.length;
|
|
572
|
+
}
|
|
573
|
+
function selectChanges(changes) {
|
|
574
|
+
if (!api || !changes.length) return;
|
|
575
|
+
let target = null;
|
|
576
|
+
for (const change of changes) {
|
|
577
|
+
const row = api.getRowNode(change.rowId)?.rowIndex;
|
|
578
|
+
const col = columnIndex.get(change.colId);
|
|
579
|
+
if (row === null || row === void 0 || col === void 0) return;
|
|
580
|
+
target = target ? {
|
|
581
|
+
top: Math.min(target.top, row),
|
|
582
|
+
bottom: Math.max(target.bottom, row),
|
|
583
|
+
left: Math.min(target.left, col),
|
|
584
|
+
right: Math.max(target.right, col)
|
|
585
|
+
} : { top: row, bottom: row, left: col, right: col };
|
|
586
|
+
}
|
|
587
|
+
if (!target) return;
|
|
588
|
+
selectRect(target);
|
|
589
|
+
ensureVisible({ row: target.top, col: target.left });
|
|
590
|
+
}
|
|
591
|
+
function replay(changes, source) {
|
|
592
|
+
if (!api) return [];
|
|
593
|
+
const writes = [];
|
|
594
|
+
const list = source === "undo" ? [...changes].reverse() : changes;
|
|
595
|
+
for (const change of list) {
|
|
596
|
+
const node = api.getRowNode(change.rowId);
|
|
597
|
+
const column = api.getColumn(change.colId);
|
|
598
|
+
if (!node || !column) continue;
|
|
599
|
+
writes.push({ node, column, value: source === "undo" ? change.oldValue : change.newValue });
|
|
600
|
+
}
|
|
601
|
+
const applied = applyWrites(writes, source, false);
|
|
602
|
+
selectChanges(applied);
|
|
603
|
+
options.notify(source === "undo" ? "undone" : "redone", applied.length, 0);
|
|
604
|
+
return applied;
|
|
605
|
+
}
|
|
606
|
+
function undo() {
|
|
607
|
+
const changes = undoStack.pop();
|
|
608
|
+
if (!changes) return false;
|
|
609
|
+
replay(changes, "undo");
|
|
610
|
+
redoStack.push(changes);
|
|
611
|
+
syncHistory();
|
|
612
|
+
return true;
|
|
613
|
+
}
|
|
614
|
+
function redo() {
|
|
615
|
+
const changes = redoStack.pop();
|
|
616
|
+
if (!changes) return false;
|
|
617
|
+
replay(changes, "redo");
|
|
618
|
+
undoStack.push(changes);
|
|
619
|
+
syncHistory();
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
function clearHistory() {
|
|
623
|
+
undoStack.length = 0;
|
|
624
|
+
redoStack.length = 0;
|
|
625
|
+
syncHistory();
|
|
626
|
+
}
|
|
627
|
+
function getDirtyCells() {
|
|
628
|
+
const cells = [];
|
|
629
|
+
for (const [rowId, row] of dirty)
|
|
630
|
+
for (const [colId, entry] of row)
|
|
631
|
+
cells.push({ rowId, colId, field: entry.field, originalValue: entry.original });
|
|
632
|
+
return cells;
|
|
633
|
+
}
|
|
634
|
+
function clearDirty(rowIds) {
|
|
635
|
+
if (!dirty.size) return;
|
|
636
|
+
if (rowIds) for (const id of rowIds) dirty.delete(id);
|
|
637
|
+
else dirty.clear();
|
|
638
|
+
refreshRendered();
|
|
639
|
+
syncDirty();
|
|
640
|
+
}
|
|
641
|
+
function ensureVisible(cell) {
|
|
642
|
+
if (!api) return;
|
|
643
|
+
api.ensureIndexVisible(cell.row);
|
|
644
|
+
const column = columns[cell.col];
|
|
645
|
+
if (column) api.ensureColumnVisible(column);
|
|
646
|
+
}
|
|
647
|
+
function extend(delta, toEdge) {
|
|
648
|
+
if (!anchor || !corner || !active) return;
|
|
649
|
+
const lastRow = rowCount() - 1;
|
|
650
|
+
const lastCol = columns.length - 1;
|
|
651
|
+
if (lastRow < 0 || lastCol < 0) return;
|
|
652
|
+
const next = toEdge ? {
|
|
653
|
+
row: delta.row < 0 ? 0 : delta.row > 0 ? lastRow : corner.row,
|
|
654
|
+
col: delta.col < 0 ? 0 : delta.col > 0 ? lastCol : corner.col
|
|
655
|
+
} : {
|
|
656
|
+
row: clampNumber(corner.row + delta.row, 0, lastRow),
|
|
657
|
+
col: clampNumber(corner.col + delta.col, 0, lastCol)
|
|
658
|
+
};
|
|
659
|
+
select(anchor, next, active);
|
|
660
|
+
ensureVisible(next);
|
|
661
|
+
}
|
|
662
|
+
function selectAll() {
|
|
663
|
+
const lastRow = rowCount() - 1;
|
|
664
|
+
const lastCol = columns.length - 1;
|
|
665
|
+
if (lastRow < 0 || lastCol < 0) return;
|
|
666
|
+
const start = { row: 0, col: 0 };
|
|
667
|
+
select(start, { row: lastRow, col: lastCol }, active ?? start, !active);
|
|
668
|
+
}
|
|
669
|
+
function selectRange(input) {
|
|
670
|
+
const lastRow = rowCount() - 1;
|
|
671
|
+
if (lastRow < 0) return;
|
|
672
|
+
const startCol = columnIndex.get(input.startColumn);
|
|
673
|
+
const endCol = columnIndex.get(input.endColumn ?? input.startColumn);
|
|
674
|
+
if (startCol === void 0 || endCol === void 0) return;
|
|
675
|
+
const start = { row: clampNumber(input.startRowIndex, 0, lastRow), col: startCol };
|
|
676
|
+
const end = {
|
|
677
|
+
row: clampNumber(input.endRowIndex ?? input.startRowIndex, 0, lastRow),
|
|
678
|
+
col: endCol
|
|
679
|
+
};
|
|
680
|
+
select(start, end, start, true);
|
|
681
|
+
ensureVisible(start);
|
|
682
|
+
}
|
|
683
|
+
function getSelectedCells() {
|
|
684
|
+
const cells = [];
|
|
685
|
+
if (!rect) return cells;
|
|
686
|
+
eachCell(rect, (node, column, cell) => {
|
|
687
|
+
cells.push({
|
|
688
|
+
rowId: node.id ?? "",
|
|
689
|
+
rowIndex: cell.row,
|
|
690
|
+
colId: column.getColId(),
|
|
691
|
+
field: fieldOf(column),
|
|
692
|
+
value: readValue(node, column),
|
|
693
|
+
data: node.data,
|
|
694
|
+
editable: isEditable(node, column)
|
|
695
|
+
});
|
|
696
|
+
});
|
|
697
|
+
return cells;
|
|
698
|
+
}
|
|
699
|
+
function isEditing() {
|
|
700
|
+
return (api?.getEditingCells().length ?? 0) > 0;
|
|
701
|
+
}
|
|
702
|
+
function cellFromTarget(target) {
|
|
703
|
+
const host = options.body();
|
|
704
|
+
if (!(target instanceof Element) || !host) return null;
|
|
705
|
+
const element = target.closest(".ag-cell");
|
|
706
|
+
if (!element || !host.contains(element)) return null;
|
|
707
|
+
const col = columnIndex.get(element.getAttribute("col-id") ?? "");
|
|
708
|
+
const row = Number(element.closest(".ag-row")?.getAttribute("row-index") ?? Number.NaN);
|
|
709
|
+
if (col === void 0 || !Number.isInteger(row)) return null;
|
|
710
|
+
return { element, cell: { row, col } };
|
|
711
|
+
}
|
|
712
|
+
function hitsFillHandle(element, event) {
|
|
713
|
+
if (!element.classList.contains("is-fill-corner")) return false;
|
|
714
|
+
const box = element.getBoundingClientRect();
|
|
715
|
+
const rtl = getComputedStyle(element).direction === "rtl";
|
|
716
|
+
const inX = rtl ? event.clientX <= box.left + HANDLE_HIT : event.clientX >= box.right - HANDLE_HIT;
|
|
717
|
+
return inX && event.clientY >= box.bottom - HANDLE_HIT;
|
|
718
|
+
}
|
|
719
|
+
function endDrag() {
|
|
720
|
+
window.removeEventListener("pointerup", endDrag);
|
|
721
|
+
const mode = drag;
|
|
722
|
+
drag = null;
|
|
723
|
+
if (mode !== "fill" || !fillOrigin || !rect) return;
|
|
724
|
+
const origin = fillOrigin;
|
|
725
|
+
const corners = fillCorners;
|
|
726
|
+
fillOrigin = null;
|
|
727
|
+
fillCorners = null;
|
|
728
|
+
filling.value = false;
|
|
729
|
+
if (rect.bottom > origin.bottom)
|
|
730
|
+
fillArea(origin, { ...origin, top: origin.bottom + 1, bottom: rect.bottom });
|
|
731
|
+
else if (corners && active) select(corners[0], corners[1], active);
|
|
732
|
+
}
|
|
733
|
+
function startDrag(mode) {
|
|
734
|
+
drag = mode;
|
|
735
|
+
window.addEventListener("pointerup", endDrag);
|
|
736
|
+
}
|
|
737
|
+
function consume(event) {
|
|
738
|
+
stopEvent(event);
|
|
739
|
+
consumedPointer = true;
|
|
740
|
+
}
|
|
741
|
+
function onMouseDown(event) {
|
|
742
|
+
if (!consumedPointer) return;
|
|
743
|
+
consumedPointer = false;
|
|
744
|
+
stopEvent(event);
|
|
745
|
+
}
|
|
746
|
+
function onPointerDown(event) {
|
|
747
|
+
consumedPointer = false;
|
|
748
|
+
if (!api || !options.enabled() || event.button !== 0 || !event.isPrimary) return;
|
|
749
|
+
const hit = cellFromTarget(event.target);
|
|
750
|
+
if (!hit || hit.element.classList.contains("ag-cell-inline-editing")) return;
|
|
751
|
+
if (rect && anchor && corner && hitsFillHandle(hit.element, event)) {
|
|
752
|
+
consume(event);
|
|
753
|
+
fillOrigin = { ...rect };
|
|
754
|
+
fillCorners = [anchor, corner];
|
|
755
|
+
filling.value = true;
|
|
756
|
+
startDrag("fill");
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
if (event.shiftKey && anchor && active) {
|
|
760
|
+
consume(event);
|
|
761
|
+
select(anchor, hit.cell, active);
|
|
762
|
+
startDrag("select");
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
select(hit.cell, hit.cell, hit.cell);
|
|
766
|
+
startDrag("select");
|
|
767
|
+
}
|
|
768
|
+
function onPointerOver(event) {
|
|
769
|
+
if (!drag || !anchor || !active) return;
|
|
770
|
+
const hit = cellFromTarget(event.target);
|
|
771
|
+
if (!hit) return;
|
|
772
|
+
if (drag === "fill" && fillOrigin) {
|
|
773
|
+
const row = Math.max(hit.cell.row, fillOrigin.bottom);
|
|
774
|
+
select(
|
|
775
|
+
{ row: fillOrigin.top, col: fillOrigin.left },
|
|
776
|
+
{ row, col: fillOrigin.right },
|
|
777
|
+
active
|
|
778
|
+
);
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
select(anchor, hit.cell, active);
|
|
782
|
+
}
|
|
783
|
+
function runShortcut(letter, shift) {
|
|
784
|
+
switch (letter) {
|
|
785
|
+
case "a":
|
|
786
|
+
selectAll();
|
|
787
|
+
return true;
|
|
788
|
+
case "c":
|
|
789
|
+
void copyRange();
|
|
790
|
+
return true;
|
|
791
|
+
case "d":
|
|
792
|
+
fillDown();
|
|
793
|
+
return true;
|
|
794
|
+
case "r":
|
|
795
|
+
fillRight();
|
|
796
|
+
return true;
|
|
797
|
+
case "z":
|
|
798
|
+
if (shift) redo();
|
|
799
|
+
else undo();
|
|
800
|
+
return true;
|
|
801
|
+
case "y":
|
|
802
|
+
redo();
|
|
803
|
+
return true;
|
|
804
|
+
default:
|
|
805
|
+
return false;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
function onKeyDown(event) {
|
|
809
|
+
if (!api || !options.enabled() || event.defaultPrevented) return;
|
|
810
|
+
const target = event.target;
|
|
811
|
+
if (!(target instanceof Element) || isTextInput(target)) return;
|
|
812
|
+
if (!target.closest(".ag-cell") || isEditing()) return;
|
|
813
|
+
const mod = isApplePlatform() ? event.metaKey : event.ctrlKey;
|
|
814
|
+
const arrow = ARROWS[event.key];
|
|
815
|
+
if (mod && !event.altKey) {
|
|
816
|
+
if (arrow && event.shiftKey) {
|
|
817
|
+
stopEvent(event);
|
|
818
|
+
extend(arrow, true);
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
const letter = shortcutLetter(event);
|
|
822
|
+
if (letter === "v") {
|
|
823
|
+
event.stopPropagation();
|
|
824
|
+
if (rect) capturePaste();
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
if (runShortcut(letter, event.shiftKey)) stopEvent(event);
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
if (event.altKey || event.metaKey || event.ctrlKey) return;
|
|
831
|
+
if (event.key === "Delete" || event.key === "Backspace") {
|
|
832
|
+
stopEvent(event);
|
|
833
|
+
clearCells();
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
if (arrow && event.shiftKey) {
|
|
837
|
+
stopEvent(event);
|
|
838
|
+
extend(arrow, false);
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
if (event.key === "Escape" && active && isMulti()) select(active, active, active);
|
|
842
|
+
}
|
|
843
|
+
function onEditingStopped(event) {
|
|
844
|
+
if (!options.enabled() || !event.node.id) return;
|
|
845
|
+
const newValue = readValue(event.node, event.column);
|
|
846
|
+
if (sameValue(event.oldValue, newValue)) return;
|
|
847
|
+
commit(
|
|
848
|
+
[
|
|
849
|
+
{
|
|
850
|
+
rowId: event.node.id,
|
|
851
|
+
colId: event.column.getColId(),
|
|
852
|
+
field: fieldOf(event.column),
|
|
853
|
+
oldValue: event.oldValue,
|
|
854
|
+
newValue
|
|
855
|
+
}
|
|
856
|
+
],
|
|
857
|
+
"edit"
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
function containsCell(rowIndex, colId) {
|
|
861
|
+
const col = columnIndex.get(colId);
|
|
862
|
+
return !!rect && isMulti() && rowIndex !== null && col !== void 0 && rowIndex >= rect.top && rowIndex <= rect.bottom && col >= rect.left && col <= rect.right;
|
|
863
|
+
}
|
|
864
|
+
function attach(next) {
|
|
865
|
+
api = next;
|
|
866
|
+
next.addEventListener("cellFocused", onCellFocused);
|
|
867
|
+
next.addEventListener("cellEditingStopped", onEditingStopped);
|
|
868
|
+
next.addEventListener("displayedColumnsChanged", syncColumns);
|
|
869
|
+
next.addEventListener("modelUpdated", onModelUpdated);
|
|
870
|
+
syncColumns();
|
|
871
|
+
}
|
|
872
|
+
function detach() {
|
|
873
|
+
window.removeEventListener("pointerup", endDrag);
|
|
874
|
+
const current = api;
|
|
875
|
+
api = null;
|
|
876
|
+
if (!current || current.isDestroyed()) return;
|
|
877
|
+
current.removeEventListener("cellFocused", onCellFocused);
|
|
878
|
+
current.removeEventListener("cellEditingStopped", onEditingStopped);
|
|
879
|
+
current.removeEventListener("displayedColumnsChanged", syncColumns);
|
|
880
|
+
current.removeEventListener("modelUpdated", onModelUpdated);
|
|
881
|
+
}
|
|
882
|
+
function disable() {
|
|
883
|
+
reset();
|
|
884
|
+
clearHistory();
|
|
885
|
+
clearDirty();
|
|
886
|
+
}
|
|
887
|
+
const methods = {
|
|
888
|
+
getRange: () => toRange(),
|
|
889
|
+
getSelectedCells,
|
|
890
|
+
selectRange,
|
|
891
|
+
selectAll,
|
|
892
|
+
clearRange: reset,
|
|
893
|
+
setRangeValue,
|
|
894
|
+
copyRange,
|
|
895
|
+
paste,
|
|
896
|
+
fillDown,
|
|
897
|
+
fillRight,
|
|
898
|
+
clearCells,
|
|
899
|
+
undo,
|
|
900
|
+
redo,
|
|
901
|
+
clearHistory,
|
|
902
|
+
getDirtyCells,
|
|
903
|
+
clearDirty
|
|
904
|
+
};
|
|
905
|
+
const slotProps = computed(() => ({
|
|
906
|
+
...methods,
|
|
907
|
+
range: range.value,
|
|
908
|
+
selectedCellCount: selectedCellCount.value,
|
|
909
|
+
dirtyCount: dirtyCount.value,
|
|
910
|
+
canUndo: canUndo.value,
|
|
911
|
+
canRedo: canRedo.value
|
|
912
|
+
}));
|
|
913
|
+
return {
|
|
914
|
+
classRules,
|
|
915
|
+
methods,
|
|
916
|
+
slotProps,
|
|
917
|
+
filling,
|
|
918
|
+
attach,
|
|
919
|
+
detach,
|
|
920
|
+
disable,
|
|
921
|
+
containsCell,
|
|
922
|
+
copyRange,
|
|
923
|
+
onKeyDown,
|
|
924
|
+
onMouseDown,
|
|
925
|
+
onPointerDown,
|
|
926
|
+
onPointerOver
|
|
927
|
+
};
|
|
928
|
+
}
|