@freegridjs/core 1.8.0 → 1.9.1
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/LICENSE +63 -29
- package/README.md +19 -4
- package/dist/cdn/freegrid.esm.js +20 -18
- package/dist/cdn/freegrid.min.js +25 -23
- package/dist/index.d.ts +12 -7
- package/dist/index.js +288 -81
- package/dist/locales/de.d.ts +1 -1
- package/dist/locales/en.d.ts +1 -1
- package/dist/locales/es.d.ts +1 -1
- package/dist/locales/fr.d.ts +1 -1
- package/dist/locales/id.d.ts +1 -1
- package/dist/locales/it.d.ts +1 -1
- package/dist/locales/ja.d.ts +1 -1
- package/dist/locales/ko.d.ts +1 -1
- package/dist/locales/pt-BR.d.ts +1 -1
- package/dist/locales/ru.d.ts +1 -1
- package/dist/locales/th.d.ts +1 -1
- package/dist/locales/vi.d.ts +1 -1
- package/dist/locales/zh-CN.d.ts +1 -1
- package/dist/locales/zh-TW.d.ts +1 -1
- package/dist/{types-Cda4EHUz.d.ts → types-Du3F8mqD.d.ts} +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1296,6 +1296,7 @@ function columnFormulaValue(def, row) {
|
|
|
1296
1296
|
if (scope) return valueIn(scope, cacheOf(scope), row, def.field);
|
|
1297
1297
|
return run(row[def.field], { row, scope, seen: /* @__PURE__ */ new Set([def.field]), depth: 0, memo: /* @__PURE__ */ new Map() });
|
|
1298
1298
|
}
|
|
1299
|
+
var formulasOff = (def) => !!scopes.get(def)?.off?.();
|
|
1299
1300
|
var isFormula = (v) => typeof v === "string" && v.length > 1 && v.startsWith("=");
|
|
1300
1301
|
function formulaRefs(formula) {
|
|
1301
1302
|
let n;
|
|
@@ -1327,10 +1328,10 @@ function getCellValue(def, row) {
|
|
|
1327
1328
|
return void 0;
|
|
1328
1329
|
}
|
|
1329
1330
|
}
|
|
1330
|
-
if (typeof def.formula === "string" && isFormula(def.formula)) return columnFormulaValue(def, row);
|
|
1331
|
+
if (typeof def.formula === "string" && isFormula(def.formula) && !formulasOff(def)) return columnFormulaValue(def, row);
|
|
1331
1332
|
if (def.field == null) return void 0;
|
|
1332
1333
|
const raw = row[def.field];
|
|
1333
|
-
return def.formulas && isFormula(raw) ? columnFormulaValue(def, row) : raw;
|
|
1334
|
+
return def.formulas && isFormula(raw) && !formulasOff(def) ? columnFormulaValue(def, row) : raw;
|
|
1334
1335
|
}
|
|
1335
1336
|
|
|
1336
1337
|
// src/interactions/filterRow.ts
|
|
@@ -3416,6 +3417,8 @@ function nextFocus(key, mods, p, s) {
|
|
|
3416
3417
|
|
|
3417
3418
|
// src/registry.ts
|
|
3418
3419
|
var liveGrids = /* @__PURE__ */ new Map();
|
|
3420
|
+
var apiGrids = /* @__PURE__ */ new WeakMap();
|
|
3421
|
+
var gridOfApi = (api) => api ? apiGrids.get(api) : void 0;
|
|
3419
3422
|
var gridOfRoot = (root) => root ? liveGrids.get(root) : void 0;
|
|
3420
3423
|
|
|
3421
3424
|
// src/interactions/body.ts
|
|
@@ -3450,6 +3453,7 @@ function attachBody(grid) {
|
|
|
3450
3453
|
const keyOf = (e) => mirrored(grid, e);
|
|
3451
3454
|
let lastPointer = "mouse";
|
|
3452
3455
|
let pressTimer = 0;
|
|
3456
|
+
let endGesture = null;
|
|
3453
3457
|
let suppressClick = false;
|
|
3454
3458
|
const toEvent = (e) => {
|
|
3455
3459
|
const hit = renderer.cellAt(e.target);
|
|
@@ -3492,7 +3496,7 @@ function attachBody(grid) {
|
|
|
3492
3496
|
const data = grid.columns.displayed().filter((c) => !isSystemCol(c.id));
|
|
3493
3497
|
if (data.length) {
|
|
3494
3498
|
grid.setFocus(ev.rowIndex, data[0].id);
|
|
3495
|
-
grid.setRange({ start: { rowIndex: ev.rowIndex, colId: data[0].id }, end: { rowIndex: ev.rowIndex, colId: data[data.length - 1].id } });
|
|
3499
|
+
if (grid.rangesOn()) grid.setRange({ start: { rowIndex: ev.rowIndex, colId: data[0].id }, end: { rowIndex: ev.rowIndex, colId: data[data.length - 1].id } });
|
|
3496
3500
|
}
|
|
3497
3501
|
return;
|
|
3498
3502
|
}
|
|
@@ -3501,9 +3505,9 @@ function attachBody(grid) {
|
|
|
3501
3505
|
const prev = grid.store.state.focus;
|
|
3502
3506
|
const onBox = ev.colId === SELECT_COL_ID;
|
|
3503
3507
|
if (dragged) {
|
|
3504
|
-
} else if (e.shiftKey && prev && !onBox && !isSystemCol(prev.colId) && grid.
|
|
3508
|
+
} else if (e.shiftKey && prev && !onBox && !isSystemCol(prev.colId) && grid.rangesOn()) {
|
|
3505
3509
|
grid.setRange({ start: prev, end: { rowIndex: ev.rowIndex, colId: ev.colId } }, true);
|
|
3506
|
-
} else if ((e.ctrlKey || e.metaKey) && !onBox && !isSystemCol(ev.colId) && grid.
|
|
3510
|
+
} else if ((e.ctrlKey || e.metaKey) && !onBox && !isSystemCol(ev.colId) && grid.rangesOn()) {
|
|
3507
3511
|
const at = { rowIndex: ev.rowIndex, colId: ev.colId };
|
|
3508
3512
|
grid.addRange({ start: at, end: at });
|
|
3509
3513
|
grid.setFocus(ev.rowIndex, ev.colId);
|
|
@@ -3569,7 +3573,7 @@ function attachBody(grid) {
|
|
|
3569
3573
|
grid.selectAllCells();
|
|
3570
3574
|
return true;
|
|
3571
3575
|
case "find":
|
|
3572
|
-
if (grid.options.findBar === false) return false;
|
|
3576
|
+
if (grid.options.findBar === false || !grid.paid) return false;
|
|
3573
3577
|
grid.finder.openBar();
|
|
3574
3578
|
return true;
|
|
3575
3579
|
case "paste":
|
|
@@ -3672,6 +3676,7 @@ function attachBody(grid) {
|
|
|
3672
3676
|
window.removeEventListener("pointermove", move);
|
|
3673
3677
|
window.removeEventListener("pointerup", cancel);
|
|
3674
3678
|
window.removeEventListener("pointercancel", cancel);
|
|
3679
|
+
if (endGesture === cancel) endGesture = null;
|
|
3675
3680
|
};
|
|
3676
3681
|
const move = (ev) => {
|
|
3677
3682
|
if (Math.hypot(ev.clientX - x0, ev.clientY - y0) > 8) cancel();
|
|
@@ -3679,7 +3684,7 @@ function attachBody(grid) {
|
|
|
3679
3684
|
clearTimeout(pressTimer);
|
|
3680
3685
|
pressTimer = window.setTimeout(() => {
|
|
3681
3686
|
cancel();
|
|
3682
|
-
if (grid.
|
|
3687
|
+
if (!grid.contextMenu.enabled()) return;
|
|
3683
3688
|
suppressClick = true;
|
|
3684
3689
|
if (!isSystemCol(hit.colId)) {
|
|
3685
3690
|
grid.setFocus(hit.rowIndex, hit.colId);
|
|
@@ -3687,6 +3692,8 @@ function attachBody(grid) {
|
|
|
3687
3692
|
}
|
|
3688
3693
|
grid.contextMenu.open(x0, y0, hit.rowIndex, hit.colId);
|
|
3689
3694
|
}, 550);
|
|
3695
|
+
endGesture?.();
|
|
3696
|
+
endGesture = cancel;
|
|
3690
3697
|
window.addEventListener("pointermove", move);
|
|
3691
3698
|
window.addEventListener("pointerup", cancel);
|
|
3692
3699
|
window.addEventListener("pointercancel", cancel);
|
|
@@ -3698,7 +3705,7 @@ function attachBody(grid) {
|
|
|
3698
3705
|
return;
|
|
3699
3706
|
}
|
|
3700
3707
|
if (e.button === 0 && onHandleDown(e)) return;
|
|
3701
|
-
if (grid.
|
|
3708
|
+
if (!grid.rangesOn()) return;
|
|
3702
3709
|
if (e.button !== 0 || e.shiftKey || e.target.closest("input, a, button")) return;
|
|
3703
3710
|
const start = renderer.cellAt(e.target);
|
|
3704
3711
|
if (!start || isSystemCol(start.colId)) return;
|
|
@@ -3720,11 +3727,16 @@ function attachBody(grid) {
|
|
|
3720
3727
|
const up = () => {
|
|
3721
3728
|
window.removeEventListener("pointermove", move);
|
|
3722
3729
|
window.removeEventListener("pointerup", up);
|
|
3730
|
+
window.removeEventListener("pointercancel", up);
|
|
3723
3731
|
root.classList.remove("fg-range-dragging");
|
|
3724
3732
|
if (dragging) suppressClick = true;
|
|
3733
|
+
if (endGesture === up) endGesture = null;
|
|
3725
3734
|
};
|
|
3735
|
+
endGesture?.();
|
|
3736
|
+
endGesture = up;
|
|
3726
3737
|
window.addEventListener("pointermove", move);
|
|
3727
3738
|
window.addEventListener("pointerup", up);
|
|
3739
|
+
window.addEventListener("pointercancel", up);
|
|
3728
3740
|
};
|
|
3729
3741
|
const onKeyDown = (e) => {
|
|
3730
3742
|
if (e.target !== root && e.target !== renderer.gridEl) return;
|
|
@@ -3746,7 +3758,7 @@ function attachBody(grid) {
|
|
|
3746
3758
|
grid.setRange(null);
|
|
3747
3759
|
return;
|
|
3748
3760
|
}
|
|
3749
|
-
if (ctrl && e.key.toLowerCase() === "a" && grid.
|
|
3761
|
+
if (ctrl && e.key.toLowerCase() === "a" && grid.rangesOn()) {
|
|
3750
3762
|
e.preventDefault();
|
|
3751
3763
|
grid.selectAllCells();
|
|
3752
3764
|
return;
|
|
@@ -3763,7 +3775,7 @@ function attachBody(grid) {
|
|
|
3763
3775
|
}
|
|
3764
3776
|
const size = { rows: count, cols: cols.length, pageRows: renderer.pageRows() };
|
|
3765
3777
|
const firstData = cols.findIndex((c) => !isSystemCol(c.id));
|
|
3766
|
-
const ranges = grid.
|
|
3778
|
+
const ranges = grid.rangesOn();
|
|
3767
3779
|
if (ranges && e.shiftKey && e.key !== "Tab" && NAV_KEYS.has(e.key)) {
|
|
3768
3780
|
const anchor = f ?? { rowIndex: 0, colId: cols[firstData].id };
|
|
3769
3781
|
const range = grid.store.state.range;
|
|
@@ -3823,6 +3835,8 @@ function attachBody(grid) {
|
|
|
3823
3835
|
root.addEventListener("paste", onPaste);
|
|
3824
3836
|
root.addEventListener("cut", onCut);
|
|
3825
3837
|
return () => {
|
|
3838
|
+
clearTimeout(pressTimer);
|
|
3839
|
+
endGesture?.();
|
|
3826
3840
|
body.removeEventListener("click", onClick);
|
|
3827
3841
|
body.removeEventListener("dblclick", onDblClick);
|
|
3828
3842
|
body.removeEventListener("pointerdown", onPointerDown);
|
|
@@ -4264,6 +4278,10 @@ var ContextMenu = class {
|
|
|
4264
4278
|
this.close();
|
|
4265
4279
|
this.detach();
|
|
4266
4280
|
}
|
|
4281
|
+
/** The cell menu is on: not switched off and the paid feature allowed (closed: the browser's menu shows). */
|
|
4282
|
+
enabled() {
|
|
4283
|
+
return this.grid.options.contextMenu !== false && this.grid.allow("contextMenu");
|
|
4284
|
+
}
|
|
4267
4285
|
onContextMenu(e) {
|
|
4268
4286
|
const { grid } = this;
|
|
4269
4287
|
if (grid.options.contextMenu === false) return;
|
|
@@ -4278,7 +4296,7 @@ var ContextMenu = class {
|
|
|
4278
4296
|
return;
|
|
4279
4297
|
}
|
|
4280
4298
|
const hit = grid.renderer.cellAt(target);
|
|
4281
|
-
if (!hit) return;
|
|
4299
|
+
if (!hit || !this.enabled()) return;
|
|
4282
4300
|
e.preventDefault();
|
|
4283
4301
|
grid.renderer.gridEl.focus({ preventScroll: true });
|
|
4284
4302
|
if (!isSystemCol(hit.colId) && !grid.rangeContains(hit.rowIndex, hit.colId)) {
|
|
@@ -4290,7 +4308,7 @@ var ContextMenu = class {
|
|
|
4290
4308
|
/** Keyboard: Shift+F10 or the ContextMenu key. */
|
|
4291
4309
|
openAtFocus() {
|
|
4292
4310
|
const f = this.grid.store.state.focus;
|
|
4293
|
-
if (!f || this.
|
|
4311
|
+
if (!f || !this.enabled()) return;
|
|
4294
4312
|
const r = this.grid.renderer.root.getBoundingClientRect();
|
|
4295
4313
|
const cell = this.grid.renderer.root.querySelector(`.fg-row[data-row="${f.rowIndex}"] .fg-cell[data-col="${CSS.escape(f.colId)}"]`);
|
|
4296
4314
|
const box = cell?.getBoundingClientRect() ?? r;
|
|
@@ -4333,7 +4351,7 @@ var ContextMenu = class {
|
|
|
4333
4351
|
if (grid.options.rowSelection === "multiple") items.push({ label: loc.selectAllRows, action: () => grid.api.selectAll() });
|
|
4334
4352
|
items.push({ label: loc.chooseColumns, action: () => grid.chooser.open() });
|
|
4335
4353
|
const b = grid.rangeBounds();
|
|
4336
|
-
if (b && (b.r2 > b.r1 || b.c2 > b.c1)) {
|
|
4354
|
+
if (b && (b.r2 > b.r1 || b.c2 > b.c1) && grid.paid) {
|
|
4337
4355
|
items.push(
|
|
4338
4356
|
"separator",
|
|
4339
4357
|
{ label: loc.chartBar, action: () => grid.api.createChart({ type: "bar" }) },
|
|
@@ -4344,12 +4362,12 @@ var ContextMenu = class {
|
|
|
4344
4362
|
items.push(
|
|
4345
4363
|
"separator",
|
|
4346
4364
|
{ label: loc.exportCsv, action: () => grid.api.exportCsv() },
|
|
4347
|
-
{ label: loc.exportExcel, action: () => grid.api.exportXlsx() },
|
|
4365
|
+
...grid.paid ? [{ label: loc.exportExcel, action: () => grid.api.exportXlsx() }] : [],
|
|
4348
4366
|
{ label: loc.exportJson, action: () => grid.api.exportJson() },
|
|
4349
|
-
...grid.options.assistant?.url ? [{ label: `${loc.ai.title}\u2026`, action: () => grid.api.openAssistant() }] : [],
|
|
4350
|
-
{ label: loc.exportPdf, action: () => grid.api.exportPdf() }
|
|
4367
|
+
...grid.options.assistant?.url && grid.paid ? [{ label: `${loc.ai.title}\u2026`, action: () => grid.api.openAssistant() }] : [],
|
|
4368
|
+
...grid.paid ? [{ label: loc.exportPdf, action: () => grid.api.exportPdf() }] : []
|
|
4351
4369
|
);
|
|
4352
|
-
if (grid.options.advancedFilter !== false && !grid.options.pivot) items.push("separator", { label: `${loc.advancedFilter}\u2026`, action: () => grid.filterBuilder.open() });
|
|
4370
|
+
if (grid.options.advancedFilter !== false && !grid.options.pivot && grid.paid) items.push("separator", { label: `${loc.advancedFilter}\u2026`, action: () => grid.filterBuilder.open() });
|
|
4353
4371
|
items.push("separator", { label: loc.print, action: () => grid.api.print() });
|
|
4354
4372
|
return items;
|
|
4355
4373
|
}
|
|
@@ -4492,8 +4510,7 @@ var FillHandle = class {
|
|
|
4492
4510
|
this.handle.addEventListener("pointerdown", this.onDown);
|
|
4493
4511
|
}
|
|
4494
4512
|
enabled() {
|
|
4495
|
-
|
|
4496
|
-
return o.fillHandle !== false && o.rangeSelection !== false;
|
|
4513
|
+
return this.grid.options.fillHandle !== false && this.grid.rangesOn();
|
|
4497
4514
|
}
|
|
4498
4515
|
/** Current source block: the range, or the focused cell. */
|
|
4499
4516
|
source() {
|
|
@@ -4670,7 +4687,7 @@ var Finder = class {
|
|
|
4670
4687
|
this.countEl.textContent = !this.query ? "" : this.matches.length ? `${this.index + 1}/${this.matches.length}` : loc.noMatches;
|
|
4671
4688
|
}
|
|
4672
4689
|
openBar() {
|
|
4673
|
-
if (this.grid.options.findBar === false) return;
|
|
4690
|
+
if (this.grid.options.findBar === false || !this.grid.paid) return;
|
|
4674
4691
|
if (this.bar) {
|
|
4675
4692
|
this.bar.querySelector("input").focus();
|
|
4676
4693
|
return;
|
|
@@ -7603,12 +7620,36 @@ function buildPivot(source, config, defOf, labels, locale) {
|
|
|
7603
7620
|
return { columns: [...rowColumns, ...valueColumns], rows, groupBy: cfg.rows.slice(0, -1) };
|
|
7604
7621
|
}
|
|
7605
7622
|
|
|
7623
|
+
// src/features.ts
|
|
7624
|
+
var PAID_FEATURES = {
|
|
7625
|
+
grouping: { en: "Row grouping and aggregation", ko: "\uD589 \uADF8\uB8F9\xB7\uC9D1\uACC4" },
|
|
7626
|
+
pivot: { en: "Pivot", ko: "\uD53C\uBC97" },
|
|
7627
|
+
charts: { en: "Charts", ko: "\uCC28\uD2B8" },
|
|
7628
|
+
range: { en: "Cell range selection", ko: "\uC140 \uBC94\uC704 \uC120\uD0DD" },
|
|
7629
|
+
clipboard: { en: "Range copy and paste", ko: "\uBC94\uC704 \uBCF5\uC0AC\xB7\uBD99\uC5EC\uB123\uAE30" },
|
|
7630
|
+
fill: { en: "Fill handle", ko: "\uCC44\uC6B0\uAE30 \uD578\uB4E4" },
|
|
7631
|
+
excel: { en: "Excel export", ko: "\uC5D1\uC140 \uB0B4\uBCF4\uB0B4\uAE30" },
|
|
7632
|
+
pdf: { en: "PDF export", ko: "PDF \uB0B4\uBCF4\uB0B4\uAE30" },
|
|
7633
|
+
serverGroups: { en: "Server-side groups", ko: "\uC11C\uBC84 \uADF8\uB8F9" },
|
|
7634
|
+
advancedFilter: { en: "Advanced filter", ko: "\uACE0\uAE09 \uD544\uD130" },
|
|
7635
|
+
sideBar: { en: "Side bar panels", ko: "\uC0AC\uC774\uB4DC\uBC14 \uD328\uB110" },
|
|
7636
|
+
contextMenu: { en: "Context menu", ko: "\uCEE8\uD14D\uC2A4\uD2B8 \uBA54\uB274" },
|
|
7637
|
+
summary: { en: "Summary rows", ko: "\uD569\uACC4 \uD589" },
|
|
7638
|
+
formulas: { en: "Formulas", ko: "\uC218\uC2DD" },
|
|
7639
|
+
find: { en: "Find", ko: "\uCC3E\uAE30" },
|
|
7640
|
+
conditional: { en: "Conditional formatting", ko: "\uC870\uAC74\uBD80 \uC11C\uC2DD" },
|
|
7641
|
+
assistant: { en: "AI assistant", ko: "AI \uC5B4\uC2DC\uC2A4\uD134\uD2B8" },
|
|
7642
|
+
merge: { en: "Merged cells", ko: "\uC140 \uBCD1\uD569" },
|
|
7643
|
+
workbook: { en: "Workbook", ko: "\uC6CC\uD06C\uBD81" }
|
|
7644
|
+
};
|
|
7645
|
+
|
|
7606
7646
|
// src/version.ts
|
|
7607
|
-
var version = "1.
|
|
7647
|
+
var version = "1.9.1";
|
|
7608
7648
|
|
|
7609
7649
|
// src/license.ts
|
|
7610
7650
|
var PUBLIC_KEY = { kty: "EC", crv: "P-256", x: "sUTKkglZmk-HMKPNub8p7AeLBKesHCU8irIkw9rJlbE", y: "j0U_aKRDR7iApY9UpaD3hUemhBLZJwDv9-QiT_hUyw8" };
|
|
7611
7651
|
var PRICING_URL = "https://freegrid.app/pricing/";
|
|
7652
|
+
var PERSONAL_URL = "https://freegrid.app/license/personal/";
|
|
7612
7653
|
var USAGE_URL = "https://freegrid.app/api/usage";
|
|
7613
7654
|
var STATUS_URL = "https://freegrid.app/api/domain-status";
|
|
7614
7655
|
var majorOf = (v) => Number.parseInt(String(v).split(".")[0], 10);
|
|
@@ -7618,17 +7659,21 @@ var b64urlDecode = (s) => {
|
|
|
7618
7659
|
};
|
|
7619
7660
|
function isDevHost(host) {
|
|
7620
7661
|
const h = host.toLowerCase().replace(/^\[|\]$/g, "");
|
|
7621
|
-
|
|
7662
|
+
if (!h || h === "localhost" || h === "127.0.0.1" || h === "::1" || h === "0.0.0.0" || h.endsWith(".localhost") || h.endsWith(".test") || h.endsWith(".local")) return true;
|
|
7663
|
+
const ip = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(h);
|
|
7664
|
+
if (!ip) return false;
|
|
7665
|
+
const [a, b, c, d] = ip.slice(1).map(Number);
|
|
7666
|
+
if ([a, b, c, d].some((n) => n > 255)) return false;
|
|
7667
|
+
return a === 10 || a === 192 && b === 168 || a === 172 && b >= 16 && b <= 31;
|
|
7622
7668
|
}
|
|
7623
7669
|
function domainMatches(host, domains) {
|
|
7624
7670
|
const h = host.toLowerCase().replace(/\.$/, "");
|
|
7625
7671
|
return domains.some((d) => {
|
|
7672
|
+
if (typeof d !== "string") return false;
|
|
7626
7673
|
const raw = d.toLowerCase().replace(/\.$/, "");
|
|
7627
|
-
const
|
|
7628
|
-
const dom = wildcard ? raw.slice(2) : raw;
|
|
7674
|
+
const dom = raw.startsWith("*.") ? raw.slice(2) : raw;
|
|
7629
7675
|
if (!dom) return false;
|
|
7630
|
-
|
|
7631
|
-
return wildcard && h.endsWith(`.${dom}`);
|
|
7676
|
+
return h === dom || h.endsWith(`.${dom}`);
|
|
7632
7677
|
});
|
|
7633
7678
|
}
|
|
7634
7679
|
var isDay = (s) => {
|
|
@@ -7638,19 +7683,32 @@ var isDay = (s) => {
|
|
|
7638
7683
|
return d.getUTCMonth() === Number(m[2]) - 1 && d.getUTCDate() === Number(m[3]);
|
|
7639
7684
|
};
|
|
7640
7685
|
var today = (now) => `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
|
7641
|
-
|
|
7686
|
+
function checkTerms(key, host, opts = {}) {
|
|
7642
7687
|
const parts = typeof key === "string" ? key.trim().split(".") : [];
|
|
7643
|
-
if (parts.length !== 3 || parts[0] !== "FG1") return { ok: false, reason: "format" };
|
|
7688
|
+
if (parts.length !== 3 || parts[0] !== "FG1") return { fail: { ok: false, reason: "format" } };
|
|
7644
7689
|
let info;
|
|
7645
7690
|
try {
|
|
7646
7691
|
info = JSON.parse(new TextDecoder().decode(b64urlDecode(parts[1])));
|
|
7647
|
-
if (!Array.isArray(info.domains) || !isDay(info.expires)) return { ok: false, reason: "format" };
|
|
7648
|
-
if (info.major !== void 0 && !(Number.isInteger(info.major) && info.major > 0)) return { ok: false, reason: "format" };
|
|
7692
|
+
if (!info || !Array.isArray(info.domains) || !info.domains.every((d) => typeof d === "string") || !isDay(info.expires)) return { fail: { ok: false, reason: "format" } };
|
|
7693
|
+
if (info.major !== void 0 && !(Number.isInteger(info.major) && info.major > 0)) return { fail: { ok: false, reason: "format" } };
|
|
7694
|
+
if (info.plan !== void 0 && info.plan !== "company" && info.plan !== "personal") return { fail: { ok: false, reason: "format" } };
|
|
7649
7695
|
} catch {
|
|
7650
|
-
return { ok: false, reason: "format" };
|
|
7696
|
+
return { fail: { ok: false, reason: "format" } };
|
|
7651
7697
|
}
|
|
7652
|
-
|
|
7653
|
-
if (
|
|
7698
|
+
let fail = null;
|
|
7699
|
+
if (today(opts.now ?? /* @__PURE__ */ new Date()) > info.expires) fail = { ok: false, reason: "expired", info };
|
|
7700
|
+
else if (!domainMatches(host, info.domains)) fail = { ok: false, reason: "domain", info };
|
|
7701
|
+
else if (info.major !== void 0 && majorOf(opts.version ?? version) > info.major) fail = { ok: false, reason: "version", info };
|
|
7702
|
+
return { parts, info, fail };
|
|
7703
|
+
}
|
|
7704
|
+
var hasSubtle = () => typeof crypto !== "undefined" && !!crypto.subtle;
|
|
7705
|
+
async function verifyLicense(key, host, opts = {}) {
|
|
7706
|
+
const checked = checkTerms(key, host, opts);
|
|
7707
|
+
if (!("info" in checked)) return checked.fail;
|
|
7708
|
+
const { parts, info } = checked;
|
|
7709
|
+
const terms = () => checked.fail;
|
|
7710
|
+
if (!hasSubtle()) return terms() ?? { ok: false, reason: "unsupported", info };
|
|
7711
|
+
const subtle = crypto.subtle;
|
|
7654
7712
|
try {
|
|
7655
7713
|
const pub = await subtle.importKey("jwk", opts.publicKey ?? PUBLIC_KEY, { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"]);
|
|
7656
7714
|
const signed = new TextEncoder().encode(`${parts[0]}.${parts[1]}`);
|
|
@@ -7659,20 +7717,22 @@ async function verifyLicense(key, host, opts = {}) {
|
|
|
7659
7717
|
} catch {
|
|
7660
7718
|
return { ok: false, reason: "signature", info };
|
|
7661
7719
|
}
|
|
7662
|
-
|
|
7663
|
-
if (!domainMatches(host, info.domains)) return { ok: false, reason: "domain", info };
|
|
7664
|
-
if (info.major !== void 0 && majorOf(opts.version ?? version) > info.major) return { ok: false, reason: "version", info };
|
|
7665
|
-
return { ok: true, info };
|
|
7720
|
+
return terms() ?? { ok: true, info };
|
|
7666
7721
|
}
|
|
7667
7722
|
var globalKey;
|
|
7668
7723
|
var statuses = /* @__PURE__ */ new Map();
|
|
7669
|
-
var
|
|
7724
|
+
var statusChecks = /* @__PURE__ */ new Map();
|
|
7725
|
+
var gateNotices = /* @__PURE__ */ new Set();
|
|
7726
|
+
var blockedWarned = /* @__PURE__ */ new Set();
|
|
7670
7727
|
function setLicenseKey(key) {
|
|
7671
7728
|
globalKey = key;
|
|
7672
7729
|
}
|
|
7673
7730
|
var NOTICE = {
|
|
7674
|
-
missing: `FreeGrid is free for
|
|
7675
|
-
FreeGrid
|
|
7731
|
+
missing: `FreeGrid: every feature is free for 30 days on a domain. After that, paid features need a free personal key (${PERSONAL_URL}) or a company key: ${PRICING_URL}
|
|
7732
|
+
FreeGrid: \uB3C4\uBA54\uC778\uB9C8\uB2E4 30\uC77C \uB3D9\uC548 \uBAA8\uB4E0 \uAE30\uB2A5\uC744 \uBB34\uB8CC\uB85C \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uADF8 \uB4A4 \uC720\uB8CC \uAE30\uB2A5\uC5D0\uB294 \uBB34\uB8CC \uAC1C\uC778 \uD0A4(${PERSONAL_URL}) \uB610\uB294 \uD68C\uC0AC \uD0A4\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4: ${PRICING_URL}`,
|
|
7733
|
+
trial: (ends) => `FreeGrid: the 30-day trial of paid features on this domain ends ${ends}. / \uC774 \uB3C4\uBA54\uC778\uC758 \uC720\uB8CC \uAE30\uB2A5 30\uC77C \uCCB4\uD5D8\uC740 ${ends}\uC5D0 \uB05D\uB0A9\uB2C8\uB2E4.`,
|
|
7734
|
+
ended: `FreeGrid: the 30-day trial on this domain has ended, so paid features are now off. Get a free personal key (${PERSONAL_URL}) or a company key: ${PRICING_URL}
|
|
7735
|
+
FreeGrid: \uC774 \uB3C4\uBA54\uC778\uC758 30\uC77C \uCCB4\uD5D8\uC774 \uB05D\uB098 \uC720\uB8CC \uAE30\uB2A5\uC774 \uAEBC\uC84C\uC2B5\uB2C8\uB2E4. \uBB34\uB8CC \uAC1C\uC778 \uD0A4(${PERSONAL_URL}) \uB610\uB294 \uD68C\uC0AC \uD0A4\uB97C \uBC1B\uC73C\uC138\uC694: ${PRICING_URL}`,
|
|
7676
7736
|
format: "FreeGrid: the license key is not in the right format. / \uB77C\uC774\uC120\uC2A4 \uD0A4 \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
7677
7737
|
signature: "FreeGrid: the license key could not be verified. / \uB77C\uC774\uC120\uC2A4 \uD0A4\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
7678
7738
|
expired: "FreeGrid: the license key has expired. / \uB77C\uC774\uC120\uC2A4 \uAE30\uAC04\uC774 \uB05D\uB0AC\uC2B5\uB2C8\uB2E4.",
|
|
@@ -7695,52 +7755,145 @@ function reportUsage(info, host = typeof location !== "undefined" ? location.hos
|
|
|
7695
7755
|
}
|
|
7696
7756
|
function checkLicense(key = globalKey, host = typeof location !== "undefined" ? location.hostname : "") {
|
|
7697
7757
|
if (isDevHost(host)) return Promise.resolve(true);
|
|
7698
|
-
|
|
7758
|
+
return keyState(key ?? globalKey, host).then((s) => s === "ok" || s === "unsupported");
|
|
7759
|
+
}
|
|
7760
|
+
function keyState(k, host) {
|
|
7699
7761
|
const id = `${k ?? ""}@${host}`;
|
|
7700
7762
|
let status = statuses.get(id);
|
|
7701
7763
|
if (status) return status;
|
|
7702
7764
|
if (!k) {
|
|
7703
7765
|
console.info(NOTICE.missing);
|
|
7704
7766
|
reportUsage({ version, licensed: false }, host);
|
|
7705
|
-
status = Promise.resolve(
|
|
7767
|
+
status = Promise.resolve("none");
|
|
7706
7768
|
} else {
|
|
7707
7769
|
status = verifyLicense(k, host).then((res) => {
|
|
7708
7770
|
reportUsage({ version, licensed: res.ok, company: res.ok ? res.info.company : void 0 }, host);
|
|
7709
|
-
if (res.ok
|
|
7771
|
+
if (res.ok) return "ok";
|
|
7772
|
+
if (res.reason === "unsupported") return "unsupported";
|
|
7710
7773
|
const extra = res.info ? ` (${res.info.domains.join(", ")}, ${res.info.major ? `${res.info.major}.x` : res.info.expires})` : "";
|
|
7711
7774
|
console.warn(`${NOTICE[res.reason]}${extra}
|
|
7712
7775
|
${PRICING_URL}`);
|
|
7713
|
-
return
|
|
7714
|
-
}, () =>
|
|
7776
|
+
return "bad";
|
|
7777
|
+
}, () => "bad");
|
|
7715
7778
|
}
|
|
7716
7779
|
statuses.set(id, status);
|
|
7717
7780
|
return status;
|
|
7718
7781
|
}
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7782
|
+
var gateHost;
|
|
7783
|
+
var currentHost = () => gateHost ?? (typeof location !== "undefined" ? location.hostname : "");
|
|
7784
|
+
var parseStatus = (d) => {
|
|
7785
|
+
if (!d || typeof d !== "object") return null;
|
|
7786
|
+
const { badge, trial } = d;
|
|
7787
|
+
const valid = !!trial && typeof trial === "object" && isDay(trial.started) && isDay(trial.ends) && typeof trial.active === "boolean";
|
|
7788
|
+
return { badge: badge === true, trial: valid ? { started: trial.started, ends: trial.ends, active: trial.active } : null };
|
|
7789
|
+
};
|
|
7790
|
+
function fetchDomainStatus(host = currentHost()) {
|
|
7791
|
+
if (isDevHost(host) || typeof fetch !== "function") return Promise.resolve(null);
|
|
7792
|
+
const pending = statusChecks.get(host);
|
|
7793
|
+
if (pending) return pending;
|
|
7722
7794
|
const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
7723
7795
|
let store = null;
|
|
7724
7796
|
try {
|
|
7725
7797
|
store = typeof localStorage !== "undefined" ? localStorage : null;
|
|
7726
|
-
const cached = JSON.parse(store?.getItem("freegrid:
|
|
7727
|
-
|
|
7798
|
+
const cached = JSON.parse(store?.getItem("freegrid:status") ?? "null");
|
|
7799
|
+
const status = cached && cached.host === host && cached.day === day ? parseStatus(cached.status) : null;
|
|
7800
|
+
if (status) {
|
|
7801
|
+
const hit = Promise.resolve(status);
|
|
7802
|
+
statusChecks.set(host, hit);
|
|
7803
|
+
return hit;
|
|
7804
|
+
}
|
|
7728
7805
|
} catch {
|
|
7729
7806
|
}
|
|
7730
|
-
|
|
7731
|
-
const
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7807
|
+
const check = fetch(STATUS_URL, { mode: "cors", credentials: "omit" }).then((r) => r.ok ? r.json() : null).then((d) => {
|
|
7808
|
+
const status = parseStatus(d);
|
|
7809
|
+
if (status) {
|
|
7810
|
+
try {
|
|
7811
|
+
store?.setItem("freegrid:status", JSON.stringify({ host, day, status }));
|
|
7812
|
+
} catch {
|
|
7813
|
+
}
|
|
7735
7814
|
}
|
|
7736
|
-
return
|
|
7737
|
-
}
|
|
7738
|
-
|
|
7815
|
+
return status;
|
|
7816
|
+
}).catch(() => null);
|
|
7817
|
+
statusChecks.set(host, check);
|
|
7818
|
+
return check;
|
|
7819
|
+
}
|
|
7820
|
+
function badgeRequested(host = currentHost()) {
|
|
7821
|
+
return fetchDomainStatus(host).then((s) => s?.badge === true);
|
|
7739
7822
|
}
|
|
7740
|
-
async function needsFreeBadge(key, host =
|
|
7823
|
+
async function needsFreeBadge(key, host = currentHost()) {
|
|
7824
|
+
await Promise.resolve();
|
|
7741
7825
|
if (await checkLicense(key, host)) return false;
|
|
7742
7826
|
return badgeRequested(host);
|
|
7743
7827
|
}
|
|
7828
|
+
var GATE_KEY = "freegrid:gate";
|
|
7829
|
+
var MAX_VERIFIED_KEYS = 5;
|
|
7830
|
+
var keyIdOf = (key) => {
|
|
7831
|
+
if (!key) return "";
|
|
7832
|
+
const parts = key.trim().split(".");
|
|
7833
|
+
return parts[parts.length - 1].slice(-16);
|
|
7834
|
+
};
|
|
7835
|
+
var readGate = (host) => {
|
|
7836
|
+
const c = JSON.parse(localStorage.getItem(GATE_KEY) ?? "null");
|
|
7837
|
+
if (!c || typeof c !== "object" || c.host !== host || typeof c.trialEnded !== "boolean" || !Array.isArray(c.verifiedKeys) || !c.verifiedKeys.every((k) => typeof k === "string")) return null;
|
|
7838
|
+
return { host, trialEnded: c.trialEnded, ...typeof c.trialEnds === "string" ? { trialEnds: c.trialEnds } : {}, verifiedKeys: c.verifiedKeys };
|
|
7839
|
+
};
|
|
7840
|
+
function paidAllowed(key, host = currentHost()) {
|
|
7841
|
+
if (isDevHost(host)) return true;
|
|
7842
|
+
const k = key ?? globalKey;
|
|
7843
|
+
if (k && !hasSubtle()) {
|
|
7844
|
+
const checked = checkTerms(k, host);
|
|
7845
|
+
if ("info" in checked && !checked.fail) return true;
|
|
7846
|
+
}
|
|
7847
|
+
try {
|
|
7848
|
+
const cache2 = readGate(host);
|
|
7849
|
+
if (!cache2) return true;
|
|
7850
|
+
const id = keyIdOf(k);
|
|
7851
|
+
if (id && cache2.verifiedKeys.includes(id)) return true;
|
|
7852
|
+
return !cache2.trialEnded;
|
|
7853
|
+
} catch {
|
|
7854
|
+
return true;
|
|
7855
|
+
}
|
|
7856
|
+
}
|
|
7857
|
+
var updateGate = (host, patch) => {
|
|
7858
|
+
try {
|
|
7859
|
+
let cur = null;
|
|
7860
|
+
try {
|
|
7861
|
+
cur = readGate(host);
|
|
7862
|
+
} catch {
|
|
7863
|
+
}
|
|
7864
|
+
localStorage.setItem(GATE_KEY, JSON.stringify(patch(cur ?? { host, trialEnded: false, verifiedKeys: [] })));
|
|
7865
|
+
} catch {
|
|
7866
|
+
}
|
|
7867
|
+
};
|
|
7868
|
+
async function resolveGate(key, host = currentHost()) {
|
|
7869
|
+
if (isDevHost(host)) return true;
|
|
7870
|
+
await Promise.resolve();
|
|
7871
|
+
const k = key ?? globalKey;
|
|
7872
|
+
const state = await keyState(k, host);
|
|
7873
|
+
if (state === "ok") {
|
|
7874
|
+
const id = keyIdOf(k);
|
|
7875
|
+
updateGate(host, (c) => ({ ...c, verifiedKeys: [id, ...c.verifiedKeys.filter((x) => x !== id)].slice(0, MAX_VERIFIED_KEYS) }));
|
|
7876
|
+
return true;
|
|
7877
|
+
}
|
|
7878
|
+
if (state === "unsupported") return true;
|
|
7879
|
+
const trial = (await fetchDomainStatus(host))?.trial;
|
|
7880
|
+
if (!trial) return true;
|
|
7881
|
+
updateGate(host, (c) => ({ ...c, trialEnded: !trial.active, trialEnds: trial.ends }));
|
|
7882
|
+
const notice = `${trial.active ? "trial" : "ended"}@${host}`;
|
|
7883
|
+
if (!gateNotices.has(notice)) {
|
|
7884
|
+
gateNotices.add(notice);
|
|
7885
|
+
if (trial.active) console.info(NOTICE.trial(trial.ends));
|
|
7886
|
+
else console.warn(NOTICE.ended);
|
|
7887
|
+
}
|
|
7888
|
+
return trial.active;
|
|
7889
|
+
}
|
|
7890
|
+
function paidBlocked(feature) {
|
|
7891
|
+
if (blockedWarned.has(feature)) return;
|
|
7892
|
+
blockedWarned.add(feature);
|
|
7893
|
+
const name = PAID_FEATURES[feature] ?? { en: feature, ko: feature };
|
|
7894
|
+
console.warn(`FreeGrid: ${name.en} is a paid feature and is off on this domain. Get a free personal key (${PERSONAL_URL}) or a company key: ${PRICING_URL}
|
|
7895
|
+
FreeGrid: ${name.ko}\uC740(\uB294) \uC720\uB8CC \uAE30\uB2A5\uC774\uB77C \uC774 \uB3C4\uBA54\uC778\uC5D0\uC11C \uAEBC\uC838 \uC788\uC2B5\uB2C8\uB2E4. \uBB34\uB8CC \uAC1C\uC778 \uD0A4(${PERSONAL_URL}) \uB610\uB294 \uD68C\uC0AC \uD0A4\uB97C \uBC1B\uC73C\uC138\uC694: ${PRICING_URL}`);
|
|
7896
|
+
}
|
|
7744
7897
|
|
|
7745
7898
|
// src/interactions/menu.ts
|
|
7746
7899
|
var OPS = {
|
|
@@ -7785,7 +7938,7 @@ var ColumnMenu = class {
|
|
|
7785
7938
|
[loc.unpin, () => this.grid.setPinned(colId, null)]
|
|
7786
7939
|
]));
|
|
7787
7940
|
const grouped = this.grid.getGroupBy();
|
|
7788
|
-
if (!this.grid.options.treeData && (this.grid.options.groupPanel || grouped.length)) {
|
|
7941
|
+
if (!this.grid.options.treeData && this.grid.paid && (this.grid.options.groupPanel || grouped.length)) {
|
|
7789
7942
|
const g = grouped.includes(colId) ? [[loc.ungroup, () => this.grid.setGroupBy(grouped.filter((x) => x !== colId))]] : [[loc.groupByThis, () => this.grid.setGroupBy([...grouped, colId])]];
|
|
7790
7943
|
if (grouped.length) g.push([loc.expandAll, () => this.grid.expandAll(true)], [loc.collapseAll, () => this.grid.expandAll(false)]);
|
|
7791
7944
|
popup.append(this.section(g));
|
|
@@ -7796,7 +7949,7 @@ var ColumnMenu = class {
|
|
|
7796
7949
|
];
|
|
7797
7950
|
if (!def.lockVisible) items.push([loc.hideColumn, () => this.grid.setColumnsVisible([colId], false)]);
|
|
7798
7951
|
items.push([loc.chooseColumns, () => this.grid.chooser.open()], [loc.resetColumns, () => this.grid.resetColumns()]);
|
|
7799
|
-
if (this.grid.options.conditionalFormatMenu !== false) items.push([`${loc.cf.title}\u2026`, () => this.grid.formatDialog.open(colId)]);
|
|
7952
|
+
if (this.grid.options.conditionalFormatMenu !== false && this.grid.paid) items.push([`${loc.cf.title}\u2026`, () => this.grid.formatDialog.open(colId)]);
|
|
7800
7953
|
popup.append(this.section(items));
|
|
7801
7954
|
const filter = this.filterSection(colId, () => this.close());
|
|
7802
7955
|
if (filter) popup.append(filter);
|
|
@@ -9704,6 +9857,7 @@ var Grid = class {
|
|
|
9704
9857
|
this.pageSize = DEFAULT_PAGE_SIZE;
|
|
9705
9858
|
/** What formulas see: every source row, and computed columns by id. */
|
|
9706
9859
|
this.formulaScope = {
|
|
9860
|
+
off: () => !this.allow("formulas"),
|
|
9707
9861
|
rows: () => this.store.state.data,
|
|
9708
9862
|
version: () => this.editVersion,
|
|
9709
9863
|
computed: (name) => {
|
|
@@ -9768,6 +9922,7 @@ var Grid = class {
|
|
|
9768
9922
|
this.selectionVersion = 0;
|
|
9769
9923
|
/** Rows select-all acts on: displayed data rows that are selectable. */
|
|
9770
9924
|
this.selectableCache = null;
|
|
9925
|
+
this.paid = paidAllowed(options.licenseKey);
|
|
9771
9926
|
if (!Array.isArray(options.columns)) warn("options.columns must be an array");
|
|
9772
9927
|
if (options.data != null && !Array.isArray(options.data)) warn("options.data must be an array");
|
|
9773
9928
|
this.store = new Store({
|
|
@@ -9809,12 +9964,12 @@ var Grid = class {
|
|
|
9809
9964
|
collator: () => this.collator(),
|
|
9810
9965
|
textVersion: () => `${this.store.state.locale.code}|${this.editVersion}`
|
|
9811
9966
|
});
|
|
9812
|
-
this.groupBy = this.validGroupBy(options.groupBy
|
|
9813
|
-
if (Array.isArray(options.conditionalFormats)) this.cfRules = options.conditionalFormats.filter((r) => r && typeof r === "object" && Array.isArray(r.columns)).map((r) => ({ ...r, columns: [...r.columns] }));
|
|
9814
|
-
this.defaultExpanded = options.groupDefaultExpanded ?? 0;
|
|
9967
|
+
if (options.groupBy?.length && this.allow(this.rowModel.server ? "serverGroups" : "grouping")) this.groupBy = this.validGroupBy(options.groupBy);
|
|
9968
|
+
if (Array.isArray(options.conditionalFormats) && options.conditionalFormats.length && this.allow("conditional")) this.cfRules = options.conditionalFormats.filter((r) => r && typeof r === "object" && Array.isArray(r.columns)).map((r) => ({ ...r, columns: [...r.columns] }));
|
|
9969
|
+
this.defaultExpanded = options.treeData || this.paid ? options.groupDefaultExpanded ?? 0 : 0;
|
|
9815
9970
|
if (options.treeData && !options.getRowId) warn("treeData needs getRowId so parent ids can be matched");
|
|
9816
9971
|
this.updateRows();
|
|
9817
|
-
this.summaryOpts = options.summary
|
|
9972
|
+
this.summaryOpts = options.summary && this.allow("summary") ? options.summary : null;
|
|
9818
9973
|
this.summarySnapshot = snapshot(this.summaryOpts);
|
|
9819
9974
|
this.refreshSummary();
|
|
9820
9975
|
const explicit = options.fontSize != null && options.fontSize > 0 ? options.fontSize : null;
|
|
@@ -9835,9 +9990,9 @@ var Grid = class {
|
|
|
9835
9990
|
this.editor = new CellEditor(this);
|
|
9836
9991
|
this.finder = new Finder(this);
|
|
9837
9992
|
this.fillHandle = new FillHandle(this);
|
|
9838
|
-
this.groupPanel = options.groupPanel ? new GroupPanel(this) : null;
|
|
9993
|
+
this.groupPanel = options.groupPanel && this.allow("grouping") ? new GroupPanel(this) : null;
|
|
9839
9994
|
this.pinnedRows = { top: cleanRows(options.pinnedTopRows ?? []), bottom: cleanRows(options.pinnedBottomRows ?? []) };
|
|
9840
|
-
this.sideBar = options.sideBar ? new SideBar(
|
|
9995
|
+
this.sideBar = options.sideBar && this.allow("sideBar") ? new SideBar(
|
|
9841
9996
|
this,
|
|
9842
9997
|
typeof options.sideBar === "object" && !!options.sideBar.open,
|
|
9843
9998
|
(typeof options.sideBar === "object" ? options.sideBar.panels : void 0) ?? (options.pivot || options.pivotPanel ? ["columns", "filters", "pivot"] : void 0)
|
|
@@ -9870,11 +10025,23 @@ var Grid = class {
|
|
|
9870
10025
|
this.renderer.render();
|
|
9871
10026
|
this.api = this.createApi();
|
|
9872
10027
|
liveGrids.set(this.renderer.root, this);
|
|
10028
|
+
apiGrids.set(this.api, this);
|
|
10029
|
+
void resolveGate(options.licenseKey);
|
|
9873
10030
|
}
|
|
9874
10031
|
/** Bumped whenever cell values change (edits, transactions, undo). */
|
|
9875
10032
|
get valuesVersion() {
|
|
9876
10033
|
return this.editVersion;
|
|
9877
10034
|
}
|
|
10035
|
+
/** Cell ranges are on: not switched off and paid features allowed. Closed behaves exactly like `rangeSelection: false`. */
|
|
10036
|
+
rangesOn() {
|
|
10037
|
+
return this.options.rangeSelection !== false && this.paid;
|
|
10038
|
+
}
|
|
10039
|
+
/** Whether a paid feature may run; warns once per feature when it may not. */
|
|
10040
|
+
allow(feature) {
|
|
10041
|
+
if (this.paid) return true;
|
|
10042
|
+
paidBlocked(feature);
|
|
10043
|
+
return false;
|
|
10044
|
+
}
|
|
9878
10045
|
/** The column definitions as given (setColumns), without the system columns. */
|
|
9879
10046
|
columnDefs() {
|
|
9880
10047
|
return [...this.sourceDefs];
|
|
@@ -9887,6 +10054,7 @@ var Grid = class {
|
|
|
9887
10054
|
warn("setConditionalFormats: formats must be an array");
|
|
9888
10055
|
return;
|
|
9889
10056
|
}
|
|
10057
|
+
if (list.length && !this.allow("conditional")) return;
|
|
9890
10058
|
this.cfRules = list.filter((r) => r && typeof r === "object" && Array.isArray(r.columns)).map((r) => ({ ...r, columns: [...r.columns] }));
|
|
9891
10059
|
this.renderer.invalidate({ rows: true });
|
|
9892
10060
|
this.events.emit("conditionalFormatsChange", { formats: this.getConditionalFormats() });
|
|
@@ -9984,6 +10152,7 @@ var Grid = class {
|
|
|
9984
10152
|
return out;
|
|
9985
10153
|
}
|
|
9986
10154
|
setPivot(cfg) {
|
|
10155
|
+
if (cfg && !this.allow("pivot")) return;
|
|
9987
10156
|
if (cfg && this.clientOnly("pivot")) return;
|
|
9988
10157
|
if (cfg && (typeof cfg !== "object" || !Array.isArray(cfg.rows) || !Array.isArray(cfg.values))) {
|
|
9989
10158
|
warn("setPivot: expected { rows: string[], values: [...] }");
|
|
@@ -10239,6 +10408,7 @@ var Grid = class {
|
|
|
10239
10408
|
}
|
|
10240
10409
|
setAdvancedFilter(filter) {
|
|
10241
10410
|
const next = filter && typeof filter === "object" && Array.isArray(filter.conditions) && filter.conditions.length ? filter : null;
|
|
10411
|
+
if (next && !this.allow("advancedFilter")) return;
|
|
10242
10412
|
if (next === this.store.state.advancedFilter) return;
|
|
10243
10413
|
this.store.set({ advancedFilter: next });
|
|
10244
10414
|
this.events.emit("advancedFilterChange", { advancedFilter: next });
|
|
@@ -10450,6 +10620,7 @@ var Grid = class {
|
|
|
10450
10620
|
return [...this.groupBy];
|
|
10451
10621
|
}
|
|
10452
10622
|
setGroupBy(ids) {
|
|
10623
|
+
if (Array.isArray(ids) && ids.length && !this.allow(this.rowModel.server ? "serverGroups" : "grouping")) return;
|
|
10453
10624
|
const next = this.validGroupBy(ids);
|
|
10454
10625
|
if (next.join("") === this.groupBy.join("")) return;
|
|
10455
10626
|
this.groupBy = next;
|
|
@@ -10735,6 +10906,7 @@ var Grid = class {
|
|
|
10735
10906
|
warn("setSummary: summary.rows must be an array");
|
|
10736
10907
|
return;
|
|
10737
10908
|
}
|
|
10909
|
+
if (opts && !this.allow("summary")) return;
|
|
10738
10910
|
if (same2(opts, this.summarySnapshot)) {
|
|
10739
10911
|
this.summaryOpts = opts;
|
|
10740
10912
|
return;
|
|
@@ -10759,13 +10931,14 @@ var Grid = class {
|
|
|
10759
10931
|
return this.columns.displayed().filter((c) => !isSystemCol(c.id));
|
|
10760
10932
|
}
|
|
10761
10933
|
validRange(range) {
|
|
10762
|
-
if (!range || this.
|
|
10934
|
+
if (!range || !this.rangesOn()) return null;
|
|
10763
10935
|
const count = this.rowModel.getRowCount();
|
|
10764
10936
|
const ok = (p) => !!p && !isSystemCol(p.colId) && !!this.columns.getColumn(p.colId) && p.rowIndex >= 0 && p.rowIndex < count;
|
|
10765
10937
|
return ok(range.start) && ok(range.end) ? { start: { ...range.start }, end: { ...range.end } } : null;
|
|
10766
10938
|
}
|
|
10767
10939
|
/** Set the active range. Earlier Ctrl ranges are dropped unless `keepOthers`. */
|
|
10768
10940
|
setRange(range, keepOthers = false) {
|
|
10941
|
+
if (range && (range.start?.rowIndex !== range.end?.rowIndex || range.start?.colId !== range.end?.colId) && !this.allow("range")) return;
|
|
10769
10942
|
const next = this.validRange(range);
|
|
10770
10943
|
const extras = keepOthers || !this.store.state.extraRanges.length ? this.store.state.extraRanges : [];
|
|
10771
10944
|
const cur = this.store.state.range;
|
|
@@ -10775,6 +10948,7 @@ var Grid = class {
|
|
|
10775
10948
|
}
|
|
10776
10949
|
/** Ctrl+click / Ctrl+drag: keep what is selected (the focused cell when there is no range) and start a new range. */
|
|
10777
10950
|
addRange(range) {
|
|
10951
|
+
if (!this.allow("range")) return;
|
|
10778
10952
|
const { range: active, focus } = this.store.state;
|
|
10779
10953
|
const keep = this.validRange(active ?? (focus ? { start: focus, end: focus } : null));
|
|
10780
10954
|
if (keep) this.store.set({ extraRanges: [...this.store.state.extraRanges, keep] });
|
|
@@ -10786,6 +10960,7 @@ var Grid = class {
|
|
|
10786
10960
|
return all2.map((r) => ({ start: { ...r.start }, end: { ...r.end } }));
|
|
10787
10961
|
}
|
|
10788
10962
|
setRanges(ranges) {
|
|
10963
|
+
if (Array.isArray(ranges) && ranges.length && !this.allow("range")) return;
|
|
10789
10964
|
const list = (Array.isArray(ranges) ? ranges : []).map((r) => this.validRange(r)).filter((r) => !!r);
|
|
10790
10965
|
this.store.set({ extraRanges: list.slice(0, -1) });
|
|
10791
10966
|
this.setRange(list[list.length - 1] ?? null, true);
|
|
@@ -10809,6 +10984,7 @@ var Grid = class {
|
|
|
10809
10984
|
return !!col && this.allRangeBounds().some((b) => rangeContains(b, rowIndex, col.index));
|
|
10810
10985
|
}
|
|
10811
10986
|
selectAllCells() {
|
|
10987
|
+
if (!this.allow("range")) return;
|
|
10812
10988
|
const cols = this.dataColumns();
|
|
10813
10989
|
const count = this.rowModel.getRowCount();
|
|
10814
10990
|
if (!cols.length || !count) return;
|
|
@@ -10818,6 +10994,7 @@ var Grid = class {
|
|
|
10818
10994
|
// ── clipboard ───────────────────────────────────────────────
|
|
10819
10995
|
/** TSV for the range, else the focused cell; `rows` copies the checked rows instead. */
|
|
10820
10996
|
selectionTSV(headers, rows = false) {
|
|
10997
|
+
if (!rows && this.multiCell() && !this.allow("clipboard")) return "";
|
|
10821
10998
|
const code = this.store.state.locale.code;
|
|
10822
10999
|
const displayed = this.columns.displayed();
|
|
10823
11000
|
const b = rows ? null : this.rangeBounds();
|
|
@@ -10859,6 +11036,11 @@ var Grid = class {
|
|
|
10859
11036
|
if (headers) matrix.unshift(cols.map((c) => c.def.header ?? c.def.field ?? c.id));
|
|
10860
11037
|
return toTSV(matrix);
|
|
10861
11038
|
}
|
|
11039
|
+
/** The selection covers more than one cell (several ranges, or one range wider than a cell). */
|
|
11040
|
+
multiCell() {
|
|
11041
|
+
const all2 = this.allRangeBounds();
|
|
11042
|
+
return all2.length > 1 || all2.some((b) => b.r1 !== b.r2 || b.c1 !== b.c2);
|
|
11043
|
+
}
|
|
10862
11044
|
/** Like Excel: ranges stack when they share columns or rows; otherwise only the active one is copied. */
|
|
10863
11045
|
rangesStack(all2) {
|
|
10864
11046
|
return all2.length > 1 && (all2.every((x) => x.c1 === all2[0].c1 && x.c2 === all2[0].c2) || all2.every((x) => x.r1 === all2[0].r1 && x.r2 === all2[0].r2));
|
|
@@ -10909,6 +11091,7 @@ var Grid = class {
|
|
|
10909
11091
|
const matrix = parseTSV(text2);
|
|
10910
11092
|
const result = { changed: 0, skipped: 0 };
|
|
10911
11093
|
if (!matrix.length) return result;
|
|
11094
|
+
if ((matrix.length > 1 || matrix[0].length > 1) && !this.allow("clipboard")) return result;
|
|
10912
11095
|
const displayed = this.columns.displayed();
|
|
10913
11096
|
const count = this.rowModel.getRowCount();
|
|
10914
11097
|
const b = this.rangeBounds();
|
|
@@ -11017,6 +11200,7 @@ var Grid = class {
|
|
|
11017
11200
|
/** Merge blocks for every `merge` column over the displayed rows (memoized). */
|
|
11018
11201
|
mergeSpans() {
|
|
11019
11202
|
if (this.rowModel.server || !this.columns.displayed().some((c) => c.def.merge || c.def.rowSpan)) return NO_SPANS;
|
|
11203
|
+
if (!this.allow("merge")) return NO_SPANS;
|
|
11020
11204
|
const rows = this.rowModel.rows();
|
|
11021
11205
|
const ver = this.editVersion * 1e6 + this.columns.displayed().length;
|
|
11022
11206
|
if (this.spanCache && this.spanCache.rows === rows && this.spanCache.ver === ver) return this.spanCache.spans;
|
|
@@ -11031,7 +11215,7 @@ var Grid = class {
|
|
|
11031
11215
|
}
|
|
11032
11216
|
rangeAggregates() {
|
|
11033
11217
|
const all2 = this.allRangeBounds();
|
|
11034
|
-
if (!all2.length) return null;
|
|
11218
|
+
if (!all2.length || !this.paid) return null;
|
|
11035
11219
|
const displayed = this.columns.displayed();
|
|
11036
11220
|
const key = [JSON.stringify(all2), this.rowModel.rows(), this.editVersion, ...displayed.map((c) => c.def)];
|
|
11037
11221
|
const memo = this.aggMemo;
|
|
@@ -11070,6 +11254,7 @@ var Grid = class {
|
|
|
11070
11254
|
}
|
|
11071
11255
|
/** Fill from the current selection into `target`, Excel-style (one undo step). */
|
|
11072
11256
|
fillRange(target) {
|
|
11257
|
+
if (!this.allow("fill")) return;
|
|
11073
11258
|
const src = this.rangeBounds() ?? (() => {
|
|
11074
11259
|
const f = this.store.state.focus;
|
|
11075
11260
|
const col = f && this.columns.getColumn(f.colId);
|
|
@@ -11655,11 +11840,13 @@ var Grid = class {
|
|
|
11655
11840
|
this.forcedOverlay = kind === "loading" || kind === "noRows" ? kind : null;
|
|
11656
11841
|
this.renderer.invalidate();
|
|
11657
11842
|
}),
|
|
11658
|
-
|
|
11843
|
+
// closed: an empty sheet, so writeXlsx([api.getXlsxSheet()]) is not an Excel export
|
|
11844
|
+
getXlsxSheet: guard((o) => this.allow("excel") ? buildXlsxSheet(this, o) : { name: o?.sheetName ?? "Sheet1", rows: [] }),
|
|
11659
11845
|
print: guard((o) => printHtml(buildPrintHtml(this, o))),
|
|
11660
11846
|
getPrintHtml: guard((o) => buildPrintHtml(this, o)),
|
|
11661
|
-
getPdf: guard((o) => renderPdf(printModel(this, o), browserSurface, { scale: o?.resolution, quality: o?.quality })),
|
|
11847
|
+
getPdf: guard((o) => this.allow("pdf") ? renderPdf(printModel(this, o), browserSurface, { scale: o?.resolution, quality: o?.quality }) : null),
|
|
11662
11848
|
exportPdf: guard((name = "export.pdf", o) => {
|
|
11849
|
+
if (!this.allow("pdf")) return;
|
|
11663
11850
|
const bytes = renderPdf(printModel(this, o), browserSurface, { scale: o?.resolution, quality: o?.quality });
|
|
11664
11851
|
if (bytes) download(name, [bytes], "application/pdf");
|
|
11665
11852
|
else warn("exportPdf: this browser cannot draw on a canvas");
|
|
@@ -11667,16 +11854,26 @@ var Grid = class {
|
|
|
11667
11854
|
setColumnGroupOpened: guard((id, open) => this.setColumnGroupOpened(id, open)),
|
|
11668
11855
|
setAdvancedFilter: guard((f) => this.setAdvancedFilter(f)),
|
|
11669
11856
|
getAdvancedFilter: guard(() => this.store.state.advancedFilter ? JSON.parse(JSON.stringify(this.store.state.advancedFilter)) : null),
|
|
11670
|
-
openFilterBuilder: guard(() =>
|
|
11857
|
+
openFilterBuilder: guard(() => {
|
|
11858
|
+
if (!this.allow("advancedFilter")) return;
|
|
11859
|
+
this.filterBuilder.open();
|
|
11860
|
+
}),
|
|
11671
11861
|
isColumnGroupOpened: guard((id) => !!this.columns.getNode(id)?.open),
|
|
11672
11862
|
applyTransaction: guard((tx) => this.applyTransaction(tx)),
|
|
11673
11863
|
applyTransactionAsync: guard((tx) => this.applyTransactionAsync(tx)),
|
|
11674
11864
|
flushAsyncTransactions: guard(() => this.flushAsyncTransactions()),
|
|
11675
11865
|
setConditionalFormats: guard((f) => this.setConditionalFormats(f)),
|
|
11676
11866
|
getConditionalFormats: guard(() => this.getConditionalFormats()),
|
|
11677
|
-
openConditionalFormats: guard((colId) =>
|
|
11678
|
-
|
|
11679
|
-
|
|
11867
|
+
openConditionalFormats: guard((colId) => {
|
|
11868
|
+
if (!this.allow("conditional")) return;
|
|
11869
|
+
this.formatDialog.open(colId);
|
|
11870
|
+
}),
|
|
11871
|
+
// closed: as if `assistant` were not set
|
|
11872
|
+
askAssistant: guard((prompt) => askAssistant(this, prompt, this.allow("assistant") ? this.options.assistant : void 0)),
|
|
11873
|
+
openAssistant: guard(() => {
|
|
11874
|
+
if (!this.allow("assistant")) return;
|
|
11875
|
+
this.assistantPanel.open();
|
|
11876
|
+
}),
|
|
11680
11877
|
getState: guard(() => this.getState()),
|
|
11681
11878
|
setState: guard((s, o) => this.setState(s, o)),
|
|
11682
11879
|
getScrollPosition: guard(() => this.renderer.getScroll()),
|
|
@@ -11690,7 +11887,10 @@ var Grid = class {
|
|
|
11690
11887
|
resetColumnState: guard(() => this.resetColumns()),
|
|
11691
11888
|
openColumnChooser: guard(() => this.chooser.open()),
|
|
11692
11889
|
closeColumnChooser: guard(() => this.chooser.close()),
|
|
11693
|
-
toggleSideBar: guard((open, panel) =>
|
|
11890
|
+
toggleSideBar: guard((open, panel) => {
|
|
11891
|
+
if (!this.allow("sideBar")) return;
|
|
11892
|
+
this.sideBar?.toggle(open, panel);
|
|
11893
|
+
}),
|
|
11694
11894
|
setSummary: guard((s) => this.setSummary(s)),
|
|
11695
11895
|
getSummaryValues: guard(() => this.summaryValues.map((v) => ({ ...v }))),
|
|
11696
11896
|
getRange: guard(() => {
|
|
@@ -11720,7 +11920,7 @@ var Grid = class {
|
|
|
11720
11920
|
canRedo: guard(() => this.history.canRedo()),
|
|
11721
11921
|
fillRange: guard((t) => this.fillRange(t)),
|
|
11722
11922
|
setPinnedRows: guard((r) => this.setPinnedRows(r)),
|
|
11723
|
-
find: guard((text2) => this.finder.find(text2)),
|
|
11923
|
+
find: guard((text2) => this.allow("find") ? this.finder.find(text2) : 0),
|
|
11724
11924
|
findNext: guard(() => this.finder.next()),
|
|
11725
11925
|
findPrevious: guard(() => this.finder.previous()),
|
|
11726
11926
|
clearFind: guard(() => this.finder.clear()),
|
|
@@ -11741,13 +11941,17 @@ var Grid = class {
|
|
|
11741
11941
|
refreshRows: guard(() => this.refreshRows()),
|
|
11742
11942
|
setPivot: guard((p) => this.setPivot(p)),
|
|
11743
11943
|
getPivot: guard(() => this.getPivot()),
|
|
11744
|
-
|
|
11944
|
+
// closed: an inert handle whose methods do nothing
|
|
11945
|
+
createChart: guard((o) => this.allow("charts") ? this.charts.create(o) : { el: el("div", "fg-chart-body"), setType: () => void 0, update: () => void 0, destroy: () => void 0 }),
|
|
11745
11946
|
getCsv: guard((o) => buildCsv(this, o)),
|
|
11746
11947
|
getJson: guard((o) => buildJson(this, o)),
|
|
11747
11948
|
exportJson: guard((name = "export.json", o) => download(name, [buildJson(this, o)], "application/json;charset=utf-8")),
|
|
11748
11949
|
exportCsv: guard((name = "export.csv", o) => download(name, ["\uFEFF", buildCsv(this, o)], "text/csv;charset=utf-8")),
|
|
11749
|
-
getXlsx: guard((o) => buildXlsx(this, o)),
|
|
11750
|
-
exportXlsx: guard((name = "export.xlsx", o) =>
|
|
11950
|
+
getXlsx: guard((o) => this.allow("excel") ? buildXlsx(this, o) : new Uint8Array(0)),
|
|
11951
|
+
exportXlsx: guard((name = "export.xlsx", o) => {
|
|
11952
|
+
if (!this.allow("excel")) return;
|
|
11953
|
+
download(name, [buildXlsx(this, o)], "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
11954
|
+
}),
|
|
11751
11955
|
importFile: guard((file, o) => importInto(this, file, o)),
|
|
11752
11956
|
on: guard((type, fn) => this.events.on(type, fn)),
|
|
11753
11957
|
destroy: () => this.destroy()
|
|
@@ -11775,10 +11979,13 @@ function buildWorkbook(sheets) {
|
|
|
11775
11979
|
warn("buildWorkbook: no grids given; the file has one empty sheet");
|
|
11776
11980
|
return writeXlsx([{ name: "Sheet1", rows: [] }]);
|
|
11777
11981
|
}
|
|
11982
|
+
if (list.some((s) => gridOfApi(s.grid)?.allow("workbook") === false)) return new Uint8Array(0);
|
|
11778
11983
|
return writeXlsx(list.map((s, i) => s.grid.getXlsxSheet({ ...s.options, sheetName: s.sheetName ?? s.options?.sheetName ?? `Sheet${i + 1}` })));
|
|
11779
11984
|
}
|
|
11780
11985
|
function exportWorkbook(filename, sheets) {
|
|
11781
|
-
|
|
11986
|
+
const bytes = buildWorkbook(sheets);
|
|
11987
|
+
if (!bytes.length) return;
|
|
11988
|
+
download(filename || "export.xlsx", [bytes], "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
11782
11989
|
}
|
|
11783
11990
|
|
|
11784
11991
|
// src/rest.ts
|