@freegridjs/core 1.9.4 → 1.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/dist/cdn/freegrid.css +27 -8
- package/dist/cdn/freegrid.esm.js +23 -23
- package/dist/cdn/freegrid.min.js +24 -24
- package/dist/index.d.ts +3 -3
- package/dist/index.js +456 -80
- package/dist/locales/de.d.ts +1 -1
- package/dist/locales/de.js +2 -0
- package/dist/locales/en.d.ts +1 -1
- package/dist/locales/en.js +2 -0
- package/dist/locales/es.d.ts +1 -1
- package/dist/locales/es.js +2 -0
- package/dist/locales/fr.d.ts +1 -1
- package/dist/locales/fr.js +2 -0
- package/dist/locales/id.d.ts +1 -1
- package/dist/locales/id.js +2 -0
- package/dist/locales/it.d.ts +1 -1
- package/dist/locales/it.js +2 -0
- package/dist/locales/ja.d.ts +1 -1
- package/dist/locales/ja.js +2 -0
- package/dist/locales/ko.d.ts +1 -1
- package/dist/locales/ko.js +2 -0
- package/dist/locales/pt-BR.d.ts +1 -1
- package/dist/locales/pt-BR.js +2 -0
- package/dist/locales/ru.d.ts +1 -1
- package/dist/locales/ru.js +2 -0
- package/dist/locales/th.d.ts +1 -1
- package/dist/locales/th.js +2 -0
- package/dist/locales/vi.d.ts +1 -1
- package/dist/locales/vi.js +2 -0
- package/dist/locales/zh-CN.d.ts +1 -1
- package/dist/locales/zh-CN.js +2 -0
- package/dist/locales/zh-TW.d.ts +1 -1
- package/dist/locales/zh-TW.js +2 -0
- package/dist/styles.css +27 -8
- package/dist/{types-CIOv3MoN.d.ts → types-D5xV-gww.d.ts} +22 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -432,9 +432,10 @@ var ColumnModel = class {
|
|
|
432
432
|
setContainerWidth(width) {
|
|
433
433
|
if (width === this.containerWidth) return false;
|
|
434
434
|
this.containerWidth = width;
|
|
435
|
-
const
|
|
435
|
+
const sig = () => this.displayed().map((c) => `${c.width}${c.region}`).join();
|
|
436
|
+
const before = sig();
|
|
436
437
|
this.relayout();
|
|
437
|
-
return before !==
|
|
438
|
+
return before !== sig();
|
|
438
439
|
}
|
|
439
440
|
roots() {
|
|
440
441
|
return this.roots_;
|
|
@@ -596,19 +597,56 @@ var ColumnModel = class {
|
|
|
596
597
|
relayout() {
|
|
597
598
|
const visible = this.leafNodes().filter((n) => !n.hide && this.shownByGroups(n));
|
|
598
599
|
const fixed = visible.reduce((s, n) => s + (n.flex ? 0 : n.width), 0);
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
600
|
+
const flexWidth = /* @__PURE__ */ new Map();
|
|
601
|
+
let pending = visible.filter((n) => n.flex);
|
|
602
|
+
let free = Math.max(0, this.containerWidth - fixed);
|
|
603
|
+
while (pending.length) {
|
|
604
|
+
const totalFlex = pending.reduce((s, n) => s + n.flex, 0);
|
|
605
|
+
const share = (n) => Math.floor(free * n.flex / totalFlex);
|
|
606
|
+
const excess = pending.reduce((s, n) => s + clampWidth(n.def, share(n)) - share(n), 0);
|
|
607
|
+
const clamped = pending.filter((n) => {
|
|
608
|
+
const d = clampWidth(n.def, share(n)) - share(n);
|
|
609
|
+
return excess > 0 ? d > 0 : excess < 0 ? d < 0 : false;
|
|
610
|
+
});
|
|
611
|
+
if (!clamped.length) {
|
|
612
|
+
let rest = free;
|
|
613
|
+
for (const n of pending) {
|
|
614
|
+
const w = clampWidth(n.def, share(n));
|
|
615
|
+
flexWidth.set(n, w);
|
|
616
|
+
rest -= w;
|
|
617
|
+
}
|
|
618
|
+
for (const n of pending) {
|
|
619
|
+
if (rest < 1) break;
|
|
620
|
+
const w = flexWidth.get(n);
|
|
621
|
+
if (clampWidth(n.def, w + 1) !== w + 1) continue;
|
|
622
|
+
flexWidth.set(n, w + 1);
|
|
623
|
+
rest--;
|
|
624
|
+
}
|
|
625
|
+
break;
|
|
626
|
+
}
|
|
627
|
+
let used = 0;
|
|
628
|
+
for (const n of clamped) {
|
|
629
|
+
const w = clampWidth(n.def, share(n));
|
|
630
|
+
flexWidth.set(n, w);
|
|
631
|
+
used += w;
|
|
632
|
+
}
|
|
633
|
+
free = Math.max(0, free - used);
|
|
634
|
+
pending = pending.filter((n) => !clamped.includes(n));
|
|
635
|
+
}
|
|
636
|
+
const widthOf = (n) => flexWidth.get(n) ?? n.width;
|
|
602
637
|
const next = { left: [], center: [], right: [] };
|
|
603
638
|
this.leafById = /* @__PURE__ */ new Map();
|
|
604
639
|
let index = 0;
|
|
640
|
+
const pinnedWidth = visible.reduce((s, n) => s + (n.pinned ? widthOf(n) : 0), 0);
|
|
641
|
+
const unpin = this.containerWidth > 0 && pinnedWidth > this.containerWidth * 0.75;
|
|
642
|
+
const x = { left: 0, center: 0, right: 0 };
|
|
605
643
|
for (const r of REGIONS) {
|
|
606
|
-
|
|
644
|
+
const to = unpin ? "center" : r;
|
|
607
645
|
for (const n of visible) {
|
|
608
646
|
if ((n.pinned ?? "center") !== r) continue;
|
|
609
|
-
const col = { id: n.id, def: n.def, node: n, width: widthOf(n), region:
|
|
610
|
-
x += col.width;
|
|
611
|
-
next[
|
|
647
|
+
const col = { id: n.id, def: n.def, node: n, width: widthOf(n), region: to, left: x[to], index: index++ };
|
|
648
|
+
x[to] += col.width;
|
|
649
|
+
next[to].push(col);
|
|
612
650
|
this.leafById.set(n.id, col);
|
|
613
651
|
}
|
|
614
652
|
}
|
|
@@ -1339,6 +1377,7 @@ var REGIONS2 = ["left", "center", "right"];
|
|
|
1339
1377
|
var NUM_OPS = [[">=", "gte"], ["<=", "lte"], ["<>", "ne"], ["!=", "ne"], [">", "gt"], ["<", "lt"], ["=", "eq"]];
|
|
1340
1378
|
var DATE_OPS = [[">", "after"], ["<", "before"], ["=", "equals"]];
|
|
1341
1379
|
var RANGE = /^(.+?)\s*(?:~|\.\.)\s*(.+)$/;
|
|
1380
|
+
var MULTI = "~many";
|
|
1342
1381
|
var toNumber = (s) => {
|
|
1343
1382
|
const n = Number(s.replace(/[,\s₩$€¥]/g, ""));
|
|
1344
1383
|
return s.trim() !== "" && Number.isFinite(n) ? n : null;
|
|
@@ -1438,8 +1477,21 @@ var FilterRow = class {
|
|
|
1438
1477
|
box.closest(".fg-filter-cell").classList.toggle("fg-filter-active", !!model);
|
|
1439
1478
|
if (box === box.ownerDocument.activeElement || box.getRootNode().activeElement === box) continue;
|
|
1440
1479
|
if (box instanceof HTMLSelectElement) {
|
|
1441
|
-
const
|
|
1442
|
-
|
|
1480
|
+
const many = model?.type === "set" && model.values.length > 1 ? model.values.length : 0;
|
|
1481
|
+
let multi = box.querySelector(`option[value="${MULTI}"]`);
|
|
1482
|
+
if (many) {
|
|
1483
|
+
if (!multi) {
|
|
1484
|
+
multi = el("option", "", { value: MULTI });
|
|
1485
|
+
multi.disabled = true;
|
|
1486
|
+
box.options[0].after(multi);
|
|
1487
|
+
}
|
|
1488
|
+
multi.textContent = this.grid.store.state.locale.setSelected.replace("{n}", String(many));
|
|
1489
|
+
box.value = MULTI;
|
|
1490
|
+
} else {
|
|
1491
|
+
multi?.remove();
|
|
1492
|
+
const v = model?.type === "set" && model.values.length === 1 ? JSON.stringify(model.values[0]) : "";
|
|
1493
|
+
if ([...box.options].some((o) => o.value === v)) box.value = v;
|
|
1494
|
+
}
|
|
1443
1495
|
} else box.value = filterText(model);
|
|
1444
1496
|
box.classList.remove("fg-filter-bad");
|
|
1445
1497
|
}
|
|
@@ -1453,6 +1505,10 @@ var FilterRow = class {
|
|
|
1453
1505
|
if (!def) continue;
|
|
1454
1506
|
const v = select.value;
|
|
1455
1507
|
this.fillOptions(select, def);
|
|
1508
|
+
if (v === MULTI) {
|
|
1509
|
+
this.rebuilt = true;
|
|
1510
|
+
continue;
|
|
1511
|
+
}
|
|
1456
1512
|
if (v && ![...select.options].some((o) => o.value === v)) {
|
|
1457
1513
|
const o = el("option", "", { value: v });
|
|
1458
1514
|
o.textContent = String(JSON.parse(v));
|
|
@@ -1473,7 +1529,7 @@ var FilterRow = class {
|
|
|
1473
1529
|
select.replaceChildren(all2, ...opts);
|
|
1474
1530
|
}
|
|
1475
1531
|
cell(c, h) {
|
|
1476
|
-
const cell = el("div", "fg-filter-cell");
|
|
1532
|
+
const cell = el("div", "fg-filter-cell", { role: "gridcell" });
|
|
1477
1533
|
cell.style.left = `${c.left}px`;
|
|
1478
1534
|
cell.style.width = `${c.width}px`;
|
|
1479
1535
|
cell.style.height = `${h}px`;
|
|
@@ -2033,6 +2089,7 @@ var Renderer = class {
|
|
|
2033
2089
|
};
|
|
2034
2090
|
this.overlayKey = "";
|
|
2035
2091
|
this.heightFn = null;
|
|
2092
|
+
this.freeBadge = null;
|
|
2036
2093
|
this.onCardClick = (e) => {
|
|
2037
2094
|
const target = e.target;
|
|
2038
2095
|
const card = target.closest(".fg-card");
|
|
@@ -2240,6 +2297,7 @@ var Renderer = class {
|
|
|
2240
2297
|
if (ref.nextElementSibling !== b) ref.after(b);
|
|
2241
2298
|
ref = b;
|
|
2242
2299
|
}
|
|
2300
|
+
this.placeFreeBadge();
|
|
2243
2301
|
}
|
|
2244
2302
|
/** "No rows" / "Loading" over the body, or the noRowsOverlay / loadingOverlay given in the options. */
|
|
2245
2303
|
paintOverlay(count) {
|
|
@@ -2330,7 +2388,7 @@ var Renderer = class {
|
|
|
2330
2388
|
const { grid } = this;
|
|
2331
2389
|
const state = grid.store.state;
|
|
2332
2390
|
const total = grid.rowModel.server ? count : grid.viewRows().length;
|
|
2333
|
-
const key = `${this.version}.${grid.valuesVersion}|${count}|${total}|${state.selected.size}|${JSON.stringify(state.range)}|${state.locale.code}`;
|
|
2391
|
+
const key = `${this.version}.${grid.valuesVersion}|${count}|${total}|${state.selected.size}|${JSON.stringify(state.range)}|${JSON.stringify(state.extraRanges)}|${state.locale.code}`;
|
|
2334
2392
|
if (this.statusEl && key === this.statusKey) return;
|
|
2335
2393
|
this.statusKey = key;
|
|
2336
2394
|
this.statusEl ?? (this.statusEl = el("div", "fg-statusbar", { role: "status", "aria-live": "polite" }));
|
|
@@ -3202,12 +3260,21 @@ var Renderer = class {
|
|
|
3202
3260
|
/** Small "free version" mark in the bottom-right corner (unlicensed company domains flagged on freegrid.app). */
|
|
3203
3261
|
showFreeBadge() {
|
|
3204
3262
|
if (this.root.querySelector(".fg-free-badge")) return;
|
|
3205
|
-
const a = el("
|
|
3263
|
+
const a = el("div", "fg-free-badge", { "aria-hidden": "true" });
|
|
3206
3264
|
a.innerHTML = '<svg viewBox="0 0 32 32" width="14" height="14" aria-hidden="true"><rect width="32" height="32" rx="7" fill="#0E1726"/><path d="M7 11.5h18M7 16.5h18M7 21.5h18M13 7v18" stroke="#fff" stroke-width="2" stroke-linecap="round"/><rect x="14" y="12.5" width="11" height="3" rx="1" fill="#F2A900"/></svg>';
|
|
3207
3265
|
const text2 = el("span");
|
|
3208
3266
|
text2.textContent = `FreeGrid \xB7 ${this.grid.store.state.locale.freeBadge}`;
|
|
3209
3267
|
a.append(text2);
|
|
3210
3268
|
this.root.append(a);
|
|
3269
|
+
this.freeBadge = a;
|
|
3270
|
+
this.placeFreeBadge();
|
|
3271
|
+
}
|
|
3272
|
+
/** The free badge sits above the status bar and pager, not on them. */
|
|
3273
|
+
placeFreeBadge() {
|
|
3274
|
+
if (!this.freeBadge) return;
|
|
3275
|
+
const below = (this.statusEl?.isConnected ? this.statusEl.offsetHeight : 0) + (this.pagerEl?.isConnected ? this.pagerEl.offsetHeight : 0);
|
|
3276
|
+
const bottom = below ? `${below + 22}px` : "";
|
|
3277
|
+
if (this.freeBadge.style.bottom !== bottom) this.freeBadge.style.bottom = bottom;
|
|
3211
3278
|
}
|
|
3212
3279
|
/** Card view applies when enabled and the grid is narrower than the breakpoint. */
|
|
3213
3280
|
useCards() {
|
|
@@ -3527,6 +3594,8 @@ var en = {
|
|
|
3527
3594
|
apply: "Apply",
|
|
3528
3595
|
reset: "Reset",
|
|
3529
3596
|
selectAll: "(Select all)",
|
|
3597
|
+
setSelected: "({n} selected)",
|
|
3598
|
+
noAggregate: "No aggregate",
|
|
3530
3599
|
search: "Search\u2026",
|
|
3531
3600
|
blanks: "(Blanks)",
|
|
3532
3601
|
value: "Value",
|
|
@@ -3757,7 +3826,8 @@ var DEFAULT_KEYMAP = {
|
|
|
3757
3826
|
"Ctrl+Z": "undo",
|
|
3758
3827
|
"Ctrl+Y": "redo",
|
|
3759
3828
|
"Ctrl+Shift+Z": "redo",
|
|
3760
|
-
"Ctrl+F": "find"
|
|
3829
|
+
"Ctrl+F": "find",
|
|
3830
|
+
"Alt+ArrowDown": "columnMenu"
|
|
3761
3831
|
};
|
|
3762
3832
|
function comboOf(e) {
|
|
3763
3833
|
const parts = [];
|
|
@@ -3906,6 +3976,8 @@ function attachBody(grid) {
|
|
|
3906
3976
|
case "paste":
|
|
3907
3977
|
navigator.clipboard?.readText?.().then((t) => grid.pasteText(t), () => void 0);
|
|
3908
3978
|
return true;
|
|
3979
|
+
case "columnMenu":
|
|
3980
|
+
return grid.menu.openAtFocus();
|
|
3909
3981
|
}
|
|
3910
3982
|
if (!f) return false;
|
|
3911
3983
|
if (!grid.editor.canEdit(f.rowIndex, f.colId)) return false;
|
|
@@ -4134,14 +4206,14 @@ function attachBody(grid) {
|
|
|
4134
4206
|
const nested = (e) => e.target?.closest?.(".fg-root") !== root;
|
|
4135
4207
|
const onCopy = (e) => {
|
|
4136
4208
|
if (fromField(e) || nested(e)) return;
|
|
4137
|
-
const text2 = grid.
|
|
4209
|
+
const text2 = grid.copyText(false);
|
|
4138
4210
|
if (!text2 || !e.clipboardData) return;
|
|
4139
4211
|
e.clipboardData.setData("text/plain", text2);
|
|
4140
4212
|
e.preventDefault();
|
|
4141
4213
|
};
|
|
4142
4214
|
const onCut = (e) => {
|
|
4143
4215
|
if (fromField(e) || nested(e)) return;
|
|
4144
|
-
const text2 = grid.
|
|
4216
|
+
const text2 = grid.copyText(false);
|
|
4145
4217
|
if (!text2 || !e.clipboardData) return;
|
|
4146
4218
|
e.clipboardData.setData("text/plain", text2);
|
|
4147
4219
|
e.preventDefault();
|
|
@@ -4508,7 +4580,9 @@ var ColumnChooserDialog = class {
|
|
|
4508
4580
|
if (!eventInside(e, popup)) this.close();
|
|
4509
4581
|
};
|
|
4510
4582
|
const onKey = (e) => {
|
|
4511
|
-
if (e.key
|
|
4583
|
+
if (e.key !== "Escape") return;
|
|
4584
|
+
this.close();
|
|
4585
|
+
this.grid.renderer.gridEl.focus();
|
|
4512
4586
|
};
|
|
4513
4587
|
document.addEventListener("pointerdown", onDown, true);
|
|
4514
4588
|
document.addEventListener("keydown", onKey, true);
|
|
@@ -4647,12 +4721,13 @@ var ContextMenu = class {
|
|
|
4647
4721
|
const node = grid.columns.getNode(colId);
|
|
4648
4722
|
const def = node?.def;
|
|
4649
4723
|
const dataCol = !!def && !isSystemCol(colId);
|
|
4724
|
+
const checked = grid.store.state.selected.size ? grid.shownSelectedRows() : [];
|
|
4650
4725
|
const items = [
|
|
4651
4726
|
{ label: loc.copy, shortcut: shortcut("C"), action: () => grid.copyToClipboard(false) },
|
|
4652
4727
|
{ label: loc.copyWithHeaders, action: () => grid.copyToClipboard(true) },
|
|
4653
4728
|
// after the copy items, so defaultItems indexes from earlier versions still point at the same entries
|
|
4654
4729
|
{ label: loc.cut, shortcut: shortcut("X"), action: () => grid.cutToClipboard() },
|
|
4655
|
-
...
|
|
4730
|
+
...checked.length ? [{ label: loc.copyRows, action: () => grid.copyToClipboard(false, true) }] : [],
|
|
4656
4731
|
{ label: loc.paste, shortcut: shortcut("V"), action: () => this.pasteFromClipboard() }
|
|
4657
4732
|
];
|
|
4658
4733
|
if (grid.history.canUndo() || grid.history.canRedo()) {
|
|
@@ -4662,8 +4737,8 @@ var ContextMenu = class {
|
|
|
4662
4737
|
{ label: loc.redo, shortcut: shortcut("Y"), action: () => grid.redo(), disabled: !grid.history.canRedo() }
|
|
4663
4738
|
);
|
|
4664
4739
|
}
|
|
4665
|
-
if (grid.options.rowSelection &&
|
|
4666
|
-
items.push({ label: loc.deleteRows, action: () => grid.
|
|
4740
|
+
if (grid.options.rowSelection && checked.length) {
|
|
4741
|
+
items.push({ label: loc.deleteRows, action: () => grid.removeRows(checked) });
|
|
4667
4742
|
}
|
|
4668
4743
|
if (dataCol) {
|
|
4669
4744
|
items.push("separator", { label: loc.autosizeThis, action: () => grid.autoSize([colId]) });
|
|
@@ -4758,7 +4833,9 @@ var ContextMenu = class {
|
|
|
4758
4833
|
popupParent(this.grid.renderer.root).append(popup);
|
|
4759
4834
|
const w = popup.offsetWidth || 220, h = popup.offsetHeight || 300;
|
|
4760
4835
|
popup.style.left = `${Math.max(4, Math.min(x, window.innerWidth - w - 4))}px`;
|
|
4761
|
-
|
|
4836
|
+
const top = Math.max(4, Math.min(y, window.innerHeight - h - 4));
|
|
4837
|
+
popup.style.top = `${top}px`;
|
|
4838
|
+
popup.style.maxHeight = `${Math.max(120, window.innerHeight - top - 8)}px`;
|
|
4762
4839
|
this.popup = popup;
|
|
4763
4840
|
const onDown = (e) => {
|
|
4764
4841
|
if (!eventInside(e, popup)) this.close();
|
|
@@ -5048,10 +5125,28 @@ var Finder = class {
|
|
|
5048
5125
|
else this.next();
|
|
5049
5126
|
}
|
|
5050
5127
|
});
|
|
5051
|
-
this.grid.renderer
|
|
5128
|
+
const { root, headerEl, main } = this.grid.renderer;
|
|
5129
|
+
root.append(bar);
|
|
5130
|
+
const box = root.getBoundingClientRect(), head = headerEl.getBoundingClientRect(), area = main.getBoundingClientRect();
|
|
5131
|
+
if (head.height) bar.style.top = `${Math.round(head.bottom - box.top) + 6}px`;
|
|
5132
|
+
if (area.width) bar.style.right = `${Math.max(0, Math.round(box.right - area.right)) + 18}px`;
|
|
5052
5133
|
this.bar = bar;
|
|
5053
5134
|
input.focus();
|
|
5054
5135
|
}
|
|
5136
|
+
/** setLocale: the open bar's placeholder, button labels and "no matches" in the new language. */
|
|
5137
|
+
relabel() {
|
|
5138
|
+
if (!this.bar) return;
|
|
5139
|
+
const loc = this.grid.store.state.locale;
|
|
5140
|
+
const input = this.bar.querySelector("input");
|
|
5141
|
+
input.placeholder = loc.findPlaceholder;
|
|
5142
|
+
input.setAttribute("aria-label", loc.findPlaceholder);
|
|
5143
|
+
const labels = [loc.findPrevious, loc.findNext, loc.close];
|
|
5144
|
+
this.bar.querySelectorAll(".fg-findbar-btn").forEach((b, i) => {
|
|
5145
|
+
b.setAttribute("aria-label", labels[i]);
|
|
5146
|
+
b.title = labels[i];
|
|
5147
|
+
});
|
|
5148
|
+
this.updateCount();
|
|
5149
|
+
}
|
|
5055
5150
|
closeBar() {
|
|
5056
5151
|
this.bar?.remove();
|
|
5057
5152
|
this.bar = null;
|
|
@@ -5304,7 +5399,7 @@ var CellEditor = class {
|
|
|
5304
5399
|
const col = this.grid.columns.getColumn(colId);
|
|
5305
5400
|
if (!col?.def.field || rowIndex < 0 || rowIndex >= this.grid.rowModel.getRowCount()) return false;
|
|
5306
5401
|
const node = this.grid.rowModel.getRow(rowIndex);
|
|
5307
|
-
return !node.kind && cellEditable(col.def, node.data, rowIndex);
|
|
5402
|
+
return !node.kind && this.grid.cellEditable(col.def, node.data, rowIndex);
|
|
5308
5403
|
}
|
|
5309
5404
|
start(rowIndex, colId, initialText) {
|
|
5310
5405
|
if (this.cur && !this.commit(null)) return false;
|
|
@@ -5530,6 +5625,7 @@ var CellEditor = class {
|
|
|
5530
5625
|
i = cols.length - 1;
|
|
5531
5626
|
if (!this.session) r--;
|
|
5532
5627
|
}
|
|
5628
|
+
while (r !== rowIndex && r >= 0 && r < count && grid.rowModel.getRow(r)?.kind) r += step;
|
|
5533
5629
|
if (r < 0 || r >= count) return;
|
|
5534
5630
|
this.start(r, cols[i].id);
|
|
5535
5631
|
}
|
|
@@ -6639,9 +6735,9 @@ function exportColumns(grid, ids) {
|
|
|
6639
6735
|
return grid.columns.displayed().filter((c) => !isSystemCol(c.id)).map((c) => ({ id: c.id, def: c.def, node: c.node, width: c.width }));
|
|
6640
6736
|
}
|
|
6641
6737
|
function exportRows(grid, mode) {
|
|
6642
|
-
if (mode === "selected") return grid.
|
|
6738
|
+
if (mode === "selected") return grid.shownSelectedRows();
|
|
6643
6739
|
if (mode === "all") return grid.rowModel.server ? grid.rowModel.dataRows().map((n) => n.data) : grid.viewRows();
|
|
6644
|
-
return grid.
|
|
6740
|
+
return grid.orderedDataRows().map((n) => n.data);
|
|
6645
6741
|
}
|
|
6646
6742
|
var header = (def, id) => def.header ?? def.field ?? id;
|
|
6647
6743
|
var ALIGNS = ["left", "center", "right"];
|
|
@@ -7732,6 +7828,35 @@ function buildPivot(source, config, defOf, labels, locale) {
|
|
|
7732
7828
|
});
|
|
7733
7829
|
return { columns: [...rowColumns, ...valueColumns], rows, groupBy: cfg.rows.slice(0, -1) };
|
|
7734
7830
|
}
|
|
7831
|
+
var ROLLUP = /* @__PURE__ */ new WeakMap();
|
|
7832
|
+
function rollupSource(row) {
|
|
7833
|
+
return ROLLUP.get(row);
|
|
7834
|
+
}
|
|
7835
|
+
function buildRollup(source, defs) {
|
|
7836
|
+
const keys = defs.filter((d) => !d.aggFunc);
|
|
7837
|
+
const values = defs.filter((d) => d.aggFunc && d.field && !d.valueGetter);
|
|
7838
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
7839
|
+
for (const r of source) {
|
|
7840
|
+
const k = keys.map((d) => setKey(getCellValue(d, r))).join("");
|
|
7841
|
+
let list = buckets.get(k);
|
|
7842
|
+
if (!list) buckets.set(k, list = []);
|
|
7843
|
+
list.push(r);
|
|
7844
|
+
}
|
|
7845
|
+
const rows = [];
|
|
7846
|
+
for (const src of buckets.values()) {
|
|
7847
|
+
const row = { ...src[0] };
|
|
7848
|
+
for (const d of values) {
|
|
7849
|
+
try {
|
|
7850
|
+
row[d.field] = aggregate(d.aggFunc, src.map((r) => getCellValue(d, r)), src);
|
|
7851
|
+
} catch {
|
|
7852
|
+
row[d.field] = null;
|
|
7853
|
+
}
|
|
7854
|
+
}
|
|
7855
|
+
ROLLUP.set(row, src);
|
|
7856
|
+
rows.push(row);
|
|
7857
|
+
}
|
|
7858
|
+
return rows;
|
|
7859
|
+
}
|
|
7735
7860
|
|
|
7736
7861
|
// src/features.ts
|
|
7737
7862
|
var PAID_FEATURES = {
|
|
@@ -7757,7 +7882,7 @@ var PAID_FEATURES = {
|
|
|
7757
7882
|
};
|
|
7758
7883
|
|
|
7759
7884
|
// src/version.ts
|
|
7760
|
-
var version = "1.
|
|
7885
|
+
var version = "1.10.0";
|
|
7761
7886
|
|
|
7762
7887
|
// src/license.ts
|
|
7763
7888
|
var PUBLIC_KEY = { kty: "EC", crv: "P-256", x: "sUTKkglZmk-HMKPNub8p7AeLBKesHCU8irIkw9rJlbE", y: "j0U_aKRDR7iApY9UpaD3hUemhBLZJwDv9-QiT_hUyw8" };
|
|
@@ -8056,6 +8181,12 @@ var ColumnMenu = class {
|
|
|
8056
8181
|
if (grouped.length) g.push([loc.expandAll, () => this.grid.expandAll(true)], [loc.collapseAll, () => this.grid.expandAll(false)]);
|
|
8057
8182
|
popup.append(this.section(g));
|
|
8058
8183
|
}
|
|
8184
|
+
if (this.grid.getRollup()) {
|
|
8185
|
+
const cur = def.aggFunc ?? null;
|
|
8186
|
+
const mark = (on, label) => `${on ? "\u2713 " : ""}${label}`;
|
|
8187
|
+
const aggs = ["sum", "avg", "min", "max", "count"].map((a) => [mark(cur === a, loc[a]), () => this.grid.setColumnAggFunc(colId, a)]);
|
|
8188
|
+
popup.append(this.section([[mark(!cur, loc.noAggregate), () => this.grid.setColumnAggFunc(colId, null)], ...aggs]));
|
|
8189
|
+
}
|
|
8059
8190
|
const items = [
|
|
8060
8191
|
[loc.autosizeThis, () => this.grid.autoSize([colId])],
|
|
8061
8192
|
[loc.autosizeAll, () => this.grid.autoSize()]
|
|
@@ -8083,14 +8214,30 @@ var ColumnMenu = class {
|
|
|
8083
8214
|
this.close();
|
|
8084
8215
|
this.grid.renderer.gridEl.focus();
|
|
8085
8216
|
};
|
|
8217
|
+
const onScroll = () => this.close();
|
|
8218
|
+
const scroller = this.grid.renderer.scroller;
|
|
8086
8219
|
document.addEventListener("pointerdown", onDown, true);
|
|
8087
8220
|
document.addEventListener("keydown", onKey, true);
|
|
8221
|
+
scroller.addEventListener("scroll", onScroll, { passive: true });
|
|
8088
8222
|
this.off.push(
|
|
8089
8223
|
() => document.removeEventListener("pointerdown", onDown, true),
|
|
8090
|
-
() => document.removeEventListener("keydown", onKey, true)
|
|
8224
|
+
() => document.removeEventListener("keydown", onKey, true),
|
|
8225
|
+
() => scroller.removeEventListener("scroll", onScroll)
|
|
8091
8226
|
);
|
|
8092
8227
|
popup.querySelector(".fg-filter-value:not([hidden]), .fg-set-search, .fg-menu-item")?.focus();
|
|
8093
8228
|
}
|
|
8229
|
+
/** Keyboard (Alt+ArrowDown): the menu of the focused cell's column (else the first column), under its header. */
|
|
8230
|
+
openAtFocus() {
|
|
8231
|
+
const { grid } = this;
|
|
8232
|
+
const f = grid.store.state.focus;
|
|
8233
|
+
const colId = f && !isSystemCol(f.colId) ? f.colId : grid.columns.displayed().find((c) => !isSystemCol(c.id))?.id;
|
|
8234
|
+
if (!colId) return false;
|
|
8235
|
+
const root = grid.renderer.root;
|
|
8236
|
+
const id = CSS.escape(colId);
|
|
8237
|
+
const anchor = root.querySelector(`.fg-header-cell:not(.fg-header-group)[data-col="${id}"]`) ?? (f ? root.querySelector(`.fg-row[data-row="${f.rowIndex}"] .fg-cell[data-col="${id}"]`) : null) ?? grid.renderer.gridEl;
|
|
8238
|
+
this.open(colId, anchor);
|
|
8239
|
+
return true;
|
|
8240
|
+
}
|
|
8094
8241
|
/** The filter UI of a column (used by the menu and the filters panel); `done` runs after apply/reset. */
|
|
8095
8242
|
filterSection(colId, done) {
|
|
8096
8243
|
const node = this.grid.columns.getNode(colId);
|
|
@@ -8115,6 +8262,8 @@ var ColumnMenu = class {
|
|
|
8115
8262
|
b.addEventListener("click", () => {
|
|
8116
8263
|
run2();
|
|
8117
8264
|
this.close();
|
|
8265
|
+
const a = activeElement(this.grid.renderer.root);
|
|
8266
|
+
if (!a || a === document.body || !a.isConnected) this.grid.renderer.gridEl.focus({ preventScroll: true });
|
|
8118
8267
|
});
|
|
8119
8268
|
s.append(b);
|
|
8120
8269
|
}
|
|
@@ -8311,6 +8460,7 @@ var RowModel = class {
|
|
|
8311
8460
|
this.sorted = [];
|
|
8312
8461
|
this.display = [];
|
|
8313
8462
|
this.indexById = null;
|
|
8463
|
+
this.orderedCache = null;
|
|
8314
8464
|
this.layoutCache = null;
|
|
8315
8465
|
/** Searchable text of each row, kept between quick filter keystrokes. */
|
|
8316
8466
|
this.quickCache = null;
|
|
@@ -8369,6 +8519,13 @@ var RowModel = class {
|
|
|
8369
8519
|
fullCount() {
|
|
8370
8520
|
return this.full.length;
|
|
8371
8521
|
}
|
|
8522
|
+
dataRowsBefore(index) {
|
|
8523
|
+
const end = Math.min(index, this.full.length);
|
|
8524
|
+
if (this.full === this.sorted) return end;
|
|
8525
|
+
let n = 0;
|
|
8526
|
+
for (let k = 0; k < end; k++) if (!this.full[k].kind) n++;
|
|
8527
|
+
return n;
|
|
8528
|
+
}
|
|
8372
8529
|
dataCount() {
|
|
8373
8530
|
return this.sorted.length;
|
|
8374
8531
|
}
|
|
@@ -8389,6 +8546,19 @@ var RowModel = class {
|
|
|
8389
8546
|
dataRows() {
|
|
8390
8547
|
return this.sorted;
|
|
8391
8548
|
}
|
|
8549
|
+
/** Filtered data rows in display order, as if every group and tree row were expanded. */
|
|
8550
|
+
orderedDataRows() {
|
|
8551
|
+
const c = this.orderedCache;
|
|
8552
|
+
if (c && c.full === this.full) return c.rows;
|
|
8553
|
+
const d = this.last.display;
|
|
8554
|
+
let rows = this.sorted;
|
|
8555
|
+
if (d && (d.getParentId || d.groupBy.length)) {
|
|
8556
|
+
const open = { ...d, expanded: /* @__PURE__ */ new Map(), defaultExpanded: -1, detailOpen: /* @__PURE__ */ new Set(), lazyChildren: void 0 };
|
|
8557
|
+
rows = this.buildDisplay(open, this.last.sort ?? [], this.last.collator ?? this.deps.collator()).filter((n) => !n.kind);
|
|
8558
|
+
}
|
|
8559
|
+
this.orderedCache = { full: this.full, rows };
|
|
8560
|
+
return rows;
|
|
8561
|
+
}
|
|
8392
8562
|
allNodes() {
|
|
8393
8563
|
return this.nodes;
|
|
8394
8564
|
}
|
|
@@ -8791,6 +8961,7 @@ var ServerRowModel = class {
|
|
|
8791
8961
|
/** Server-side grouping, while groupBy has columns. */
|
|
8792
8962
|
this.groups = null;
|
|
8793
8963
|
this.displayIn = null;
|
|
8964
|
+
this.quiet = false;
|
|
8794
8965
|
}
|
|
8795
8966
|
get bs() {
|
|
8796
8967
|
return this.page ? this.page.size : this.deps.blockSize;
|
|
@@ -8889,9 +9060,19 @@ var ServerRowModel = class {
|
|
|
8889
9060
|
const abs = this.base + index;
|
|
8890
9061
|
const hit = this.peek(abs);
|
|
8891
9062
|
if (hit) return hit;
|
|
8892
|
-
if (index >= 0 && index < this.getRowCount()) this.ensure(Math.floor(abs / this.bs));
|
|
9063
|
+
if (!this.quiet && index >= 0 && index < this.getRowCount()) this.ensure(Math.floor(abs / this.bs));
|
|
8893
9064
|
return this.placeholder(abs);
|
|
8894
9065
|
}
|
|
9066
|
+
/** Run `fn` with getRow answering from loaded blocks only (rows not loaded stay placeholders, nothing is requested). */
|
|
9067
|
+
withoutLoading(fn) {
|
|
9068
|
+
const was = this.quiet;
|
|
9069
|
+
this.quiet = true;
|
|
9070
|
+
try {
|
|
9071
|
+
return fn();
|
|
9072
|
+
} finally {
|
|
9073
|
+
this.quiet = was;
|
|
9074
|
+
}
|
|
9075
|
+
}
|
|
8895
9076
|
ensure(k) {
|
|
8896
9077
|
const cur = this.blocks.get(k);
|
|
8897
9078
|
if (cur && (cur.state !== "failed" || Date.now() < (cur.retryAt ?? 0))) return;
|
|
@@ -9313,17 +9494,23 @@ var FilterBuilder = class {
|
|
|
9313
9494
|
actions.append(reset, ok);
|
|
9314
9495
|
popup.append(head, join, list, addBtn, actions);
|
|
9315
9496
|
popupParent(grid.renderer.root).append(popup);
|
|
9497
|
+
if (!rows.length) addBtn.click();
|
|
9316
9498
|
const r = grid.renderer.root.getBoundingClientRect();
|
|
9317
9499
|
const w = popup.offsetWidth || 460;
|
|
9318
9500
|
popup.style.left = `${Math.max(4, Math.min(r.left + 24, (window.innerWidth || 1024) - w - 4))}px`;
|
|
9319
|
-
|
|
9501
|
+
const header2 = grid.renderer.headerEl.getBoundingClientRect();
|
|
9502
|
+
const vh = window.innerHeight || 768;
|
|
9503
|
+
const top = Math.max(4, Math.min((header2.height ? header2.bottom : r.top) + 8, vh - (popup.offsetHeight || 0) - 4));
|
|
9504
|
+
popup.style.top = `${top}px`;
|
|
9505
|
+
popup.style.maxHeight = `${Math.max(160, vh - top - 8)}px`;
|
|
9320
9506
|
this.popup = popup;
|
|
9321
|
-
if (!rows.length) addBtn.click();
|
|
9322
9507
|
const onDown = (e) => {
|
|
9323
9508
|
if (!eventInside(e, popup)) this.close();
|
|
9324
9509
|
};
|
|
9325
9510
|
const onKey = (e) => {
|
|
9326
|
-
if (e.key
|
|
9511
|
+
if (e.key !== "Escape") return;
|
|
9512
|
+
this.close();
|
|
9513
|
+
grid.renderer.gridEl.focus();
|
|
9327
9514
|
};
|
|
9328
9515
|
document.addEventListener("pointerdown", onDown, true);
|
|
9329
9516
|
document.addEventListener("keydown", onKey, true);
|
|
@@ -9461,8 +9648,8 @@ var FormatDialog = class {
|
|
|
9461
9648
|
CF_PRESETS.forEach((p, k) => {
|
|
9462
9649
|
const b = el("button", "fg-cf-swatch", { type: "button", "aria-label": cf.styles[p.key], title: cf.styles[p.key], "aria-pressed": String(k === preset) });
|
|
9463
9650
|
b.textContent = p.key === "bold" ? "B" : "Aa";
|
|
9464
|
-
|
|
9465
|
-
|
|
9651
|
+
b.style.background = p.style.background ?? "#ffffff";
|
|
9652
|
+
b.style.color = p.style.color ?? "#1f2430";
|
|
9466
9653
|
b.addEventListener("click", () => {
|
|
9467
9654
|
preset = k;
|
|
9468
9655
|
for (const s of swatches.children) s.setAttribute("aria-pressed", String(s === b));
|
|
@@ -9561,7 +9748,9 @@ var FormatDialog = class {
|
|
|
9561
9748
|
if (!eventInside(e, popup)) this.close();
|
|
9562
9749
|
};
|
|
9563
9750
|
const onKey = (e) => {
|
|
9564
|
-
if (e.key
|
|
9751
|
+
if (e.key !== "Escape") return;
|
|
9752
|
+
this.close();
|
|
9753
|
+
grid.renderer.gridEl.focus();
|
|
9565
9754
|
};
|
|
9566
9755
|
document.addEventListener("pointerdown", onDown, true);
|
|
9567
9756
|
document.addEventListener("keydown", onKey, true);
|
|
@@ -10005,6 +10194,10 @@ var Grid = class {
|
|
|
10005
10194
|
this.sourceDefs = [];
|
|
10006
10195
|
this.pivotCfg = null;
|
|
10007
10196
|
this.pivotData = null;
|
|
10197
|
+
/** rollup option / setRollup: rows merged by the shown columns without an aggFunc. */
|
|
10198
|
+
this.rollupOn = false;
|
|
10199
|
+
/** The merged rows while rollup applies (not while pivoting), else null. */
|
|
10200
|
+
this.rollupData = null;
|
|
10008
10201
|
/** Grouping state from before pivot mode, restored when it ends. */
|
|
10009
10202
|
this.savedGroup = null;
|
|
10010
10203
|
/** 0-based page and rows per page (pagination only). */
|
|
@@ -10071,6 +10264,8 @@ var Grid = class {
|
|
|
10071
10264
|
}
|
|
10072
10265
|
};
|
|
10073
10266
|
this.density = "normal";
|
|
10267
|
+
/** Set by the cellPadding option or setCellPadding; null: the theme / density value. */
|
|
10268
|
+
this.cellPadding = null;
|
|
10074
10269
|
// ── merge, aggregates, fill, pinned rows ────────────────────
|
|
10075
10270
|
/** `sortWithinMerges` is on. */
|
|
10076
10271
|
this.sortWithin = false;
|
|
@@ -10151,6 +10346,7 @@ var Grid = class {
|
|
|
10151
10346
|
this.renderer.applyTheme();
|
|
10152
10347
|
if (options.flashDuration) this.renderer.root.style.setProperty("--fg-flash-duration", `${this.flashMs()}ms`);
|
|
10153
10348
|
this.renderer.applyFont(this.font.size, this.font.family);
|
|
10349
|
+
if (options.cellPadding != null) this.applyCellPadding(options.cellPadding);
|
|
10154
10350
|
this.menu = new ColumnMenu(this);
|
|
10155
10351
|
this.chooser = new ColumnChooserDialog(this);
|
|
10156
10352
|
this.contextMenu = new ContextMenu(this);
|
|
@@ -10186,6 +10382,7 @@ var Grid = class {
|
|
|
10186
10382
|
this.disposers.push(() => ro.disconnect());
|
|
10187
10383
|
}
|
|
10188
10384
|
if (options.pivot) this.setPivot(options.pivot);
|
|
10385
|
+
if (options.rollup) this.setRollup(true);
|
|
10189
10386
|
void needsFreeBadge(options.licenseKey).then((show) => {
|
|
10190
10387
|
if (show && !this.destroyed) this.renderer.showFreeBadge();
|
|
10191
10388
|
});
|
|
@@ -10264,6 +10461,7 @@ var Grid = class {
|
|
|
10264
10461
|
}
|
|
10265
10462
|
/** Column definitions or visibility changed; filters/quick filter may depend on them. */
|
|
10266
10463
|
columnsChanged() {
|
|
10464
|
+
this.rebuildRollup();
|
|
10267
10465
|
this.rowModel.invalidate();
|
|
10268
10466
|
this.updateRows();
|
|
10269
10467
|
this.refreshSummary();
|
|
@@ -10286,7 +10484,7 @@ var Grid = class {
|
|
|
10286
10484
|
}
|
|
10287
10485
|
updateRows() {
|
|
10288
10486
|
const paged = !!this.options.pagination;
|
|
10289
|
-
const data = this.
|
|
10487
|
+
const data = this.viewRows();
|
|
10290
10488
|
this.rowModel.update({ ...this.store.state, data, display: this.display(), page: paged ? { index: this.page, size: this.pageSize } : null });
|
|
10291
10489
|
if (paged && this.page >= this.getPageCount()) {
|
|
10292
10490
|
this.page = this.getPageCount() - 1;
|
|
@@ -10294,9 +10492,63 @@ var Grid = class {
|
|
|
10294
10492
|
}
|
|
10295
10493
|
}
|
|
10296
10494
|
// ── pivot ───────────────────────────────────────────────────
|
|
10297
|
-
/** Rows behind the view: the pivot table while pivoting, else the source data. */
|
|
10495
|
+
/** Rows behind the view: the pivot table while pivoting, the merged rows with rollup, else the source data. */
|
|
10298
10496
|
viewRows() {
|
|
10299
|
-
return this.pivotData ?? this.store.state.data;
|
|
10497
|
+
return this.pivotData ?? this.rollupData ?? this.store.state.data;
|
|
10498
|
+
}
|
|
10499
|
+
// ── rollup ──────────────────────────────────────────────────
|
|
10500
|
+
getRollup() {
|
|
10501
|
+
return this.rollupOn;
|
|
10502
|
+
}
|
|
10503
|
+
setRollup(on) {
|
|
10504
|
+
on = !!on;
|
|
10505
|
+
if (on && !this.allow("pivot")) return;
|
|
10506
|
+
if (on && this.clientOnly("rollup")) return;
|
|
10507
|
+
if (on && this.options.treeData) {
|
|
10508
|
+
warn("rollup is not available with treeData");
|
|
10509
|
+
return;
|
|
10510
|
+
}
|
|
10511
|
+
if (on === this.rollupOn) return;
|
|
10512
|
+
this.editor.cancel();
|
|
10513
|
+
this.rollupOn = on;
|
|
10514
|
+
this.store.set({ range: null, focus: null });
|
|
10515
|
+
this.columnsChanged();
|
|
10516
|
+
}
|
|
10517
|
+
/** Merge the source rows again (rollup on, not pivoting); the view is updated by the caller. */
|
|
10518
|
+
rebuildRollup() {
|
|
10519
|
+
this.rollupData = this.rollupOn && !this.pivotCfg ? buildRollup(this.store.state.data, this.dataColumns().map((c) => c.def)) : null;
|
|
10520
|
+
}
|
|
10521
|
+
/** The source rows behind `rows`: merged rollup rows stand for the rows they merge (for group and summary values). */
|
|
10522
|
+
sourceRowsOf(rows) {
|
|
10523
|
+
return this.rollupData ? rows.flatMap((r) => rollupSource(r) ?? [r]) : rows;
|
|
10524
|
+
}
|
|
10525
|
+
/** Whether a cell can be changed: never on merged rollup rows. */
|
|
10526
|
+
cellEditable(def, row, rowIndex) {
|
|
10527
|
+
return !this.rollupData && cellEditable(def, row, rowIndex);
|
|
10528
|
+
}
|
|
10529
|
+
/** Set or clear a column's aggFunc (null: no aggregate, so with rollup it becomes a column the rows merge by). */
|
|
10530
|
+
setColumnAggFunc(colId, aggFunc) {
|
|
10531
|
+
if (aggFunc !== null && typeof aggFunc !== "function" && !["sum", "avg", "min", "max", "count"].includes(aggFunc)) {
|
|
10532
|
+
warn(`setColumnAggFunc: unknown aggFunc "${String(aggFunc)}"`);
|
|
10533
|
+
return;
|
|
10534
|
+
}
|
|
10535
|
+
let found = false;
|
|
10536
|
+
const map = (defs2) => defs2.map((d) => {
|
|
10537
|
+
if (!d || typeof d !== "object") return d;
|
|
10538
|
+
if (Array.isArray(d.children)) return { ...d, children: map(d.children) };
|
|
10539
|
+
if ((d.id ?? d.field) !== colId) return d;
|
|
10540
|
+
found = true;
|
|
10541
|
+
const next = { ...d };
|
|
10542
|
+
if (aggFunc) next.aggFunc = aggFunc;
|
|
10543
|
+
else delete next.aggFunc;
|
|
10544
|
+
return next;
|
|
10545
|
+
});
|
|
10546
|
+
const defs = map(this.sourceDefs);
|
|
10547
|
+
if (!found) {
|
|
10548
|
+
warn(`setColumnAggFunc: no column "${colId}"`);
|
|
10549
|
+
return;
|
|
10550
|
+
}
|
|
10551
|
+
this.setColumns(defs);
|
|
10300
10552
|
}
|
|
10301
10553
|
/** Leaf columns of the user's definitions (not the pivot columns). */
|
|
10302
10554
|
sourceLeaves() {
|
|
@@ -10354,6 +10606,7 @@ var Grid = class {
|
|
|
10354
10606
|
afterPivotSwitch() {
|
|
10355
10607
|
this.page = 0;
|
|
10356
10608
|
this.store.set({ sort: [], filters: {}, range: null, focus: null });
|
|
10609
|
+
this.rebuildRollup();
|
|
10357
10610
|
this.rowModel.invalidate();
|
|
10358
10611
|
this.updateRows();
|
|
10359
10612
|
this.displayVersion++;
|
|
@@ -10462,12 +10715,31 @@ var Grid = class {
|
|
|
10462
10715
|
} finally {
|
|
10463
10716
|
this.keepRange = false;
|
|
10464
10717
|
}
|
|
10718
|
+
this.clampRanges();
|
|
10465
10719
|
}
|
|
10466
10720
|
this.editor.sync();
|
|
10467
10721
|
if (flashKeys.size && this.options.flashCells !== false) this.flash(flashKeys);
|
|
10468
10722
|
this.events.emit("transactionApplied", result);
|
|
10469
10723
|
return result;
|
|
10470
10724
|
}
|
|
10725
|
+
/** Kept ranges and focus after the row count shrank: cut to the last row, dropped when wholly past it. */
|
|
10726
|
+
clampRanges() {
|
|
10727
|
+
const count = this.rowModel.getRowCount();
|
|
10728
|
+
const { range, extraRanges, focus } = this.store.state;
|
|
10729
|
+
const clamp = (r) => {
|
|
10730
|
+
if (!r || r.start.rowIndex < count && r.end.rowIndex < count) return r;
|
|
10731
|
+
if (Math.min(r.start.rowIndex, r.end.rowIndex) >= count) return null;
|
|
10732
|
+
return { start: { ...r.start, rowIndex: Math.min(r.start.rowIndex, count - 1) }, end: { ...r.end, rowIndex: Math.min(r.end.rowIndex, count - 1) } };
|
|
10733
|
+
};
|
|
10734
|
+
const extras = extraRanges.map(clamp).filter((r) => !!r);
|
|
10735
|
+
if (extras.length !== extraRanges.length || extras.some((r, i) => r !== extraRanges[i])) this.store.set({ extraRanges: extras });
|
|
10736
|
+
if (focus && focus.rowIndex >= count) this.store.set({ focus: count ? { ...focus, rowIndex: count - 1 } : null });
|
|
10737
|
+
const next = clamp(range);
|
|
10738
|
+
if (next !== range) {
|
|
10739
|
+
this.store.set({ range: next });
|
|
10740
|
+
this.events.emit("rangeChange", { range: next && { start: { ...next.start }, end: { ...next.end } } });
|
|
10741
|
+
}
|
|
10742
|
+
}
|
|
10471
10743
|
/** One transaction against `data` (remove → update → add); returns the new array. */
|
|
10472
10744
|
/** Whether rows changed in `fields` could filter, sort, group or move differently. */
|
|
10473
10745
|
viewReads(fields) {
|
|
@@ -10622,14 +10894,24 @@ var Grid = class {
|
|
|
10622
10894
|
}
|
|
10623
10895
|
if (want("groupBy") && Array.isArray(state.groupBy)) this.setGroupBy(state.groupBy.filter(known));
|
|
10624
10896
|
if (want("pivot")) this.setPivot(state.pivot ?? null);
|
|
10625
|
-
|
|
10626
|
-
if (want("
|
|
10627
|
-
const
|
|
10628
|
-
|
|
10629
|
-
this.events.emit("filterChange", { filters: { ...filters } });
|
|
10897
|
+
const query = {};
|
|
10898
|
+
if (want("sort") && Array.isArray(state.sort)) {
|
|
10899
|
+
const sort = this.checkSort(state.sort.filter((x) => x && known(x.colId)));
|
|
10900
|
+
if (sort) query.sort = sort;
|
|
10630
10901
|
}
|
|
10631
|
-
if (want("
|
|
10632
|
-
|
|
10902
|
+
if (want("filters") && state.filters && typeof state.filters === "object") {
|
|
10903
|
+
query.filters = Object.fromEntries(Object.entries(state.filters).filter(([id]) => known(id)));
|
|
10904
|
+
}
|
|
10905
|
+
if (want("advancedFilter")) {
|
|
10906
|
+
const f = state.advancedFilter;
|
|
10907
|
+
const next = f && typeof f === "object" && Array.isArray(f.conditions) && f.conditions.length ? f : null;
|
|
10908
|
+
if (next !== this.store.state.advancedFilter && (!next || this.allow("advancedFilter"))) query.advancedFilter = next;
|
|
10909
|
+
}
|
|
10910
|
+
if (want("quickFilter") && typeof state.quickFilter === "string") query.quickFilter = state.quickFilter;
|
|
10911
|
+
this.store.set(query);
|
|
10912
|
+
if (query.sort) this.events.emit("sortChange", { sort: [...query.sort] });
|
|
10913
|
+
if (query.filters) this.events.emit("filterChange", { filters: { ...query.filters } });
|
|
10914
|
+
if ("advancedFilter" in query) this.events.emit("advancedFilterChange", { advancedFilter: query.advancedFilter ?? null });
|
|
10633
10915
|
if (want("expanded") && state.expanded && typeof state.expanded === "object") {
|
|
10634
10916
|
const expanded = new Map(Object.entries(state.expanded).filter(([, v]) => typeof v === "boolean"));
|
|
10635
10917
|
if (this.savedGroup) this.savedGroup.expanded = expanded;
|
|
@@ -10655,11 +10937,13 @@ var Grid = class {
|
|
|
10655
10937
|
rows.forEach((r, k) => {
|
|
10656
10938
|
nums[k] = r.kind ? 0 : ++n;
|
|
10657
10939
|
});
|
|
10658
|
-
|
|
10940
|
+
const first = this.page * this.pageSize;
|
|
10941
|
+
const offset = this.options.pagination && !this.rowModel.server ? this.rowModel.dataRowsBefore?.(first) ?? first : 0;
|
|
10942
|
+
this.rowNumberCache = { rows, nums, offset };
|
|
10659
10943
|
}
|
|
10660
10944
|
const v = this.rowNumberCache.nums[i];
|
|
10661
10945
|
if (!v) return null;
|
|
10662
|
-
return v +
|
|
10946
|
+
return v + this.rowNumberCache.offset;
|
|
10663
10947
|
}
|
|
10664
10948
|
getPage() {
|
|
10665
10949
|
return this.options.pagination ? this.page : 0;
|
|
@@ -10711,6 +10995,7 @@ var Grid = class {
|
|
|
10711
10995
|
/** Server rows: drop the cache and load again. */
|
|
10712
10996
|
refreshRows() {
|
|
10713
10997
|
if (this.rowModel instanceof ServerRowModel) {
|
|
10998
|
+
this.saveEditBeforeReload();
|
|
10714
10999
|
this.rowModel.purge();
|
|
10715
11000
|
this.renderer.invalidate({ rows: true });
|
|
10716
11001
|
}
|
|
@@ -10720,6 +11005,12 @@ var Grid = class {
|
|
|
10720
11005
|
this.renderer.invalidate({ header: true, rows: true });
|
|
10721
11006
|
this.events.emit("rowsLoaded", total === null ? { start, end } : { start, end, total });
|
|
10722
11007
|
}
|
|
11008
|
+
/** Server rows are about to be dropped: save an open editor to its row first, else it is left over another row. */
|
|
11009
|
+
saveEditBeforeReload() {
|
|
11010
|
+
if (!this.rowModel.server) return;
|
|
11011
|
+
this.editor.endRow(true);
|
|
11012
|
+
if (this.editor.active && !this.editor.commit(null)) this.editor.cancel();
|
|
11013
|
+
}
|
|
10723
11014
|
serverFailed(start, end, error) {
|
|
10724
11015
|
if (this.destroyed) return;
|
|
10725
11016
|
warn(`datasource.getRows failed for rows ${start}\u2013${end}`);
|
|
@@ -10868,7 +11159,7 @@ var Grid = class {
|
|
|
10868
11159
|
let m = this.aggCache.map.get(node.group);
|
|
10869
11160
|
if (!m) this.aggCache.map.set(node.group, m = /* @__PURE__ */ new Map());
|
|
10870
11161
|
if (!m.has(colId)) {
|
|
10871
|
-
const rows = node.group.rows;
|
|
11162
|
+
const rows = this.sourceRowsOf(node.group.rows);
|
|
10872
11163
|
try {
|
|
10873
11164
|
m.set(colId, aggregate(def.aggFunc, rows.map((r) => getCellValue(def, r)), rows));
|
|
10874
11165
|
} catch {
|
|
@@ -11061,10 +11352,33 @@ var Grid = class {
|
|
|
11061
11352
|
this.renderer.invalidateHeights();
|
|
11062
11353
|
this.layoutChanged();
|
|
11063
11354
|
}
|
|
11355
|
+
/** Store and apply the padding; false when the value is not valid. */
|
|
11356
|
+
applyCellPadding(px) {
|
|
11357
|
+
if (px != null && !(typeof px === "number" && Number.isFinite(px) && px >= 0)) {
|
|
11358
|
+
warn("cellPadding must be a number of px, 0 or more");
|
|
11359
|
+
return false;
|
|
11360
|
+
}
|
|
11361
|
+
this.cellPadding = px;
|
|
11362
|
+
if (px == null) this.renderer.root.style.removeProperty("--fg-cell-px");
|
|
11363
|
+
else this.renderer.root.style.setProperty("--fg-cell-px", `${px}px`);
|
|
11364
|
+
return true;
|
|
11365
|
+
}
|
|
11366
|
+
setCellPadding(px) {
|
|
11367
|
+
if (px === this.cellPadding || !this.applyCellPadding(px)) return;
|
|
11368
|
+
this.menu.close();
|
|
11369
|
+
this.layoutChanged();
|
|
11370
|
+
}
|
|
11371
|
+
/** The padding in use: the set value, else the theme / density CSS variable. */
|
|
11372
|
+
getCellPadding() {
|
|
11373
|
+
if (this.cellPadding != null) return this.cellPadding;
|
|
11374
|
+
const v = parseFloat(getComputedStyle(this.renderer.root).getPropertyValue("--fg-cell-px"));
|
|
11375
|
+
return Number.isFinite(v) ? v : 12;
|
|
11376
|
+
}
|
|
11064
11377
|
/** Copy the grid font variables onto an element rendered outside the root (popups, drag ghost). */
|
|
11065
11378
|
applyFontTo(target) {
|
|
11066
11379
|
if (this.font.size) target.style.setProperty("--fg-font-size", `${this.font.size}px`);
|
|
11067
11380
|
if (this.font.family) target.style.setProperty("--fg-font", this.font.family);
|
|
11381
|
+
if (this.cellPadding != null) target.style.setProperty("--fg-cell-px", `${this.cellPadding}px`);
|
|
11068
11382
|
}
|
|
11069
11383
|
/** Current summary configuration and values, or null when there are no summary rows. */
|
|
11070
11384
|
summary() {
|
|
@@ -11093,7 +11407,7 @@ var Grid = class {
|
|
|
11093
11407
|
}
|
|
11094
11408
|
const scope = opts.scope ?? "filtered";
|
|
11095
11409
|
const rows = scope === "all" ? this.rowModel.allNodes().map((n) => n.data) : scope === "selected" ? this.selectedRows() : this.rowModel.dataRows().map((n) => n.data);
|
|
11096
|
-
this.summaryValues = computeSummary(opts.rows, rows, (id) => this.columns.getNode(id)?.def);
|
|
11410
|
+
this.summaryValues = computeSummary(opts.rows, this.sourceRowsOf(rows), (id) => this.columns.getNode(id)?.def);
|
|
11097
11411
|
}
|
|
11098
11412
|
// ── cell ranges ─────────────────────────────────────────────
|
|
11099
11413
|
dataColumns() {
|
|
@@ -11186,12 +11500,11 @@ var Grid = class {
|
|
|
11186
11500
|
out = [];
|
|
11187
11501
|
for (let i = b.r1; i <= b.r2; i++) {
|
|
11188
11502
|
const node = this.rowModel.getRow(i);
|
|
11189
|
-
if (!node.kind) out.push(node.data);
|
|
11503
|
+
if (node && !node.kind) out.push(node.data);
|
|
11190
11504
|
}
|
|
11191
11505
|
cols = displayed.slice(b.c1, b.c2 + 1).filter((c) => !isSystemCol(c.id));
|
|
11192
11506
|
} else if (checkedRows) {
|
|
11193
|
-
|
|
11194
|
-
out = this.rowModel.dataRows().filter((n) => sel.has(n.id)).map((n) => n.data);
|
|
11507
|
+
out = this.shownSelectedRows();
|
|
11195
11508
|
cols = this.dataColumns();
|
|
11196
11509
|
} else {
|
|
11197
11510
|
const f = this.store.state.focus;
|
|
@@ -11246,8 +11559,17 @@ var Grid = class {
|
|
|
11246
11559
|
if (text2) this.clearCells(true);
|
|
11247
11560
|
return text2;
|
|
11248
11561
|
}
|
|
11562
|
+
/** Text a copy puts on the clipboard. Server rows: only the loaded rows, with a warning about the rest. */
|
|
11563
|
+
copyText(headers, rows = false) {
|
|
11564
|
+
const m = this.rowModel;
|
|
11565
|
+
if (!(m instanceof ServerRowModel)) return this.selectionTSV(headers, rows);
|
|
11566
|
+
const text2 = m.withoutLoading(() => this.selectionTSV(headers, rows));
|
|
11567
|
+
const missing = rows ? 0 : m.withoutLoading(() => this.unloadedInRanges());
|
|
11568
|
+
if (missing) warn(`copy: ${missing} row${missing > 1 ? "s" : ""} of the range ${missing > 1 ? "are" : "is"} not loaded and ${missing > 1 ? "were" : "was"} not copied`);
|
|
11569
|
+
return text2;
|
|
11570
|
+
}
|
|
11249
11571
|
copyToClipboard(headers, rows = false) {
|
|
11250
|
-
const text2 = this.
|
|
11572
|
+
const text2 = this.copyText(headers, rows);
|
|
11251
11573
|
if (text2 && typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
|
|
11252
11574
|
try {
|
|
11253
11575
|
navigator.clipboard.writeText(text2)?.catch?.(() => void 0);
|
|
@@ -11256,6 +11578,14 @@ var Grid = class {
|
|
|
11256
11578
|
}
|
|
11257
11579
|
return text2;
|
|
11258
11580
|
}
|
|
11581
|
+
/** Server rows: how many rows the ranges cover that are not loaded (placeholders). */
|
|
11582
|
+
unloadedInRanges() {
|
|
11583
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
11584
|
+
for (const b of this.allRangeBounds()) for (let i = b.r1; i <= b.r2; i++) {
|
|
11585
|
+
if (this.rowModel.getRow(i)?.kind === "loading") seen2.add(i);
|
|
11586
|
+
}
|
|
11587
|
+
return seen2.size;
|
|
11588
|
+
}
|
|
11259
11589
|
pasteText(text2) {
|
|
11260
11590
|
const matrix = parseTSV(text2);
|
|
11261
11591
|
const result = { changed: 0, skipped: 0 };
|
|
@@ -11278,19 +11608,21 @@ var Grid = class {
|
|
|
11278
11608
|
const single = matrix.length === 1 && matrix[0].length === 1;
|
|
11279
11609
|
const rows = single && b ? b.r2 - b.r1 + 1 : matrix.length;
|
|
11280
11610
|
const width = single && b ? b.c2 - b.c1 + 1 : Math.max(...matrix.map((r) => r.length));
|
|
11281
|
-
for (let dr = 0; dr < rows;
|
|
11282
|
-
const ri = r0 + dr;
|
|
11283
|
-
if (ri >= count) break;
|
|
11611
|
+
for (let ri = r0, dr = 0; ri < count && dr < rows; ri++) {
|
|
11284
11612
|
const node = this.rowModel.getRow(ri);
|
|
11285
|
-
if (node.kind)
|
|
11613
|
+
if (node.kind) {
|
|
11614
|
+
if (single && b) dr++;
|
|
11615
|
+
continue;
|
|
11616
|
+
}
|
|
11617
|
+
const line2 = dr++;
|
|
11286
11618
|
for (let dc = 0; dc < width; dc++) {
|
|
11287
11619
|
const col = displayed[c0 + dc];
|
|
11288
11620
|
if (!col) break;
|
|
11289
11621
|
if (isSystemCol(col.id)) continue;
|
|
11290
|
-
const raw = single && b ? matrix[0][0] : matrix[
|
|
11622
|
+
const raw = single && b ? matrix[0][0] : matrix[line2]?.[dc];
|
|
11291
11623
|
if (raw === void 0) continue;
|
|
11292
11624
|
const def = col.def;
|
|
11293
|
-
if (!def.field || !cellEditable(def, node.data, ri)) {
|
|
11625
|
+
if (!def.field || !this.cellEditable(def, node.data, ri)) {
|
|
11294
11626
|
result.skipped++;
|
|
11295
11627
|
continue;
|
|
11296
11628
|
}
|
|
@@ -11358,7 +11690,7 @@ var Grid = class {
|
|
|
11358
11690
|
const id = this.rowModel.idOf(row);
|
|
11359
11691
|
const rowIndex = this.rowModel.indexOfId(id);
|
|
11360
11692
|
for (const c of cols) {
|
|
11361
|
-
if (!cellEditable(c.def, row, rowIndex < 0 ? i : rowIndex)) continue;
|
|
11693
|
+
if (!this.cellEditable(c.def, row, rowIndex < 0 ? i : rowIndex)) continue;
|
|
11362
11694
|
const message = this.cellError(c.def, row, row[c.def.field]);
|
|
11363
11695
|
if (message !== null) out.push({ row, rowIndex, colId: c.id, message });
|
|
11364
11696
|
}
|
|
@@ -11623,26 +11955,36 @@ var Grid = class {
|
|
|
11623
11955
|
const col = displayed[c];
|
|
11624
11956
|
const node = this.rowModel.getRow(r);
|
|
11625
11957
|
const def = col?.def;
|
|
11626
|
-
if (!node || node.kind || !def?.field || isSystemCol(col.id) || !cellEditable(def, node.data, r)) return;
|
|
11958
|
+
if (!node || node.kind || !def?.field || isSystemCol(col.id) || !this.cellEditable(def, node.data, r)) return;
|
|
11627
11959
|
if (this.cellError(def, node.data, value2) !== null) return;
|
|
11628
11960
|
this.writeCell(changes, node.data, def.field, col.id, r, value2);
|
|
11629
11961
|
};
|
|
11630
11962
|
const value = (r, c) => getCellValue(displayed[c].def, this.rowModel.getRow(r).data);
|
|
11963
|
+
const dataRow = (r) => {
|
|
11964
|
+
const node = this.rowModel.getRow(r);
|
|
11965
|
+
return !!node && !node.kind;
|
|
11966
|
+
};
|
|
11967
|
+
const keep = (from, to, ok) => {
|
|
11968
|
+
const out = [];
|
|
11969
|
+
for (let i = from; i <= to; i++) if (ok(i)) out.push(i);
|
|
11970
|
+
return out;
|
|
11971
|
+
};
|
|
11972
|
+
const dataCol = (c) => !!displayed[c] && !isSystemCol(displayed[c].id);
|
|
11631
11973
|
if (t.r1 < src.r1 || t.r2 > src.r2) {
|
|
11974
|
+
const down = keep(src.r2 + 1, t.r2, dataRow), up = keep(t.r1, src.r1 - 1, dataRow).reverse();
|
|
11975
|
+
const rows = keep(src.r1, src.r2, dataRow);
|
|
11632
11976
|
for (let c = src.c1; c <= src.c2; c++) {
|
|
11633
|
-
const
|
|
11634
|
-
|
|
11635
|
-
|
|
11636
|
-
fillSeries(down, t.r2 - src.r2).forEach((v, k) => write(src.r2 + 1 + k, c, v));
|
|
11637
|
-
fillSeries(up, src.r1 - t.r1).forEach((v, k) => write(src.r1 - 1 - k, c, v));
|
|
11977
|
+
const seed = rows.map((r) => value(r, c));
|
|
11978
|
+
fillSeries(seed, down.length).forEach((v, k) => write(down[k], c, v));
|
|
11979
|
+
fillSeries([...seed].reverse(), up.length).forEach((v, k) => write(up[k], c, v));
|
|
11638
11980
|
}
|
|
11639
11981
|
} else if (t.c1 < src.c1 || t.c2 > src.c2) {
|
|
11640
|
-
|
|
11641
|
-
|
|
11642
|
-
|
|
11643
|
-
|
|
11644
|
-
fillSeries(
|
|
11645
|
-
fillSeries(
|
|
11982
|
+
const right = keep(src.c2 + 1, t.c2, dataCol), left = keep(t.c1, src.c1 - 1, dataCol).reverse();
|
|
11983
|
+
const cols = keep(src.c1, src.c2, dataCol);
|
|
11984
|
+
for (const r of keep(src.r1, src.r2, dataRow)) {
|
|
11985
|
+
const seed = cols.map((c) => value(r, c));
|
|
11986
|
+
fillSeries(seed, right.length).forEach((v, k) => write(r, right[k], v));
|
|
11987
|
+
fillSeries([...seed].reverse(), left.length).forEach((v, k) => write(r, left[k], v));
|
|
11646
11988
|
}
|
|
11647
11989
|
} else return;
|
|
11648
11990
|
this.endCellTx(changes);
|
|
@@ -11711,7 +12053,7 @@ var Grid = class {
|
|
|
11711
12053
|
const node = this.rowModel.getRow(r);
|
|
11712
12054
|
for (let c = box.c1; c <= box.c2; c++) {
|
|
11713
12055
|
const def = displayed[c]?.def;
|
|
11714
|
-
if (node && !node.kind && def?.field && cellEditable(def, node.data, r) && (!cut || this.copyAllowed(def, node.data))) this.writeCell(changes, node.data, def.field, displayed[c].id, r, null);
|
|
12056
|
+
if (node && !node.kind && def?.field && this.cellEditable(def, node.data, r) && (!cut || this.copyAllowed(def, node.data))) this.writeCell(changes, node.data, def.field, displayed[c].id, r, null);
|
|
11715
12057
|
}
|
|
11716
12058
|
}
|
|
11717
12059
|
this.endCellTx(changes);
|
|
@@ -11865,8 +12207,9 @@ var Grid = class {
|
|
|
11865
12207
|
const cols = (ids ? ids.map((id) => this.columns.getColumn(id)) : this.columns.displayed()).filter((c) => !!c && isResizable(c.def));
|
|
11866
12208
|
const { first, last } = this.renderer.renderedRange();
|
|
11867
12209
|
const code = this.store.state.locale.code;
|
|
11868
|
-
const
|
|
11869
|
-
const
|
|
12210
|
+
const pad4 = this.getCellPadding() * 2;
|
|
12211
|
+
const HEADER_EXTRA = pad4 + 22 + 6 + 14;
|
|
12212
|
+
const CELL_EXTRA = pad4;
|
|
11870
12213
|
for (const col of cols) {
|
|
11871
12214
|
let w = this.renderer.measureText(col.def.header ?? col.def.field ?? "", true) + HEADER_EXTRA;
|
|
11872
12215
|
const fmt = getFormatter(col.def, code);
|
|
@@ -11884,6 +12227,13 @@ var Grid = class {
|
|
|
11884
12227
|
this.columnsChanged();
|
|
11885
12228
|
}
|
|
11886
12229
|
setSort(sort) {
|
|
12230
|
+
const valid = this.checkSort(sort);
|
|
12231
|
+
if (!valid) return;
|
|
12232
|
+
this.store.set({ sort: valid });
|
|
12233
|
+
this.events.emit("sortChange", { sort: [...valid] });
|
|
12234
|
+
}
|
|
12235
|
+
/** The known, well-formed sort items, or null when a beforeSort handler refused them. */
|
|
12236
|
+
checkSort(sort) {
|
|
11887
12237
|
const valid = sort.filter((s) => {
|
|
11888
12238
|
const node = this.columns.getNode(s.colId);
|
|
11889
12239
|
if (!node || node.children) {
|
|
@@ -11892,9 +12242,7 @@ var Grid = class {
|
|
|
11892
12242
|
}
|
|
11893
12243
|
return s.dir === "asc" || s.dir === "desc";
|
|
11894
12244
|
});
|
|
11895
|
-
|
|
11896
|
-
this.store.set({ sort: valid });
|
|
11897
|
-
this.events.emit("sortChange", { sort: [...valid] });
|
|
12245
|
+
return this.veto("beforeSort", { sort: valid.map((s) => ({ ...s })) }) ? null : valid;
|
|
11898
12246
|
}
|
|
11899
12247
|
toggleSort(colId, additive) {
|
|
11900
12248
|
const cur = this.store.state.sort;
|
|
@@ -12064,6 +12412,15 @@ var Grid = class {
|
|
|
12064
12412
|
const sel = this.store.state.selected;
|
|
12065
12413
|
return sel.size ? this.rowModel.allNodes().filter((n) => sel.has(n.id)).map((n) => n.data) : [];
|
|
12066
12414
|
}
|
|
12415
|
+
/** Filtered data rows in display order (group buckets, parents before children), collapsed ones included. */
|
|
12416
|
+
orderedDataRows() {
|
|
12417
|
+
return this.rowModel.orderedDataRows?.() ?? this.rowModel.dataRows();
|
|
12418
|
+
}
|
|
12419
|
+
/** Checked rows that pass the filters, in display order: what copy, export and delete of the checked rows act on. */
|
|
12420
|
+
shownSelectedRows() {
|
|
12421
|
+
const sel = this.store.state.selected;
|
|
12422
|
+
return sel.size ? this.orderedDataRows().filter((n) => sel.has(n.id)).map((n) => n.data) : [];
|
|
12423
|
+
}
|
|
12067
12424
|
withSelect(defs) {
|
|
12068
12425
|
const sys = [];
|
|
12069
12426
|
const rn = this.options.rowNumbers;
|
|
@@ -12135,12 +12492,26 @@ var Grid = class {
|
|
|
12135
12492
|
});
|
|
12136
12493
|
this.columnsChanged();
|
|
12137
12494
|
}
|
|
12495
|
+
/** Close every popup of this grid (menus and dialogs); focus that was in one goes back to the grid. */
|
|
12496
|
+
closePopups() {
|
|
12497
|
+
const r = this.renderer.root.getRootNode();
|
|
12498
|
+
const inPopup = !!(r.activeElement ?? document.activeElement)?.closest(".fg-menu");
|
|
12499
|
+
this.menu.close();
|
|
12500
|
+
this.chooser.close();
|
|
12501
|
+
this.contextMenu.close();
|
|
12502
|
+
this.filterBuilder.close();
|
|
12503
|
+
this.formatDialog.close();
|
|
12504
|
+
this.assistantPanel.close();
|
|
12505
|
+
if (inPopup) this.renderer.gridEl.focus({ preventScroll: true });
|
|
12506
|
+
}
|
|
12138
12507
|
onChange(keys) {
|
|
12139
12508
|
const has = (...k) => k.some((x) => keys.includes(x));
|
|
12509
|
+
if (has("sort", "filters", "quickFilter", "advancedFilter")) this.saveEditBeforeReload();
|
|
12140
12510
|
if (this.pivotCfg && has("data", "locale")) this.rebuildPivot(false);
|
|
12511
|
+
if (this.rollupOn && has("data")) this.rebuildRollup();
|
|
12512
|
+
if (has("locale", "theme")) this.closePopups();
|
|
12141
12513
|
if (has("locale")) {
|
|
12142
|
-
this.
|
|
12143
|
-
this.chooser.close();
|
|
12514
|
+
this.finder.relabel();
|
|
12144
12515
|
this.sideBar?.refresh();
|
|
12145
12516
|
this.rowModel.invalidate();
|
|
12146
12517
|
}
|
|
@@ -12245,6 +12616,11 @@ var Grid = class {
|
|
|
12245
12616
|
setTheme: guard((t) => this.store.set({ theme: t })),
|
|
12246
12617
|
setLocale: guard((l) => this.store.set({ locale: resolveLocale(l) })),
|
|
12247
12618
|
setFont: guard((f) => this.setFont(f)),
|
|
12619
|
+
setCellPadding: guard((px) => this.setCellPadding(px)),
|
|
12620
|
+
getCellPadding: guard(() => this.getCellPadding()),
|
|
12621
|
+
setRollup: guard((on) => this.setRollup(on)),
|
|
12622
|
+
getRollup: guard(() => this.getRollup()),
|
|
12623
|
+
setColumnAggFunc: guard((id, agg) => this.setColumnAggFunc(id, agg)),
|
|
12248
12624
|
setColumnVisible: guard((id, v) => this.setColumnsVisible([id], v)),
|
|
12249
12625
|
autoSizeColumns: guard((ids) => this.autoSize(ids)),
|
|
12250
12626
|
resetColumnState: guard(() => this.resetColumns()),
|