@odoo/o-spreadsheet 17.2.1 → 17.3.0-alpha.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/dist/o-spreadsheet.cjs.js +461 -174
- package/dist/o-spreadsheet.d.ts +58 -20
- package/dist/o-spreadsheet.esm.js +461 -174
- package/dist/o-spreadsheet.iife.js +461 -174
- package/dist/o-spreadsheet.iife.min.js +269 -264
- package/dist/o_spreadsheet.xml +28 -6
- package/package.json +2 -2
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
5
5
|
* @see https://github.com/odoo/o-spreadsheet
|
|
6
|
-
* @version 17.
|
|
7
|
-
* @date 2024-03-25T09:
|
|
8
|
-
* @hash
|
|
6
|
+
* @version 17.3.0-alpha.1
|
|
7
|
+
* @date 2024-03-25T09:43:36.072Z
|
|
8
|
+
* @hash 4095c41
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
@@ -4203,6 +4203,10 @@ function organizeZone(zone) {
|
|
|
4203
4203
|
function positionToZone(position) {
|
|
4204
4204
|
return { left: position.col, right: position.col, top: position.row, bottom: position.row };
|
|
4205
4205
|
}
|
|
4206
|
+
/** Transform a zone into a zone with only its top-left position */
|
|
4207
|
+
function zoneToTopLeft(zone) {
|
|
4208
|
+
return { ...zone, right: zone.left, bottom: zone.top };
|
|
4209
|
+
}
|
|
4206
4210
|
function isFullRow(zone) {
|
|
4207
4211
|
return zone.right === undefined;
|
|
4208
4212
|
}
|
|
@@ -4242,6 +4246,16 @@ function getZonesRows(zones) {
|
|
|
4242
4246
|
}
|
|
4243
4247
|
return set;
|
|
4244
4248
|
}
|
|
4249
|
+
function unionPositionsToZone(positions) {
|
|
4250
|
+
const zone = { top: Infinity, left: Infinity, bottom: -Infinity, right: -Infinity };
|
|
4251
|
+
for (const { col, row } of positions) {
|
|
4252
|
+
zone.top = Math.min(zone.top, row);
|
|
4253
|
+
zone.left = Math.min(zone.left, col);
|
|
4254
|
+
zone.bottom = Math.max(zone.bottom, row);
|
|
4255
|
+
zone.right = Math.max(zone.right, col);
|
|
4256
|
+
}
|
|
4257
|
+
return zone;
|
|
4258
|
+
}
|
|
4245
4259
|
|
|
4246
4260
|
class RangeImpl {
|
|
4247
4261
|
getSheetSize;
|
|
@@ -5571,7 +5585,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
5571
5585
|
const spreader = this.getters.getArrayFormulaSpreadingOn(position);
|
|
5572
5586
|
let cell = this.getters.getCell(position);
|
|
5573
5587
|
const evaluatedCell = this.getters.getEvaluatedCell(position);
|
|
5574
|
-
if (spreader) {
|
|
5588
|
+
if (spreader && !deepEquals(spreader, position)) {
|
|
5575
5589
|
const isSpreaderCopied = rowsIndexes.includes(spreader.row) && columnsIndexes.includes(spreader.col);
|
|
5576
5590
|
const content = isSpreaderCopied
|
|
5577
5591
|
? ""
|
|
@@ -6218,19 +6232,25 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
6218
6232
|
tableCellsInRow.push({});
|
|
6219
6233
|
continue;
|
|
6220
6234
|
}
|
|
6235
|
+
const coreTable = this.getters.getCoreTable(position);
|
|
6236
|
+
const tableZone = coreTable?.range.zone;
|
|
6221
6237
|
// Copy whole table
|
|
6222
|
-
if (zones.some((z) => isZoneInside(
|
|
6223
|
-
copiedTablesIds.add(
|
|
6238
|
+
if (coreTable && tableZone && zones.some((z) => isZoneInside(tableZone, z))) {
|
|
6239
|
+
copiedTablesIds.add(coreTable.id);
|
|
6224
6240
|
const values = [];
|
|
6225
|
-
for (const col of range(
|
|
6226
|
-
values.push(this.getters.getFilterHiddenValues({ sheetId, col, row:
|
|
6241
|
+
for (const col of range(tableZone.left, tableZone.right + 1)) {
|
|
6242
|
+
values.push(this.getters.getFilterHiddenValues({ sheetId, col, row: tableZone.top }));
|
|
6227
6243
|
}
|
|
6228
6244
|
tableCellsInRow.push({
|
|
6229
|
-
table: {
|
|
6245
|
+
table: {
|
|
6246
|
+
range: coreTable.range,
|
|
6247
|
+
config: coreTable.config,
|
|
6248
|
+
type: coreTable.type,
|
|
6249
|
+
},
|
|
6230
6250
|
});
|
|
6231
6251
|
}
|
|
6232
6252
|
// Copy only style of cell
|
|
6233
|
-
else {
|
|
6253
|
+
else if (table) {
|
|
6234
6254
|
tableCellsInRow.push({ style: this.getTableStyleToCopy(position) });
|
|
6235
6255
|
}
|
|
6236
6256
|
}
|
|
@@ -6301,7 +6321,7 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
6301
6321
|
}
|
|
6302
6322
|
pasteTableCell(sheetId, tableCell, position, options) {
|
|
6303
6323
|
if (tableCell.table && !options?.pasteOption) {
|
|
6304
|
-
const { range: tableRange
|
|
6324
|
+
const { range: tableRange } = tableCell.table;
|
|
6305
6325
|
const zoneDims = zoneToDimension(tableRange.zone);
|
|
6306
6326
|
const newTableZone = {
|
|
6307
6327
|
left: position.col,
|
|
@@ -6313,18 +6333,13 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
6313
6333
|
sheetId: position.sheetId,
|
|
6314
6334
|
ranges: [this.getters.getRangeDataFromZone(sheetId, newTableZone)],
|
|
6315
6335
|
config: tableCell.table.config,
|
|
6336
|
+
tableType: tableCell.table.type,
|
|
6316
6337
|
});
|
|
6317
|
-
for (const i of range(0, filtersValues.length)) {
|
|
6318
|
-
this.dispatch("UPDATE_FILTER", {
|
|
6319
|
-
sheetId: position.sheetId,
|
|
6320
|
-
col: newTableZone.left + i,
|
|
6321
|
-
row: newTableZone.top,
|
|
6322
|
-
hiddenValues: filtersValues[i],
|
|
6323
|
-
});
|
|
6324
|
-
}
|
|
6325
6338
|
}
|
|
6326
6339
|
// Do not paste table style if we're inside another table
|
|
6327
|
-
|
|
6340
|
+
// We cannot check for dynamic tables, because at this point the paste can have changed the evaluation, and the
|
|
6341
|
+
// dynamic tables are not yet computed
|
|
6342
|
+
if (!this.getters.getCoreTable(position)) {
|
|
6328
6343
|
if (tableCell.style?.style && options?.pasteOption !== "asValue") {
|
|
6329
6344
|
this.dispatch("UPDATE_CELL", { ...position, style: tableCell.style.style });
|
|
6330
6345
|
}
|
|
@@ -7426,9 +7441,11 @@ const TableTerms = {
|
|
|
7426
7441
|
bandedColumns: _t("Banded columns"),
|
|
7427
7442
|
automaticAutofill: _t("Automatically autofill formulas"),
|
|
7428
7443
|
totalRow: _t("Total row"),
|
|
7444
|
+
isDynamic: _t("Auto-adjust to formula result"),
|
|
7429
7445
|
},
|
|
7430
7446
|
Tooltips: {
|
|
7431
7447
|
filterWithoutHeader: _t("Cannot have filters without a header row"),
|
|
7448
|
+
isDynamic: _t("For tables based on array formulas only"),
|
|
7432
7449
|
},
|
|
7433
7450
|
};
|
|
7434
7451
|
|
|
@@ -22229,6 +22246,7 @@ class LinkDisplay extends owl.Component {
|
|
|
22229
22246
|
}
|
|
22230
22247
|
edit() {
|
|
22231
22248
|
const { col, row } = this.props.cellPosition;
|
|
22249
|
+
this.env.model.selection.selectCell(col, row);
|
|
22232
22250
|
this.cellPopovers.open({ col, row }, "LinkEditor");
|
|
22233
22251
|
}
|
|
22234
22252
|
unlink() {
|
|
@@ -23345,13 +23363,20 @@ const TABLE_PRESETS = {
|
|
|
23345
23363
|
* If a single cell is selected, expand the selection to non-empty adjacent cells to create a table.
|
|
23346
23364
|
*/
|
|
23347
23365
|
function interactiveCreateTable(env, sheetId, tableConfig) {
|
|
23348
|
-
|
|
23349
|
-
|
|
23366
|
+
let target = env.model.getters.getSelectedZones();
|
|
23367
|
+
let isDynamic = env.model.getters.canCreateDynamicTableOnZones(sheetId, target);
|
|
23368
|
+
if (target.length === 1 && !isDynamic && getZoneArea(target[0]) === 1) {
|
|
23350
23369
|
env.model.selection.selectTableAroundSelection();
|
|
23370
|
+
target = env.model.getters.getSelectedZones();
|
|
23371
|
+
isDynamic = env.model.getters.canCreateDynamicTableOnZones(sheetId, target);
|
|
23351
23372
|
}
|
|
23352
|
-
const target = env.model.getters.getSelectedZones();
|
|
23353
23373
|
const ranges = target.map((zone) => env.model.getters.getRangeDataFromZone(sheetId, zone));
|
|
23354
|
-
const result = env.model.dispatch("CREATE_TABLE", {
|
|
23374
|
+
const result = env.model.dispatch("CREATE_TABLE", {
|
|
23375
|
+
ranges,
|
|
23376
|
+
sheetId,
|
|
23377
|
+
config: tableConfig,
|
|
23378
|
+
tableType: isDynamic ? "dynamic" : "static",
|
|
23379
|
+
});
|
|
23355
23380
|
if (result.isCancelledBecause("TableOverlap" /* CommandResult.TableOverlap */)) {
|
|
23356
23381
|
env.raiseError(TableTerms.Errors.TableOverlap);
|
|
23357
23382
|
}
|
|
@@ -23799,9 +23824,13 @@ const INSERT_TABLE = (env) => {
|
|
|
23799
23824
|
};
|
|
23800
23825
|
const DELETE_SELECTED_TABLE = (env) => {
|
|
23801
23826
|
const position = env.model.getters.getActivePosition();
|
|
23827
|
+
const table = env.model.getters.getTable(position);
|
|
23828
|
+
if (!table) {
|
|
23829
|
+
return;
|
|
23830
|
+
}
|
|
23802
23831
|
env.model.dispatch("REMOVE_TABLE", {
|
|
23803
23832
|
sheetId: position.sheetId,
|
|
23804
|
-
target: [
|
|
23833
|
+
target: [table.range.zone],
|
|
23805
23834
|
});
|
|
23806
23835
|
};
|
|
23807
23836
|
//------------------------------------------------------------------------------
|
|
@@ -30309,6 +30338,24 @@ function getTableContentZone(tableZone, tableConfig) {
|
|
|
30309
30338
|
const contentZone = { ...tableZone, top: tableZone.top + numberOfHeaders };
|
|
30310
30339
|
return contentZone.top <= contentZone.bottom ? contentZone : undefined;
|
|
30311
30340
|
}
|
|
30341
|
+
function getTableTopLeft(table) {
|
|
30342
|
+
const range = table.range;
|
|
30343
|
+
return { row: range.zone.top, col: range.zone.left, sheetId: range.sheetId };
|
|
30344
|
+
}
|
|
30345
|
+
function createFilter(id, range, config, createRange) {
|
|
30346
|
+
const zone = range.zone;
|
|
30347
|
+
if (zone.left !== zone.right) {
|
|
30348
|
+
throw new Error("Can only define a filter on a single column");
|
|
30349
|
+
}
|
|
30350
|
+
const filteredZone = { ...zone, top: zone.top + config.numberOfHeaders };
|
|
30351
|
+
const filteredRange = createRange(range.sheetId, filteredZone);
|
|
30352
|
+
return {
|
|
30353
|
+
id,
|
|
30354
|
+
rangeWithHeaders: range,
|
|
30355
|
+
col: zone.left,
|
|
30356
|
+
filteredRange: filteredZone.top > filteredZone.bottom ? undefined : filteredRange,
|
|
30357
|
+
};
|
|
30358
|
+
}
|
|
30312
30359
|
function getComputedTableStyle(tableConfig, numberOfCols, numberOfRows) {
|
|
30313
30360
|
return {
|
|
30314
30361
|
borders: getAllTableBorders(tableConfig, numberOfCols, numberOfRows),
|
|
@@ -30746,6 +30793,11 @@ css /* scss */ `
|
|
|
30746
30793
|
color: #ffffff;
|
|
30747
30794
|
background: #d94b4b;
|
|
30748
30795
|
}
|
|
30796
|
+
|
|
30797
|
+
.o-info-icon {
|
|
30798
|
+
width: 14px;
|
|
30799
|
+
height: 14px;
|
|
30800
|
+
}
|
|
30749
30801
|
}
|
|
30750
30802
|
`;
|
|
30751
30803
|
class TablePanel extends owl.Component {
|
|
@@ -30777,6 +30829,29 @@ class TablePanel extends owl.Component {
|
|
|
30777
30829
|
const numberOfHeaders = hasHeaders ? 1 : 0;
|
|
30778
30830
|
this.updateNumberOfHeaders(numberOfHeaders);
|
|
30779
30831
|
}
|
|
30832
|
+
updateTableIsDynamic(isDynamic) {
|
|
30833
|
+
const newTableType = isDynamic ? "dynamic" : "forceStatic";
|
|
30834
|
+
if (newTableType === this.props.table.type) {
|
|
30835
|
+
return;
|
|
30836
|
+
}
|
|
30837
|
+
const uiTable = this.env.model.getters.getTable(getTableTopLeft(this.props.table));
|
|
30838
|
+
if (!uiTable) {
|
|
30839
|
+
return;
|
|
30840
|
+
}
|
|
30841
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
30842
|
+
const result = this.env.model.dispatch("UPDATE_TABLE", {
|
|
30843
|
+
sheetId,
|
|
30844
|
+
zone: this.props.table.range.zone,
|
|
30845
|
+
newTableRange: uiTable.range.rangeData,
|
|
30846
|
+
tableType: newTableType,
|
|
30847
|
+
});
|
|
30848
|
+
const updatedTable = this.env.model.getters.getCoreTable(getTableTopLeft(this.props.table));
|
|
30849
|
+
if (result.isSuccessful && updatedTable) {
|
|
30850
|
+
const newTableRange = updatedTable.range;
|
|
30851
|
+
this.state.tableXc = this.env.model.getters.getRangeString(newTableRange, sheetId);
|
|
30852
|
+
this.state.tableZoneErrors = [];
|
|
30853
|
+
}
|
|
30854
|
+
}
|
|
30780
30855
|
onChangeNumberOfHeaders(ev) {
|
|
30781
30856
|
const input = ev.target;
|
|
30782
30857
|
const numberOfHeaders = parseInt(input.value);
|
|
@@ -30800,35 +30875,59 @@ class TablePanel extends owl.Component {
|
|
|
30800
30875
|
}
|
|
30801
30876
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
30802
30877
|
this.state.tableXc = ranges[0];
|
|
30878
|
+
const newTableRange = this.env.model.getters.getRangeFromSheetXC(sheetId, this.state.tableXc);
|
|
30803
30879
|
this.state.tableZoneErrors = this.env.model.canDispatch("UPDATE_TABLE", {
|
|
30804
30880
|
sheetId,
|
|
30805
30881
|
zone: this.props.table.range.zone,
|
|
30806
30882
|
newTableRange: this.env.model.getters.getRangeDataFromXc(sheetId, this.state.tableXc),
|
|
30883
|
+
tableType: this.getNewTableType(newTableRange.zone),
|
|
30807
30884
|
}).reasons;
|
|
30808
30885
|
}
|
|
30809
30886
|
onRangeConfirmed() {
|
|
30810
30887
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
30811
|
-
|
|
30888
|
+
let newRange = this.env.model.getters.getRangeFromSheetXC(sheetId, this.state.tableXc);
|
|
30889
|
+
if (getZoneArea(newRange.zone) === 1) {
|
|
30890
|
+
const extendedZone = this.env.model.getters.getContiguousZone(sheetId, newRange.zone);
|
|
30891
|
+
newRange = this.env.model.getters.getRangeFromZone(sheetId, extendedZone);
|
|
30892
|
+
}
|
|
30812
30893
|
const result = this.env.model.dispatch("UPDATE_TABLE", {
|
|
30813
30894
|
sheetId,
|
|
30814
30895
|
zone: this.props.table.range.zone,
|
|
30815
30896
|
newTableRange: newRange.rangeData,
|
|
30897
|
+
tableType: this.getNewTableType(newRange.zone),
|
|
30816
30898
|
});
|
|
30817
|
-
|
|
30818
|
-
|
|
30899
|
+
const position = { sheetId, col: newRange.zone.left, row: newRange.zone.top };
|
|
30900
|
+
const updatedTable = this.env.model.getters.getCoreTable(position);
|
|
30901
|
+
if (result.isSuccessful && updatedTable) {
|
|
30902
|
+
const newTopLeft = getTableTopLeft(updatedTable);
|
|
30819
30903
|
this.env.model.selection.selectZone({
|
|
30820
|
-
zone: positionToZone(
|
|
30821
|
-
cell:
|
|
30904
|
+
zone: positionToZone(newTopLeft),
|
|
30905
|
+
cell: newTopLeft,
|
|
30822
30906
|
});
|
|
30907
|
+
const newTableRange = updatedTable.range;
|
|
30908
|
+
this.state.tableXc = this.env.model.getters.getRangeString(newTableRange, sheetId);
|
|
30909
|
+
}
|
|
30910
|
+
else {
|
|
30911
|
+
const oldTableRange = this.props.table.range;
|
|
30912
|
+
this.state.tableXc = this.env.model.getters.getRangeString(oldTableRange, sheetId);
|
|
30823
30913
|
}
|
|
30824
30914
|
this.state.tableZoneErrors = [];
|
|
30825
|
-
this.state.tableXc = result.isSuccessful
|
|
30826
|
-
? this.state.tableXc
|
|
30827
|
-
: this.env.model.getters.getRangeString(this.props.table.range, sheetId);
|
|
30828
30915
|
}
|
|
30829
30916
|
deleteTable() {
|
|
30830
30917
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
30831
|
-
this.env.model.dispatch("REMOVE_TABLE", {
|
|
30918
|
+
this.env.model.dispatch("REMOVE_TABLE", {
|
|
30919
|
+
sheetId,
|
|
30920
|
+
target: [this.props.table.range.zone],
|
|
30921
|
+
});
|
|
30922
|
+
}
|
|
30923
|
+
getNewTableType(newTableZone) {
|
|
30924
|
+
if (this.props.table.type === "forceStatic") {
|
|
30925
|
+
return "forceStatic";
|
|
30926
|
+
}
|
|
30927
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
30928
|
+
return this.env.model.getters.canCreateDynamicTableOnZones(sheetId, [newTableZone])
|
|
30929
|
+
? "dynamic"
|
|
30930
|
+
: "static";
|
|
30832
30931
|
}
|
|
30833
30932
|
get tableConfig() {
|
|
30834
30933
|
return this.props.table.config;
|
|
@@ -30846,6 +30945,14 @@ class TablePanel extends owl.Component {
|
|
|
30846
30945
|
get hasFilterCheckboxTooltip() {
|
|
30847
30946
|
return this.canHaveFilters ? undefined : TableTerms.Tooltips.filterWithoutHeader;
|
|
30848
30947
|
}
|
|
30948
|
+
get canBeDynamic() {
|
|
30949
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
30950
|
+
return (this.props.table.type === "dynamic" ||
|
|
30951
|
+
this.env.model.getters.canCreateDynamicTableOnZones(sheetId, [this.props.table.range.zone]));
|
|
30952
|
+
}
|
|
30953
|
+
get dynamicTableTooltip() {
|
|
30954
|
+
return TableTerms.Tooltips.isDynamic;
|
|
30955
|
+
}
|
|
30849
30956
|
}
|
|
30850
30957
|
|
|
30851
30958
|
const sidePanelRegistry = new Registry();
|
|
@@ -30908,11 +31015,8 @@ sidePanelRegistry.add("TableSidePanel", {
|
|
|
30908
31015
|
if (!table) {
|
|
30909
31016
|
return { isOpen: false };
|
|
30910
31017
|
}
|
|
30911
|
-
|
|
30912
|
-
|
|
30913
|
-
props: { table },
|
|
30914
|
-
key: table.id,
|
|
30915
|
-
};
|
|
31018
|
+
const coreTable = getters.getCoreTable(getTableTopLeft(table));
|
|
31019
|
+
return { isOpen: true, props: { table: coreTable }, key: table.id };
|
|
30916
31020
|
},
|
|
30917
31021
|
});
|
|
30918
31022
|
|
|
@@ -31857,9 +31961,6 @@ class FunctionDescriptionProvider extends owl.Component {
|
|
|
31857
31961
|
this.assistantState.allowCellSelectionBehind = false;
|
|
31858
31962
|
}, 2000);
|
|
31859
31963
|
}
|
|
31860
|
-
get formulaArgSeparator() {
|
|
31861
|
-
return this.env.model.getters.getLocale().formulaArgSeparator + " ";
|
|
31862
|
-
}
|
|
31863
31964
|
}
|
|
31864
31965
|
|
|
31865
31966
|
const functions$2 = functionRegistry.content;
|
|
@@ -32757,8 +32858,7 @@ class FilterIconsOverlay extends owl.Component {
|
|
|
32757
32858
|
};
|
|
32758
32859
|
getFilterHeadersPositions() {
|
|
32759
32860
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
32760
|
-
|
|
32761
|
-
return headerPositions.map((position) => ({ sheetId, ...position }));
|
|
32861
|
+
return this.env.model.getters.getFilterHeaders(sheetId);
|
|
32762
32862
|
}
|
|
32763
32863
|
}
|
|
32764
32864
|
|
|
@@ -44827,22 +44927,12 @@ class SheetPlugin extends CorePlugin {
|
|
|
44827
44927
|
}
|
|
44828
44928
|
|
|
44829
44929
|
class TablePlugin extends CorePlugin {
|
|
44830
|
-
static getters = [
|
|
44831
|
-
"getFilter",
|
|
44832
|
-
"getFilters",
|
|
44833
|
-
"getTable",
|
|
44834
|
-
"getTables",
|
|
44835
|
-
"getTablesInZone",
|
|
44836
|
-
"getTablesOverlappingZones",
|
|
44837
|
-
"getFilterId",
|
|
44838
|
-
"getFilterHeaders",
|
|
44839
|
-
"isFilterHeader",
|
|
44840
|
-
];
|
|
44930
|
+
static getters = ["getCoreTable", "getCoreTables"];
|
|
44841
44931
|
tables = {};
|
|
44842
44932
|
adaptRanges(applyChange, sheetId) {
|
|
44843
44933
|
const sheetIds = sheetId ? [sheetId] : this.getters.getSheetIds();
|
|
44844
44934
|
for (const sheetId of sheetIds) {
|
|
44845
|
-
for (const table of this.
|
|
44935
|
+
for (const table of this.getCoreTables(sheetId)) {
|
|
44846
44936
|
this.applyRangeChangeOnTable(sheetId, table, applyChange);
|
|
44847
44937
|
}
|
|
44848
44938
|
}
|
|
@@ -44858,15 +44948,16 @@ class TablePlugin extends CorePlugin {
|
|
|
44858
44948
|
? "TableOverlap" /* CommandResult.TableOverlap */
|
|
44859
44949
|
: "Success" /* CommandResult.Success */, (cmd) => this.checkTableConfigUpdateIsValid(cmd.config));
|
|
44860
44950
|
case "UPDATE_TABLE":
|
|
44861
|
-
const updatedTable = this.
|
|
44951
|
+
const updatedTable = this.getTableFromZone(cmd.sheetId, cmd.zone);
|
|
44862
44952
|
if (!updatedTable) {
|
|
44863
44953
|
return "TableNotFound" /* CommandResult.TableNotFound */;
|
|
44864
44954
|
}
|
|
44865
44955
|
return this.checkValidations(cmd, this.checkUpdatedTableZoneIsValid, (cmd) => this.checkTableConfigUpdateIsValid(cmd.config));
|
|
44866
44956
|
case "ADD_MERGE":
|
|
44867
|
-
for (const
|
|
44868
|
-
|
|
44869
|
-
|
|
44957
|
+
for (const table of this.getCoreTables(cmd.sheetId)) {
|
|
44958
|
+
const tableZone = table.range.zone;
|
|
44959
|
+
for (const merge of cmd.target) {
|
|
44960
|
+
if (overlap(tableZone, merge)) {
|
|
44870
44961
|
return "MergeInTable" /* CommandResult.MergeInTable */;
|
|
44871
44962
|
}
|
|
44872
44963
|
}
|
|
@@ -44888,8 +44979,11 @@ class TablePlugin extends CorePlugin {
|
|
|
44888
44979
|
}
|
|
44889
44980
|
case "DUPLICATE_SHEET": {
|
|
44890
44981
|
const newTables = {};
|
|
44891
|
-
for (const table of this.
|
|
44892
|
-
newTables[table.id] =
|
|
44982
|
+
for (const table of this.getCoreTables(cmd.sheetId)) {
|
|
44983
|
+
newTables[table.id] =
|
|
44984
|
+
table.type === "dynamic"
|
|
44985
|
+
? this.copyDynamicTableForSheet(cmd.sheetIdTo, table)
|
|
44986
|
+
: this.copyStaticTableForSheet(cmd.sheetIdTo, table);
|
|
44893
44987
|
}
|
|
44894
44988
|
this.history.update("tables", cmd.sheetIdTo, newTables);
|
|
44895
44989
|
break;
|
|
@@ -44900,14 +44994,17 @@ class TablePlugin extends CorePlugin {
|
|
|
44900
44994
|
const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
|
|
44901
44995
|
this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
|
|
44902
44996
|
const id = this.uuidGenerator.uuidv4();
|
|
44903
|
-
const
|
|
44997
|
+
const config = cmd.config || DEFAULT_TABLE_CONFIG;
|
|
44998
|
+
const newTable = cmd.tableType === "dynamic"
|
|
44999
|
+
? this.createDynamicTable(id, union, config)
|
|
45000
|
+
: this.createStaticTable(id, cmd.tableType, union, config);
|
|
44904
45001
|
this.history.update("tables", cmd.sheetId, newTable.id, newTable);
|
|
44905
45002
|
break;
|
|
44906
45003
|
}
|
|
44907
45004
|
case "REMOVE_TABLE": {
|
|
44908
45005
|
const tables = {};
|
|
44909
|
-
for (const table of this.
|
|
44910
|
-
if (cmd.target.every((zone) => !intersection(
|
|
45006
|
+
for (const table of this.getCoreTables(cmd.sheetId)) {
|
|
45007
|
+
if (cmd.target.every((zone) => !intersection(table.range.zone, zone))) {
|
|
44911
45008
|
tables[table.id] = table;
|
|
44912
45009
|
}
|
|
44913
45010
|
}
|
|
@@ -44915,23 +45012,15 @@ class TablePlugin extends CorePlugin {
|
|
|
44915
45012
|
break;
|
|
44916
45013
|
}
|
|
44917
45014
|
case "UPDATE_TABLE": {
|
|
44918
|
-
|
|
44919
|
-
if (table) {
|
|
44920
|
-
const newTableRange = cmd.newTableRange
|
|
44921
|
-
? this.getters.getRangeFromRangeData(cmd.newTableRange)
|
|
44922
|
-
: undefined;
|
|
44923
|
-
if (newTableRange) {
|
|
44924
|
-
const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, newTableRange.zone);
|
|
44925
|
-
this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
|
|
44926
|
-
}
|
|
44927
|
-
const newTable = this.updateTable(table, newTableRange, cmd.config);
|
|
44928
|
-
this.history.update("tables", cmd.sheetId, table.id, newTable);
|
|
44929
|
-
}
|
|
45015
|
+
this.updateTable(cmd);
|
|
44930
45016
|
break;
|
|
44931
45017
|
}
|
|
44932
45018
|
case "UPDATE_CELL": {
|
|
44933
45019
|
const sheetId = cmd.sheetId;
|
|
44934
|
-
for (const table of this.
|
|
45020
|
+
for (const table of this.getCoreTables(sheetId)) {
|
|
45021
|
+
if (table.type === "dynamic") {
|
|
45022
|
+
continue;
|
|
45023
|
+
}
|
|
44935
45024
|
const direction = this.canUpdateCellCmdExtendTable(cmd, table);
|
|
44936
45025
|
if (direction === "down") {
|
|
44937
45026
|
this.extendTableDown(sheetId, table);
|
|
@@ -44955,62 +45044,24 @@ class TablePlugin extends CorePlugin {
|
|
|
44955
45044
|
}
|
|
44956
45045
|
}
|
|
44957
45046
|
}
|
|
44958
|
-
|
|
44959
|
-
return this.getTables(sheetId)
|
|
44960
|
-
.filter((table) => table.config.hasFilters)
|
|
44961
|
-
.map((table) => table.filters)
|
|
44962
|
-
.flat();
|
|
44963
|
-
}
|
|
44964
|
-
getTables(sheetId) {
|
|
45047
|
+
getCoreTables(sheetId) {
|
|
44965
45048
|
return this.tables[sheetId] ? Object.values(this.tables[sheetId]).filter(isDefined$1) : [];
|
|
44966
45049
|
}
|
|
44967
|
-
|
|
44968
|
-
|
|
44969
|
-
if (!table || !table.config.hasFilters) {
|
|
44970
|
-
return undefined;
|
|
44971
|
-
}
|
|
44972
|
-
return table.filters.find((filter) => filter.col === position.col);
|
|
44973
|
-
}
|
|
44974
|
-
getFilterId(position) {
|
|
44975
|
-
return this.getFilter(position)?.id;
|
|
44976
|
-
}
|
|
44977
|
-
getTable({ sheetId, col, row }) {
|
|
44978
|
-
return this.getTables(sheetId).find((table) => isInside(col, row, table.range.zone));
|
|
44979
|
-
}
|
|
44980
|
-
/** Get the filter tables that are fully inside the given zone */
|
|
44981
|
-
getTablesInZone(sheetId, zone) {
|
|
44982
|
-
return this.getTables(sheetId).filter((table) => isZoneInside(table.range.zone, zone));
|
|
45050
|
+
getCoreTable({ sheetId, col, row }) {
|
|
45051
|
+
return this.getCoreTables(sheetId).find((table) => isInside(col, row, table.range.zone));
|
|
44983
45052
|
}
|
|
44984
45053
|
getTablesOverlappingZones(sheetId, zones) {
|
|
44985
|
-
return this.
|
|
44986
|
-
}
|
|
44987
|
-
getFilterHeaders(sheetId) {
|
|
44988
|
-
const headers = [];
|
|
44989
|
-
for (const table of this.getTables(sheetId)) {
|
|
44990
|
-
if (!table.config.hasFilters) {
|
|
44991
|
-
continue;
|
|
44992
|
-
}
|
|
44993
|
-
const zone = table.range.zone;
|
|
44994
|
-
const row = zone.top;
|
|
44995
|
-
for (let col = zone.left; col <= zone.right; col++) {
|
|
44996
|
-
headers.push({ col, row });
|
|
44997
|
-
}
|
|
44998
|
-
}
|
|
44999
|
-
return headers;
|
|
45000
|
-
}
|
|
45001
|
-
isFilterHeader({ sheetId, col, row }) {
|
|
45002
|
-
const headers = this.getFilterHeaders(sheetId);
|
|
45003
|
-
return headers.some((header) => header.col === col && header.row === row);
|
|
45054
|
+
return this.getCoreTables(sheetId).filter((table) => zones.some((zone) => overlap(table.range.zone, zone)));
|
|
45004
45055
|
}
|
|
45005
45056
|
/** Extend a table down one row */
|
|
45006
45057
|
extendTableDown(sheetId, table) {
|
|
45007
45058
|
const newRange = this.getters.extendRange(table.range, "ROW", 1);
|
|
45008
|
-
this.history.update("tables", sheetId, table.id, this.
|
|
45059
|
+
this.history.update("tables", sheetId, table.id, this.updateStaticTable(table, newRange));
|
|
45009
45060
|
}
|
|
45010
45061
|
/** Extend a table right one col */
|
|
45011
45062
|
extendTableRight(sheetId, table) {
|
|
45012
45063
|
const newRange = this.getters.extendRange(table.range, "COL", 1);
|
|
45013
|
-
this.history.update("tables", sheetId, table.id, this.
|
|
45064
|
+
this.history.update("tables", sheetId, table.id, this.updateStaticTable(table, newRange));
|
|
45014
45065
|
}
|
|
45015
45066
|
/**
|
|
45016
45067
|
* Check if an UpdateCell command should cause the given table to be extended by one row or col.
|
|
@@ -45047,12 +45098,22 @@ class TablePlugin extends CorePlugin {
|
|
|
45047
45098
|
const cellContent = this.getters.getCell(cellPosition)?.content;
|
|
45048
45099
|
if (cellContent ||
|
|
45049
45100
|
this.getters.isInMerge(cellPosition) ||
|
|
45050
|
-
this.
|
|
45101
|
+
this.getTablesOverlappingZones(sheetId, [positionToZone(position)]).length) {
|
|
45051
45102
|
return "none";
|
|
45052
45103
|
}
|
|
45053
45104
|
}
|
|
45054
45105
|
return direction;
|
|
45055
45106
|
}
|
|
45107
|
+
getTableFromZone(sheetId, zone) {
|
|
45108
|
+
for (const table of this.getCoreTables(sheetId)) {
|
|
45109
|
+
const tableZone = table.range.zone;
|
|
45110
|
+
// Only check top left to match dynamic tables
|
|
45111
|
+
if (tableZone.left === zone.left && tableZone.top === zone.top) {
|
|
45112
|
+
return table;
|
|
45113
|
+
}
|
|
45114
|
+
}
|
|
45115
|
+
return undefined;
|
|
45116
|
+
}
|
|
45056
45117
|
checkUpdatedTableZoneIsValid(cmd) {
|
|
45057
45118
|
if (!cmd.newTableRange) {
|
|
45058
45119
|
return "Success" /* CommandResult.Success */;
|
|
@@ -45062,7 +45123,11 @@ class TablePlugin extends CorePlugin {
|
|
|
45062
45123
|
if (zoneIsInSheet !== "Success" /* CommandResult.Success */) {
|
|
45063
45124
|
return zoneIsInSheet;
|
|
45064
45125
|
}
|
|
45065
|
-
const
|
|
45126
|
+
const updatedTable = this.getTableFromZone(cmd.sheetId, cmd.zone);
|
|
45127
|
+
if (!updatedTable) {
|
|
45128
|
+
return "TableNotFound" /* CommandResult.TableNotFound */;
|
|
45129
|
+
}
|
|
45130
|
+
const overlappingTables = this.getTablesOverlappingZones(cmd.sheetId, [newTableZone]).filter((table) => table.id !== updatedTable.id);
|
|
45066
45131
|
return overlappingTables.length ? "TableOverlap" /* CommandResult.TableOverlap */ : "Success" /* CommandResult.Success */;
|
|
45067
45132
|
}
|
|
45068
45133
|
checkTableConfigUpdateIsValid(config) {
|
|
@@ -45080,7 +45145,7 @@ class TablePlugin extends CorePlugin {
|
|
|
45080
45145
|
}
|
|
45081
45146
|
return "Success" /* CommandResult.Success */;
|
|
45082
45147
|
}
|
|
45083
|
-
|
|
45148
|
+
createStaticTable(id, type, tableRange, config, filters) {
|
|
45084
45149
|
const zone = tableRange.zone;
|
|
45085
45150
|
if (!filters) {
|
|
45086
45151
|
filters = [];
|
|
@@ -45095,9 +45160,51 @@ class TablePlugin extends CorePlugin {
|
|
|
45095
45160
|
range: tableRange,
|
|
45096
45161
|
filters,
|
|
45097
45162
|
config,
|
|
45163
|
+
type,
|
|
45164
|
+
};
|
|
45165
|
+
}
|
|
45166
|
+
createDynamicTable(id, tableRange, config) {
|
|
45167
|
+
const zone = zoneToTopLeft(tableRange.zone);
|
|
45168
|
+
return {
|
|
45169
|
+
id,
|
|
45170
|
+
range: this.getters.getRangeFromZone(tableRange.sheetId, zone),
|
|
45171
|
+
config,
|
|
45172
|
+
type: "dynamic",
|
|
45098
45173
|
};
|
|
45099
45174
|
}
|
|
45100
|
-
updateTable(
|
|
45175
|
+
updateTable(cmd) {
|
|
45176
|
+
const table = this.getTableFromZone(cmd.sheetId, cmd.zone);
|
|
45177
|
+
if (!table) {
|
|
45178
|
+
return;
|
|
45179
|
+
}
|
|
45180
|
+
const newTableRange = cmd.newTableRange
|
|
45181
|
+
? this.getters.getRangeFromRangeData(cmd.newTableRange)
|
|
45182
|
+
: undefined;
|
|
45183
|
+
if (newTableRange) {
|
|
45184
|
+
const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, newTableRange.zone);
|
|
45185
|
+
this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
|
|
45186
|
+
}
|
|
45187
|
+
const range = newTableRange || table.range;
|
|
45188
|
+
const newConfig = this.updateTableConfig(cmd.config, table.config);
|
|
45189
|
+
const newTableType = cmd.tableType ?? table.type;
|
|
45190
|
+
if ((newTableType === "dynamic" && table.type !== "dynamic") ||
|
|
45191
|
+
(newTableType !== "dynamic" && table.type === "dynamic")) {
|
|
45192
|
+
const newTable = newTableType === "dynamic"
|
|
45193
|
+
? this.createDynamicTable(table.id, range, newConfig)
|
|
45194
|
+
: this.createStaticTable(table.id, newTableType, range, newConfig);
|
|
45195
|
+
this.history.update("tables", cmd.sheetId, table.id, newTable);
|
|
45196
|
+
}
|
|
45197
|
+
else {
|
|
45198
|
+
const updatedTable = table.type === "dynamic"
|
|
45199
|
+
? this.updateDynamicTable(table, range, newConfig)
|
|
45200
|
+
: this.updateStaticTable(table, range, newConfig, newTableType);
|
|
45201
|
+
this.history.update("tables", cmd.sheetId, table.id, updatedTable);
|
|
45202
|
+
}
|
|
45203
|
+
}
|
|
45204
|
+
updateStaticTable(table, newRange, configUpdate, newTableType = table.type) {
|
|
45205
|
+
if (newTableType === "dynamic") {
|
|
45206
|
+
throw new Error("Cannot use updateStaticTable to update a dynamic table");
|
|
45207
|
+
}
|
|
45101
45208
|
const tableRange = newRange ? newRange : table.range;
|
|
45102
45209
|
const tableZone = tableRange.zone;
|
|
45103
45210
|
const newConfig = this.updateTableConfig(configUpdate, table.config);
|
|
@@ -45118,8 +45225,16 @@ class TablePlugin extends CorePlugin {
|
|
|
45118
45225
|
range: tableRange,
|
|
45119
45226
|
config,
|
|
45120
45227
|
filters: filters.length ? filters : table.filters,
|
|
45228
|
+
type: newTableType,
|
|
45121
45229
|
};
|
|
45122
45230
|
}
|
|
45231
|
+
updateDynamicTable(table, newRange, newConfig) {
|
|
45232
|
+
const range = newRange
|
|
45233
|
+
? this.getters.getRangeFromZone(newRange.sheetId, zoneToTopLeft(newRange.zone))
|
|
45234
|
+
: table.range;
|
|
45235
|
+
const config = newConfig ? newConfig : table.config;
|
|
45236
|
+
return { ...table, range, config };
|
|
45237
|
+
}
|
|
45123
45238
|
/**
|
|
45124
45239
|
* Update the old config of a table with the new partial config from an UpdateTable command.
|
|
45125
45240
|
*
|
|
@@ -45141,35 +45256,29 @@ class TablePlugin extends CorePlugin {
|
|
|
45141
45256
|
}
|
|
45142
45257
|
createFilterFromZone(id, sheetId, zone, config) {
|
|
45143
45258
|
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
45144
|
-
return
|
|
45145
|
-
}
|
|
45146
|
-
createFilter(id, range, config) {
|
|
45147
|
-
const zone = range.zone;
|
|
45148
|
-
if (zone.left !== zone.right) {
|
|
45149
|
-
throw new Error("Can only define a filter on a single column");
|
|
45150
|
-
}
|
|
45151
|
-
const contentZone = getTableContentZone(zone, config);
|
|
45152
|
-
const filteredRange = contentZone
|
|
45153
|
-
? this.getters.getRangeFromZone(range.sheetId, contentZone)
|
|
45154
|
-
: undefined;
|
|
45155
|
-
return {
|
|
45156
|
-
id,
|
|
45157
|
-
rangeWithHeaders: range,
|
|
45158
|
-
col: zone.left,
|
|
45159
|
-
filteredRange,
|
|
45160
|
-
};
|
|
45259
|
+
return createFilter(id, range, config, this.getters.getRangeFromZone);
|
|
45161
45260
|
}
|
|
45162
|
-
|
|
45261
|
+
copyStaticTableForSheet(sheetId, table) {
|
|
45163
45262
|
const newRange = this.getters.getRangeFromZone(sheetId, table.range.zone);
|
|
45164
45263
|
const newFilters = table.filters.map((filter) => {
|
|
45165
45264
|
const newFilterRange = this.getters.getRangeFromZone(sheetId, filter.rangeWithHeaders.zone);
|
|
45166
|
-
return
|
|
45265
|
+
return createFilter(filter.id, newFilterRange, table.config, this.getters.getRangeFromZone);
|
|
45167
45266
|
});
|
|
45168
45267
|
return {
|
|
45169
45268
|
id: table.id,
|
|
45170
45269
|
range: newRange,
|
|
45171
45270
|
filters: newFilters,
|
|
45172
45271
|
config: deepCopy(table.config),
|
|
45272
|
+
type: table.type,
|
|
45273
|
+
};
|
|
45274
|
+
}
|
|
45275
|
+
copyDynamicTableForSheet(sheetId, table) {
|
|
45276
|
+
const newRange = this.getters.getRangeFromZone(sheetId, table.range.zone);
|
|
45277
|
+
return {
|
|
45278
|
+
id: table.id,
|
|
45279
|
+
range: newRange,
|
|
45280
|
+
config: deepCopy(table.config),
|
|
45281
|
+
type: "dynamic",
|
|
45173
45282
|
};
|
|
45174
45283
|
}
|
|
45175
45284
|
applyRangeChangeOnTable(sheetId, table, applyChange) {
|
|
@@ -45184,6 +45293,11 @@ class TablePlugin extends CorePlugin {
|
|
|
45184
45293
|
default:
|
|
45185
45294
|
newTableRange = tableRangeChange.range;
|
|
45186
45295
|
}
|
|
45296
|
+
if (table.type === "dynamic") {
|
|
45297
|
+
const newTable = this.updateDynamicTable(table, newTableRange);
|
|
45298
|
+
this.history.update("tables", sheetId, table.id, newTable);
|
|
45299
|
+
return;
|
|
45300
|
+
}
|
|
45187
45301
|
const filters = [];
|
|
45188
45302
|
for (const filter of table.filters) {
|
|
45189
45303
|
const filterRangeChange = applyChange(filter.rangeWithHeaders);
|
|
@@ -45195,7 +45309,7 @@ class TablePlugin extends CorePlugin {
|
|
|
45195
45309
|
break;
|
|
45196
45310
|
default:
|
|
45197
45311
|
const newFilterRange = filterRangeChange.range;
|
|
45198
|
-
const newFilter =
|
|
45312
|
+
const newFilter = createFilter(filter.id, newFilterRange, table.config, this.getters.getRangeFromZone);
|
|
45199
45313
|
filters.push(newFilter);
|
|
45200
45314
|
}
|
|
45201
45315
|
}
|
|
@@ -45210,7 +45324,7 @@ class TablePlugin extends CorePlugin {
|
|
|
45210
45324
|
}
|
|
45211
45325
|
filters.sort((f1, f2) => f1.col - f2.col);
|
|
45212
45326
|
}
|
|
45213
|
-
const newTable = this.
|
|
45327
|
+
const newTable = this.createStaticTable(table.id, table.type, newTableRange, table.config, filters);
|
|
45214
45328
|
this.history.update("tables", sheetId, table.id, newTable);
|
|
45215
45329
|
}
|
|
45216
45330
|
// ---------------------------------------------------------------------------
|
|
@@ -45221,16 +45335,20 @@ class TablePlugin extends CorePlugin {
|
|
|
45221
45335
|
for (const tableData of sheet.tables || []) {
|
|
45222
45336
|
const uuid = this.uuidGenerator.uuidv4();
|
|
45223
45337
|
const tableConfig = tableData.config || DEFAULT_TABLE_CONFIG;
|
|
45224
|
-
const
|
|
45225
|
-
const
|
|
45338
|
+
const range = this.getters.getRangeFromSheetXC(sheet.id, tableData.range);
|
|
45339
|
+
const tableType = tableData.type || "static";
|
|
45340
|
+
const table = tableType === "dynamic"
|
|
45341
|
+
? this.createDynamicTable(uuid, range, tableConfig)
|
|
45342
|
+
: this.createStaticTable(uuid, tableType, range, tableConfig);
|
|
45226
45343
|
this.history.update("tables", sheet.id, table.id, table);
|
|
45227
45344
|
}
|
|
45228
45345
|
}
|
|
45229
45346
|
}
|
|
45230
45347
|
export(data) {
|
|
45231
45348
|
for (const sheet of data.sheets) {
|
|
45232
|
-
for (const table of this.
|
|
45233
|
-
const
|
|
45349
|
+
for (const table of this.getCoreTables(sheet.id)) {
|
|
45350
|
+
const range = zoneToXc(table.range.zone);
|
|
45351
|
+
const tableData = { range, type: table.type };
|
|
45234
45352
|
if (!deepEquals(table.config, DEFAULT_TABLE_CONFIG)) {
|
|
45235
45353
|
tableData.config = table.config;
|
|
45236
45354
|
}
|
|
@@ -46946,14 +47064,18 @@ class Evaluator {
|
|
|
46946
47064
|
if (!this.spreadingRelations.isArrayFormula(position)) {
|
|
46947
47065
|
return [];
|
|
46948
47066
|
}
|
|
46949
|
-
|
|
47067
|
+
if (this.evaluatedCells.get(position)?.type === CellValueType.error) {
|
|
47068
|
+
return [position];
|
|
47069
|
+
}
|
|
47070
|
+
const spreadPositions = Array.from(this.spreadingRelations.getArrayResultPositions(position));
|
|
47071
|
+
return [position, ...spreadPositions];
|
|
46950
47072
|
}
|
|
46951
47073
|
getEvaluatedPositions() {
|
|
46952
47074
|
return this.evaluatedCells.keys();
|
|
46953
47075
|
}
|
|
46954
47076
|
getArrayFormulaSpreadingOn(position) {
|
|
46955
47077
|
if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
|
|
46956
|
-
return undefined;
|
|
47078
|
+
return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
|
|
46957
47079
|
}
|
|
46958
47080
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
|
|
46959
47081
|
return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
|
|
@@ -47082,6 +47204,7 @@ class Evaluator {
|
|
|
47082
47204
|
if (!this.blockedArrayFormulas.has(position)) {
|
|
47083
47205
|
this.invalidateSpreading(position);
|
|
47084
47206
|
}
|
|
47207
|
+
this.spreadingRelations.removeNode(position);
|
|
47085
47208
|
const cell = this.getters.getCell(position);
|
|
47086
47209
|
if (cell === undefined) {
|
|
47087
47210
|
return EMPTY_CELL;
|
|
@@ -47192,7 +47315,6 @@ class Evaluator {
|
|
|
47192
47315
|
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
47193
47316
|
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
47194
47317
|
}
|
|
47195
|
-
this.spreadingRelations.removeNode(position);
|
|
47196
47318
|
}
|
|
47197
47319
|
// ----------------------------------------------------------
|
|
47198
47320
|
// COMMON FUNCTIONALITY
|
|
@@ -48290,6 +48412,181 @@ class EvaluationDataValidationPlugin extends UIPlugin {
|
|
|
48290
48412
|
}
|
|
48291
48413
|
}
|
|
48292
48414
|
|
|
48415
|
+
class DynamicTablesPlugin extends UIPlugin {
|
|
48416
|
+
static getters = [
|
|
48417
|
+
"canCreateDynamicTableOnZones",
|
|
48418
|
+
"doesZonesContainFilter",
|
|
48419
|
+
"getFilter",
|
|
48420
|
+
"getFilters",
|
|
48421
|
+
"getTable",
|
|
48422
|
+
"getTables",
|
|
48423
|
+
"getTablesOverlappingZones",
|
|
48424
|
+
"getFilterId",
|
|
48425
|
+
"getFilterHeaders",
|
|
48426
|
+
"isFilterHeader",
|
|
48427
|
+
];
|
|
48428
|
+
tables = {};
|
|
48429
|
+
handle(cmd) {
|
|
48430
|
+
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
48431
|
+
(cmd.type === "UPDATE_CELL" && "content" in cmd) ||
|
|
48432
|
+
cmd.type === "EVALUATE_CELLS") {
|
|
48433
|
+
this.tables = {};
|
|
48434
|
+
return;
|
|
48435
|
+
}
|
|
48436
|
+
switch (cmd.type) {
|
|
48437
|
+
case "CREATE_TABLE":
|
|
48438
|
+
case "REMOVE_TABLE":
|
|
48439
|
+
case "UPDATE_TABLE":
|
|
48440
|
+
case "DELETE_CONTENT":
|
|
48441
|
+
this.tables = {};
|
|
48442
|
+
break;
|
|
48443
|
+
}
|
|
48444
|
+
}
|
|
48445
|
+
finalize() {
|
|
48446
|
+
for (const sheetId of this.getters.getSheetIds()) {
|
|
48447
|
+
if (!this.tables[sheetId]) {
|
|
48448
|
+
this.tables[sheetId] = this.computeTables(sheetId);
|
|
48449
|
+
}
|
|
48450
|
+
}
|
|
48451
|
+
}
|
|
48452
|
+
computeTables(sheetId) {
|
|
48453
|
+
const tables = [];
|
|
48454
|
+
const coreTables = this.getters.getCoreTables(sheetId);
|
|
48455
|
+
// First we create the static tables, so we can use them to compute collision with dynamic tables
|
|
48456
|
+
for (const table of coreTables) {
|
|
48457
|
+
if (table.type === "dynamic")
|
|
48458
|
+
continue;
|
|
48459
|
+
tables.push(table);
|
|
48460
|
+
}
|
|
48461
|
+
const staticTables = [...tables];
|
|
48462
|
+
// Then we create the dynamic tables
|
|
48463
|
+
for (const coreTable of coreTables) {
|
|
48464
|
+
if (coreTable.type !== "dynamic")
|
|
48465
|
+
continue;
|
|
48466
|
+
const table = this.coreTableToTable(sheetId, coreTable);
|
|
48467
|
+
let tableZone = table.range.zone;
|
|
48468
|
+
// Reduce the zone to avoid collision with static tables. Per design, dynamic tables can't overlap with other
|
|
48469
|
+
// dynamic tables, because formulas cannot spread on the same area, so we don't need to check for that.
|
|
48470
|
+
for (const staticTable of staticTables) {
|
|
48471
|
+
if (overlap(tableZone, staticTable.range.zone)) {
|
|
48472
|
+
tableZone = { ...tableZone, right: staticTable.range.zone.left - 1 };
|
|
48473
|
+
}
|
|
48474
|
+
}
|
|
48475
|
+
tables.push({ ...table, range: this.getters.getRangeFromZone(sheetId, tableZone) });
|
|
48476
|
+
}
|
|
48477
|
+
return tables;
|
|
48478
|
+
}
|
|
48479
|
+
getFilters(sheetId) {
|
|
48480
|
+
return this.getTables(sheetId)
|
|
48481
|
+
.filter((table) => table.config.hasFilters)
|
|
48482
|
+
.map((table) => table.filters)
|
|
48483
|
+
.flat();
|
|
48484
|
+
}
|
|
48485
|
+
getTables(sheetId) {
|
|
48486
|
+
return this.tables[sheetId] || [];
|
|
48487
|
+
}
|
|
48488
|
+
getFilter(position) {
|
|
48489
|
+
const table = this.getTable(position);
|
|
48490
|
+
if (!table || !table.config.hasFilters) {
|
|
48491
|
+
return undefined;
|
|
48492
|
+
}
|
|
48493
|
+
return table.filters.find((filter) => filter.col === position.col);
|
|
48494
|
+
}
|
|
48495
|
+
getFilterId(position) {
|
|
48496
|
+
return this.getFilter(position)?.id;
|
|
48497
|
+
}
|
|
48498
|
+
getTable({ sheetId, col, row }) {
|
|
48499
|
+
return this.getTables(sheetId).find((table) => isInside(col, row, table.range.zone));
|
|
48500
|
+
}
|
|
48501
|
+
getTablesOverlappingZones(sheetId, zones) {
|
|
48502
|
+
return this.getTables(sheetId).filter((table) => zones.some((zone) => overlap(table.range.zone, zone)));
|
|
48503
|
+
}
|
|
48504
|
+
doesZonesContainFilter(sheetId, zones) {
|
|
48505
|
+
return this.getTablesOverlappingZones(sheetId, zones).some((table) => table.config.hasFilters);
|
|
48506
|
+
}
|
|
48507
|
+
getFilterHeaders(sheetId) {
|
|
48508
|
+
const headers = [];
|
|
48509
|
+
for (const table of this.getTables(sheetId)) {
|
|
48510
|
+
if (!table.config.hasFilters) {
|
|
48511
|
+
continue;
|
|
48512
|
+
}
|
|
48513
|
+
const zone = table.range.zone;
|
|
48514
|
+
const row = zone.top;
|
|
48515
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
48516
|
+
headers.push({ sheetId, col, row });
|
|
48517
|
+
}
|
|
48518
|
+
}
|
|
48519
|
+
return headers;
|
|
48520
|
+
}
|
|
48521
|
+
isFilterHeader({ sheetId, col, row }) {
|
|
48522
|
+
const headers = this.getFilterHeaders(sheetId);
|
|
48523
|
+
return headers.some((header) => header.col === col && header.row === row);
|
|
48524
|
+
}
|
|
48525
|
+
/**
|
|
48526
|
+
* Check if we can create a dynamic table on the given zones.
|
|
48527
|
+
* - The zones must be continuous
|
|
48528
|
+
* - The union of the zones must be either:
|
|
48529
|
+
* - A single cell that contains an array formula
|
|
48530
|
+
* - All the spread cells of a single array formula
|
|
48531
|
+
*/
|
|
48532
|
+
canCreateDynamicTableOnZones(sheetId, zones) {
|
|
48533
|
+
if (!areZonesContinuous(zones)) {
|
|
48534
|
+
return false;
|
|
48535
|
+
}
|
|
48536
|
+
const unionZone = union(...zones);
|
|
48537
|
+
const topLeft = { col: unionZone.left, row: unionZone.top, sheetId };
|
|
48538
|
+
const parentSpreadingCell = this.getters.getArrayFormulaSpreadingOn(topLeft);
|
|
48539
|
+
if (!parentSpreadingCell) {
|
|
48540
|
+
return false;
|
|
48541
|
+
}
|
|
48542
|
+
else if (deepEquals(parentSpreadingCell, topLeft) && getZoneArea(unionZone) === 1) {
|
|
48543
|
+
return true;
|
|
48544
|
+
}
|
|
48545
|
+
const spreadPositions = this.getters.getSpreadPositionsOf(parentSpreadingCell);
|
|
48546
|
+
return deepEquals(unionZone, unionPositionsToZone(spreadPositions));
|
|
48547
|
+
}
|
|
48548
|
+
coreTableToTable(sheetId, table) {
|
|
48549
|
+
if (table.type !== "dynamic") {
|
|
48550
|
+
return table;
|
|
48551
|
+
}
|
|
48552
|
+
const tableZone = table.range.zone;
|
|
48553
|
+
const tablePosition = { sheetId, col: tableZone.left, row: tableZone.top };
|
|
48554
|
+
const spreadPositions = this.getters.getSpreadPositionsOf(tablePosition);
|
|
48555
|
+
const zone = spreadPositions.length ? unionPositionsToZone(spreadPositions) : table.range.zone;
|
|
48556
|
+
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
48557
|
+
const filters = this.getDynamicTableFilters(sheetId, table, zone);
|
|
48558
|
+
return { id: table.id, range, filters, config: table.config };
|
|
48559
|
+
}
|
|
48560
|
+
getDynamicTableFilters(sheetId, table, tableZone) {
|
|
48561
|
+
const filters = [];
|
|
48562
|
+
const { top, bottom, left, right } = tableZone;
|
|
48563
|
+
for (let col = left; col <= right; col++) {
|
|
48564
|
+
const tableColIndex = col - left;
|
|
48565
|
+
const zone = { left: col, right: col, top, bottom };
|
|
48566
|
+
const filter = createFilter(this.getDynamicTableFilterId(table.id, tableColIndex), this.getters.getRangeFromZone(sheetId, zone), table.config, this.getters.getRangeFromZone);
|
|
48567
|
+
filters.push(filter);
|
|
48568
|
+
}
|
|
48569
|
+
return filters;
|
|
48570
|
+
}
|
|
48571
|
+
getDynamicTableFilterId(tableId, tableCol) {
|
|
48572
|
+
return tableId + "_" + tableCol;
|
|
48573
|
+
}
|
|
48574
|
+
exportForExcel(data) {
|
|
48575
|
+
for (const sheet of data.sheets) {
|
|
48576
|
+
for (const tableData of sheet.tables) {
|
|
48577
|
+
const zone = toZone(tableData.range);
|
|
48578
|
+
const topLeft = { sheetId: sheet.id, col: zone.left, row: zone.top };
|
|
48579
|
+
const coreTable = this.getters.getCoreTable(topLeft);
|
|
48580
|
+
const table = this.getTable(topLeft);
|
|
48581
|
+
if (coreTable?.type !== "dynamic" || !table) {
|
|
48582
|
+
continue;
|
|
48583
|
+
}
|
|
48584
|
+
tableData.range = zoneToXc(table.range.zone);
|
|
48585
|
+
}
|
|
48586
|
+
}
|
|
48587
|
+
}
|
|
48588
|
+
}
|
|
48589
|
+
|
|
48293
48590
|
class HeaderSizeUIPlugin extends UIPlugin {
|
|
48294
48591
|
static getters = ["getRowSize", "getHeaderSize"];
|
|
48295
48592
|
tallestCellInRow = {};
|
|
@@ -51337,10 +51634,11 @@ class TableAutofillPlugin extends UIPlugin {
|
|
|
51337
51634
|
handle(cmd) {
|
|
51338
51635
|
switch (cmd.type) {
|
|
51339
51636
|
case "AUTOFILL_TABLE_COLUMN":
|
|
51340
|
-
const table = this.getters.
|
|
51637
|
+
const table = this.getters.getCoreTable(cmd);
|
|
51341
51638
|
const cell = this.getters.getCell(cmd);
|
|
51342
|
-
if (!table ||
|
|
51639
|
+
if (!table?.config.automaticAutofill || table.type === "dynamic" || !cell?.isFormula) {
|
|
51343
51640
|
return;
|
|
51641
|
+
}
|
|
51344
51642
|
const { col, row } = cmd;
|
|
51345
51643
|
const tableContentZone = getTableContentZone(table.range.zone, table.config);
|
|
51346
51644
|
if (tableContentZone && isInside(col, row, tableContentZone)) {
|
|
@@ -52069,9 +52367,6 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
52069
52367
|
case "START":
|
|
52070
52368
|
for (const sheetId of this.getters.getSheetIds()) {
|
|
52071
52369
|
this.filterValues[sheetId] = {};
|
|
52072
|
-
for (const filter of this.getters.getFilters(sheetId)) {
|
|
52073
|
-
this.filterValues[sheetId][filter.id] = [];
|
|
52074
|
-
}
|
|
52075
52370
|
}
|
|
52076
52371
|
break;
|
|
52077
52372
|
case "CREATE_SHEET":
|
|
@@ -52092,16 +52387,7 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
52092
52387
|
this.updateHiddenRows();
|
|
52093
52388
|
break;
|
|
52094
52389
|
case "DUPLICATE_SHEET":
|
|
52095
|
-
|
|
52096
|
-
for (const newFilter of this.getters.getFilters(cmd.sheetIdTo)) {
|
|
52097
|
-
const zone = newFilter.rangeWithHeaders.zone;
|
|
52098
|
-
filterValues[newFilter.id] = this.getFilterHiddenValues({
|
|
52099
|
-
sheetId: cmd.sheetId,
|
|
52100
|
-
col: zone.left,
|
|
52101
|
-
row: zone.top,
|
|
52102
|
-
});
|
|
52103
|
-
}
|
|
52104
|
-
this.filterValues[cmd.sheetIdTo] = filterValues;
|
|
52390
|
+
this.filterValues[cmd.sheetIdTo] = deepCopy(this.filterValues[cmd.sheetId]);
|
|
52105
52391
|
break;
|
|
52106
52392
|
// If we don't handle DELETE_SHEET, on one hand we will have some residual data, on the other hand we keep the data
|
|
52107
52393
|
// on DELETE_SHEET followed by undo
|
|
@@ -54045,8 +54331,9 @@ const coreViewsPluginRegistry = new Registry()
|
|
|
54045
54331
|
.add("evaluation_chart", EvaluationChartPlugin)
|
|
54046
54332
|
.add("evaluation_cf", EvaluationConditionalFormatPlugin)
|
|
54047
54333
|
.add("row_size", HeaderSizeUIPlugin)
|
|
54048
|
-
.add("
|
|
54049
|
-
.add("
|
|
54334
|
+
.add("data_validation_ui", EvaluationDataValidationPlugin)
|
|
54335
|
+
.add("dynamic_tables", DynamicTablesPlugin)
|
|
54336
|
+
.add("custom_colors", CustomColorsPlugin);
|
|
54050
54337
|
|
|
54051
54338
|
const clickableCellRegistry = new Registry();
|
|
54052
54339
|
clickableCellRegistry.add("link", {
|
|
@@ -60177,6 +60464,6 @@ exports.tokenColors = tokenColors;
|
|
|
60177
60464
|
exports.tokenize = tokenize;
|
|
60178
60465
|
|
|
60179
60466
|
|
|
60180
|
-
__info__.version = "17.
|
|
60181
|
-
__info__.date = "2024-03-25T09:
|
|
60182
|
-
__info__.hash = "
|
|
60467
|
+
__info__.version = "17.3.0-alpha.1";
|
|
60468
|
+
__info__.date = "2024-03-25T09:43:36.072Z";
|
|
60469
|
+
__info__.hash = "4095c41";
|