@odoo/o-spreadsheet 17.3.0-alpha.0 → 17.3.0-alpha.2
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 +1427 -603
- package/dist/o-spreadsheet.d.ts +122 -72
- package/dist/o-spreadsheet.esm.js +1427 -603
- package/dist/o-spreadsheet.iife.js +1427 -603
- package/dist/o-spreadsheet.iife.min.js +391 -341
- package/dist/o_spreadsheet.xml +156 -62
- package/package.json +5 -5
|
@@ -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.3.0-alpha.
|
|
7
|
-
* @date 2024-
|
|
8
|
-
* @hash
|
|
6
|
+
* @version 17.3.0-alpha.2
|
|
7
|
+
* @date 2024-04-05T14:01:07.060Z
|
|
8
|
+
* @hash 8c5a229
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
(function (exports, owl) {
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
const LINK_COLOR = "#017E84";
|
|
31
31
|
const FILTERS_COLOR = "#188038";
|
|
32
32
|
const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
|
|
33
|
-
const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
|
|
34
33
|
const SEPARATOR_COLOR = "#E0E2E4";
|
|
35
34
|
const ICONS_COLOR = "#4A4F59";
|
|
36
35
|
const HEADER_GROUPING_BACKGROUND_COLOR = "#F5F5F5";
|
|
@@ -466,7 +465,7 @@
|
|
|
466
465
|
}
|
|
467
466
|
// Generate new Id if the item didn't exist in the dictionary
|
|
468
467
|
const ids = Object.keys(itemsDic);
|
|
469
|
-
const maxId = ids.length === 0 ? 0 :
|
|
468
|
+
const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
|
|
470
469
|
itemsDic[maxId + 1] = item;
|
|
471
470
|
return maxId + 1;
|
|
472
471
|
}
|
|
@@ -484,7 +483,7 @@
|
|
|
484
483
|
let timeout = undefined;
|
|
485
484
|
const debounced = function () {
|
|
486
485
|
const context = this;
|
|
487
|
-
const args = arguments;
|
|
486
|
+
const args = Array.from(arguments);
|
|
488
487
|
function later() {
|
|
489
488
|
timeout = undefined;
|
|
490
489
|
if (!immediate) {
|
|
@@ -686,6 +685,34 @@
|
|
|
686
685
|
}
|
|
687
686
|
return RegExp(searchValue, flags);
|
|
688
687
|
}
|
|
688
|
+
/**
|
|
689
|
+
* Alternative to Math.max that works with large arrays.
|
|
690
|
+
* Typically useful for arrays bigger than 100k elements.
|
|
691
|
+
*/
|
|
692
|
+
function largeMax(array) {
|
|
693
|
+
let len = array.length;
|
|
694
|
+
if (len < 100_000)
|
|
695
|
+
return Math.max(...array);
|
|
696
|
+
let max = -Infinity;
|
|
697
|
+
while (len--) {
|
|
698
|
+
max = array[len] > max ? array[len] : max;
|
|
699
|
+
}
|
|
700
|
+
return max;
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Alternative to Math.min that works with large arrays.
|
|
704
|
+
* Typically useful for arrays bigger than 100k elements.
|
|
705
|
+
*/
|
|
706
|
+
function largeMin(array) {
|
|
707
|
+
let len = array.length;
|
|
708
|
+
if (len < 100_000)
|
|
709
|
+
return Math.min(...array);
|
|
710
|
+
let min = +Infinity;
|
|
711
|
+
while (len--) {
|
|
712
|
+
min = array[len] < min ? array[len] : min;
|
|
713
|
+
}
|
|
714
|
+
return min;
|
|
715
|
+
}
|
|
689
716
|
|
|
690
717
|
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
691
718
|
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
|
|
@@ -2088,6 +2115,7 @@
|
|
|
2088
2115
|
CommandResult["InvalidCopyPasteSelection"] = "InvalidCopyPasteSelection";
|
|
2089
2116
|
CommandResult["NoChanges"] = "NoChanges";
|
|
2090
2117
|
CommandResult["InvalidInputId"] = "InvalidInputId";
|
|
2118
|
+
CommandResult["SheetIsHidden"] = "SheetIsHidden";
|
|
2091
2119
|
})(exports.CommandResult || (exports.CommandResult = {}));
|
|
2092
2120
|
|
|
2093
2121
|
const PLAIN_TEXT_FORMAT = "@"; // see OpenXML spec §18.8.31
|
|
@@ -4203,6 +4231,10 @@
|
|
|
4203
4231
|
function positionToZone(position) {
|
|
4204
4232
|
return { left: position.col, right: position.col, top: position.row, bottom: position.row };
|
|
4205
4233
|
}
|
|
4234
|
+
/** Transform a zone into a zone with only its top-left position */
|
|
4235
|
+
function zoneToTopLeft(zone) {
|
|
4236
|
+
return { ...zone, right: zone.left, bottom: zone.top };
|
|
4237
|
+
}
|
|
4206
4238
|
function isFullRow(zone) {
|
|
4207
4239
|
return zone.right === undefined;
|
|
4208
4240
|
}
|
|
@@ -4242,6 +4274,16 @@
|
|
|
4242
4274
|
}
|
|
4243
4275
|
return set;
|
|
4244
4276
|
}
|
|
4277
|
+
function unionPositionsToZone(positions) {
|
|
4278
|
+
const zone = { top: Infinity, left: Infinity, bottom: -Infinity, right: -Infinity };
|
|
4279
|
+
for (const { col, row } of positions) {
|
|
4280
|
+
zone.top = Math.min(zone.top, row);
|
|
4281
|
+
zone.left = Math.min(zone.left, col);
|
|
4282
|
+
zone.bottom = Math.max(zone.bottom, row);
|
|
4283
|
+
zone.right = Math.max(zone.right, col);
|
|
4284
|
+
}
|
|
4285
|
+
return zone;
|
|
4286
|
+
}
|
|
4245
4287
|
|
|
4246
4288
|
class RangeImpl {
|
|
4247
4289
|
getSheetSize;
|
|
@@ -4545,8 +4587,9 @@
|
|
|
4545
4587
|
* Get the default height of the cell given its style.
|
|
4546
4588
|
*/
|
|
4547
4589
|
function getDefaultCellHeight(ctx, cell, colSize) {
|
|
4548
|
-
if (!cell || !cell.content)
|
|
4590
|
+
if (!cell || (!cell.isFormula && !cell.content)) {
|
|
4549
4591
|
return DEFAULT_CELL_HEIGHT;
|
|
4592
|
+
}
|
|
4550
4593
|
const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
|
|
4551
4594
|
const numberOfLines = cell.isFormula
|
|
4552
4595
|
? 1
|
|
@@ -5571,7 +5614,7 @@
|
|
|
5571
5614
|
const spreader = this.getters.getArrayFormulaSpreadingOn(position);
|
|
5572
5615
|
let cell = this.getters.getCell(position);
|
|
5573
5616
|
const evaluatedCell = this.getters.getEvaluatedCell(position);
|
|
5574
|
-
if (spreader) {
|
|
5617
|
+
if (spreader && !deepEquals(spreader, position)) {
|
|
5575
5618
|
const isSpreaderCopied = rowsIndexes.includes(spreader.row) && columnsIndexes.includes(spreader.col);
|
|
5576
5619
|
const content = isSpreaderCopied
|
|
5577
5620
|
? ""
|
|
@@ -6218,19 +6261,25 @@
|
|
|
6218
6261
|
tableCellsInRow.push({});
|
|
6219
6262
|
continue;
|
|
6220
6263
|
}
|
|
6264
|
+
const coreTable = this.getters.getCoreTable(position);
|
|
6265
|
+
const tableZone = coreTable?.range.zone;
|
|
6221
6266
|
// Copy whole table
|
|
6222
|
-
if (zones.some((z) => isZoneInside(
|
|
6223
|
-
copiedTablesIds.add(
|
|
6267
|
+
if (coreTable && tableZone && zones.some((z) => isZoneInside(tableZone, z))) {
|
|
6268
|
+
copiedTablesIds.add(coreTable.id);
|
|
6224
6269
|
const values = [];
|
|
6225
|
-
for (const col of range(
|
|
6226
|
-
values.push(this.getters.getFilterHiddenValues({ sheetId, col, row:
|
|
6270
|
+
for (const col of range(tableZone.left, tableZone.right + 1)) {
|
|
6271
|
+
values.push(this.getters.getFilterHiddenValues({ sheetId, col, row: tableZone.top }));
|
|
6227
6272
|
}
|
|
6228
6273
|
tableCellsInRow.push({
|
|
6229
|
-
table: {
|
|
6274
|
+
table: {
|
|
6275
|
+
range: coreTable.range,
|
|
6276
|
+
config: coreTable.config,
|
|
6277
|
+
type: coreTable.type,
|
|
6278
|
+
},
|
|
6230
6279
|
});
|
|
6231
6280
|
}
|
|
6232
6281
|
// Copy only style of cell
|
|
6233
|
-
else {
|
|
6282
|
+
else if (table) {
|
|
6234
6283
|
tableCellsInRow.push({ style: this.getTableStyleToCopy(position) });
|
|
6235
6284
|
}
|
|
6236
6285
|
}
|
|
@@ -6301,7 +6350,7 @@
|
|
|
6301
6350
|
}
|
|
6302
6351
|
pasteTableCell(sheetId, tableCell, position, options) {
|
|
6303
6352
|
if (tableCell.table && !options?.pasteOption) {
|
|
6304
|
-
const { range: tableRange
|
|
6353
|
+
const { range: tableRange } = tableCell.table;
|
|
6305
6354
|
const zoneDims = zoneToDimension(tableRange.zone);
|
|
6306
6355
|
const newTableZone = {
|
|
6307
6356
|
left: position.col,
|
|
@@ -6313,18 +6362,13 @@
|
|
|
6313
6362
|
sheetId: position.sheetId,
|
|
6314
6363
|
ranges: [this.getters.getRangeDataFromZone(sheetId, newTableZone)],
|
|
6315
6364
|
config: tableCell.table.config,
|
|
6365
|
+
tableType: tableCell.table.type,
|
|
6316
6366
|
});
|
|
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
6367
|
}
|
|
6326
6368
|
// Do not paste table style if we're inside another table
|
|
6327
|
-
|
|
6369
|
+
// We cannot check for dynamic tables, because at this point the paste can have changed the evaluation, and the
|
|
6370
|
+
// dynamic tables are not yet computed
|
|
6371
|
+
if (!this.getters.getCoreTable(position)) {
|
|
6328
6372
|
if (tableCell.style?.style && options?.pasteOption !== "asValue") {
|
|
6329
6373
|
this.dispatch("UPDATE_CELL", { ...position, style: tableCell.style.style });
|
|
6330
6374
|
}
|
|
@@ -6979,10 +7023,17 @@
|
|
|
6979
7023
|
},
|
|
6980
7024
|
open(url, env) {
|
|
6981
7025
|
const sheetId = parseSheetUrl(url);
|
|
6982
|
-
env.model.dispatch("ACTIVATE_SHEET", {
|
|
7026
|
+
const result = env.model.dispatch("ACTIVATE_SHEET", {
|
|
6983
7027
|
sheetIdFrom: env.model.getters.getActiveSheetId(),
|
|
6984
7028
|
sheetIdTo: sheetId,
|
|
6985
7029
|
});
|
|
7030
|
+
if (result.isCancelledBecause("SheetIsHidden" /* CommandResult.SheetIsHidden */)) {
|
|
7031
|
+
env.notifyUser({
|
|
7032
|
+
type: "warning",
|
|
7033
|
+
sticky: false,
|
|
7034
|
+
text: _t("Cannot open the link because the linked sheet is hidden."),
|
|
7035
|
+
});
|
|
7036
|
+
}
|
|
6986
7037
|
},
|
|
6987
7038
|
sequence: 0,
|
|
6988
7039
|
});
|
|
@@ -7098,7 +7149,7 @@
|
|
|
7098
7149
|
}
|
|
7099
7150
|
function numberCell(value, format, formattedValue) {
|
|
7100
7151
|
return {
|
|
7101
|
-
value: value || 0,
|
|
7152
|
+
value: value || 0, // necessary to avoid "-0" and NaN values,
|
|
7102
7153
|
format,
|
|
7103
7154
|
formattedValue,
|
|
7104
7155
|
type: CellValueType.number,
|
|
@@ -7426,9 +7477,11 @@
|
|
|
7426
7477
|
bandedColumns: _t("Banded columns"),
|
|
7427
7478
|
automaticAutofill: _t("Automatically autofill formulas"),
|
|
7428
7479
|
totalRow: _t("Total row"),
|
|
7480
|
+
isDynamic: _t("Auto-adjust to formula result"),
|
|
7429
7481
|
},
|
|
7430
7482
|
Tooltips: {
|
|
7431
7483
|
filterWithoutHeader: _t("Cannot have filters without a header row"),
|
|
7484
|
+
isDynamic: _t("For tables based on array formulas only"),
|
|
7432
7485
|
},
|
|
7433
7486
|
};
|
|
7434
7487
|
|
|
@@ -8004,6 +8057,9 @@
|
|
|
8004
8057
|
instantiate(Store, ...args) {
|
|
8005
8058
|
return this.factory.build(Store, ...args);
|
|
8006
8059
|
}
|
|
8060
|
+
resetStores() {
|
|
8061
|
+
this.dependencies.clear();
|
|
8062
|
+
}
|
|
8007
8063
|
}
|
|
8008
8064
|
class StoreFactory {
|
|
8009
8065
|
get;
|
|
@@ -9937,11 +9993,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9937
9993
|
}
|
|
9938
9994
|
else {
|
|
9939
9995
|
const range = this.getters.getRangeFromSheetXC(position.sheetId, rule.criterion.values[0]);
|
|
9940
|
-
values = this.getters
|
|
9996
|
+
values = Array.from(new Set(this.getters
|
|
9941
9997
|
.getRangeValues(range)
|
|
9942
9998
|
.filter(isNotNull)
|
|
9943
9999
|
.map((value) => value.toString())
|
|
9944
|
-
.filter((val) => val !== "");
|
|
10000
|
+
.filter((val) => val !== "")));
|
|
9945
10001
|
}
|
|
9946
10002
|
return values.map((value) => ({ text: value }));
|
|
9947
10003
|
},
|
|
@@ -19388,10 +19444,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19388
19444
|
}
|
|
19389
19445
|
}
|
|
19390
19446
|
return {
|
|
19391
|
-
labels:
|
|
19447
|
+
labels: Array.from(labelSet),
|
|
19392
19448
|
dataSetsValues: datasets.map((dataset, indexOfDataset) => ({
|
|
19393
19449
|
...dataset,
|
|
19394
|
-
data:
|
|
19450
|
+
data: Array.from(labelSet).map((label) => labelMap[label][indexOfDataset]),
|
|
19395
19451
|
})),
|
|
19396
19452
|
};
|
|
19397
19453
|
}
|
|
@@ -19410,8 +19466,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19410
19466
|
function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale }) {
|
|
19411
19467
|
const options = {
|
|
19412
19468
|
// https://www.chartjs.org/docs/latest/general/responsive.html
|
|
19413
|
-
responsive: true,
|
|
19414
|
-
maintainAspectRatio: false,
|
|
19469
|
+
responsive: true, // will resize when its container is resized
|
|
19470
|
+
maintainAspectRatio: false, // doesn't maintain the aspect ration (width/height =2 by default) so the user has the choice of the exact layout
|
|
19415
19471
|
layout: {
|
|
19416
19472
|
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
|
|
19417
19473
|
},
|
|
@@ -19457,7 +19513,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19457
19513
|
labels: labels.map(truncateLabel),
|
|
19458
19514
|
datasets: [],
|
|
19459
19515
|
},
|
|
19460
|
-
platform: undefined,
|
|
19516
|
+
platform: undefined, // This key is optional and will be set by chart.js
|
|
19461
19517
|
plugins: [],
|
|
19462
19518
|
};
|
|
19463
19519
|
}
|
|
@@ -19734,7 +19790,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19734
19790
|
},
|
|
19735
19791
|
y: {
|
|
19736
19792
|
position: chart.verticalAxisPosition,
|
|
19737
|
-
beginAtZero: true,
|
|
19793
|
+
beginAtZero: true, // the origin of the y axis is always zero
|
|
19738
19794
|
ticks: {
|
|
19739
19795
|
color: fontColor,
|
|
19740
19796
|
callback: (value) => {
|
|
@@ -19785,6 +19841,204 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19785
19841
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
19786
19842
|
}
|
|
19787
19843
|
|
|
19844
|
+
class ComboChart extends AbstractChart {
|
|
19845
|
+
useBothYAxis;
|
|
19846
|
+
dataSets;
|
|
19847
|
+
labelRange;
|
|
19848
|
+
background;
|
|
19849
|
+
verticalAxisPosition;
|
|
19850
|
+
legendPosition;
|
|
19851
|
+
aggregated;
|
|
19852
|
+
dataSetsHaveTitle;
|
|
19853
|
+
type = "combo";
|
|
19854
|
+
constructor(definition, sheetId, getters) {
|
|
19855
|
+
super(definition, sheetId, getters);
|
|
19856
|
+
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
19857
|
+
this.labelRange = createRange(getters, sheetId, definition.labelRange);
|
|
19858
|
+
this.background = definition.background;
|
|
19859
|
+
this.verticalAxisPosition = definition.verticalAxisPosition;
|
|
19860
|
+
this.legendPosition = definition.legendPosition;
|
|
19861
|
+
this.aggregated = definition.aggregated;
|
|
19862
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
19863
|
+
this.useBothYAxis = definition.useBothYAxis;
|
|
19864
|
+
}
|
|
19865
|
+
static transformDefinition(definition, executed) {
|
|
19866
|
+
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
19867
|
+
}
|
|
19868
|
+
static validateChartDefinition(validator, definition) {
|
|
19869
|
+
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
19870
|
+
}
|
|
19871
|
+
getContextCreation() {
|
|
19872
|
+
return {
|
|
19873
|
+
background: this.background,
|
|
19874
|
+
title: this.title,
|
|
19875
|
+
range: this.dataSets.map((ds) => this.getters.getRangeString(ds.dataRange, this.sheetId)),
|
|
19876
|
+
auxiliaryRange: this.labelRange
|
|
19877
|
+
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
19878
|
+
: undefined,
|
|
19879
|
+
aggregated: this.aggregated,
|
|
19880
|
+
};
|
|
19881
|
+
}
|
|
19882
|
+
getDefinition() {
|
|
19883
|
+
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
19884
|
+
}
|
|
19885
|
+
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
19886
|
+
return {
|
|
19887
|
+
type: "combo",
|
|
19888
|
+
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
19889
|
+
background: this.background,
|
|
19890
|
+
dataSets: dataSets.map((ds) => this.getters.getRangeString(ds.dataRange, targetSheetId || this.sheetId)),
|
|
19891
|
+
legendPosition: this.legendPosition,
|
|
19892
|
+
verticalAxisPosition: this.verticalAxisPosition,
|
|
19893
|
+
labelRange: labelRange
|
|
19894
|
+
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
19895
|
+
: undefined,
|
|
19896
|
+
title: this.title,
|
|
19897
|
+
aggregated: this.aggregated,
|
|
19898
|
+
useBothYAxis: this.useBothYAxis,
|
|
19899
|
+
};
|
|
19900
|
+
}
|
|
19901
|
+
getDefinitionForExcel() {
|
|
19902
|
+
// Excel does not support aggregating labels
|
|
19903
|
+
if (this.aggregated) {
|
|
19904
|
+
return undefined;
|
|
19905
|
+
}
|
|
19906
|
+
const dataSets = this.dataSets
|
|
19907
|
+
.map((ds) => toExcelDataset(this.getters, ds))
|
|
19908
|
+
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
19909
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
19910
|
+
return {
|
|
19911
|
+
...this.getDefinition(),
|
|
19912
|
+
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
19913
|
+
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
19914
|
+
dataSets,
|
|
19915
|
+
labelRange,
|
|
19916
|
+
};
|
|
19917
|
+
}
|
|
19918
|
+
updateRanges(applyChange) {
|
|
19919
|
+
const { dataSets, labelRange, isStale } = updateChartRangesWithDataSets(this.getters, applyChange, this.dataSets, this.labelRange);
|
|
19920
|
+
if (!isStale) {
|
|
19921
|
+
return this;
|
|
19922
|
+
}
|
|
19923
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange);
|
|
19924
|
+
return new ComboChart(definition, this.sheetId, this.getters);
|
|
19925
|
+
}
|
|
19926
|
+
static getDefinitionFromContextCreation(context) {
|
|
19927
|
+
return {
|
|
19928
|
+
background: context.background,
|
|
19929
|
+
dataSets: context.range ? context.range : [],
|
|
19930
|
+
dataSetsHaveTitle: false,
|
|
19931
|
+
aggregated: context.aggregated,
|
|
19932
|
+
legendPosition: "top",
|
|
19933
|
+
title: context.title || "",
|
|
19934
|
+
verticalAxisPosition: "left",
|
|
19935
|
+
labelRange: context.auxiliaryRange || undefined,
|
|
19936
|
+
type: "combo",
|
|
19937
|
+
useBothYAxis: false,
|
|
19938
|
+
};
|
|
19939
|
+
}
|
|
19940
|
+
copyForSheetId(sheetId) {
|
|
19941
|
+
const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
|
|
19942
|
+
const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
|
|
19943
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
|
|
19944
|
+
return new ComboChart(definition, sheetId, this.getters);
|
|
19945
|
+
}
|
|
19946
|
+
copyInSheetId(sheetId) {
|
|
19947
|
+
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
19948
|
+
return new ComboChart(definition, sheetId, this.getters);
|
|
19949
|
+
}
|
|
19950
|
+
}
|
|
19951
|
+
function createComboChartRuntime(chart, getters) {
|
|
19952
|
+
const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
|
|
19953
|
+
const locale = getters.getLocale();
|
|
19954
|
+
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
19955
|
+
let labels = labelValues.formattedValues;
|
|
19956
|
+
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
19957
|
+
if (chart.dataSetsHaveTitle &&
|
|
19958
|
+
dataSetsValues[0] &&
|
|
19959
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
19960
|
+
labels.shift();
|
|
19961
|
+
}
|
|
19962
|
+
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
19963
|
+
if (chart.aggregated) {
|
|
19964
|
+
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
19965
|
+
}
|
|
19966
|
+
const localeFormat = { format: dataSetFormat, locale };
|
|
19967
|
+
const fontColor = chartFontColor(chart.background);
|
|
19968
|
+
const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
|
|
19969
|
+
const legend = {
|
|
19970
|
+
labels: { color: fontColor },
|
|
19971
|
+
};
|
|
19972
|
+
if ((!chart.labelRange && chart.dataSets.length === 1) || chart.legendPosition === "none") {
|
|
19973
|
+
legend.display = false;
|
|
19974
|
+
}
|
|
19975
|
+
else {
|
|
19976
|
+
legend.position = chart.legendPosition;
|
|
19977
|
+
}
|
|
19978
|
+
config.options.plugins.legend = { ...config.options.plugins?.legend, ...legend };
|
|
19979
|
+
config.options.layout = {
|
|
19980
|
+
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
|
|
19981
|
+
};
|
|
19982
|
+
config.options.scales = {
|
|
19983
|
+
x: {
|
|
19984
|
+
ticks: {
|
|
19985
|
+
padding: 5,
|
|
19986
|
+
color: fontColor,
|
|
19987
|
+
},
|
|
19988
|
+
},
|
|
19989
|
+
};
|
|
19990
|
+
const verticalAxis = {
|
|
19991
|
+
beginAtZero: true, // the origin of the y axis is always zero
|
|
19992
|
+
ticks: {
|
|
19993
|
+
color: fontColor,
|
|
19994
|
+
callback: (value) => {
|
|
19995
|
+
value = Number(value);
|
|
19996
|
+
if (isNaN(value))
|
|
19997
|
+
return value;
|
|
19998
|
+
const { locale, format } = localeFormat;
|
|
19999
|
+
return formatValue(value, {
|
|
20000
|
+
locale,
|
|
20001
|
+
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
|
20002
|
+
});
|
|
20003
|
+
},
|
|
20004
|
+
},
|
|
20005
|
+
};
|
|
20006
|
+
if (chart.useBothYAxis) {
|
|
20007
|
+
config.options.scales.y = {
|
|
20008
|
+
...verticalAxis,
|
|
20009
|
+
position: "left",
|
|
20010
|
+
};
|
|
20011
|
+
config.options.scales.y1 = {
|
|
20012
|
+
...verticalAxis,
|
|
20013
|
+
position: "right",
|
|
20014
|
+
grid: {
|
|
20015
|
+
display: false,
|
|
20016
|
+
},
|
|
20017
|
+
};
|
|
20018
|
+
}
|
|
20019
|
+
else {
|
|
20020
|
+
config.options.scales.y = {
|
|
20021
|
+
...verticalAxis,
|
|
20022
|
+
position: chart.verticalAxisPosition,
|
|
20023
|
+
};
|
|
20024
|
+
}
|
|
20025
|
+
const colors = new ChartColors();
|
|
20026
|
+
for (let [index, { label, data }] of dataSetsValues.entries()) {
|
|
20027
|
+
const color = colors.next();
|
|
20028
|
+
const dataset = {
|
|
20029
|
+
label,
|
|
20030
|
+
data,
|
|
20031
|
+
borderColor: color,
|
|
20032
|
+
backgroundColor: color,
|
|
20033
|
+
yAxisID: index > 0 && chart.useBothYAxis ? "y1" : "y",
|
|
20034
|
+
type: index === 0 ? "bar" : "line",
|
|
20035
|
+
order: -index,
|
|
20036
|
+
};
|
|
20037
|
+
config.data.datasets.push(dataset);
|
|
20038
|
+
}
|
|
20039
|
+
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
20040
|
+
}
|
|
20041
|
+
|
|
19788
20042
|
function isDataRangeValid(definition) {
|
|
19789
20043
|
return definition.dataRange && !rangeReference.test(definition.dataRange)
|
|
19790
20044
|
? "InvalidGaugeDataRange" /* CommandResult.InvalidGaugeDataRange */
|
|
@@ -20123,7 +20377,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20123
20377
|
return undefined;
|
|
20124
20378
|
}
|
|
20125
20379
|
const labelsTimestamps = labelDates.map((date) => date.getTime());
|
|
20126
|
-
const period =
|
|
20380
|
+
const period = largeMax(labelsTimestamps) - largeMin(labelsTimestamps);
|
|
20127
20381
|
const minUnit = getFormatMinDisplayUnit(format);
|
|
20128
20382
|
if (UNIT_LENGTH.second >= UNIT_LENGTH[minUnit] && Milliseconds.inSeconds(period) < 180) {
|
|
20129
20383
|
return "second";
|
|
@@ -20255,7 +20509,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20255
20509
|
},
|
|
20256
20510
|
y: {
|
|
20257
20511
|
position: chart.verticalAxisPosition,
|
|
20258
|
-
beginAtZero: true,
|
|
20512
|
+
beginAtZero: true, // the origin of the y axis is always zero
|
|
20259
20513
|
ticks: {
|
|
20260
20514
|
color: fontColor,
|
|
20261
20515
|
callback: (value) => {
|
|
@@ -20341,7 +20595,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20341
20595
|
const dataset = {
|
|
20342
20596
|
label,
|
|
20343
20597
|
data,
|
|
20344
|
-
tension: 0,
|
|
20598
|
+
tension: 0, // 0 -> render straight lines, which is much faster
|
|
20345
20599
|
borderColor: color,
|
|
20346
20600
|
backgroundColor,
|
|
20347
20601
|
pointBackgroundColor: color,
|
|
@@ -20563,7 +20817,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20563
20817
|
...this.getDefinition(),
|
|
20564
20818
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
20565
20819
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
20566
|
-
verticalAxisPosition: "left",
|
|
20820
|
+
verticalAxisPosition: "left", //TODO ExcelChartDefinition should be adapted, but can be done later
|
|
20567
20821
|
dataSets,
|
|
20568
20822
|
labelRange,
|
|
20569
20823
|
};
|
|
@@ -20611,7 +20865,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20611
20865
|
}
|
|
20612
20866
|
function getPieColors(colors, dataSetsValues) {
|
|
20613
20867
|
const pieColors = [];
|
|
20614
|
-
const maxLength =
|
|
20868
|
+
const maxLength = largeMax(dataSetsValues.map((ds) => ds.data.length));
|
|
20615
20869
|
for (let i = 0; i <= maxLength; i++) {
|
|
20616
20870
|
pieColors.push(colors.next());
|
|
20617
20871
|
}
|
|
@@ -20780,7 +21034,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20780
21034
|
configOptions.elements = {
|
|
20781
21035
|
point: {
|
|
20782
21036
|
radius: 3,
|
|
20783
|
-
hoverRadius: 3,
|
|
21037
|
+
hoverRadius: 3, // chartJS seems bugged, the point starts with the "hoverRadius" value
|
|
20784
21038
|
hitRadius: 8,
|
|
20785
21039
|
},
|
|
20786
21040
|
};
|
|
@@ -20820,6 +21074,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20820
21074
|
name: _t("Bar"),
|
|
20821
21075
|
sequence: 10,
|
|
20822
21076
|
});
|
|
21077
|
+
chartRegistry.add("combo", {
|
|
21078
|
+
match: (type) => type === "combo",
|
|
21079
|
+
createChart: (definition, sheetId, getters) => new ComboChart(definition, sheetId, getters),
|
|
21080
|
+
getChartRuntime: createComboChartRuntime,
|
|
21081
|
+
validateChartDefinition: (validator, definition) => ComboChart.validateChartDefinition(validator, definition),
|
|
21082
|
+
transformDefinition: (definition, executed) => ComboChart.transformDefinition(definition, executed),
|
|
21083
|
+
getChartDefinitionFromContextCreation: (context) => ComboChart.getDefinitionFromContextCreation(context),
|
|
21084
|
+
name: _t("Combo"),
|
|
21085
|
+
sequence: 15,
|
|
21086
|
+
});
|
|
20823
21087
|
chartRegistry.add("line", {
|
|
20824
21088
|
match: (type) => type === "line",
|
|
20825
21089
|
createChart: (definition, sheetId, getters) => new LineChart(definition, sheetId, getters),
|
|
@@ -20873,6 +21137,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20873
21137
|
const chartComponentRegistry = new Registry();
|
|
20874
21138
|
chartComponentRegistry.add("line", ChartJsComponent);
|
|
20875
21139
|
chartComponentRegistry.add("bar", ChartJsComponent);
|
|
21140
|
+
chartComponentRegistry.add("combo", ChartJsComponent);
|
|
20876
21141
|
chartComponentRegistry.add("pie", ChartJsComponent);
|
|
20877
21142
|
chartComponentRegistry.add("gauge", GaugeChartComponent);
|
|
20878
21143
|
chartComponentRegistry.add("scatter", ChartJsComponent);
|
|
@@ -22226,6 +22491,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
22226
22491
|
}
|
|
22227
22492
|
edit() {
|
|
22228
22493
|
const { col, row } = this.props.cellPosition;
|
|
22494
|
+
this.env.model.selection.selectCell(col, row);
|
|
22229
22495
|
this.cellPopovers.open({ col, row }, "LinkEditor");
|
|
22230
22496
|
}
|
|
22231
22497
|
unlink() {
|
|
@@ -23130,7 +23396,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23130
23396
|
style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
|
|
23131
23397
|
border: { bottom: { color: colorSet.highlight, style: "thin" } },
|
|
23132
23398
|
},
|
|
23133
|
-
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
|
|
23399
|
+
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
|
|
23134
23400
|
firstRowStripe: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
|
|
23135
23401
|
secondRowStripe: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
|
|
23136
23402
|
});
|
|
@@ -23148,7 +23414,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23148
23414
|
},
|
|
23149
23415
|
},
|
|
23150
23416
|
headerRow: { border: { bottom: { color: colorSet.highlight, style: "medium" } } },
|
|
23151
|
-
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
|
|
23417
|
+
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
|
|
23152
23418
|
firstRowStripe: { style: { fillColor: colorSet.light } },
|
|
23153
23419
|
firstColumnStripe: { style: { fillColor: colorSet.light } },
|
|
23154
23420
|
});
|
|
@@ -23167,7 +23433,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23167
23433
|
headerRow: {
|
|
23168
23434
|
style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
|
|
23169
23435
|
},
|
|
23170
|
-
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
|
|
23436
|
+
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
|
|
23171
23437
|
firstRowStripe: { style: { fillColor: colorSet.light } },
|
|
23172
23438
|
firstColumnStripe: { style: { fillColor: colorSet.light } },
|
|
23173
23439
|
});
|
|
@@ -23203,7 +23469,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23203
23469
|
bottom: { color: "#000000", style: "medium" },
|
|
23204
23470
|
},
|
|
23205
23471
|
},
|
|
23206
|
-
totalRow: { border: { top: { color: "#000000", style: "medium" } } },
|
|
23472
|
+
totalRow: { border: { top: { color: "#000000", style: "medium" } } }, // @compatibility: should be double line
|
|
23207
23473
|
headerRow: {
|
|
23208
23474
|
style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
|
|
23209
23475
|
border: { bottom: { color: "#000000", style: "medium" } },
|
|
@@ -23227,7 +23493,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23227
23493
|
},
|
|
23228
23494
|
style: { fillColor: colorSet.light },
|
|
23229
23495
|
},
|
|
23230
|
-
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
|
|
23496
|
+
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
|
|
23231
23497
|
firstRowStripe: { style: { fillColor: colorSet.medium } },
|
|
23232
23498
|
firstColumnStripe: { style: { fillColor: colorSet.medium } },
|
|
23233
23499
|
});
|
|
@@ -23258,7 +23524,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23258
23524
|
category: "dark",
|
|
23259
23525
|
colorName: colorSet.name,
|
|
23260
23526
|
wholeTable: { style: { fillColor: colorSet.light } },
|
|
23261
|
-
totalRow: { border: { top: { color: "#000000", style: "medium" } } },
|
|
23527
|
+
totalRow: { border: { top: { color: "#000000", style: "medium" } } }, // @compatibility: should be double line
|
|
23262
23528
|
headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
|
|
23263
23529
|
firstRowStripe: { style: { fillColor: colorSet.medium } },
|
|
23264
23530
|
firstColumnStripe: { style: { fillColor: colorSet.medium } },
|
|
@@ -23342,13 +23608,20 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23342
23608
|
* If a single cell is selected, expand the selection to non-empty adjacent cells to create a table.
|
|
23343
23609
|
*/
|
|
23344
23610
|
function interactiveCreateTable(env, sheetId, tableConfig) {
|
|
23345
|
-
|
|
23346
|
-
|
|
23611
|
+
let target = env.model.getters.getSelectedZones();
|
|
23612
|
+
let isDynamic = env.model.getters.canCreateDynamicTableOnZones(sheetId, target);
|
|
23613
|
+
if (target.length === 1 && !isDynamic && getZoneArea(target[0]) === 1) {
|
|
23347
23614
|
env.model.selection.selectTableAroundSelection();
|
|
23615
|
+
target = env.model.getters.getSelectedZones();
|
|
23616
|
+
isDynamic = env.model.getters.canCreateDynamicTableOnZones(sheetId, target);
|
|
23348
23617
|
}
|
|
23349
|
-
const target = env.model.getters.getSelectedZones();
|
|
23350
23618
|
const ranges = target.map((zone) => env.model.getters.getRangeDataFromZone(sheetId, zone));
|
|
23351
|
-
const result = env.model.dispatch("CREATE_TABLE", {
|
|
23619
|
+
const result = env.model.dispatch("CREATE_TABLE", {
|
|
23620
|
+
ranges,
|
|
23621
|
+
sheetId,
|
|
23622
|
+
config: tableConfig,
|
|
23623
|
+
tableType: isDynamic ? "dynamic" : "static",
|
|
23624
|
+
});
|
|
23352
23625
|
if (result.isCancelledBecause("TableOverlap" /* CommandResult.TableOverlap */)) {
|
|
23353
23626
|
env.raiseError(TableTerms.Errors.TableOverlap);
|
|
23354
23627
|
}
|
|
@@ -23416,8 +23689,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23416
23689
|
let last;
|
|
23417
23690
|
const activesRows = env.model.getters.getActiveRows();
|
|
23418
23691
|
if (activesRows.size !== 0) {
|
|
23419
|
-
first =
|
|
23420
|
-
last =
|
|
23692
|
+
first = largeMin([...activesRows]);
|
|
23693
|
+
last = largeMax([...activesRows]);
|
|
23421
23694
|
}
|
|
23422
23695
|
else {
|
|
23423
23696
|
const zone = env.model.getters.getSelectedZones()[0];
|
|
@@ -23445,8 +23718,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23445
23718
|
let last;
|
|
23446
23719
|
const activeCols = env.model.getters.getActiveCols();
|
|
23447
23720
|
if (activeCols.size !== 0) {
|
|
23448
|
-
first =
|
|
23449
|
-
last =
|
|
23721
|
+
first = largeMin([...activeCols]);
|
|
23722
|
+
last = largeMax([...activeCols]);
|
|
23450
23723
|
}
|
|
23451
23724
|
else {
|
|
23452
23725
|
const zone = env.model.getters.getSelectedZones()[0];
|
|
@@ -23474,8 +23747,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23474
23747
|
let last;
|
|
23475
23748
|
const activesRows = env.model.getters.getActiveRows();
|
|
23476
23749
|
if (activesRows.size !== 0) {
|
|
23477
|
-
first =
|
|
23478
|
-
last =
|
|
23750
|
+
first = largeMin([...activesRows]);
|
|
23751
|
+
last = largeMax([...activesRows]);
|
|
23479
23752
|
}
|
|
23480
23753
|
else {
|
|
23481
23754
|
const zone = env.model.getters.getSelectedZones()[0];
|
|
@@ -23516,8 +23789,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23516
23789
|
let last;
|
|
23517
23790
|
const activeCols = env.model.getters.getActiveCols();
|
|
23518
23791
|
if (activeCols.size !== 0) {
|
|
23519
|
-
first =
|
|
23520
|
-
last =
|
|
23792
|
+
first = largeMin([...activeCols]);
|
|
23793
|
+
last = largeMax([...activeCols]);
|
|
23521
23794
|
}
|
|
23522
23795
|
else {
|
|
23523
23796
|
const zone = env.model.getters.getSelectedZones()[0];
|
|
@@ -23558,7 +23831,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23558
23831
|
let row;
|
|
23559
23832
|
let quantity;
|
|
23560
23833
|
if (activeRows.size) {
|
|
23561
|
-
row =
|
|
23834
|
+
row = largeMin([...activeRows]);
|
|
23562
23835
|
quantity = activeRows.size;
|
|
23563
23836
|
}
|
|
23564
23837
|
else {
|
|
@@ -23579,7 +23852,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23579
23852
|
let row;
|
|
23580
23853
|
let quantity;
|
|
23581
23854
|
if (activeRows.size) {
|
|
23582
|
-
row =
|
|
23855
|
+
row = largeMax([...activeRows]);
|
|
23583
23856
|
quantity = activeRows.size;
|
|
23584
23857
|
}
|
|
23585
23858
|
else {
|
|
@@ -23600,7 +23873,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23600
23873
|
let column;
|
|
23601
23874
|
let quantity;
|
|
23602
23875
|
if (activeCols.size) {
|
|
23603
|
-
column =
|
|
23876
|
+
column = largeMin([...activeCols]);
|
|
23604
23877
|
quantity = activeCols.size;
|
|
23605
23878
|
}
|
|
23606
23879
|
else {
|
|
@@ -23621,7 +23894,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23621
23894
|
let column;
|
|
23622
23895
|
let quantity;
|
|
23623
23896
|
if (activeCols.size) {
|
|
23624
|
-
column =
|
|
23897
|
+
column = largeMax([...activeCols]);
|
|
23625
23898
|
quantity = activeCols.size;
|
|
23626
23899
|
}
|
|
23627
23900
|
else {
|
|
@@ -23796,9 +24069,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23796
24069
|
};
|
|
23797
24070
|
const DELETE_SELECTED_TABLE = (env) => {
|
|
23798
24071
|
const position = env.model.getters.getActivePosition();
|
|
24072
|
+
const table = env.model.getters.getTable(position);
|
|
24073
|
+
if (!table) {
|
|
24074
|
+
return;
|
|
24075
|
+
}
|
|
23799
24076
|
env.model.dispatch("REMOVE_TABLE", {
|
|
23800
24077
|
sheetId: position.sheetId,
|
|
23801
|
-
target: [
|
|
24078
|
+
target: [table.range.zone],
|
|
23802
24079
|
});
|
|
23803
24080
|
};
|
|
23804
24081
|
//------------------------------------------------------------------------------
|
|
@@ -24214,14 +24491,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24214
24491
|
children: [allFunctionListMenuBuilder],
|
|
24215
24492
|
};
|
|
24216
24493
|
function allFunctionListMenuBuilder() {
|
|
24217
|
-
const fnNames = functionRegistry.getKeys();
|
|
24494
|
+
const fnNames = functionRegistry.getKeys().filter((key) => !functionRegistry.get(key).hidden);
|
|
24218
24495
|
return createFormulaFunctions(fnNames);
|
|
24219
24496
|
}
|
|
24220
24497
|
const categoriesFunctionListMenuBuilder = () => {
|
|
24221
24498
|
const functions = functionRegistry.content;
|
|
24222
|
-
const categories = [
|
|
24499
|
+
const categories = [
|
|
24500
|
+
...new Set(functionRegistry
|
|
24501
|
+
.getAll()
|
|
24502
|
+
.filter((fn) => !fn.hidden)
|
|
24503
|
+
.map((fn) => fn.category)),
|
|
24504
|
+
].filter(isDefined$1);
|
|
24223
24505
|
return categories.sort().map((category, i) => {
|
|
24224
|
-
const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category);
|
|
24506
|
+
const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category && !functions[key].hidden);
|
|
24225
24507
|
return {
|
|
24226
24508
|
name: category,
|
|
24227
24509
|
children: createFormulaFunctions(functionsInCategory),
|
|
@@ -27218,6 +27500,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27218
27500
|
static template = "o-spreadsheet-BarChartDesignPanel";
|
|
27219
27501
|
}
|
|
27220
27502
|
|
|
27503
|
+
class ComboChartConfigPanel extends LineBarPieConfigPanel {
|
|
27504
|
+
static template = "o-spreadsheet-ComboChartConfigPanel";
|
|
27505
|
+
get shouldUseRightAxis() {
|
|
27506
|
+
return _t("Use right axis for line series");
|
|
27507
|
+
}
|
|
27508
|
+
onUpdateUseRightAxis(useBothYAxis) {
|
|
27509
|
+
this.props.updateChart(this.props.figureId, {
|
|
27510
|
+
useBothYAxis,
|
|
27511
|
+
});
|
|
27512
|
+
}
|
|
27513
|
+
}
|
|
27514
|
+
|
|
27515
|
+
class ComboChartDesignPanel extends LineBarPieDesignPanel {
|
|
27516
|
+
static template = "o-spreadsheet-ComboChartDesignPanel";
|
|
27517
|
+
}
|
|
27518
|
+
|
|
27221
27519
|
class GaugeChartConfigPanel extends owl.Component {
|
|
27222
27520
|
static template = "o-spreadsheet-GaugeChartConfigPanel";
|
|
27223
27521
|
static components = { ChartErrorSection, ChartDataSeries };
|
|
@@ -27575,6 +27873,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27575
27873
|
.add("bar", {
|
|
27576
27874
|
configuration: BarConfigPanel,
|
|
27577
27875
|
design: BarChartDesignPanel,
|
|
27876
|
+
})
|
|
27877
|
+
.add("combo", {
|
|
27878
|
+
configuration: ComboChartConfigPanel,
|
|
27879
|
+
design: ComboChartDesignPanel,
|
|
27578
27880
|
})
|
|
27579
27881
|
.add("pie", {
|
|
27580
27882
|
configuration: LineBarPieConfigPanel,
|
|
@@ -28379,11 +28681,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28379
28681
|
}
|
|
28380
28682
|
.o-cell-is-operator {
|
|
28381
28683
|
margin-bottom: 5px;
|
|
28382
|
-
width: 96%;
|
|
28383
28684
|
}
|
|
28384
28685
|
.o-cell-is-value {
|
|
28385
28686
|
margin-bottom: 5px;
|
|
28386
|
-
width: 96%;
|
|
28387
28687
|
}
|
|
28388
28688
|
.o-color-picker-widget .o-color-picker-button {
|
|
28389
28689
|
pointer-events: all;
|
|
@@ -30217,7 +30517,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30217
30517
|
const composerStore = useStore(ComposerStore);
|
|
30218
30518
|
// The feature makes no sense if we are editing a cell, because then the selection isn't active
|
|
30219
30519
|
// Stop the edition when the panel is mounted, and close the panel if the user start editing a cell
|
|
30220
|
-
owl.useEffect(
|
|
30520
|
+
owl.useEffect((editionMode) => {
|
|
30521
|
+
if (editionMode !== "inactive") {
|
|
30522
|
+
this.props.onCloseSidePanel();
|
|
30523
|
+
}
|
|
30524
|
+
}, () => [composerStore.editionMode]);
|
|
30221
30525
|
owl.onMounted(() => {
|
|
30222
30526
|
composerStore.stopEdition();
|
|
30223
30527
|
});
|
|
@@ -30303,6 +30607,24 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30303
30607
|
const contentZone = { ...tableZone, top: tableZone.top + numberOfHeaders };
|
|
30304
30608
|
return contentZone.top <= contentZone.bottom ? contentZone : undefined;
|
|
30305
30609
|
}
|
|
30610
|
+
function getTableTopLeft(table) {
|
|
30611
|
+
const range = table.range;
|
|
30612
|
+
return { row: range.zone.top, col: range.zone.left, sheetId: range.sheetId };
|
|
30613
|
+
}
|
|
30614
|
+
function createFilter(id, range, config, createRange) {
|
|
30615
|
+
const zone = range.zone;
|
|
30616
|
+
if (zone.left !== zone.right) {
|
|
30617
|
+
throw new Error("Can only define a filter on a single column");
|
|
30618
|
+
}
|
|
30619
|
+
const filteredZone = { ...zone, top: zone.top + config.numberOfHeaders };
|
|
30620
|
+
const filteredRange = createRange(range.sheetId, filteredZone);
|
|
30621
|
+
return {
|
|
30622
|
+
id,
|
|
30623
|
+
rangeWithHeaders: range,
|
|
30624
|
+
col: zone.left,
|
|
30625
|
+
filteredRange: filteredZone.top > filteredZone.bottom ? undefined : filteredRange,
|
|
30626
|
+
};
|
|
30627
|
+
}
|
|
30306
30628
|
function getComputedTableStyle(tableConfig, numberOfCols, numberOfRows) {
|
|
30307
30629
|
return {
|
|
30308
30630
|
borders: getAllTableBorders(tableConfig, numberOfCols, numberOfRows),
|
|
@@ -30740,6 +31062,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30740
31062
|
color: #ffffff;
|
|
30741
31063
|
background: #d94b4b;
|
|
30742
31064
|
}
|
|
31065
|
+
|
|
31066
|
+
.o-info-icon {
|
|
31067
|
+
width: 14px;
|
|
31068
|
+
height: 14px;
|
|
31069
|
+
}
|
|
30743
31070
|
}
|
|
30744
31071
|
`;
|
|
30745
31072
|
class TablePanel extends owl.Component {
|
|
@@ -30771,6 +31098,29 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30771
31098
|
const numberOfHeaders = hasHeaders ? 1 : 0;
|
|
30772
31099
|
this.updateNumberOfHeaders(numberOfHeaders);
|
|
30773
31100
|
}
|
|
31101
|
+
updateTableIsDynamic(isDynamic) {
|
|
31102
|
+
const newTableType = isDynamic ? "dynamic" : "forceStatic";
|
|
31103
|
+
if (newTableType === this.props.table.type) {
|
|
31104
|
+
return;
|
|
31105
|
+
}
|
|
31106
|
+
const uiTable = this.env.model.getters.getTable(getTableTopLeft(this.props.table));
|
|
31107
|
+
if (!uiTable) {
|
|
31108
|
+
return;
|
|
31109
|
+
}
|
|
31110
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
31111
|
+
const result = this.env.model.dispatch("UPDATE_TABLE", {
|
|
31112
|
+
sheetId,
|
|
31113
|
+
zone: this.props.table.range.zone,
|
|
31114
|
+
newTableRange: uiTable.range.rangeData,
|
|
31115
|
+
tableType: newTableType,
|
|
31116
|
+
});
|
|
31117
|
+
const updatedTable = this.env.model.getters.getCoreTable(getTableTopLeft(this.props.table));
|
|
31118
|
+
if (result.isSuccessful && updatedTable) {
|
|
31119
|
+
const newTableRange = updatedTable.range;
|
|
31120
|
+
this.state.tableXc = this.env.model.getters.getRangeString(newTableRange, sheetId);
|
|
31121
|
+
this.state.tableZoneErrors = [];
|
|
31122
|
+
}
|
|
31123
|
+
}
|
|
30774
31124
|
onChangeNumberOfHeaders(ev) {
|
|
30775
31125
|
const input = ev.target;
|
|
30776
31126
|
const numberOfHeaders = parseInt(input.value);
|
|
@@ -30794,35 +31144,59 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30794
31144
|
}
|
|
30795
31145
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
30796
31146
|
this.state.tableXc = ranges[0];
|
|
31147
|
+
const newTableRange = this.env.model.getters.getRangeFromSheetXC(sheetId, this.state.tableXc);
|
|
30797
31148
|
this.state.tableZoneErrors = this.env.model.canDispatch("UPDATE_TABLE", {
|
|
30798
31149
|
sheetId,
|
|
30799
31150
|
zone: this.props.table.range.zone,
|
|
30800
31151
|
newTableRange: this.env.model.getters.getRangeDataFromXc(sheetId, this.state.tableXc),
|
|
31152
|
+
tableType: this.getNewTableType(newTableRange.zone),
|
|
30801
31153
|
}).reasons;
|
|
30802
31154
|
}
|
|
30803
31155
|
onRangeConfirmed() {
|
|
30804
31156
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
30805
|
-
|
|
31157
|
+
let newRange = this.env.model.getters.getRangeFromSheetXC(sheetId, this.state.tableXc);
|
|
31158
|
+
if (getZoneArea(newRange.zone) === 1) {
|
|
31159
|
+
const extendedZone = this.env.model.getters.getContiguousZone(sheetId, newRange.zone);
|
|
31160
|
+
newRange = this.env.model.getters.getRangeFromZone(sheetId, extendedZone);
|
|
31161
|
+
}
|
|
30806
31162
|
const result = this.env.model.dispatch("UPDATE_TABLE", {
|
|
30807
31163
|
sheetId,
|
|
30808
31164
|
zone: this.props.table.range.zone,
|
|
30809
31165
|
newTableRange: newRange.rangeData,
|
|
31166
|
+
tableType: this.getNewTableType(newRange.zone),
|
|
30810
31167
|
});
|
|
30811
|
-
|
|
30812
|
-
|
|
31168
|
+
const position = { sheetId, col: newRange.zone.left, row: newRange.zone.top };
|
|
31169
|
+
const updatedTable = this.env.model.getters.getCoreTable(position);
|
|
31170
|
+
if (result.isSuccessful && updatedTable) {
|
|
31171
|
+
const newTopLeft = getTableTopLeft(updatedTable);
|
|
30813
31172
|
this.env.model.selection.selectZone({
|
|
30814
|
-
zone: positionToZone(
|
|
30815
|
-
cell:
|
|
31173
|
+
zone: positionToZone(newTopLeft),
|
|
31174
|
+
cell: newTopLeft,
|
|
30816
31175
|
});
|
|
31176
|
+
const newTableRange = updatedTable.range;
|
|
31177
|
+
this.state.tableXc = this.env.model.getters.getRangeString(newTableRange, sheetId);
|
|
31178
|
+
}
|
|
31179
|
+
else {
|
|
31180
|
+
const oldTableRange = this.props.table.range;
|
|
31181
|
+
this.state.tableXc = this.env.model.getters.getRangeString(oldTableRange, sheetId);
|
|
30817
31182
|
}
|
|
30818
31183
|
this.state.tableZoneErrors = [];
|
|
30819
|
-
this.state.tableXc = result.isSuccessful
|
|
30820
|
-
? this.state.tableXc
|
|
30821
|
-
: this.env.model.getters.getRangeString(this.props.table.range, sheetId);
|
|
30822
31184
|
}
|
|
30823
31185
|
deleteTable() {
|
|
30824
31186
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
30825
|
-
this.env.model.dispatch("REMOVE_TABLE", {
|
|
31187
|
+
this.env.model.dispatch("REMOVE_TABLE", {
|
|
31188
|
+
sheetId,
|
|
31189
|
+
target: [this.props.table.range.zone],
|
|
31190
|
+
});
|
|
31191
|
+
}
|
|
31192
|
+
getNewTableType(newTableZone) {
|
|
31193
|
+
if (this.props.table.type === "forceStatic") {
|
|
31194
|
+
return "forceStatic";
|
|
31195
|
+
}
|
|
31196
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
31197
|
+
return this.env.model.getters.canCreateDynamicTableOnZones(sheetId, [newTableZone])
|
|
31198
|
+
? "dynamic"
|
|
31199
|
+
: "static";
|
|
30826
31200
|
}
|
|
30827
31201
|
get tableConfig() {
|
|
30828
31202
|
return this.props.table.config;
|
|
@@ -30840,6 +31214,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30840
31214
|
get hasFilterCheckboxTooltip() {
|
|
30841
31215
|
return this.canHaveFilters ? undefined : TableTerms.Tooltips.filterWithoutHeader;
|
|
30842
31216
|
}
|
|
31217
|
+
get canBeDynamic() {
|
|
31218
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
31219
|
+
return (this.props.table.type === "dynamic" ||
|
|
31220
|
+
this.env.model.getters.canCreateDynamicTableOnZones(sheetId, [this.props.table.range.zone]));
|
|
31221
|
+
}
|
|
31222
|
+
get dynamicTableTooltip() {
|
|
31223
|
+
return TableTerms.Tooltips.isDynamic;
|
|
31224
|
+
}
|
|
30843
31225
|
}
|
|
30844
31226
|
|
|
30845
31227
|
const sidePanelRegistry = new Registry();
|
|
@@ -30902,11 +31284,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30902
31284
|
if (!table) {
|
|
30903
31285
|
return { isOpen: false };
|
|
30904
31286
|
}
|
|
30905
|
-
|
|
30906
|
-
|
|
30907
|
-
props: { table },
|
|
30908
|
-
key: table.id,
|
|
30909
|
-
};
|
|
31287
|
+
const coreTable = getters.getCoreTable(getTableTopLeft(table));
|
|
31288
|
+
return { isOpen: true, props: { table: coreTable }, key: table.id };
|
|
30910
31289
|
},
|
|
30911
31290
|
});
|
|
30912
31291
|
|
|
@@ -31085,6 +31464,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31085
31464
|
el?.focus({ preventScroll: true });
|
|
31086
31465
|
}
|
|
31087
31466
|
}, () => [this.env.model.getters.getSelectedFigureId(), this.props.figure.id, this.figureRef.el]);
|
|
31467
|
+
owl.onWillUnmount(() => {
|
|
31468
|
+
this.props.onFigureDeleted();
|
|
31469
|
+
});
|
|
31088
31470
|
}
|
|
31089
31471
|
clickAnchor(dirX, dirY, ev) {
|
|
31090
31472
|
this.props.onClickAnchor(dirX, dirY, ev);
|
|
@@ -31103,6 +31485,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31103
31485
|
this.props.onFigureDeleted();
|
|
31104
31486
|
ev.stopPropagation();
|
|
31105
31487
|
ev.preventDefault();
|
|
31488
|
+
ev.stopPropagation();
|
|
31106
31489
|
break;
|
|
31107
31490
|
case "ArrowDown":
|
|
31108
31491
|
case "ArrowLeft":
|
|
@@ -31123,6 +31506,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31123
31506
|
});
|
|
31124
31507
|
ev.stopPropagation();
|
|
31125
31508
|
ev.preventDefault();
|
|
31509
|
+
ev.stopPropagation();
|
|
31126
31510
|
break;
|
|
31127
31511
|
}
|
|
31128
31512
|
}
|
|
@@ -31790,6 +32174,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31790
32174
|
// -----------------------------------------------------------------------------
|
|
31791
32175
|
css /* scss */ `
|
|
31792
32176
|
.o-formula-assistant {
|
|
32177
|
+
background: #ffffff;
|
|
31793
32178
|
.o-formula-assistant-head {
|
|
31794
32179
|
background-color: #f2f2f2;
|
|
31795
32180
|
padding: 10px;
|
|
@@ -31845,6 +32230,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31845
32230
|
this.assistantState.allowCellSelectionBehind = false;
|
|
31846
32231
|
}, 2000);
|
|
31847
32232
|
}
|
|
32233
|
+
get formulaArgSeparator() {
|
|
32234
|
+
return this.env.model.getters.getLocale().formulaArgSeparator + " ";
|
|
32235
|
+
}
|
|
31848
32236
|
}
|
|
31849
32237
|
|
|
31850
32238
|
const functions$2 = functionRegistry.content;
|
|
@@ -32004,6 +32392,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32004
32392
|
owl.useEffect(() => {
|
|
32005
32393
|
this.processContent();
|
|
32006
32394
|
});
|
|
32395
|
+
owl.onPatched(() => {
|
|
32396
|
+
// Required because typing '=SUM' and double-clicking another cell leaves ShowProvider/ShowDescription true
|
|
32397
|
+
if (this.composerStore.editionMode === "inactive") {
|
|
32398
|
+
this.processTokenAtCursor();
|
|
32399
|
+
}
|
|
32400
|
+
});
|
|
32007
32401
|
}
|
|
32008
32402
|
// ---------------------------------------------------------------------------
|
|
32009
32403
|
// Handlers
|
|
@@ -32742,8 +33136,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32742
33136
|
};
|
|
32743
33137
|
getFilterHeadersPositions() {
|
|
32744
33138
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
32745
|
-
|
|
32746
|
-
return headerPositions.map((position) => ({ sheetId, ...position }));
|
|
33139
|
+
return this.env.model.getters.getFilterHeaders(sheetId);
|
|
32747
33140
|
}
|
|
32748
33141
|
}
|
|
32749
33142
|
|
|
@@ -33984,11 +34377,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
33984
34377
|
height: 10000px;
|
|
33985
34378
|
background-color: ${SELECTION_BORDER_COLOR};
|
|
33986
34379
|
}
|
|
33987
|
-
.o-unhide-buttons {
|
|
33988
|
-
width: fit-content;
|
|
33989
|
-
gap: 5px;
|
|
33990
|
-
transform: translate(-50%, 0);
|
|
33991
|
-
}
|
|
33992
34380
|
.o-unhide:hover {
|
|
33993
34381
|
z-index: ${ComponentsImportance.Grid + 1};
|
|
33994
34382
|
background-color: lightgrey;
|
|
@@ -34150,10 +34538,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34150
34538
|
height: 1px;
|
|
34151
34539
|
background-color: ${SELECTION_BORDER_COLOR};
|
|
34152
34540
|
}
|
|
34153
|
-
.o-unhide-buttons {
|
|
34154
|
-
height: fit-content;
|
|
34155
|
-
transform: translate(0, -50%);
|
|
34156
|
-
}
|
|
34157
34541
|
.o-unhide:hover {
|
|
34158
34542
|
z-index: ${ComponentsImportance.Grid + 1};
|
|
34159
34543
|
background-color: lightgrey;
|
|
@@ -34614,19 +34998,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34614
34998
|
for (let col = left; col <= right; col++) {
|
|
34615
34999
|
const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
|
|
34616
35000
|
const { x, width } = this.getters.getVisibleRect(colZone);
|
|
34617
|
-
const colHasFilter = this.getters.doesZonesContainFilter(sheetId, [colZone]);
|
|
34618
35001
|
const isColActive = activeCols.has(col);
|
|
34619
35002
|
const isColSelected = selectedCols.has(col);
|
|
34620
35003
|
if (isColActive) {
|
|
34621
|
-
ctx.fillStyle =
|
|
35004
|
+
ctx.fillStyle = BACKGROUND_HEADER_ACTIVE_COLOR;
|
|
34622
35005
|
}
|
|
34623
35006
|
else if (isColSelected) {
|
|
34624
|
-
ctx.fillStyle =
|
|
34625
|
-
? BACKGROUND_HEADER_SELECTED_FILTER_COLOR
|
|
34626
|
-
: BACKGROUND_HEADER_SELECTED_COLOR;
|
|
35007
|
+
ctx.fillStyle = BACKGROUND_HEADER_SELECTED_COLOR;
|
|
34627
35008
|
}
|
|
34628
35009
|
else {
|
|
34629
|
-
ctx.fillStyle =
|
|
35010
|
+
ctx.fillStyle = BACKGROUND_HEADER_COLOR;
|
|
34630
35011
|
}
|
|
34631
35012
|
ctx.fillRect(x, 0, width, HEADER_HEIGHT);
|
|
34632
35013
|
}
|
|
@@ -34634,19 +35015,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34634
35015
|
for (let row = top; row <= bottom; row++) {
|
|
34635
35016
|
const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
|
|
34636
35017
|
const { y, height } = this.getters.getVisibleRect(rowZone);
|
|
34637
|
-
const rowHasFilter = this.getters.doesZonesContainFilter(sheetId, [rowZone]);
|
|
34638
35018
|
const isRowActive = activeRows.has(row);
|
|
34639
35019
|
const isRowSelected = selectedRows.has(row);
|
|
34640
35020
|
if (isRowActive) {
|
|
34641
|
-
ctx.fillStyle =
|
|
35021
|
+
ctx.fillStyle = BACKGROUND_HEADER_ACTIVE_COLOR;
|
|
34642
35022
|
}
|
|
34643
35023
|
else if (isRowSelected) {
|
|
34644
|
-
ctx.fillStyle =
|
|
34645
|
-
? BACKGROUND_HEADER_SELECTED_FILTER_COLOR
|
|
34646
|
-
: BACKGROUND_HEADER_SELECTED_COLOR;
|
|
35024
|
+
ctx.fillStyle = BACKGROUND_HEADER_SELECTED_COLOR;
|
|
34647
35025
|
}
|
|
34648
35026
|
else {
|
|
34649
|
-
ctx.fillStyle =
|
|
35027
|
+
ctx.fillStyle = BACKGROUND_HEADER_COLOR;
|
|
34650
35028
|
}
|
|
34651
35029
|
ctx.fillRect(0, y, HEADER_WIDTH, height);
|
|
34652
35030
|
}
|
|
@@ -35367,7 +35745,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35367
35745
|
onScroll(offset) {
|
|
35368
35746
|
const { scrollX } = this.env.model.getters.getActiveSheetDOMScrollInfo();
|
|
35369
35747
|
this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
|
|
35370
|
-
offsetX: scrollX,
|
|
35748
|
+
offsetX: scrollX, // offsetX is the same
|
|
35371
35749
|
offsetY: offset,
|
|
35372
35750
|
});
|
|
35373
35751
|
}
|
|
@@ -35655,8 +36033,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35655
36033
|
"Ctrl+Shift+L": () => this.setHorizontalAlign("left"),
|
|
35656
36034
|
"Ctrl+Shift+R": () => this.setHorizontalAlign("right"),
|
|
35657
36035
|
"Ctrl+Shift+V": () => PASTE_AS_VALUE_ACTION(this.env),
|
|
35658
|
-
"Ctrl+Shift+<": () => this.clearFormatting(),
|
|
35659
|
-
"Ctrl+<": () => this.clearFormatting(),
|
|
36036
|
+
"Ctrl+Shift+<": () => this.clearFormatting(), // for qwerty
|
|
36037
|
+
"Ctrl+<": () => this.clearFormatting(), // for azerty
|
|
35660
36038
|
"Ctrl+Shift+ ": () => {
|
|
35661
36039
|
this.env.model.selection.selectAll();
|
|
35662
36040
|
},
|
|
@@ -36092,6 +36470,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36092
36470
|
"surfaceChart",
|
|
36093
36471
|
"surface3DChart",
|
|
36094
36472
|
"bubbleChart",
|
|
36473
|
+
"comboChart",
|
|
36095
36474
|
];
|
|
36096
36475
|
|
|
36097
36476
|
/** In XLSX color format (no #) */
|
|
@@ -36423,10 +36802,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36423
36802
|
const CF_TYPE_CONVERSION_MAP = {
|
|
36424
36803
|
aboveAverage: undefined,
|
|
36425
36804
|
expression: undefined,
|
|
36426
|
-
cellIs: undefined,
|
|
36427
|
-
colorScale: undefined,
|
|
36805
|
+
cellIs: undefined, // exist but isn't an operator in o_spreadsheet
|
|
36806
|
+
colorScale: undefined, // exist but isn't an operator in o_spreadsheet
|
|
36428
36807
|
dataBar: undefined,
|
|
36429
|
-
iconSet: undefined,
|
|
36808
|
+
iconSet: undefined, // exist but isn't an operator in o_spreadsheet
|
|
36430
36809
|
top10: undefined,
|
|
36431
36810
|
uniqueValues: undefined,
|
|
36432
36811
|
duplicateValues: undefined,
|
|
@@ -36503,6 +36882,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36503
36882
|
surfaceChart: undefined,
|
|
36504
36883
|
surface3DChart: undefined,
|
|
36505
36884
|
bubbleChart: undefined,
|
|
36885
|
+
comboChart: "combo",
|
|
36506
36886
|
};
|
|
36507
36887
|
/** Conversion map for the SUBTOTAL(index, formula) function in xlsx, index <=> actual function*/
|
|
36508
36888
|
const SUBTOTAL_FUNCTION_CONVERSION_MAP = {
|
|
@@ -36661,7 +37041,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36661
37041
|
61: "993366",
|
|
36662
37042
|
62: "333399",
|
|
36663
37043
|
63: "333333",
|
|
36664
|
-
64: "000000",
|
|
37044
|
+
64: "000000", // system foreground
|
|
36665
37045
|
65: "FFFFFF", // system background
|
|
36666
37046
|
};
|
|
36667
37047
|
const IMAGE_MIMETYPE_TO_EXTENSION_MAPPING = {
|
|
@@ -37853,7 +38233,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37853
38233
|
function getSheetDims(sheet) {
|
|
37854
38234
|
const dims = [0, 0];
|
|
37855
38235
|
for (let row of sheet.rows) {
|
|
37856
|
-
dims[0] = Math.max(dims[0],
|
|
38236
|
+
dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
|
|
37857
38237
|
dims[1] = Math.max(dims[1], row.index);
|
|
37858
38238
|
}
|
|
37859
38239
|
dims[0] = Math.max(dims[0], EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
|
|
@@ -38719,6 +39099,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38719
39099
|
if (!CHART_TYPE_CONVERSION_MAP[chartType]) {
|
|
38720
39100
|
throw new Error(`Unsupported chart type ${chartType}`);
|
|
38721
39101
|
}
|
|
39102
|
+
if (CHART_TYPE_CONVERSION_MAP[chartType] === "combo") {
|
|
39103
|
+
return this.extractComboChart(rootChartElement);
|
|
39104
|
+
}
|
|
38722
39105
|
// Title can be separated into multiple xml elements (for styling and such), we only import the text
|
|
38723
39106
|
const chartTitle = this.mapOnElements({ parent: rootChartElement, query: "c:title a:t" }, (textElement) => {
|
|
38724
39107
|
return textElement.textContent || "";
|
|
@@ -38747,6 +39130,37 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38747
39130
|
};
|
|
38748
39131
|
})[0];
|
|
38749
39132
|
}
|
|
39133
|
+
extractComboChart(chartElement) {
|
|
39134
|
+
// Title can be separated into multiple xml elements (for styling and such), we only import the text
|
|
39135
|
+
const chartTitle = this.mapOnElements({ parent: chartElement, query: "c:title a:t" }, (textElement) => {
|
|
39136
|
+
return textElement.textContent || "";
|
|
39137
|
+
}).join("");
|
|
39138
|
+
const barChartGrouping = this.extractChildAttr(chartElement, "c:grouping", "val", {
|
|
39139
|
+
default: "clustered",
|
|
39140
|
+
}).asString();
|
|
39141
|
+
return {
|
|
39142
|
+
title: chartTitle,
|
|
39143
|
+
type: "combo",
|
|
39144
|
+
dataSets: [
|
|
39145
|
+
...this.extractChartDatasets(this.querySelector(chartElement, `c:barChart`)),
|
|
39146
|
+
...this.extractChartDatasets(this.querySelector(chartElement, `c:lineChart`)),
|
|
39147
|
+
],
|
|
39148
|
+
labelRange: this.extractChildTextContent(chartElement, "c:ser c:cat c:f"),
|
|
39149
|
+
backgroundColor: this.extractChildAttr(chartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
39150
|
+
default: "ffffff",
|
|
39151
|
+
}).asString(),
|
|
39152
|
+
verticalAxisPosition: this.extractChildAttr(chartElement, "c:valAx > c:axPos", "val", {
|
|
39153
|
+
default: "l",
|
|
39154
|
+
}).asString() === "r"
|
|
39155
|
+
? "right"
|
|
39156
|
+
: "left",
|
|
39157
|
+
legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(chartElement, "c:legendPos", "val", {
|
|
39158
|
+
default: "b",
|
|
39159
|
+
}).asString()],
|
|
39160
|
+
stacked: barChartGrouping === "stacked",
|
|
39161
|
+
fontColor: "000000",
|
|
39162
|
+
};
|
|
39163
|
+
}
|
|
38750
39164
|
extractChartDatasets(chartElement) {
|
|
38751
39165
|
return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
|
|
38752
39166
|
return {
|
|
@@ -38764,12 +39178,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38764
39178
|
if (!plotAreaElement) {
|
|
38765
39179
|
throw new Error("Missing plot area in the chart definition.");
|
|
38766
39180
|
}
|
|
39181
|
+
let globalTag = undefined;
|
|
38767
39182
|
for (let child of plotAreaElement.children) {
|
|
38768
39183
|
const tag = removeTagEscapedNamespaces(child.tagName);
|
|
38769
39184
|
if (XLSX_CHART_TYPES.some((chartType) => chartType === tag)) {
|
|
38770
|
-
|
|
39185
|
+
if (!globalTag) {
|
|
39186
|
+
globalTag = tag;
|
|
39187
|
+
}
|
|
39188
|
+
else if (globalTag !== tag) {
|
|
39189
|
+
globalTag = "comboChart";
|
|
39190
|
+
}
|
|
38771
39191
|
}
|
|
38772
39192
|
}
|
|
39193
|
+
if (globalTag) {
|
|
39194
|
+
return globalTag;
|
|
39195
|
+
}
|
|
38773
39196
|
throw new Error("Unknown chart type");
|
|
38774
39197
|
}
|
|
38775
39198
|
}
|
|
@@ -42360,6 +42783,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42360
42783
|
if (newRule.criterion.type === "isBoolean") {
|
|
42361
42784
|
this.setCenterStyleToBooleanCells(newRule);
|
|
42362
42785
|
}
|
|
42786
|
+
else if (newRule.criterion.type === "isValueInList") {
|
|
42787
|
+
newRule.criterion.values = Array.from(new Set(newRule.criterion.values));
|
|
42788
|
+
}
|
|
42363
42789
|
const adaptedRules = this.removeRangesFromRules(sheetId, newRule.ranges, rules);
|
|
42364
42790
|
const ruleIndex = adaptedRules.findIndex((rule) => rule.id === newRule.id);
|
|
42365
42791
|
if (ruleIndex !== -1) {
|
|
@@ -42756,7 +43182,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42756
43182
|
if (hiddenElements.size >= elements) {
|
|
42757
43183
|
return "TooManyHiddenElements" /* CommandResult.TooManyHiddenElements */;
|
|
42758
43184
|
}
|
|
42759
|
-
else if (
|
|
43185
|
+
else if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
|
|
42760
43186
|
return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
|
|
42761
43187
|
}
|
|
42762
43188
|
else {
|
|
@@ -43085,7 +43511,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43085
43511
|
"isInSameMerge",
|
|
43086
43512
|
"isMergeHidden",
|
|
43087
43513
|
"getMainCellPosition",
|
|
43088
|
-
"getBottomLeftCell",
|
|
43089
43514
|
"expandZone",
|
|
43090
43515
|
"doesIntersectMerge",
|
|
43091
43516
|
"doesColumnsHaveCommonMerges",
|
|
@@ -43267,13 +43692,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43267
43692
|
const mergeTopLeftPos = this.getMerge(position).topLeft;
|
|
43268
43693
|
return { sheetId: position.sheetId, col: mergeTopLeftPos.col, row: mergeTopLeftPos.row };
|
|
43269
43694
|
}
|
|
43270
|
-
getBottomLeftCell(position) {
|
|
43271
|
-
if (!this.isInMerge(position)) {
|
|
43272
|
-
return position;
|
|
43273
|
-
}
|
|
43274
|
-
const { bottom, left } = this.getMerge(position);
|
|
43275
|
-
return { sheetId: position.sheetId, col: left, row: bottom };
|
|
43276
|
-
}
|
|
43277
43695
|
isMergeHidden(sheetId, merge) {
|
|
43278
43696
|
const hiddenColsGroups = this.getters.getHiddenColsGroups(sheetId);
|
|
43279
43697
|
const hiddenRowsGroups = this.getters.getHiddenRowsGroups(sheetId);
|
|
@@ -43574,8 +43992,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43574
43992
|
let newRange = range;
|
|
43575
43993
|
let changeType = "NONE";
|
|
43576
43994
|
for (let group of groups) {
|
|
43577
|
-
const min =
|
|
43578
|
-
const max =
|
|
43995
|
+
const min = largeMin(group);
|
|
43996
|
+
const max = largeMax(group);
|
|
43579
43997
|
if (range.zone[start] <= min && min <= range.zone[end]) {
|
|
43580
43998
|
const toRemove = Math.min(range.zone[end], max) - min + 1;
|
|
43581
43999
|
changeType = "RESIZE";
|
|
@@ -43957,7 +44375,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43957
44375
|
"getSheetIds",
|
|
43958
44376
|
"getVisibleSheetIds",
|
|
43959
44377
|
"isSheetVisible",
|
|
43960
|
-
"getEvaluationSheets",
|
|
43961
44378
|
"doesHeaderExist",
|
|
43962
44379
|
"doesHeadersExist",
|
|
43963
44380
|
"getCell",
|
|
@@ -44024,8 +44441,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44024
44441
|
}
|
|
44025
44442
|
return "Success" /* CommandResult.Success */;
|
|
44026
44443
|
case "REMOVE_COLUMNS_ROWS": {
|
|
44027
|
-
const min =
|
|
44028
|
-
const max =
|
|
44444
|
+
const min = largeMin(cmd.elements);
|
|
44445
|
+
const max = largeMax(cmd.elements);
|
|
44029
44446
|
if (min < 0 || !this.doesHeaderExist(cmd.sheetId, cmd.dimension, max)) {
|
|
44030
44447
|
return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
|
|
44031
44448
|
}
|
|
@@ -44216,9 +44633,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44216
44633
|
getVisibleSheetIds() {
|
|
44217
44634
|
return this.orderedSheetIds.filter(this.isSheetVisible.bind(this));
|
|
44218
44635
|
}
|
|
44219
|
-
getEvaluationSheets() {
|
|
44220
|
-
return this.sheets;
|
|
44221
|
-
}
|
|
44222
44636
|
doesHeaderExist(sheetId, dimension, index) {
|
|
44223
44637
|
return dimension === "COL"
|
|
44224
44638
|
? index >= 0 && index < this.getNumberCols(sheetId)
|
|
@@ -44227,13 +44641,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44227
44641
|
doesHeadersExist(sheetId, dimension, headerIndexes) {
|
|
44228
44642
|
return headerIndexes.every((index) => this.doesHeaderExist(sheetId, dimension, index));
|
|
44229
44643
|
}
|
|
44230
|
-
getRow(sheetId, index) {
|
|
44231
|
-
const row = this.getSheet(sheetId).rows[index];
|
|
44232
|
-
if (!row) {
|
|
44233
|
-
throw new Error(`Row ${row} not found.`);
|
|
44234
|
-
}
|
|
44235
|
-
return row;
|
|
44236
|
-
}
|
|
44237
44644
|
getCell({ sheetId, col, row }) {
|
|
44238
44645
|
const sheet = this.tryGetSheet(sheetId);
|
|
44239
44646
|
const cellId = sheet?.rows[row]?.cells[col];
|
|
@@ -44818,23 +45225,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44818
45225
|
}
|
|
44819
45226
|
|
|
44820
45227
|
class TablePlugin extends CorePlugin {
|
|
44821
|
-
static getters = [
|
|
44822
|
-
"doesZonesContainFilter",
|
|
44823
|
-
"getFilter",
|
|
44824
|
-
"getFilters",
|
|
44825
|
-
"getTable",
|
|
44826
|
-
"getTables",
|
|
44827
|
-
"getTablesInZone",
|
|
44828
|
-
"getTablesOverlappingZones",
|
|
44829
|
-
"getFilterId",
|
|
44830
|
-
"getFilterHeaders",
|
|
44831
|
-
"isFilterHeader",
|
|
44832
|
-
];
|
|
45228
|
+
static getters = ["getCoreTable", "getCoreTables"];
|
|
44833
45229
|
tables = {};
|
|
44834
45230
|
adaptRanges(applyChange, sheetId) {
|
|
44835
45231
|
const sheetIds = sheetId ? [sheetId] : this.getters.getSheetIds();
|
|
44836
45232
|
for (const sheetId of sheetIds) {
|
|
44837
|
-
for (const table of this.
|
|
45233
|
+
for (const table of this.getCoreTables(sheetId)) {
|
|
44838
45234
|
this.applyRangeChangeOnTable(sheetId, table, applyChange);
|
|
44839
45235
|
}
|
|
44840
45236
|
}
|
|
@@ -44850,15 +45246,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44850
45246
|
? "TableOverlap" /* CommandResult.TableOverlap */
|
|
44851
45247
|
: "Success" /* CommandResult.Success */, (cmd) => this.checkTableConfigUpdateIsValid(cmd.config));
|
|
44852
45248
|
case "UPDATE_TABLE":
|
|
44853
|
-
const updatedTable = this.
|
|
45249
|
+
const updatedTable = this.getTableFromZone(cmd.sheetId, cmd.zone);
|
|
44854
45250
|
if (!updatedTable) {
|
|
44855
45251
|
return "TableNotFound" /* CommandResult.TableNotFound */;
|
|
44856
45252
|
}
|
|
44857
45253
|
return this.checkValidations(cmd, this.checkUpdatedTableZoneIsValid, (cmd) => this.checkTableConfigUpdateIsValid(cmd.config));
|
|
44858
45254
|
case "ADD_MERGE":
|
|
44859
|
-
for (const
|
|
44860
|
-
|
|
44861
|
-
|
|
45255
|
+
for (const table of this.getCoreTables(cmd.sheetId)) {
|
|
45256
|
+
const tableZone = table.range.zone;
|
|
45257
|
+
for (const merge of cmd.target) {
|
|
45258
|
+
if (overlap(tableZone, merge)) {
|
|
44862
45259
|
return "MergeInTable" /* CommandResult.MergeInTable */;
|
|
44863
45260
|
}
|
|
44864
45261
|
}
|
|
@@ -44880,8 +45277,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44880
45277
|
}
|
|
44881
45278
|
case "DUPLICATE_SHEET": {
|
|
44882
45279
|
const newTables = {};
|
|
44883
|
-
for (const table of this.
|
|
44884
|
-
newTables[table.id] =
|
|
45280
|
+
for (const table of this.getCoreTables(cmd.sheetId)) {
|
|
45281
|
+
newTables[table.id] =
|
|
45282
|
+
table.type === "dynamic"
|
|
45283
|
+
? this.copyDynamicTableForSheet(cmd.sheetIdTo, table)
|
|
45284
|
+
: this.copyStaticTableForSheet(cmd.sheetIdTo, table);
|
|
44885
45285
|
}
|
|
44886
45286
|
this.history.update("tables", cmd.sheetIdTo, newTables);
|
|
44887
45287
|
break;
|
|
@@ -44892,14 +45292,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44892
45292
|
const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
|
|
44893
45293
|
this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
|
|
44894
45294
|
const id = this.uuidGenerator.uuidv4();
|
|
44895
|
-
const
|
|
45295
|
+
const config = cmd.config || DEFAULT_TABLE_CONFIG;
|
|
45296
|
+
const newTable = cmd.tableType === "dynamic"
|
|
45297
|
+
? this.createDynamicTable(id, union, config)
|
|
45298
|
+
: this.createStaticTable(id, cmd.tableType, union, config);
|
|
44896
45299
|
this.history.update("tables", cmd.sheetId, newTable.id, newTable);
|
|
44897
45300
|
break;
|
|
44898
45301
|
}
|
|
44899
45302
|
case "REMOVE_TABLE": {
|
|
44900
45303
|
const tables = {};
|
|
44901
|
-
for (const table of this.
|
|
44902
|
-
if (cmd.target.every((zone) => !intersection(
|
|
45304
|
+
for (const table of this.getCoreTables(cmd.sheetId)) {
|
|
45305
|
+
if (cmd.target.every((zone) => !intersection(table.range.zone, zone))) {
|
|
44903
45306
|
tables[table.id] = table;
|
|
44904
45307
|
}
|
|
44905
45308
|
}
|
|
@@ -44907,23 +45310,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44907
45310
|
break;
|
|
44908
45311
|
}
|
|
44909
45312
|
case "UPDATE_TABLE": {
|
|
44910
|
-
|
|
44911
|
-
if (table) {
|
|
44912
|
-
const newTableRange = cmd.newTableRange
|
|
44913
|
-
? this.getters.getRangeFromRangeData(cmd.newTableRange)
|
|
44914
|
-
: undefined;
|
|
44915
|
-
if (newTableRange) {
|
|
44916
|
-
const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, newTableRange.zone);
|
|
44917
|
-
this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
|
|
44918
|
-
}
|
|
44919
|
-
const newTable = this.updateTable(table, newTableRange, cmd.config);
|
|
44920
|
-
this.history.update("tables", cmd.sheetId, table.id, newTable);
|
|
44921
|
-
}
|
|
45313
|
+
this.updateTable(cmd);
|
|
44922
45314
|
break;
|
|
44923
45315
|
}
|
|
44924
45316
|
case "UPDATE_CELL": {
|
|
44925
45317
|
const sheetId = cmd.sheetId;
|
|
44926
|
-
for (const table of this.
|
|
45318
|
+
for (const table of this.getCoreTables(sheetId)) {
|
|
45319
|
+
if (table.type === "dynamic") {
|
|
45320
|
+
continue;
|
|
45321
|
+
}
|
|
44927
45322
|
const direction = this.canUpdateCellCmdExtendTable(cmd, table);
|
|
44928
45323
|
if (direction === "down") {
|
|
44929
45324
|
this.extendTableDown(sheetId, table);
|
|
@@ -44947,66 +45342,24 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44947
45342
|
}
|
|
44948
45343
|
}
|
|
44949
45344
|
}
|
|
44950
|
-
|
|
44951
|
-
return this.getTables(sheetId)
|
|
44952
|
-
.filter((table) => table.config.hasFilters)
|
|
44953
|
-
.map((table) => table.filters)
|
|
44954
|
-
.flat();
|
|
44955
|
-
}
|
|
44956
|
-
getTables(sheetId) {
|
|
45345
|
+
getCoreTables(sheetId) {
|
|
44957
45346
|
return this.tables[sheetId] ? Object.values(this.tables[sheetId]).filter(isDefined$1) : [];
|
|
44958
45347
|
}
|
|
44959
|
-
|
|
44960
|
-
|
|
44961
|
-
if (!table || !table.config.hasFilters) {
|
|
44962
|
-
return undefined;
|
|
44963
|
-
}
|
|
44964
|
-
return table.filters.find((filter) => filter.col === position.col);
|
|
44965
|
-
}
|
|
44966
|
-
getFilterId(position) {
|
|
44967
|
-
return this.getFilter(position)?.id;
|
|
44968
|
-
}
|
|
44969
|
-
getTable({ sheetId, col, row }) {
|
|
44970
|
-
return this.getTables(sheetId).find((table) => isInside(col, row, table.range.zone));
|
|
44971
|
-
}
|
|
44972
|
-
/** Get the filter tables that are fully inside the given zone */
|
|
44973
|
-
getTablesInZone(sheetId, zone) {
|
|
44974
|
-
return this.getTables(sheetId).filter((table) => isZoneInside(table.range.zone, zone));
|
|
45348
|
+
getCoreTable({ sheetId, col, row }) {
|
|
45349
|
+
return this.getCoreTables(sheetId).find((table) => isInside(col, row, table.range.zone));
|
|
44975
45350
|
}
|
|
44976
45351
|
getTablesOverlappingZones(sheetId, zones) {
|
|
44977
|
-
return this.
|
|
44978
|
-
}
|
|
44979
|
-
doesZonesContainFilter(sheetId, zones) {
|
|
44980
|
-
return (this.getTablesOverlappingZones(sheetId, zones).filter((table) => table.config.hasFilters)
|
|
44981
|
-
.length > 0);
|
|
44982
|
-
}
|
|
44983
|
-
getFilterHeaders(sheetId) {
|
|
44984
|
-
const headers = [];
|
|
44985
|
-
for (const table of this.getTables(sheetId)) {
|
|
44986
|
-
if (!table.config.hasFilters) {
|
|
44987
|
-
continue;
|
|
44988
|
-
}
|
|
44989
|
-
const zone = table.range.zone;
|
|
44990
|
-
const row = zone.top;
|
|
44991
|
-
for (let col = zone.left; col <= zone.right; col++) {
|
|
44992
|
-
headers.push({ col, row });
|
|
44993
|
-
}
|
|
44994
|
-
}
|
|
44995
|
-
return headers;
|
|
44996
|
-
}
|
|
44997
|
-
isFilterHeader({ sheetId, col, row }) {
|
|
44998
|
-
const headers = this.getFilterHeaders(sheetId);
|
|
44999
|
-
return headers.some((header) => header.col === col && header.row === row);
|
|
45352
|
+
return this.getCoreTables(sheetId).filter((table) => zones.some((zone) => overlap(table.range.zone, zone)));
|
|
45000
45353
|
}
|
|
45001
45354
|
/** Extend a table down one row */
|
|
45002
45355
|
extendTableDown(sheetId, table) {
|
|
45003
45356
|
const newRange = this.getters.extendRange(table.range, "ROW", 1);
|
|
45004
|
-
this.history.update("tables", sheetId, table.id, this.
|
|
45357
|
+
this.history.update("tables", sheetId, table.id, this.updateStaticTable(table, newRange));
|
|
45005
45358
|
}
|
|
45006
45359
|
/** Extend a table right one col */
|
|
45007
45360
|
extendTableRight(sheetId, table) {
|
|
45008
45361
|
const newRange = this.getters.extendRange(table.range, "COL", 1);
|
|
45009
|
-
this.history.update("tables", sheetId, table.id, this.
|
|
45362
|
+
this.history.update("tables", sheetId, table.id, this.updateStaticTable(table, newRange));
|
|
45010
45363
|
}
|
|
45011
45364
|
/**
|
|
45012
45365
|
* Check if an UpdateCell command should cause the given table to be extended by one row or col.
|
|
@@ -45043,12 +45396,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45043
45396
|
const cellContent = this.getters.getCell(cellPosition)?.content;
|
|
45044
45397
|
if (cellContent ||
|
|
45045
45398
|
this.getters.isInMerge(cellPosition) ||
|
|
45046
|
-
this.
|
|
45399
|
+
this.getTablesOverlappingZones(sheetId, [positionToZone(position)]).length) {
|
|
45047
45400
|
return "none";
|
|
45048
45401
|
}
|
|
45049
45402
|
}
|
|
45050
45403
|
return direction;
|
|
45051
45404
|
}
|
|
45405
|
+
getTableFromZone(sheetId, zone) {
|
|
45406
|
+
for (const table of this.getCoreTables(sheetId)) {
|
|
45407
|
+
const tableZone = table.range.zone;
|
|
45408
|
+
// Only check top left to match dynamic tables
|
|
45409
|
+
if (tableZone.left === zone.left && tableZone.top === zone.top) {
|
|
45410
|
+
return table;
|
|
45411
|
+
}
|
|
45412
|
+
}
|
|
45413
|
+
return undefined;
|
|
45414
|
+
}
|
|
45052
45415
|
checkUpdatedTableZoneIsValid(cmd) {
|
|
45053
45416
|
if (!cmd.newTableRange) {
|
|
45054
45417
|
return "Success" /* CommandResult.Success */;
|
|
@@ -45058,7 +45421,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45058
45421
|
if (zoneIsInSheet !== "Success" /* CommandResult.Success */) {
|
|
45059
45422
|
return zoneIsInSheet;
|
|
45060
45423
|
}
|
|
45061
|
-
const
|
|
45424
|
+
const updatedTable = this.getTableFromZone(cmd.sheetId, cmd.zone);
|
|
45425
|
+
if (!updatedTable) {
|
|
45426
|
+
return "TableNotFound" /* CommandResult.TableNotFound */;
|
|
45427
|
+
}
|
|
45428
|
+
const overlappingTables = this.getTablesOverlappingZones(cmd.sheetId, [newTableZone]).filter((table) => table.id !== updatedTable.id);
|
|
45062
45429
|
return overlappingTables.length ? "TableOverlap" /* CommandResult.TableOverlap */ : "Success" /* CommandResult.Success */;
|
|
45063
45430
|
}
|
|
45064
45431
|
checkTableConfigUpdateIsValid(config) {
|
|
@@ -45076,7 +45443,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45076
45443
|
}
|
|
45077
45444
|
return "Success" /* CommandResult.Success */;
|
|
45078
45445
|
}
|
|
45079
|
-
|
|
45446
|
+
createStaticTable(id, type, tableRange, config, filters) {
|
|
45080
45447
|
const zone = tableRange.zone;
|
|
45081
45448
|
if (!filters) {
|
|
45082
45449
|
filters = [];
|
|
@@ -45091,9 +45458,51 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45091
45458
|
range: tableRange,
|
|
45092
45459
|
filters,
|
|
45093
45460
|
config,
|
|
45461
|
+
type,
|
|
45094
45462
|
};
|
|
45095
45463
|
}
|
|
45096
|
-
|
|
45464
|
+
createDynamicTable(id, tableRange, config) {
|
|
45465
|
+
const zone = zoneToTopLeft(tableRange.zone);
|
|
45466
|
+
return {
|
|
45467
|
+
id,
|
|
45468
|
+
range: this.getters.getRangeFromZone(tableRange.sheetId, zone),
|
|
45469
|
+
config,
|
|
45470
|
+
type: "dynamic",
|
|
45471
|
+
};
|
|
45472
|
+
}
|
|
45473
|
+
updateTable(cmd) {
|
|
45474
|
+
const table = this.getTableFromZone(cmd.sheetId, cmd.zone);
|
|
45475
|
+
if (!table) {
|
|
45476
|
+
return;
|
|
45477
|
+
}
|
|
45478
|
+
const newTableRange = cmd.newTableRange
|
|
45479
|
+
? this.getters.getRangeFromRangeData(cmd.newTableRange)
|
|
45480
|
+
: undefined;
|
|
45481
|
+
if (newTableRange) {
|
|
45482
|
+
const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, newTableRange.zone);
|
|
45483
|
+
this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
|
|
45484
|
+
}
|
|
45485
|
+
const range = newTableRange || table.range;
|
|
45486
|
+
const newConfig = this.updateTableConfig(cmd.config, table.config);
|
|
45487
|
+
const newTableType = cmd.tableType ?? table.type;
|
|
45488
|
+
if ((newTableType === "dynamic" && table.type !== "dynamic") ||
|
|
45489
|
+
(newTableType !== "dynamic" && table.type === "dynamic")) {
|
|
45490
|
+
const newTable = newTableType === "dynamic"
|
|
45491
|
+
? this.createDynamicTable(table.id, range, newConfig)
|
|
45492
|
+
: this.createStaticTable(table.id, newTableType, range, newConfig);
|
|
45493
|
+
this.history.update("tables", cmd.sheetId, table.id, newTable);
|
|
45494
|
+
}
|
|
45495
|
+
else {
|
|
45496
|
+
const updatedTable = table.type === "dynamic"
|
|
45497
|
+
? this.updateDynamicTable(table, range, newConfig)
|
|
45498
|
+
: this.updateStaticTable(table, range, newConfig, newTableType);
|
|
45499
|
+
this.history.update("tables", cmd.sheetId, table.id, updatedTable);
|
|
45500
|
+
}
|
|
45501
|
+
}
|
|
45502
|
+
updateStaticTable(table, newRange, configUpdate, newTableType = table.type) {
|
|
45503
|
+
if (newTableType === "dynamic") {
|
|
45504
|
+
throw new Error("Cannot use updateStaticTable to update a dynamic table");
|
|
45505
|
+
}
|
|
45097
45506
|
const tableRange = newRange ? newRange : table.range;
|
|
45098
45507
|
const tableZone = tableRange.zone;
|
|
45099
45508
|
const newConfig = this.updateTableConfig(configUpdate, table.config);
|
|
@@ -45114,8 +45523,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45114
45523
|
range: tableRange,
|
|
45115
45524
|
config,
|
|
45116
45525
|
filters: filters.length ? filters : table.filters,
|
|
45526
|
+
type: newTableType,
|
|
45117
45527
|
};
|
|
45118
45528
|
}
|
|
45529
|
+
updateDynamicTable(table, newRange, newConfig) {
|
|
45530
|
+
const range = newRange
|
|
45531
|
+
? this.getters.getRangeFromZone(newRange.sheetId, zoneToTopLeft(newRange.zone))
|
|
45532
|
+
: table.range;
|
|
45533
|
+
const config = newConfig ? newConfig : table.config;
|
|
45534
|
+
return { ...table, range, config };
|
|
45535
|
+
}
|
|
45119
45536
|
/**
|
|
45120
45537
|
* Update the old config of a table with the new partial config from an UpdateTable command.
|
|
45121
45538
|
*
|
|
@@ -45137,35 +45554,29 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45137
45554
|
}
|
|
45138
45555
|
createFilterFromZone(id, sheetId, zone, config) {
|
|
45139
45556
|
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
45140
|
-
return
|
|
45141
|
-
}
|
|
45142
|
-
createFilter(id, range, config) {
|
|
45143
|
-
const zone = range.zone;
|
|
45144
|
-
if (zone.left !== zone.right) {
|
|
45145
|
-
throw new Error("Can only define a filter on a single column");
|
|
45146
|
-
}
|
|
45147
|
-
const contentZone = getTableContentZone(zone, config);
|
|
45148
|
-
const filteredRange = contentZone
|
|
45149
|
-
? this.getters.getRangeFromZone(range.sheetId, contentZone)
|
|
45150
|
-
: undefined;
|
|
45151
|
-
return {
|
|
45152
|
-
id,
|
|
45153
|
-
rangeWithHeaders: range,
|
|
45154
|
-
col: zone.left,
|
|
45155
|
-
filteredRange,
|
|
45156
|
-
};
|
|
45557
|
+
return createFilter(id, range, config, this.getters.getRangeFromZone);
|
|
45157
45558
|
}
|
|
45158
|
-
|
|
45559
|
+
copyStaticTableForSheet(sheetId, table) {
|
|
45159
45560
|
const newRange = this.getters.getRangeFromZone(sheetId, table.range.zone);
|
|
45160
45561
|
const newFilters = table.filters.map((filter) => {
|
|
45161
45562
|
const newFilterRange = this.getters.getRangeFromZone(sheetId, filter.rangeWithHeaders.zone);
|
|
45162
|
-
return
|
|
45563
|
+
return createFilter(filter.id, newFilterRange, table.config, this.getters.getRangeFromZone);
|
|
45163
45564
|
});
|
|
45164
45565
|
return {
|
|
45165
45566
|
id: table.id,
|
|
45166
45567
|
range: newRange,
|
|
45167
45568
|
filters: newFilters,
|
|
45168
45569
|
config: deepCopy(table.config),
|
|
45570
|
+
type: table.type,
|
|
45571
|
+
};
|
|
45572
|
+
}
|
|
45573
|
+
copyDynamicTableForSheet(sheetId, table) {
|
|
45574
|
+
const newRange = this.getters.getRangeFromZone(sheetId, table.range.zone);
|
|
45575
|
+
return {
|
|
45576
|
+
id: table.id,
|
|
45577
|
+
range: newRange,
|
|
45578
|
+
config: deepCopy(table.config),
|
|
45579
|
+
type: "dynamic",
|
|
45169
45580
|
};
|
|
45170
45581
|
}
|
|
45171
45582
|
applyRangeChangeOnTable(sheetId, table, applyChange) {
|
|
@@ -45180,6 +45591,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45180
45591
|
default:
|
|
45181
45592
|
newTableRange = tableRangeChange.range;
|
|
45182
45593
|
}
|
|
45594
|
+
if (table.type === "dynamic") {
|
|
45595
|
+
const newTable = this.updateDynamicTable(table, newTableRange);
|
|
45596
|
+
this.history.update("tables", sheetId, table.id, newTable);
|
|
45597
|
+
return;
|
|
45598
|
+
}
|
|
45183
45599
|
const filters = [];
|
|
45184
45600
|
for (const filter of table.filters) {
|
|
45185
45601
|
const filterRangeChange = applyChange(filter.rangeWithHeaders);
|
|
@@ -45191,7 +45607,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45191
45607
|
break;
|
|
45192
45608
|
default:
|
|
45193
45609
|
const newFilterRange = filterRangeChange.range;
|
|
45194
|
-
const newFilter =
|
|
45610
|
+
const newFilter = createFilter(filter.id, newFilterRange, table.config, this.getters.getRangeFromZone);
|
|
45195
45611
|
filters.push(newFilter);
|
|
45196
45612
|
}
|
|
45197
45613
|
}
|
|
@@ -45206,7 +45622,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45206
45622
|
}
|
|
45207
45623
|
filters.sort((f1, f2) => f1.col - f2.col);
|
|
45208
45624
|
}
|
|
45209
|
-
const newTable = this.
|
|
45625
|
+
const newTable = this.createStaticTable(table.id, table.type, newTableRange, table.config, filters);
|
|
45210
45626
|
this.history.update("tables", sheetId, table.id, newTable);
|
|
45211
45627
|
}
|
|
45212
45628
|
// ---------------------------------------------------------------------------
|
|
@@ -45217,16 +45633,20 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45217
45633
|
for (const tableData of sheet.tables || []) {
|
|
45218
45634
|
const uuid = this.uuidGenerator.uuidv4();
|
|
45219
45635
|
const tableConfig = tableData.config || DEFAULT_TABLE_CONFIG;
|
|
45220
|
-
const
|
|
45221
|
-
const
|
|
45636
|
+
const range = this.getters.getRangeFromSheetXC(sheet.id, tableData.range);
|
|
45637
|
+
const tableType = tableData.type || "static";
|
|
45638
|
+
const table = tableType === "dynamic"
|
|
45639
|
+
? this.createDynamicTable(uuid, range, tableConfig)
|
|
45640
|
+
: this.createStaticTable(uuid, tableType, range, tableConfig);
|
|
45222
45641
|
this.history.update("tables", sheet.id, table.id, table);
|
|
45223
45642
|
}
|
|
45224
45643
|
}
|
|
45225
45644
|
}
|
|
45226
45645
|
export(data) {
|
|
45227
45646
|
for (const sheet of data.sheets) {
|
|
45228
|
-
for (const table of this.
|
|
45229
|
-
const
|
|
45647
|
+
for (const table of this.getCoreTables(sheet.id)) {
|
|
45648
|
+
const range = zoneToXc(table.range.zone);
|
|
45649
|
+
const tableData = { range, type: table.type };
|
|
45230
45650
|
if (!deepEquals(table.config, DEFAULT_TABLE_CONFIG)) {
|
|
45231
45651
|
tableData.config = table.config;
|
|
45232
45652
|
}
|
|
@@ -45789,12 +46209,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45789
46209
|
: _t("Function %s expects its parameters to be single values or single cell references, not ranges.", functionName.toString()));
|
|
45790
46210
|
}
|
|
45791
46211
|
const position = { sheetId: range.sheetId, col: range.zone.left, row: range.zone.top };
|
|
45792
|
-
return this.readCell(position);
|
|
45793
|
-
}
|
|
45794
|
-
readCell(position) {
|
|
45795
|
-
if (!this.getters.tryGetSheet(position.sheetId)) {
|
|
45796
|
-
throw new EvaluationError(_t("Invalid sheet name"));
|
|
45797
|
-
}
|
|
45798
46212
|
return this.computeCell(position);
|
|
45799
46213
|
}
|
|
45800
46214
|
/**
|
|
@@ -45830,7 +46244,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45830
46244
|
matrix[colIndex] = new Array(height);
|
|
45831
46245
|
for (let row = _zone.top; row <= _zone.bottom; row++) {
|
|
45832
46246
|
const rowIndex = row - _zone.top;
|
|
45833
|
-
matrix[colIndex][rowIndex] = this.
|
|
46247
|
+
matrix[colIndex][rowIndex] = this.computeCell({ sheetId, col, row });
|
|
45834
46248
|
}
|
|
45835
46249
|
}
|
|
45836
46250
|
this.rangeCache[cacheKey] = matrix;
|
|
@@ -46938,18 +47352,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46938
47352
|
getEvaluatedCell(position) {
|
|
46939
47353
|
return this.evaluatedCells.get(position) || EMPTY_CELL;
|
|
46940
47354
|
}
|
|
46941
|
-
|
|
47355
|
+
getSpreadZone(position) {
|
|
46942
47356
|
if (!this.spreadingRelations.isArrayFormula(position)) {
|
|
46943
|
-
return
|
|
47357
|
+
return undefined;
|
|
46944
47358
|
}
|
|
46945
|
-
|
|
47359
|
+
if (this.evaluatedCells.get(position)?.type === CellValueType.error) {
|
|
47360
|
+
return positionToZone(position);
|
|
47361
|
+
}
|
|
47362
|
+
const spreadPositions = Array.from(this.spreadingRelations.getArrayResultPositions(position));
|
|
47363
|
+
return union(positionToZone(position), unionPositionsToZone(spreadPositions));
|
|
46946
47364
|
}
|
|
46947
47365
|
getEvaluatedPositions() {
|
|
46948
47366
|
return this.evaluatedCells.keys();
|
|
46949
47367
|
}
|
|
46950
47368
|
getArrayFormulaSpreadingOn(position) {
|
|
46951
47369
|
if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
|
|
46952
|
-
return undefined;
|
|
47370
|
+
return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
|
|
46953
47371
|
}
|
|
46954
47372
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
|
|
46955
47373
|
return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
|
|
@@ -47078,6 +47496,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47078
47496
|
if (!this.blockedArrayFormulas.has(position)) {
|
|
47079
47497
|
this.invalidateSpreading(position);
|
|
47080
47498
|
}
|
|
47499
|
+
this.spreadingRelations.removeNode(position);
|
|
47081
47500
|
const cell = this.getters.getCell(position);
|
|
47082
47501
|
if (cell === undefined) {
|
|
47083
47502
|
return EMPTY_CELL;
|
|
@@ -47188,7 +47607,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47188
47607
|
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
47189
47608
|
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
47190
47609
|
}
|
|
47191
|
-
this.spreadingRelations.removeNode(position);
|
|
47192
47610
|
}
|
|
47193
47611
|
// ----------------------------------------------------------
|
|
47194
47612
|
// COMMON FUNCTIONALITY
|
|
@@ -47347,7 +47765,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47347
47765
|
"getEvaluatedCell",
|
|
47348
47766
|
"getEvaluatedCells",
|
|
47349
47767
|
"getEvaluatedCellsInZone",
|
|
47350
|
-
"
|
|
47768
|
+
"getSpreadZone",
|
|
47351
47769
|
"getArrayFormulaSpreadingOn",
|
|
47352
47770
|
"isEmpty",
|
|
47353
47771
|
];
|
|
@@ -47453,8 +47871,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47453
47871
|
getEvaluatedCellsInZone(sheetId, zone) {
|
|
47454
47872
|
return positions(zone).map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }));
|
|
47455
47873
|
}
|
|
47456
|
-
|
|
47457
|
-
|
|
47874
|
+
/**
|
|
47875
|
+
* Return the spread zone the position is part of, if any
|
|
47876
|
+
*/
|
|
47877
|
+
getSpreadZone(position) {
|
|
47878
|
+
return this.evaluator.getSpreadZone(position);
|
|
47458
47879
|
}
|
|
47459
47880
|
getArrayFormulaSpreadingOn(position) {
|
|
47460
47881
|
return this.evaluator.getArrayFormulaSpreadingOn(position);
|
|
@@ -47494,7 +47915,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47494
47915
|
? getItemId(newFormat, data.formats)
|
|
47495
47916
|
: exportedCellData.format;
|
|
47496
47917
|
let content;
|
|
47497
|
-
if (formulaCell instanceof FormulaCellWithDependencies) {
|
|
47918
|
+
if (isFormula && formulaCell instanceof FormulaCellWithDependencies) {
|
|
47498
47919
|
content = formulaCell.contentWithFixedReferences;
|
|
47499
47920
|
}
|
|
47500
47921
|
else {
|
|
@@ -47542,17 +47963,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47542
47963
|
*/
|
|
47543
47964
|
function sortWithClusters(colorsToSort) {
|
|
47544
47965
|
const clusters = [
|
|
47545
|
-
{ leadColor: rgba(255, 0, 0), colors: [] },
|
|
47546
|
-
{ leadColor: rgba(255, 128, 0), colors: [] },
|
|
47547
|
-
{ leadColor: rgba(128, 128, 0), colors: [] },
|
|
47548
|
-
{ leadColor: rgba(128, 255, 0), colors: [] },
|
|
47549
|
-
{ leadColor: rgba(0, 255, 0), colors: [] },
|
|
47550
|
-
{ leadColor: rgba(0, 255, 128), colors: [] },
|
|
47551
|
-
{ leadColor: rgba(0, 255, 255), colors: [] },
|
|
47552
|
-
{ leadColor: rgba(0, 127, 255), colors: [] },
|
|
47553
|
-
{ leadColor: rgba(0, 0, 255), colors: [] },
|
|
47554
|
-
{ leadColor: rgba(127, 0, 255), colors: [] },
|
|
47555
|
-
{ leadColor: rgba(128, 0, 128), colors: [] },
|
|
47966
|
+
{ leadColor: rgba(255, 0, 0), colors: [] }, // red
|
|
47967
|
+
{ leadColor: rgba(255, 128, 0), colors: [] }, // orange
|
|
47968
|
+
{ leadColor: rgba(128, 128, 0), colors: [] }, // yellow
|
|
47969
|
+
{ leadColor: rgba(128, 255, 0), colors: [] }, // chartreuse
|
|
47970
|
+
{ leadColor: rgba(0, 255, 0), colors: [] }, // green
|
|
47971
|
+
{ leadColor: rgba(0, 255, 128), colors: [] }, // spring green
|
|
47972
|
+
{ leadColor: rgba(0, 255, 255), colors: [] }, // cyan
|
|
47973
|
+
{ leadColor: rgba(0, 127, 255), colors: [] }, // azure
|
|
47974
|
+
{ leadColor: rgba(0, 0, 255), colors: [] }, // blue
|
|
47975
|
+
{ leadColor: rgba(127, 0, 255), colors: [] }, // violet
|
|
47976
|
+
{ leadColor: rgba(128, 0, 128), colors: [] }, // magenta
|
|
47556
47977
|
{ leadColor: rgba(255, 0, 128), colors: [] }, // rose
|
|
47557
47978
|
];
|
|
47558
47979
|
for (const color of colorsToSort.map(colorToRGBA)) {
|
|
@@ -47943,13 +48364,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47943
48364
|
.map((cell) => cell.value);
|
|
47944
48365
|
switch (threshold.type) {
|
|
47945
48366
|
case "value":
|
|
47946
|
-
const result = functionName === "max" ?
|
|
48367
|
+
const result = functionName === "max" ? largeMax(rangeValues) : largeMin(rangeValues);
|
|
47947
48368
|
return result;
|
|
47948
48369
|
case "number":
|
|
47949
48370
|
return Number(threshold.value);
|
|
47950
48371
|
case "percentage":
|
|
47951
|
-
const min =
|
|
47952
|
-
const max =
|
|
48372
|
+
const min = largeMin(rangeValues);
|
|
48373
|
+
const max = largeMax(rangeValues);
|
|
47953
48374
|
const delta = max - min;
|
|
47954
48375
|
return min + (delta * Number(threshold.value)) / 100;
|
|
47955
48376
|
case "percentile":
|
|
@@ -48286,6 +48707,180 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48286
48707
|
}
|
|
48287
48708
|
}
|
|
48288
48709
|
|
|
48710
|
+
class DynamicTablesPlugin extends UIPlugin {
|
|
48711
|
+
static getters = [
|
|
48712
|
+
"canCreateDynamicTableOnZones",
|
|
48713
|
+
"doesZonesContainFilter",
|
|
48714
|
+
"getFilter",
|
|
48715
|
+
"getFilters",
|
|
48716
|
+
"getTable",
|
|
48717
|
+
"getTables",
|
|
48718
|
+
"getTablesOverlappingZones",
|
|
48719
|
+
"getFilterId",
|
|
48720
|
+
"getFilterHeaders",
|
|
48721
|
+
"isFilterHeader",
|
|
48722
|
+
];
|
|
48723
|
+
tables = {};
|
|
48724
|
+
handle(cmd) {
|
|
48725
|
+
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
48726
|
+
(cmd.type === "UPDATE_CELL" && "content" in cmd) ||
|
|
48727
|
+
cmd.type === "EVALUATE_CELLS") {
|
|
48728
|
+
this.tables = {};
|
|
48729
|
+
return;
|
|
48730
|
+
}
|
|
48731
|
+
switch (cmd.type) {
|
|
48732
|
+
case "CREATE_TABLE":
|
|
48733
|
+
case "REMOVE_TABLE":
|
|
48734
|
+
case "UPDATE_TABLE":
|
|
48735
|
+
case "DELETE_CONTENT":
|
|
48736
|
+
this.tables = {};
|
|
48737
|
+
break;
|
|
48738
|
+
}
|
|
48739
|
+
}
|
|
48740
|
+
finalize() {
|
|
48741
|
+
for (const sheetId of this.getters.getSheetIds()) {
|
|
48742
|
+
if (!this.tables[sheetId]) {
|
|
48743
|
+
this.tables[sheetId] = this.computeTables(sheetId);
|
|
48744
|
+
}
|
|
48745
|
+
}
|
|
48746
|
+
}
|
|
48747
|
+
computeTables(sheetId) {
|
|
48748
|
+
const tables = [];
|
|
48749
|
+
const coreTables = this.getters.getCoreTables(sheetId);
|
|
48750
|
+
// First we create the static tables, so we can use them to compute collision with dynamic tables
|
|
48751
|
+
for (const table of coreTables) {
|
|
48752
|
+
if (table.type === "dynamic")
|
|
48753
|
+
continue;
|
|
48754
|
+
tables.push(table);
|
|
48755
|
+
}
|
|
48756
|
+
const staticTables = [...tables];
|
|
48757
|
+
// Then we create the dynamic tables
|
|
48758
|
+
for (const coreTable of coreTables) {
|
|
48759
|
+
if (coreTable.type !== "dynamic")
|
|
48760
|
+
continue;
|
|
48761
|
+
const table = this.coreTableToTable(sheetId, coreTable);
|
|
48762
|
+
let tableZone = table.range.zone;
|
|
48763
|
+
// Reduce the zone to avoid collision with static tables. Per design, dynamic tables can't overlap with other
|
|
48764
|
+
// dynamic tables, because formulas cannot spread on the same area, so we don't need to check for that.
|
|
48765
|
+
for (const staticTable of staticTables) {
|
|
48766
|
+
if (overlap(tableZone, staticTable.range.zone)) {
|
|
48767
|
+
tableZone = { ...tableZone, right: staticTable.range.zone.left - 1 };
|
|
48768
|
+
}
|
|
48769
|
+
}
|
|
48770
|
+
tables.push({ ...table, range: this.getters.getRangeFromZone(sheetId, tableZone) });
|
|
48771
|
+
}
|
|
48772
|
+
return tables;
|
|
48773
|
+
}
|
|
48774
|
+
getFilters(sheetId) {
|
|
48775
|
+
return this.getTables(sheetId)
|
|
48776
|
+
.filter((table) => table.config.hasFilters)
|
|
48777
|
+
.map((table) => table.filters)
|
|
48778
|
+
.flat();
|
|
48779
|
+
}
|
|
48780
|
+
getTables(sheetId) {
|
|
48781
|
+
return this.tables[sheetId] || [];
|
|
48782
|
+
}
|
|
48783
|
+
getFilter(position) {
|
|
48784
|
+
const table = this.getTable(position);
|
|
48785
|
+
if (!table || !table.config.hasFilters) {
|
|
48786
|
+
return undefined;
|
|
48787
|
+
}
|
|
48788
|
+
return table.filters.find((filter) => filter.col === position.col);
|
|
48789
|
+
}
|
|
48790
|
+
getFilterId(position) {
|
|
48791
|
+
return this.getFilter(position)?.id;
|
|
48792
|
+
}
|
|
48793
|
+
getTable({ sheetId, col, row }) {
|
|
48794
|
+
return this.getTables(sheetId).find((table) => isInside(col, row, table.range.zone));
|
|
48795
|
+
}
|
|
48796
|
+
getTablesOverlappingZones(sheetId, zones) {
|
|
48797
|
+
return this.getTables(sheetId).filter((table) => zones.some((zone) => overlap(table.range.zone, zone)));
|
|
48798
|
+
}
|
|
48799
|
+
doesZonesContainFilter(sheetId, zones) {
|
|
48800
|
+
return this.getTablesOverlappingZones(sheetId, zones).some((table) => table.config.hasFilters);
|
|
48801
|
+
}
|
|
48802
|
+
getFilterHeaders(sheetId) {
|
|
48803
|
+
const headers = [];
|
|
48804
|
+
for (const table of this.getTables(sheetId)) {
|
|
48805
|
+
if (!table.config.hasFilters) {
|
|
48806
|
+
continue;
|
|
48807
|
+
}
|
|
48808
|
+
const zone = table.range.zone;
|
|
48809
|
+
const row = zone.top;
|
|
48810
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
48811
|
+
headers.push({ sheetId, col, row });
|
|
48812
|
+
}
|
|
48813
|
+
}
|
|
48814
|
+
return headers;
|
|
48815
|
+
}
|
|
48816
|
+
isFilterHeader({ sheetId, col, row }) {
|
|
48817
|
+
const headers = this.getFilterHeaders(sheetId);
|
|
48818
|
+
return headers.some((header) => header.col === col && header.row === row);
|
|
48819
|
+
}
|
|
48820
|
+
/**
|
|
48821
|
+
* Check if we can create a dynamic table on the given zones.
|
|
48822
|
+
* - The zones must be continuous
|
|
48823
|
+
* - The union of the zones must be either:
|
|
48824
|
+
* - A single cell that contains an array formula
|
|
48825
|
+
* - All the spread cells of a single array formula
|
|
48826
|
+
*/
|
|
48827
|
+
canCreateDynamicTableOnZones(sheetId, zones) {
|
|
48828
|
+
if (!areZonesContinuous(zones)) {
|
|
48829
|
+
return false;
|
|
48830
|
+
}
|
|
48831
|
+
const unionZone = union(...zones);
|
|
48832
|
+
const topLeft = { col: unionZone.left, row: unionZone.top, sheetId };
|
|
48833
|
+
const parentSpreadingCell = this.getters.getArrayFormulaSpreadingOn(topLeft);
|
|
48834
|
+
if (!parentSpreadingCell) {
|
|
48835
|
+
return false;
|
|
48836
|
+
}
|
|
48837
|
+
else if (deepEquals(parentSpreadingCell, topLeft) && getZoneArea(unionZone) === 1) {
|
|
48838
|
+
return true;
|
|
48839
|
+
}
|
|
48840
|
+
const zone = this.getters.getSpreadZone(parentSpreadingCell);
|
|
48841
|
+
return deepEquals(unionZone, zone);
|
|
48842
|
+
}
|
|
48843
|
+
coreTableToTable(sheetId, table) {
|
|
48844
|
+
if (table.type !== "dynamic") {
|
|
48845
|
+
return table;
|
|
48846
|
+
}
|
|
48847
|
+
const tableZone = table.range.zone;
|
|
48848
|
+
const tablePosition = { sheetId, col: tableZone.left, row: tableZone.top };
|
|
48849
|
+
const zone = this.getters.getSpreadZone(tablePosition) ?? table.range.zone;
|
|
48850
|
+
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
48851
|
+
const filters = this.getDynamicTableFilters(sheetId, table, zone);
|
|
48852
|
+
return { id: table.id, range, filters, config: table.config };
|
|
48853
|
+
}
|
|
48854
|
+
getDynamicTableFilters(sheetId, table, tableZone) {
|
|
48855
|
+
const filters = [];
|
|
48856
|
+
const { top, bottom, left, right } = tableZone;
|
|
48857
|
+
for (let col = left; col <= right; col++) {
|
|
48858
|
+
const tableColIndex = col - left;
|
|
48859
|
+
const zone = { left: col, right: col, top, bottom };
|
|
48860
|
+
const filter = createFilter(this.getDynamicTableFilterId(table.id, tableColIndex), this.getters.getRangeFromZone(sheetId, zone), table.config, this.getters.getRangeFromZone);
|
|
48861
|
+
filters.push(filter);
|
|
48862
|
+
}
|
|
48863
|
+
return filters;
|
|
48864
|
+
}
|
|
48865
|
+
getDynamicTableFilterId(tableId, tableCol) {
|
|
48866
|
+
return tableId + "_" + tableCol;
|
|
48867
|
+
}
|
|
48868
|
+
exportForExcel(data) {
|
|
48869
|
+
for (const sheet of data.sheets) {
|
|
48870
|
+
for (const tableData of sheet.tables) {
|
|
48871
|
+
const zone = toZone(tableData.range);
|
|
48872
|
+
const topLeft = { sheetId: sheet.id, col: zone.left, row: zone.top };
|
|
48873
|
+
const coreTable = this.getters.getCoreTable(topLeft);
|
|
48874
|
+
const table = this.getTable(topLeft);
|
|
48875
|
+
if (coreTable?.type !== "dynamic" || !table) {
|
|
48876
|
+
continue;
|
|
48877
|
+
}
|
|
48878
|
+
tableData.range = zoneToXc(table.range.zone);
|
|
48879
|
+
}
|
|
48880
|
+
}
|
|
48881
|
+
}
|
|
48882
|
+
}
|
|
48883
|
+
|
|
48289
48884
|
class HeaderSizeUIPlugin extends UIPlugin {
|
|
48290
48885
|
static getters = ["getRowSize", "getHeaderSize"];
|
|
48291
48886
|
tallestCellInRow = {};
|
|
@@ -48701,8 +49296,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48701
49296
|
let row = zone.bottom;
|
|
48702
49297
|
if (col > 0) {
|
|
48703
49298
|
let leftPosition = { sheetId, col: col - 1, row };
|
|
48704
|
-
while (this.getters.
|
|
48705
|
-
this.getters.getCell(leftPosition)?.content) {
|
|
49299
|
+
while (this.getters.getEvaluatedCell(leftPosition).type !== CellValueType.empty) {
|
|
48706
49300
|
row += 1;
|
|
48707
49301
|
leftPosition = { sheetId, col: col - 1, row };
|
|
48708
49302
|
}
|
|
@@ -48711,8 +49305,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48711
49305
|
col = zone.right;
|
|
48712
49306
|
if (col <= this.getters.getNumberCols(sheetId)) {
|
|
48713
49307
|
let rightPosition = { sheetId, col: col + 1, row };
|
|
48714
|
-
while (this.getters.
|
|
48715
|
-
this.getters.getCell(rightPosition)?.content) {
|
|
49308
|
+
while (this.getters.getEvaluatedCell(rightPosition).type !== CellValueType.empty) {
|
|
48716
49309
|
row += 1;
|
|
48717
49310
|
rightPosition = { sheetId, col: col + 1, row };
|
|
48718
49311
|
}
|
|
@@ -49022,13 +49615,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49022
49615
|
const cells = this.getters.getEvaluatedCellsInZone(sheet.id, zone);
|
|
49023
49616
|
const cellPositions = range(end, -1, -1);
|
|
49024
49617
|
const invalidCells = cellPositions.filter((position) => cells[position] && !cells[position].isAutoSummable);
|
|
49025
|
-
const maxValidPosition =
|
|
49618
|
+
const maxValidPosition = largeMax(invalidCells);
|
|
49026
49619
|
const numberSequences = groupConsecutive(cellPositions.filter((position) => this.isNumber(cells[position])));
|
|
49027
49620
|
const firstSequence = numberSequences[0] || [];
|
|
49028
|
-
if (
|
|
49621
|
+
if (largeMax(firstSequence) < maxValidPosition) {
|
|
49029
49622
|
return Infinity;
|
|
49030
49623
|
}
|
|
49031
|
-
return
|
|
49624
|
+
return largeMin(firstSequence);
|
|
49032
49625
|
}
|
|
49033
49626
|
shouldFindData(sheetId, zone) {
|
|
49034
49627
|
return this.getters.isEmpty(sheetId, zone) || this.getters.isSingleCellOrMerge(sheetId, zone);
|
|
@@ -50603,8 +51196,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
50603
51196
|
static getters = [
|
|
50604
51197
|
"doesCellHaveGridIcon",
|
|
50605
51198
|
"getCellWidth",
|
|
50606
|
-
"getCellComputedBorder",
|
|
50607
|
-
"getCellComputedStyle",
|
|
50608
51199
|
"getTextWidth",
|
|
50609
51200
|
"getCellText",
|
|
50610
51201
|
"getCellMultiLineText",
|
|
@@ -50648,7 +51239,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
50648
51239
|
// Getters
|
|
50649
51240
|
// ---------------------------------------------------------------------------
|
|
50650
51241
|
getCellWidth(position) {
|
|
50651
|
-
const style = this.getCellComputedStyle(position);
|
|
51242
|
+
const style = this.getters.getCellComputedStyle(position);
|
|
50652
51243
|
let contentWidth = 0;
|
|
50653
51244
|
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
50654
51245
|
if (content) {
|
|
@@ -50741,35 +51332,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
50741
51332
|
*/
|
|
50742
51333
|
isCellEmpty(position) {
|
|
50743
51334
|
const mainPosition = this.getters.getMainCellPosition(position);
|
|
50744
|
-
return
|
|
50745
|
-
this.getters.getCell(mainPosition)?.content);
|
|
50746
|
-
}
|
|
50747
|
-
getCellComputedBorder(position) {
|
|
50748
|
-
const cellBorder = this.getters.getCellBorder(position) || {};
|
|
50749
|
-
const cellTableBorder = this.getters.getCellTableBorder(position) || {};
|
|
50750
|
-
// Use removeFalsyAttributes to avoid overwriting borders with undefined values
|
|
50751
|
-
const border = { ...cellTableBorder, ...removeFalsyAttributes(cellBorder) };
|
|
50752
|
-
return isObjectEmptyRecursive(border) ? null : border;
|
|
50753
|
-
}
|
|
50754
|
-
getCellComputedStyle(position) {
|
|
50755
|
-
const cell = this.getters.getCell(position);
|
|
50756
|
-
const cfStyle = this.getters.getCellConditionalFormatStyle(position);
|
|
50757
|
-
const tableStyle = this.getters.getCellTableStyle(position);
|
|
50758
|
-
const computedStyle = {
|
|
50759
|
-
...removeFalsyAttributes(tableStyle),
|
|
50760
|
-
...removeFalsyAttributes(cell?.style),
|
|
50761
|
-
...removeFalsyAttributes(cfStyle),
|
|
50762
|
-
};
|
|
50763
|
-
const evaluatedCell = this.getters.getEvaluatedCell(position);
|
|
50764
|
-
if (evaluatedCell.link && !computedStyle.textColor) {
|
|
50765
|
-
computedStyle.textColor = LINK_COLOR;
|
|
50766
|
-
}
|
|
50767
|
-
return computedStyle;
|
|
51335
|
+
return this.getters.getEvaluatedCell(mainPosition).type === CellValueType.empty;
|
|
50768
51336
|
}
|
|
50769
51337
|
getColMaxWidth(sheetId, index) {
|
|
50770
51338
|
const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
|
|
50771
51339
|
const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
|
|
50772
|
-
return Math.max(0,
|
|
51340
|
+
return Math.max(0, largeMax(sizes));
|
|
50773
51341
|
}
|
|
50774
51342
|
/**
|
|
50775
51343
|
* Check that any "sheetId" in the command matches an existing
|
|
@@ -50798,6 +51366,236 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
50798
51366
|
}
|
|
50799
51367
|
}
|
|
50800
51368
|
|
|
51369
|
+
class TableStylePlugin extends UIPlugin {
|
|
51370
|
+
static getters = ["getCellTableStyle", "getCellTableBorder"];
|
|
51371
|
+
tableStyles = {};
|
|
51372
|
+
handle(cmd) {
|
|
51373
|
+
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
51374
|
+
(cmd.type === "UPDATE_CELL" && "content" in cmd) ||
|
|
51375
|
+
cmd.type === "EVALUATE_CELLS") {
|
|
51376
|
+
this.tableStyles = {};
|
|
51377
|
+
return;
|
|
51378
|
+
}
|
|
51379
|
+
if (doesCommandInvalidatesTableStyle(cmd)) {
|
|
51380
|
+
delete this.tableStyles[cmd.sheetId];
|
|
51381
|
+
return;
|
|
51382
|
+
}
|
|
51383
|
+
}
|
|
51384
|
+
finalize() {
|
|
51385
|
+
for (const sheetId of this.getters.getSheetIds()) {
|
|
51386
|
+
if (!this.tableStyles[sheetId]) {
|
|
51387
|
+
this.tableStyles[sheetId] = {};
|
|
51388
|
+
}
|
|
51389
|
+
for (const table of this.getters.getTables(sheetId)) {
|
|
51390
|
+
if (!this.tableStyles[sheetId][table.id]) {
|
|
51391
|
+
this.tableStyles[sheetId][table.id] = this.computeTableStyle(sheetId, table);
|
|
51392
|
+
}
|
|
51393
|
+
}
|
|
51394
|
+
}
|
|
51395
|
+
}
|
|
51396
|
+
getCellTableStyle(position) {
|
|
51397
|
+
const table = this.getters.getTable(position);
|
|
51398
|
+
if (!table) {
|
|
51399
|
+
return undefined;
|
|
51400
|
+
}
|
|
51401
|
+
return this.tableStyles[position.sheetId][table.id]().styles[position.col]?.[position.row];
|
|
51402
|
+
}
|
|
51403
|
+
getCellTableBorder(position) {
|
|
51404
|
+
const table = this.getters.getTable(position);
|
|
51405
|
+
if (!table) {
|
|
51406
|
+
return undefined;
|
|
51407
|
+
}
|
|
51408
|
+
return this.tableStyles[position.sheetId][table.id]().borders[position.col]?.[position.row];
|
|
51409
|
+
}
|
|
51410
|
+
computeTableStyle(sheetId, table) {
|
|
51411
|
+
return lazy(() => {
|
|
51412
|
+
const { config, numberOfCols, numberOfRows } = this.getTableRuntimeConfig(sheetId, table);
|
|
51413
|
+
const relativeTableStyle = getComputedTableStyle(config, numberOfCols, numberOfRows);
|
|
51414
|
+
// Return the style with sheet coordinates instead of tables coordinates
|
|
51415
|
+
const mapping = this.getTableMapping(sheetId, table);
|
|
51416
|
+
const absoluteTableStyle = { borders: {}, styles: {} };
|
|
51417
|
+
for (let col = 0; col < numberOfCols; col++) {
|
|
51418
|
+
const colInSheet = mapping.colMapping[col];
|
|
51419
|
+
absoluteTableStyle.borders[colInSheet] = {};
|
|
51420
|
+
absoluteTableStyle.styles[colInSheet] = {};
|
|
51421
|
+
for (let row = 0; row < numberOfRows; row++) {
|
|
51422
|
+
const rowInSheet = mapping.rowMapping[row];
|
|
51423
|
+
absoluteTableStyle.borders[colInSheet][rowInSheet] = relativeTableStyle.borders[col][row];
|
|
51424
|
+
absoluteTableStyle.styles[colInSheet][rowInSheet] = relativeTableStyle.styles[col][row];
|
|
51425
|
+
}
|
|
51426
|
+
}
|
|
51427
|
+
return absoluteTableStyle;
|
|
51428
|
+
});
|
|
51429
|
+
}
|
|
51430
|
+
/**
|
|
51431
|
+
* Get the actual table config that will be used to compute the table style. It is different from
|
|
51432
|
+
* the config of the table because of hidden rows and columns in the sheet. For example remove the
|
|
51433
|
+
* hidden rows from config.numberOfHeaders.
|
|
51434
|
+
*/
|
|
51435
|
+
getTableRuntimeConfig(sheetId, table) {
|
|
51436
|
+
const tableZone = table.range.zone;
|
|
51437
|
+
const config = { ...table.config };
|
|
51438
|
+
let numberOfCols = tableZone.right - tableZone.left + 1;
|
|
51439
|
+
let numberOfRows = tableZone.bottom - tableZone.top + 1;
|
|
51440
|
+
for (let row = tableZone.top; row <= tableZone.bottom; row++) {
|
|
51441
|
+
if (!this.getters.isRowHidden(sheetId, row)) {
|
|
51442
|
+
continue;
|
|
51443
|
+
}
|
|
51444
|
+
numberOfRows--;
|
|
51445
|
+
if (row - tableZone.top < table.config.numberOfHeaders) {
|
|
51446
|
+
config.numberOfHeaders--;
|
|
51447
|
+
if (config.numberOfHeaders < 0) {
|
|
51448
|
+
config.numberOfHeaders = 0;
|
|
51449
|
+
}
|
|
51450
|
+
}
|
|
51451
|
+
if (row === tableZone.bottom) {
|
|
51452
|
+
config.totalRow = false;
|
|
51453
|
+
}
|
|
51454
|
+
}
|
|
51455
|
+
for (let col = tableZone.left; col <= tableZone.right; col++) {
|
|
51456
|
+
if (!this.getters.isColHidden(sheetId, col)) {
|
|
51457
|
+
continue;
|
|
51458
|
+
}
|
|
51459
|
+
numberOfCols--;
|
|
51460
|
+
if (col === tableZone.left) {
|
|
51461
|
+
config.firstColumn = false;
|
|
51462
|
+
}
|
|
51463
|
+
if (col === tableZone.right) {
|
|
51464
|
+
config.lastColumn = false;
|
|
51465
|
+
}
|
|
51466
|
+
}
|
|
51467
|
+
return {
|
|
51468
|
+
config,
|
|
51469
|
+
numberOfCols,
|
|
51470
|
+
numberOfRows,
|
|
51471
|
+
};
|
|
51472
|
+
}
|
|
51473
|
+
/**
|
|
51474
|
+
* Get a mapping: relative col/row position in the table <=> col/row in the sheet
|
|
51475
|
+
*/
|
|
51476
|
+
getTableMapping(sheetId, table) {
|
|
51477
|
+
const colMapping = {};
|
|
51478
|
+
const rowMapping = {};
|
|
51479
|
+
let colOffset = 0;
|
|
51480
|
+
let rowOffset = 0;
|
|
51481
|
+
const tableZone = table.range.zone;
|
|
51482
|
+
for (let col = tableZone.left; col <= tableZone.right; col++) {
|
|
51483
|
+
if (this.getters.isColHidden(sheetId, col)) {
|
|
51484
|
+
continue;
|
|
51485
|
+
}
|
|
51486
|
+
colMapping[colOffset] = col;
|
|
51487
|
+
colOffset++;
|
|
51488
|
+
for (let row = tableZone.top; row <= tableZone.bottom; row++) {
|
|
51489
|
+
if (this.getters.isRowHidden(sheetId, row)) {
|
|
51490
|
+
continue;
|
|
51491
|
+
}
|
|
51492
|
+
rowMapping[rowOffset] = row;
|
|
51493
|
+
rowOffset++;
|
|
51494
|
+
}
|
|
51495
|
+
}
|
|
51496
|
+
return {
|
|
51497
|
+
colMapping,
|
|
51498
|
+
rowMapping,
|
|
51499
|
+
};
|
|
51500
|
+
}
|
|
51501
|
+
}
|
|
51502
|
+
const invalidateTableStyleCommands = [
|
|
51503
|
+
"HIDE_COLUMNS_ROWS",
|
|
51504
|
+
"UNHIDE_COLUMNS_ROWS",
|
|
51505
|
+
"UNFOLD_HEADER_GROUP",
|
|
51506
|
+
"FOLD_HEADER_GROUP",
|
|
51507
|
+
"FOLD_ALL_HEADER_GROUPS",
|
|
51508
|
+
"UNFOLD_ALL_HEADER_GROUPS",
|
|
51509
|
+
"CREATE_TABLE",
|
|
51510
|
+
"UPDATE_TABLE",
|
|
51511
|
+
"UPDATE_FILTER",
|
|
51512
|
+
];
|
|
51513
|
+
const invalidateTableStyleCommandsSet = new Set(invalidateTableStyleCommands);
|
|
51514
|
+
function doesCommandInvalidatesTableStyle(cmd) {
|
|
51515
|
+
return invalidateTableStyleCommandsSet.has(cmd.type);
|
|
51516
|
+
}
|
|
51517
|
+
|
|
51518
|
+
class CellComputedStylePlugin extends UIPlugin {
|
|
51519
|
+
static getters = ["getCellComputedBorder", "getCellComputedStyle"];
|
|
51520
|
+
styles = {};
|
|
51521
|
+
borders = {};
|
|
51522
|
+
handle(cmd) {
|
|
51523
|
+
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
51524
|
+
cmd.type === "UPDATE_CELL" ||
|
|
51525
|
+
cmd.type === "EVALUATE_CELLS") {
|
|
51526
|
+
this.styles = {};
|
|
51527
|
+
this.borders = {};
|
|
51528
|
+
return;
|
|
51529
|
+
}
|
|
51530
|
+
if (doesCommandInvalidatesTableStyle(cmd)) {
|
|
51531
|
+
delete this.styles[cmd.sheetId];
|
|
51532
|
+
delete this.borders[cmd.sheetId];
|
|
51533
|
+
return;
|
|
51534
|
+
}
|
|
51535
|
+
if (invalidateCFEvaluationCommands.has(cmd.type)) {
|
|
51536
|
+
this.styles = {};
|
|
51537
|
+
return;
|
|
51538
|
+
}
|
|
51539
|
+
}
|
|
51540
|
+
getCellComputedBorder(position) {
|
|
51541
|
+
const { sheetId, row, col } = position;
|
|
51542
|
+
if (this.borders[sheetId]?.[row]?.[col] !== undefined) {
|
|
51543
|
+
return this.borders[sheetId][row][col];
|
|
51544
|
+
}
|
|
51545
|
+
if (!this.borders[sheetId]) {
|
|
51546
|
+
this.borders[sheetId] = {};
|
|
51547
|
+
}
|
|
51548
|
+
if (!this.borders[sheetId][row]) {
|
|
51549
|
+
this.borders[sheetId][row] = {};
|
|
51550
|
+
}
|
|
51551
|
+
if (!this.borders[sheetId][row][col]) {
|
|
51552
|
+
this.borders[sheetId][row][col] = this.computeCellBorder(position);
|
|
51553
|
+
}
|
|
51554
|
+
return this.borders[sheetId][row][col];
|
|
51555
|
+
}
|
|
51556
|
+
getCellComputedStyle(position) {
|
|
51557
|
+
const { sheetId, row, col } = position;
|
|
51558
|
+
if (this.styles[sheetId]?.[row]?.[col] !== undefined) {
|
|
51559
|
+
return this.styles[sheetId][row][col];
|
|
51560
|
+
}
|
|
51561
|
+
if (!this.styles[sheetId]) {
|
|
51562
|
+
this.styles[sheetId] = {};
|
|
51563
|
+
}
|
|
51564
|
+
if (!this.styles[sheetId][row]) {
|
|
51565
|
+
this.styles[sheetId][row] = {};
|
|
51566
|
+
}
|
|
51567
|
+
if (!this.styles[sheetId][row][col]) {
|
|
51568
|
+
this.styles[sheetId][row][col] = this.computeCellStyle(position);
|
|
51569
|
+
}
|
|
51570
|
+
return this.styles[sheetId][row][col];
|
|
51571
|
+
}
|
|
51572
|
+
computeCellBorder(position) {
|
|
51573
|
+
const cellBorder = this.getters.getCellBorder(position) || {};
|
|
51574
|
+
const cellTableBorder = this.getters.getCellTableBorder(position) || {};
|
|
51575
|
+
// Use removeFalsyAttributes to avoid overwriting borders with undefined values
|
|
51576
|
+
const border = {
|
|
51577
|
+
...removeFalsyAttributes(cellTableBorder),
|
|
51578
|
+
...removeFalsyAttributes(cellBorder),
|
|
51579
|
+
};
|
|
51580
|
+
return isObjectEmptyRecursive(border) ? null : border;
|
|
51581
|
+
}
|
|
51582
|
+
computeCellStyle(position) {
|
|
51583
|
+
const cell = this.getters.getCell(position);
|
|
51584
|
+
const cfStyle = this.getters.getCellConditionalFormatStyle(position);
|
|
51585
|
+
const tableStyle = this.getters.getCellTableStyle(position);
|
|
51586
|
+
const computedStyle = {
|
|
51587
|
+
...removeFalsyAttributes(tableStyle),
|
|
51588
|
+
...removeFalsyAttributes(cell?.style),
|
|
51589
|
+
...removeFalsyAttributes(cfStyle),
|
|
51590
|
+
};
|
|
51591
|
+
const evaluatedCell = this.getters.getEvaluatedCell(position);
|
|
51592
|
+
if (evaluatedCell.link && !computedStyle.textColor) {
|
|
51593
|
+
computedStyle.textColor = LINK_COLOR;
|
|
51594
|
+
}
|
|
51595
|
+
return computedStyle;
|
|
51596
|
+
}
|
|
51597
|
+
}
|
|
51598
|
+
|
|
50801
51599
|
const genericRepeatsTransforms = [
|
|
50802
51600
|
repeatSheetDependantCommand,
|
|
50803
51601
|
repeatTargetDependantCommand,
|
|
@@ -51333,10 +52131,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51333
52131
|
handle(cmd) {
|
|
51334
52132
|
switch (cmd.type) {
|
|
51335
52133
|
case "AUTOFILL_TABLE_COLUMN":
|
|
51336
|
-
const table = this.getters.
|
|
52134
|
+
const table = this.getters.getCoreTable(cmd);
|
|
51337
52135
|
const cell = this.getters.getCell(cmd);
|
|
51338
|
-
if (!table ||
|
|
52136
|
+
if (!table?.config.automaticAutofill || table.type === "dynamic" || !cell?.isFormula) {
|
|
51339
52137
|
return;
|
|
52138
|
+
}
|
|
51340
52139
|
const { col, row } = cmd;
|
|
51341
52140
|
const tableContentZone = getTableContentZone(table.range.zone, table.config);
|
|
51342
52141
|
if (tableContentZone && isInside(col, row, tableContentZone)) {
|
|
@@ -51374,148 +52173,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51374
52173
|
}
|
|
51375
52174
|
}
|
|
51376
52175
|
|
|
51377
|
-
class TableStylePlugin extends UIPlugin {
|
|
51378
|
-
static getters = ["getCellTableStyle", "getCellTableBorder"];
|
|
51379
|
-
tableStyles = {};
|
|
51380
|
-
handle(cmd) {
|
|
51381
|
-
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
51382
|
-
(cmd.type === "UPDATE_CELL" && "content" in cmd) ||
|
|
51383
|
-
cmd.type === "EVALUATE_CELLS") {
|
|
51384
|
-
this.tableStyles = {};
|
|
51385
|
-
return;
|
|
51386
|
-
}
|
|
51387
|
-
switch (cmd.type) {
|
|
51388
|
-
case "HIDE_COLUMNS_ROWS":
|
|
51389
|
-
case "UNHIDE_COLUMNS_ROWS":
|
|
51390
|
-
case "UNFOLD_HEADER_GROUP":
|
|
51391
|
-
case "FOLD_HEADER_GROUP":
|
|
51392
|
-
case "FOLD_ALL_HEADER_GROUPS":
|
|
51393
|
-
case "UNFOLD_ALL_HEADER_GROUPS":
|
|
51394
|
-
case "UPDATE_TABLE":
|
|
51395
|
-
case "UPDATE_FILTER":
|
|
51396
|
-
delete this.tableStyles[cmd.sheetId];
|
|
51397
|
-
break;
|
|
51398
|
-
}
|
|
51399
|
-
}
|
|
51400
|
-
finalize() {
|
|
51401
|
-
for (const sheetId of this.getters.getSheetIds()) {
|
|
51402
|
-
if (!this.tableStyles[sheetId]) {
|
|
51403
|
-
this.tableStyles[sheetId] = {};
|
|
51404
|
-
}
|
|
51405
|
-
for (const table of this.getters.getTables(sheetId)) {
|
|
51406
|
-
if (!this.tableStyles[sheetId][table.id]) {
|
|
51407
|
-
this.tableStyles[sheetId][table.id] = this.computeTableStyle(sheetId, table);
|
|
51408
|
-
}
|
|
51409
|
-
}
|
|
51410
|
-
}
|
|
51411
|
-
}
|
|
51412
|
-
getCellTableStyle(position) {
|
|
51413
|
-
const table = this.getters.getTable(position);
|
|
51414
|
-
if (!table) {
|
|
51415
|
-
return undefined;
|
|
51416
|
-
}
|
|
51417
|
-
return this.tableStyles[position.sheetId][table.id]().styles[position.col]?.[position.row];
|
|
51418
|
-
}
|
|
51419
|
-
getCellTableBorder(position) {
|
|
51420
|
-
const table = this.getters.getTable(position);
|
|
51421
|
-
if (!table) {
|
|
51422
|
-
return undefined;
|
|
51423
|
-
}
|
|
51424
|
-
return this.tableStyles[position.sheetId][table.id]().borders[position.col]?.[position.row];
|
|
51425
|
-
}
|
|
51426
|
-
computeTableStyle(sheetId, table) {
|
|
51427
|
-
return lazy(() => {
|
|
51428
|
-
const { config, numberOfCols, numberOfRows } = this.getTableRuntimeConfig(sheetId, table);
|
|
51429
|
-
const relativeTableStyle = getComputedTableStyle(config, numberOfCols, numberOfRows);
|
|
51430
|
-
// Return the style with sheet coordinates instead of tables coordinates
|
|
51431
|
-
const mapping = this.getTableMapping(sheetId, table);
|
|
51432
|
-
const absoluteTableStyle = { borders: {}, styles: {} };
|
|
51433
|
-
for (let col = 0; col < numberOfCols; col++) {
|
|
51434
|
-
const colInSheet = mapping.colMapping[col];
|
|
51435
|
-
absoluteTableStyle.borders[colInSheet] = {};
|
|
51436
|
-
absoluteTableStyle.styles[colInSheet] = {};
|
|
51437
|
-
for (let row = 0; row < numberOfRows; row++) {
|
|
51438
|
-
const rowInSheet = mapping.rowMapping[row];
|
|
51439
|
-
absoluteTableStyle.borders[colInSheet][rowInSheet] = relativeTableStyle.borders[col][row];
|
|
51440
|
-
absoluteTableStyle.styles[colInSheet][rowInSheet] = relativeTableStyle.styles[col][row];
|
|
51441
|
-
}
|
|
51442
|
-
}
|
|
51443
|
-
return absoluteTableStyle;
|
|
51444
|
-
});
|
|
51445
|
-
}
|
|
51446
|
-
/**
|
|
51447
|
-
* Get the actual table config that will be used to compute the table style. It is different from
|
|
51448
|
-
* the config of the table because of hidden rows and columns in the sheet. For example remove the
|
|
51449
|
-
* hidden rows from config.numberOfHeaders.
|
|
51450
|
-
*/
|
|
51451
|
-
getTableRuntimeConfig(sheetId, table) {
|
|
51452
|
-
const tableZone = table.range.zone;
|
|
51453
|
-
const config = { ...table.config };
|
|
51454
|
-
let numberOfCols = tableZone.right - tableZone.left + 1;
|
|
51455
|
-
let numberOfRows = tableZone.bottom - tableZone.top + 1;
|
|
51456
|
-
for (let row = tableZone.top; row <= tableZone.bottom; row++) {
|
|
51457
|
-
if (!this.getters.isRowHidden(sheetId, row)) {
|
|
51458
|
-
continue;
|
|
51459
|
-
}
|
|
51460
|
-
numberOfRows--;
|
|
51461
|
-
if (row - tableZone.top < table.config.numberOfHeaders) {
|
|
51462
|
-
config.numberOfHeaders--;
|
|
51463
|
-
if (config.numberOfHeaders < 0) {
|
|
51464
|
-
config.numberOfHeaders = 0;
|
|
51465
|
-
}
|
|
51466
|
-
}
|
|
51467
|
-
if (row === tableZone.bottom) {
|
|
51468
|
-
config.totalRow = false;
|
|
51469
|
-
}
|
|
51470
|
-
}
|
|
51471
|
-
for (let col = tableZone.left; col <= tableZone.right; col++) {
|
|
51472
|
-
if (!this.getters.isColHidden(sheetId, col)) {
|
|
51473
|
-
continue;
|
|
51474
|
-
}
|
|
51475
|
-
numberOfCols--;
|
|
51476
|
-
if (col === tableZone.left) {
|
|
51477
|
-
config.firstColumn = false;
|
|
51478
|
-
}
|
|
51479
|
-
if (col === tableZone.right) {
|
|
51480
|
-
config.lastColumn = false;
|
|
51481
|
-
}
|
|
51482
|
-
}
|
|
51483
|
-
return {
|
|
51484
|
-
config,
|
|
51485
|
-
numberOfCols,
|
|
51486
|
-
numberOfRows,
|
|
51487
|
-
};
|
|
51488
|
-
}
|
|
51489
|
-
/**
|
|
51490
|
-
* Get a mapping: relative col/row position in the table <=> col/row in the sheet
|
|
51491
|
-
*/
|
|
51492
|
-
getTableMapping(sheetId, table) {
|
|
51493
|
-
const colMapping = {};
|
|
51494
|
-
const rowMapping = {};
|
|
51495
|
-
let colOffset = 0;
|
|
51496
|
-
let rowOffset = 0;
|
|
51497
|
-
const tableZone = table.range.zone;
|
|
51498
|
-
for (let col = tableZone.left; col <= tableZone.right; col++) {
|
|
51499
|
-
if (this.getters.isColHidden(sheetId, col)) {
|
|
51500
|
-
continue;
|
|
51501
|
-
}
|
|
51502
|
-
colMapping[colOffset] = col;
|
|
51503
|
-
colOffset++;
|
|
51504
|
-
for (let row = tableZone.top; row <= tableZone.bottom; row++) {
|
|
51505
|
-
if (this.getters.isRowHidden(sheetId, row)) {
|
|
51506
|
-
continue;
|
|
51507
|
-
}
|
|
51508
|
-
rowMapping[rowOffset] = row;
|
|
51509
|
-
rowOffset++;
|
|
51510
|
-
}
|
|
51511
|
-
}
|
|
51512
|
-
return {
|
|
51513
|
-
colMapping,
|
|
51514
|
-
rowMapping,
|
|
51515
|
-
};
|
|
51516
|
-
}
|
|
51517
|
-
}
|
|
51518
|
-
|
|
51519
52176
|
/**
|
|
51520
52177
|
* Clipboard Plugin
|
|
51521
52178
|
*
|
|
@@ -52065,9 +52722,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52065
52722
|
case "START":
|
|
52066
52723
|
for (const sheetId of this.getters.getSheetIds()) {
|
|
52067
52724
|
this.filterValues[sheetId] = {};
|
|
52068
|
-
for (const filter of this.getters.getFilters(sheetId)) {
|
|
52069
|
-
this.filterValues[sheetId][filter.id] = [];
|
|
52070
|
-
}
|
|
52071
52725
|
}
|
|
52072
52726
|
break;
|
|
52073
52727
|
case "CREATE_SHEET":
|
|
@@ -52088,16 +52742,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52088
52742
|
this.updateHiddenRows();
|
|
52089
52743
|
break;
|
|
52090
52744
|
case "DUPLICATE_SHEET":
|
|
52091
|
-
|
|
52092
|
-
for (const newFilter of this.getters.getFilters(cmd.sheetIdTo)) {
|
|
52093
|
-
const zone = newFilter.rangeWithHeaders.zone;
|
|
52094
|
-
filterValues[newFilter.id] = this.getFilterHiddenValues({
|
|
52095
|
-
sheetId: cmd.sheetId,
|
|
52096
|
-
col: zone.left,
|
|
52097
|
-
row: zone.top,
|
|
52098
|
-
});
|
|
52099
|
-
}
|
|
52100
|
-
this.filterValues[cmd.sheetIdTo] = filterValues;
|
|
52745
|
+
this.filterValues[cmd.sheetIdTo] = deepCopy(this.filterValues[cmd.sheetId]);
|
|
52101
52746
|
break;
|
|
52102
52747
|
// If we don't handle DELETE_SHEET, on one hand we will have some residual data, on the other hand we keep the data
|
|
52103
52748
|
// on DELETE_SHEET followed by undo
|
|
@@ -52237,38 +52882,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52237
52882
|
}
|
|
52238
52883
|
}
|
|
52239
52884
|
|
|
52240
|
-
const selectionStatisticFunctions = [
|
|
52241
|
-
{
|
|
52242
|
-
name: _t("Sum"),
|
|
52243
|
-
types: [CellValueType.number],
|
|
52244
|
-
compute: (values, locale) => sum([[values]], locale),
|
|
52245
|
-
},
|
|
52246
|
-
{
|
|
52247
|
-
name: _t("Avg"),
|
|
52248
|
-
types: [CellValueType.number],
|
|
52249
|
-
compute: (values, locale) => average([[values]], locale),
|
|
52250
|
-
},
|
|
52251
|
-
{
|
|
52252
|
-
name: _t("Min"),
|
|
52253
|
-
types: [CellValueType.number],
|
|
52254
|
-
compute: (values, locale) => min([[values]], locale),
|
|
52255
|
-
},
|
|
52256
|
-
{
|
|
52257
|
-
name: _t("Max"),
|
|
52258
|
-
types: [CellValueType.number],
|
|
52259
|
-
compute: (values, locale) => max([[values]], locale),
|
|
52260
|
-
},
|
|
52261
|
-
{
|
|
52262
|
-
name: _t("Count"),
|
|
52263
|
-
types: [CellValueType.number, CellValueType.text, CellValueType.boolean, CellValueType.error],
|
|
52264
|
-
compute: (values) => countAny([[values]]),
|
|
52265
|
-
},
|
|
52266
|
-
{
|
|
52267
|
-
name: _t("Count Numbers"),
|
|
52268
|
-
types: [CellValueType.number, CellValueType.text, CellValueType.boolean, CellValueType.error],
|
|
52269
|
-
compute: (values, locale) => countNumbers([[values]], locale),
|
|
52270
|
-
},
|
|
52271
|
-
];
|
|
52272
52885
|
/**
|
|
52273
52886
|
* SelectionPlugin
|
|
52274
52887
|
*/
|
|
@@ -52284,8 +52897,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52284
52897
|
"getSelectedZones",
|
|
52285
52898
|
"getSelectedZone",
|
|
52286
52899
|
"getSelectedCells",
|
|
52287
|
-
"getStatisticFnResults",
|
|
52288
|
-
"getAggregate",
|
|
52289
52900
|
"getSelectedFigureId",
|
|
52290
52901
|
"getSelection",
|
|
52291
52902
|
"getActivePosition",
|
|
@@ -52320,7 +52931,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52320
52931
|
switch (cmd.type) {
|
|
52321
52932
|
case "ACTIVATE_SHEET":
|
|
52322
52933
|
try {
|
|
52323
|
-
this.getters.getSheet(cmd.sheetIdTo);
|
|
52934
|
+
const sheet = this.getters.getSheet(cmd.sheetIdTo);
|
|
52935
|
+
if (!sheet.isVisible) {
|
|
52936
|
+
return "SheetIsHidden" /* CommandResult.SheetIsHidden */;
|
|
52937
|
+
}
|
|
52324
52938
|
break;
|
|
52325
52939
|
}
|
|
52326
52940
|
catch (error) {
|
|
@@ -52474,6 +53088,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52474
53088
|
this.gridSelection.zones = this.gridSelection.zones.map((z) => this.getters.expandZone(sheetId, z));
|
|
52475
53089
|
this.gridSelection.anchor.zone = this.getters.expandZone(sheetId, this.gridSelection.anchor.zone);
|
|
52476
53090
|
this.setSelectionMixin(this.gridSelection.anchor, this.gridSelection.zones);
|
|
53091
|
+
this.selectedFigureId = null;
|
|
52477
53092
|
break;
|
|
52478
53093
|
}
|
|
52479
53094
|
/** Any change to the selection has to be reflected in the selection processor. */
|
|
@@ -52568,52 +53183,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52568
53183
|
: this.getters.getNextVisibleCellPosition({ sheetId, col: 0, row: 0 });
|
|
52569
53184
|
}
|
|
52570
53185
|
}
|
|
52571
|
-
getStatisticFnResults() {
|
|
52572
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
52573
|
-
const cells = new Set();
|
|
52574
|
-
for (const zone of this.gridSelection.zones) {
|
|
52575
|
-
for (const { col, row } of positions(zone)) {
|
|
52576
|
-
if (this.getters.isRowHidden(sheetId, row) || this.getters.isColHidden(sheetId, col)) {
|
|
52577
|
-
continue; // Skip hidden cells
|
|
52578
|
-
}
|
|
52579
|
-
const evaluatedCell = this.getters.getEvaluatedCell({ sheetId, col, row });
|
|
52580
|
-
if (evaluatedCell.type !== CellValueType.empty) {
|
|
52581
|
-
cells.add(evaluatedCell);
|
|
52582
|
-
}
|
|
52583
|
-
}
|
|
52584
|
-
}
|
|
52585
|
-
const locale = this.getters.getLocale();
|
|
52586
|
-
let statisticFnResults = {};
|
|
52587
|
-
for (let fn of selectionStatisticFunctions) {
|
|
52588
|
-
// We don't want to display statistical information when there is no interest:
|
|
52589
|
-
// We set the statistical result to undefined if the data handled by the selection
|
|
52590
|
-
// does not match the data handled by the function.
|
|
52591
|
-
// Ex: if there are only texts in the selection, we prefer that the SUM result
|
|
52592
|
-
// be displayed as undefined rather than 0.
|
|
52593
|
-
let fnResult = undefined;
|
|
52594
|
-
const evaluatedCells = [...cells].filter((c) => fn.types.includes(c.type));
|
|
52595
|
-
if (evaluatedCells.length) {
|
|
52596
|
-
fnResult = fn.compute(evaluatedCells, locale);
|
|
52597
|
-
}
|
|
52598
|
-
statisticFnResults[fn.name] = fnResult;
|
|
52599
|
-
}
|
|
52600
|
-
return statisticFnResults;
|
|
52601
|
-
}
|
|
52602
|
-
getAggregate() {
|
|
52603
|
-
let aggregate = 0;
|
|
52604
|
-
let n = 0;
|
|
52605
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
52606
|
-
const cellPositions = this.gridSelection.zones.map(positions).flat();
|
|
52607
|
-
for (const { col, row } of cellPositions) {
|
|
52608
|
-
const cell = this.getters.getEvaluatedCell({ sheetId, col, row });
|
|
52609
|
-
if (cell.type === CellValueType.number) {
|
|
52610
|
-
n++;
|
|
52611
|
-
aggregate += cell.value;
|
|
52612
|
-
}
|
|
52613
|
-
}
|
|
52614
|
-
const locale = this.getters.getLocale();
|
|
52615
|
-
return n < 2 ? null : formatValue(aggregate, { locale });
|
|
52616
|
-
}
|
|
52617
53186
|
isSelected(zone) {
|
|
52618
53187
|
return !!this.getters.getSelectedZones().find((z) => isEqual(z, zone));
|
|
52619
53188
|
}
|
|
@@ -52655,9 +53224,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52655
53224
|
// Other
|
|
52656
53225
|
// ---------------------------------------------------------------------------
|
|
52657
53226
|
activateSheet(sheetIdFrom, sheetIdTo) {
|
|
52658
|
-
if (!this.getters.isSheetVisible(sheetIdTo)) {
|
|
52659
|
-
this.dispatch("SHOW_SHEET", { sheetId: sheetIdTo });
|
|
52660
|
-
}
|
|
52661
53227
|
this.setActiveSheet(sheetIdTo);
|
|
52662
53228
|
this.sheetsData[sheetIdFrom] = {
|
|
52663
53229
|
gridSelection: deepCopy(this.gridSelection),
|
|
@@ -53664,7 +54230,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
53664
54230
|
* column of the current viewport
|
|
53665
54231
|
*/
|
|
53666
54232
|
getColDimensionsInViewport(sheetId, col) {
|
|
53667
|
-
const left =
|
|
54233
|
+
const left = largeMin(this.getters.getSheetViewVisibleCols());
|
|
53668
54234
|
const start = this.getters.getColRowOffsetInViewport("COL", left, col);
|
|
53669
54235
|
const size = this.getters.getColSize(sheetId, col);
|
|
53670
54236
|
const isColHidden = this.getters.isColHidden(sheetId, col);
|
|
@@ -53679,7 +54245,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
53679
54245
|
* of the current viewport
|
|
53680
54246
|
*/
|
|
53681
54247
|
getRowDimensionsInViewport(sheetId, row) {
|
|
53682
|
-
const top =
|
|
54248
|
+
const top = largeMin(this.getters.getSheetViewVisibleRows());
|
|
53683
54249
|
const start = this.getters.getColRowOffsetInViewport("ROW", top, row);
|
|
53684
54250
|
const size = this.getters.getRowSize(sheetId, row);
|
|
53685
54251
|
const isRowHidden = this.getters.isRowHidden(sheetId, row);
|
|
@@ -54031,6 +54597,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54031
54597
|
.add("evaluation_filter", FilterEvaluationPlugin)
|
|
54032
54598
|
.add("header_visibility_ui", HeaderVisibilityUIPlugin)
|
|
54033
54599
|
.add("table_style", TableStylePlugin)
|
|
54600
|
+
.add("cell_computed_style", CellComputedStylePlugin)
|
|
54034
54601
|
.add("header_positions", HeaderPositionsUIPlugin)
|
|
54035
54602
|
.add("viewport", SheetViewPlugin)
|
|
54036
54603
|
.add("clipboard", ClipboardPlugin);
|
|
@@ -54040,8 +54607,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54040
54607
|
.add("evaluation_chart", EvaluationChartPlugin)
|
|
54041
54608
|
.add("evaluation_cf", EvaluationConditionalFormatPlugin)
|
|
54042
54609
|
.add("row_size", HeaderSizeUIPlugin)
|
|
54043
|
-
.add("
|
|
54044
|
-
.add("
|
|
54610
|
+
.add("data_validation_ui", EvaluationDataValidationPlugin)
|
|
54611
|
+
.add("dynamic_tables", DynamicTablesPlugin)
|
|
54612
|
+
.add("custom_colors", CustomColorsPlugin);
|
|
54045
54613
|
|
|
54046
54614
|
const clickableCellRegistry = new Registry();
|
|
54047
54615
|
clickableCellRegistry.add("link", {
|
|
@@ -54090,6 +54658,38 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54090
54658
|
}
|
|
54091
54659
|
}
|
|
54092
54660
|
|
|
54661
|
+
class ArrayFormulaHighlight extends SpreadsheetStore {
|
|
54662
|
+
highlightStore = this.get(HighlightStore);
|
|
54663
|
+
constructor(get) {
|
|
54664
|
+
super(get);
|
|
54665
|
+
this.highlightStore.register(this);
|
|
54666
|
+
}
|
|
54667
|
+
get highlights() {
|
|
54668
|
+
const zone = this.getHighlightZone();
|
|
54669
|
+
if (!zone) {
|
|
54670
|
+
return [];
|
|
54671
|
+
}
|
|
54672
|
+
const sheetId = this.model.getters.getActiveSheetId();
|
|
54673
|
+
return [
|
|
54674
|
+
{
|
|
54675
|
+
sheetId,
|
|
54676
|
+
zone,
|
|
54677
|
+
color: "#17A2B8",
|
|
54678
|
+
noFill: true,
|
|
54679
|
+
thinLine: true,
|
|
54680
|
+
},
|
|
54681
|
+
];
|
|
54682
|
+
}
|
|
54683
|
+
getHighlightZone() {
|
|
54684
|
+
const position = this.model.getters.getActivePosition();
|
|
54685
|
+
const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
|
|
54686
|
+
const spreadZone = spreader
|
|
54687
|
+
? this.model.getters.getSpreadZone(spreader)
|
|
54688
|
+
: this.model.getters.getSpreadZone(position);
|
|
54689
|
+
return spreadZone;
|
|
54690
|
+
}
|
|
54691
|
+
}
|
|
54692
|
+
|
|
54093
54693
|
const RIPPLE_KEY_FRAMES = [
|
|
54094
54694
|
{ transform: "scale(0)" },
|
|
54095
54695
|
{ transform: "scale(0.8)", offset: 0.33 },
|
|
@@ -54392,12 +54992,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54392
54992
|
this.editionState = "initializing";
|
|
54393
54993
|
}
|
|
54394
54994
|
stopEdition() {
|
|
54395
|
-
|
|
54995
|
+
const input = this.sheetNameRef.el;
|
|
54996
|
+
if (!this.state.isEditing || !input)
|
|
54396
54997
|
return;
|
|
54397
54998
|
this.state.isEditing = false;
|
|
54398
54999
|
this.editionState = "initializing";
|
|
54399
|
-
|
|
55000
|
+
input.blur();
|
|
54400
55001
|
const inputValue = this.getInputContent() || "";
|
|
55002
|
+
input.innerText = inputValue;
|
|
54401
55003
|
interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
|
|
54402
55004
|
}
|
|
54403
55005
|
cancelEdition() {
|
|
@@ -54441,6 +55043,115 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54441
55043
|
}
|
|
54442
55044
|
}
|
|
54443
55045
|
|
|
55046
|
+
const selectionStatisticFunctions = [
|
|
55047
|
+
{
|
|
55048
|
+
name: _t("Sum"),
|
|
55049
|
+
types: [CellValueType.number],
|
|
55050
|
+
compute: (values, locale) => sum([[values]], locale),
|
|
55051
|
+
},
|
|
55052
|
+
{
|
|
55053
|
+
name: _t("Avg"),
|
|
55054
|
+
types: [CellValueType.number],
|
|
55055
|
+
compute: (values, locale) => average([[values]], locale),
|
|
55056
|
+
},
|
|
55057
|
+
{
|
|
55058
|
+
name: _t("Min"),
|
|
55059
|
+
types: [CellValueType.number],
|
|
55060
|
+
compute: (values, locale) => min([[values]], locale),
|
|
55061
|
+
},
|
|
55062
|
+
{
|
|
55063
|
+
name: _t("Max"),
|
|
55064
|
+
types: [CellValueType.number],
|
|
55065
|
+
compute: (values, locale) => max([[values]], locale),
|
|
55066
|
+
},
|
|
55067
|
+
{
|
|
55068
|
+
name: _t("Count"),
|
|
55069
|
+
types: [CellValueType.number, CellValueType.text, CellValueType.boolean, CellValueType.error],
|
|
55070
|
+
compute: (values) => countAny([[values]]),
|
|
55071
|
+
},
|
|
55072
|
+
{
|
|
55073
|
+
name: _t("Count Numbers"),
|
|
55074
|
+
types: [CellValueType.number, CellValueType.text, CellValueType.boolean, CellValueType.error],
|
|
55075
|
+
compute: (values, locale) => countNumbers([[values]], locale),
|
|
55076
|
+
},
|
|
55077
|
+
];
|
|
55078
|
+
class AggregateStatisticsStore extends SpreadsheetStore {
|
|
55079
|
+
statisticFnResults = this._computeStatisticFnResults();
|
|
55080
|
+
isDirty = false;
|
|
55081
|
+
constructor(get) {
|
|
55082
|
+
super(get);
|
|
55083
|
+
this.model.selection.observe(this, {
|
|
55084
|
+
handleEvent: this.handleEvent.bind(this),
|
|
55085
|
+
});
|
|
55086
|
+
}
|
|
55087
|
+
handle(cmd) {
|
|
55088
|
+
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
55089
|
+
(cmd.type === "UPDATE_CELL" && "content" in cmd)) {
|
|
55090
|
+
this.isDirty = true;
|
|
55091
|
+
}
|
|
55092
|
+
switch (cmd.type) {
|
|
55093
|
+
case "HIDE_COLUMNS_ROWS":
|
|
55094
|
+
case "UNHIDE_COLUMNS_ROWS":
|
|
55095
|
+
case "GROUP_HEADERS":
|
|
55096
|
+
case "UNGROUP_HEADERS":
|
|
55097
|
+
case "ACTIVATE_SHEET":
|
|
55098
|
+
case "ACTIVATE_NEXT_SHEET":
|
|
55099
|
+
case "ACTIVATE_PREVIOUS_SHEET":
|
|
55100
|
+
case "EVALUATE_CELLS":
|
|
55101
|
+
case "UNDO":
|
|
55102
|
+
case "REDO":
|
|
55103
|
+
this.isDirty = true;
|
|
55104
|
+
}
|
|
55105
|
+
}
|
|
55106
|
+
finalize() {
|
|
55107
|
+
if (this.isDirty) {
|
|
55108
|
+
this.isDirty = false;
|
|
55109
|
+
this.statisticFnResults = this._computeStatisticFnResults();
|
|
55110
|
+
}
|
|
55111
|
+
}
|
|
55112
|
+
handleEvent() {
|
|
55113
|
+
if (this.getters.isGridSelectionActive()) {
|
|
55114
|
+
this.statisticFnResults = this._computeStatisticFnResults();
|
|
55115
|
+
}
|
|
55116
|
+
}
|
|
55117
|
+
_computeStatisticFnResults() {
|
|
55118
|
+
const getters = this.getters;
|
|
55119
|
+
const sheetId = getters.getActiveSheetId();
|
|
55120
|
+
const cells = new Set();
|
|
55121
|
+
const zones = getters.getSelectedZones();
|
|
55122
|
+
for (const zone of zones) {
|
|
55123
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
55124
|
+
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
55125
|
+
if (getters.isRowHidden(sheetId, row) || getters.isColHidden(sheetId, col)) {
|
|
55126
|
+
continue; // Skip hidden cells
|
|
55127
|
+
}
|
|
55128
|
+
const evaluatedCell = getters.getEvaluatedCell({ sheetId, col, row });
|
|
55129
|
+
if (evaluatedCell.type !== CellValueType.empty) {
|
|
55130
|
+
cells.add(evaluatedCell);
|
|
55131
|
+
}
|
|
55132
|
+
}
|
|
55133
|
+
}
|
|
55134
|
+
}
|
|
55135
|
+
const locale = getters.getLocale();
|
|
55136
|
+
let statisticFnResults = {};
|
|
55137
|
+
const cellsArray = [...cells];
|
|
55138
|
+
for (let fn of selectionStatisticFunctions) {
|
|
55139
|
+
// We don't want to display statistical information when there is no interest:
|
|
55140
|
+
// We set the statistical result to undefined if the data handled by the selection
|
|
55141
|
+
// does not match the data handled by the function.
|
|
55142
|
+
// Ex: if there are only texts in the selection, we prefer that the SUM result
|
|
55143
|
+
// be displayed as undefined rather than 0.
|
|
55144
|
+
let fnResult = undefined;
|
|
55145
|
+
const evaluatedCells = cellsArray.filter((c) => fn.types.includes(c.type));
|
|
55146
|
+
if (evaluatedCells.length) {
|
|
55147
|
+
fnResult = fn.compute(evaluatedCells, locale);
|
|
55148
|
+
}
|
|
55149
|
+
statisticFnResults[fn.name] = fnResult;
|
|
55150
|
+
}
|
|
55151
|
+
return statisticFnResults;
|
|
55152
|
+
}
|
|
55153
|
+
}
|
|
55154
|
+
|
|
54444
55155
|
// -----------------------------------------------------------------------------
|
|
54445
55156
|
// SpreadSheet
|
|
54446
55157
|
// -----------------------------------------------------------------------------
|
|
@@ -54456,40 +55167,38 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54456
55167
|
}
|
|
54457
55168
|
`;
|
|
54458
55169
|
class BottomBarStatistic extends owl.Component {
|
|
54459
|
-
static template = "o-spreadsheet-
|
|
55170
|
+
static template = "o-spreadsheet-BottomBarStatistic";
|
|
54460
55171
|
static props = {
|
|
54461
55172
|
openContextMenu: Function,
|
|
54462
55173
|
closeContextMenu: Function,
|
|
54463
55174
|
};
|
|
54464
55175
|
static components = { Ripple };
|
|
54465
55176
|
selectedStatisticFn = "";
|
|
54466
|
-
|
|
55177
|
+
store;
|
|
54467
55178
|
setup() {
|
|
54468
|
-
this.
|
|
55179
|
+
this.store = useStore(AggregateStatisticsStore);
|
|
54469
55180
|
owl.onWillUpdateProps(() => {
|
|
54470
|
-
|
|
54471
|
-
if (!deepEquals(newStatisticFnResults, this.statisticFnResults)) {
|
|
55181
|
+
if (Object.values(this.store.statisticFnResults).every((result) => result === undefined)) {
|
|
54472
55182
|
this.props.closeContextMenu();
|
|
54473
55183
|
}
|
|
54474
|
-
this.statisticFnResults = newStatisticFnResults;
|
|
54475
55184
|
});
|
|
54476
55185
|
}
|
|
54477
55186
|
getSelectedStatistic() {
|
|
54478
55187
|
// don't display button if no function has a result
|
|
54479
|
-
if (Object.values(this.statisticFnResults).every((result) => result === undefined)) {
|
|
55188
|
+
if (Object.values(this.store.statisticFnResults).every((result) => result === undefined)) {
|
|
54480
55189
|
return undefined;
|
|
54481
55190
|
}
|
|
54482
55191
|
if (this.selectedStatisticFn === "") {
|
|
54483
|
-
this.selectedStatisticFn = Object.keys(this.statisticFnResults)[0];
|
|
55192
|
+
this.selectedStatisticFn = Object.keys(this.store.statisticFnResults)[0];
|
|
54484
55193
|
}
|
|
54485
|
-
return this.getComposedFnName(this.selectedStatisticFn
|
|
55194
|
+
return this.getComposedFnName(this.selectedStatisticFn);
|
|
54486
55195
|
}
|
|
54487
55196
|
listSelectionStatistics(ev) {
|
|
54488
55197
|
const registry = new MenuItemRegistry();
|
|
54489
55198
|
let i = 0;
|
|
54490
|
-
for (let [fnName
|
|
55199
|
+
for (let [fnName] of Object.entries(this.store.statisticFnResults)) {
|
|
54491
55200
|
registry.add(fnName, {
|
|
54492
|
-
name: this.getComposedFnName(fnName
|
|
55201
|
+
name: () => this.getComposedFnName(fnName),
|
|
54493
55202
|
sequence: i,
|
|
54494
55203
|
isReadonlyAllowed: true,
|
|
54495
55204
|
execute: () => {
|
|
@@ -54502,8 +55211,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54502
55211
|
const { top, left, width } = target.getBoundingClientRect();
|
|
54503
55212
|
this.props.openContextMenu(left + width, top, registry);
|
|
54504
55213
|
}
|
|
54505
|
-
getComposedFnName(fnName
|
|
55214
|
+
getComposedFnName(fnName) {
|
|
54506
55215
|
const locale = this.env.model.getters.getLocale();
|
|
55216
|
+
const fnValue = this.store.statisticFnResults[fnName];
|
|
54507
55217
|
return fnName + ": " + (fnValue !== undefined ? formatValue(fnValue, { locale }) : "__");
|
|
54508
55218
|
}
|
|
54509
55219
|
}
|
|
@@ -54612,10 +55322,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54612
55322
|
name: sheet.name,
|
|
54613
55323
|
sequence: i,
|
|
54614
55324
|
isReadonlyAllowed: true,
|
|
54615
|
-
textColor: sheet.isVisible ? undefined : "
|
|
55325
|
+
textColor: sheet.isVisible ? undefined : "#808080",
|
|
54616
55326
|
execute: (env) => {
|
|
55327
|
+
if (!this.env.model.getters.isSheetVisible(sheetId)) {
|
|
55328
|
+
this.env.model.dispatch("SHOW_SHEET", { sheetId });
|
|
55329
|
+
}
|
|
54617
55330
|
env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: from, sheetIdTo: sheetId });
|
|
54618
55331
|
},
|
|
55332
|
+
isEnabled: (env) => (env.model.getters.isReadonly() ? sheet.isVisible : true),
|
|
54619
55333
|
});
|
|
54620
55334
|
i++;
|
|
54621
55335
|
}
|
|
@@ -54688,7 +55402,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54688
55402
|
this.sheetListRef.el.scrollTo({ top: 0, left: scroll, behavior: "smooth" });
|
|
54689
55403
|
}
|
|
54690
55404
|
onSheetMouseDown(sheetId, event) {
|
|
54691
|
-
if (event.button !== 0)
|
|
55405
|
+
if (event.button !== 0 || this.env.model.getters.isReadonly())
|
|
54692
55406
|
return;
|
|
54693
55407
|
this.closeMenu();
|
|
54694
55408
|
const visibleSheets = this.getVisibleSheets();
|
|
@@ -54724,7 +55438,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54724
55438
|
.map((sheetEl) => sheetEl.getBoundingClientRect())
|
|
54725
55439
|
.map((rect) => ({
|
|
54726
55440
|
x: rect.x,
|
|
54727
|
-
width: rect.width - 1,
|
|
55441
|
+
width: rect.width - 1, // -1 to compensate negative margin
|
|
54728
55442
|
y: rect.y,
|
|
54729
55443
|
height: rect.height,
|
|
54730
55444
|
}));
|
|
@@ -54951,7 +55665,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54951
55665
|
}
|
|
54952
55666
|
return cssPropertiesToCss({
|
|
54953
55667
|
top: `${groupBox.headerRect.height / 2}px`,
|
|
54954
|
-
left: `calc(50% - 1px)`,
|
|
55668
|
+
left: `calc(50% - 1px)`, // -1px: we want the border to be on the center
|
|
54955
55669
|
width: `30%`,
|
|
54956
55670
|
height: `calc(100% - ${groupBox.headerRect.height / 2}px)`,
|
|
54957
55671
|
"border-left": `1px solid ${HEADER_GROUPING_BORDER_COLOR}`,
|
|
@@ -55003,7 +55717,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55003
55717
|
return "";
|
|
55004
55718
|
}
|
|
55005
55719
|
return cssPropertiesToCss({
|
|
55006
|
-
top: `calc(50% - 1px)`,
|
|
55720
|
+
top: `calc(50% - 1px)`, // -1px: we want the border to be on the center
|
|
55007
55721
|
left: `${groupBox.headerRect.width / 2}px`,
|
|
55008
55722
|
width: `calc(100% - ${groupBox.headerRect.width / 2}px)`,
|
|
55009
55723
|
height: `30%`,
|
|
@@ -56092,12 +56806,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56092
56806
|
.text-muted {
|
|
56093
56807
|
color: grey !important;
|
|
56094
56808
|
}
|
|
56095
|
-
button {
|
|
56096
|
-
color: #333;
|
|
56097
|
-
}
|
|
56098
56809
|
.o-disabled {
|
|
56099
56810
|
opacity: 0.4;
|
|
56100
|
-
|
|
56811
|
+
cursor: default;
|
|
56101
56812
|
pointer-events: none;
|
|
56102
56813
|
}
|
|
56103
56814
|
|
|
@@ -56215,17 +56926,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56215
56926
|
}
|
|
56216
56927
|
|
|
56217
56928
|
.o-button {
|
|
56218
|
-
border: 1px solid
|
|
56929
|
+
border: 1px solid;
|
|
56219
56930
|
padding: 0px 20px 0px 20px;
|
|
56220
56931
|
border-radius: 4px;
|
|
56221
56932
|
font-weight: 500;
|
|
56222
56933
|
font-size: 14px;
|
|
56223
56934
|
height: 30px;
|
|
56224
56935
|
line-height: 16px;
|
|
56225
|
-
background: white;
|
|
56226
56936
|
margin-right: 8px;
|
|
56227
|
-
|
|
56228
|
-
|
|
56937
|
+
|
|
56938
|
+
&:not(:hover) {
|
|
56939
|
+
background-color: transparent;
|
|
56229
56940
|
}
|
|
56230
56941
|
|
|
56231
56942
|
&:enabled {
|
|
@@ -56239,6 +56950,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56239
56950
|
&:last-child {
|
|
56240
56951
|
margin-right: 0px;
|
|
56241
56952
|
}
|
|
56953
|
+
|
|
56954
|
+
&.o-button-grey {
|
|
56955
|
+
border-color: lightgrey;
|
|
56956
|
+
background: #ffffff;
|
|
56957
|
+
color: #333;
|
|
56958
|
+
&:hover:enabled {
|
|
56959
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
56960
|
+
}
|
|
56961
|
+
}
|
|
56242
56962
|
}
|
|
56243
56963
|
|
|
56244
56964
|
.o-input {
|
|
@@ -56254,7 +56974,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56254
56974
|
|
|
56255
56975
|
.o-number-input {
|
|
56256
56976
|
/* Remove number input arrows */
|
|
56257
|
-
|
|
56977
|
+
appearance: textfield;
|
|
56258
56978
|
&::-webkit-outer-spin-button,
|
|
56259
56979
|
&::-webkit-inner-spin-button {
|
|
56260
56980
|
-webkit-appearance: none;
|
|
@@ -56297,6 +57017,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56297
57017
|
this.notificationStore = useStore(NotificationStore);
|
|
56298
57018
|
this.composerFocusStore = useStore(ComposerFocusStore);
|
|
56299
57019
|
this.sidePanel = useStore(SidePanelStore);
|
|
57020
|
+
useStore(ArrayFormulaHighlight);
|
|
56300
57021
|
this.keyDownMapping = {
|
|
56301
57022
|
"CTRL+H": () => this.sidePanel.toggle("FindAndReplace", {}),
|
|
56302
57023
|
"CTRL+F": () => this.sidePanel.toggle("FindAndReplace", {}),
|
|
@@ -56399,7 +57120,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56399
57120
|
const gridColSize = GROUP_LAYER_WIDTH * this.rowLayers.length;
|
|
56400
57121
|
const gridRowSize = GROUP_LAYER_WIDTH * this.colLayers.length;
|
|
56401
57122
|
return cssPropertiesToCss({
|
|
56402
|
-
"grid-template-columns": `${gridColSize ? gridColSize + 2 : 0}px auto`,
|
|
57123
|
+
"grid-template-columns": `${gridColSize ? gridColSize + 2 : 0}px auto`, // +2: margins
|
|
56403
57124
|
"grid-template-rows": `${gridRowSize ? gridRowSize + 2 : 0}px auto`,
|
|
56404
57125
|
});
|
|
56405
57126
|
}
|
|
@@ -57131,14 +57852,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57131
57852
|
this.revertBefore(operationId);
|
|
57132
57853
|
this.tree.drop(operationId);
|
|
57133
57854
|
}
|
|
57134
|
-
getRevertedExecution() {
|
|
57135
|
-
const data = [];
|
|
57136
|
-
const operations = this.tree.revertedExecution(this.HEAD_BRANCH);
|
|
57137
|
-
for (const { operation } of operations) {
|
|
57138
|
-
data.push(operation.data);
|
|
57139
|
-
}
|
|
57140
|
-
return data;
|
|
57141
|
-
}
|
|
57142
57855
|
/**
|
|
57143
57856
|
* Revert the state as it was *before* the given operation was executed.
|
|
57144
57857
|
*/
|
|
@@ -57927,6 +58640,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57927
58640
|
case "bar":
|
|
57928
58641
|
plot = addBarChart(chart.data);
|
|
57929
58642
|
break;
|
|
58643
|
+
case "combo":
|
|
58644
|
+
plot = addComboChart(chart.data);
|
|
58645
|
+
break;
|
|
57930
58646
|
case "line":
|
|
57931
58647
|
plot = addLineChart(chart.data);
|
|
57932
58648
|
break;
|
|
@@ -58089,6 +58805,79 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58089
58805
|
${addAx(axisPos, "c:valAx", valAxId, catAxId, { fontColor: chart.fontColor })}
|
|
58090
58806
|
`;
|
|
58091
58807
|
}
|
|
58808
|
+
function addComboChart(chart) {
|
|
58809
|
+
// gapWitdh and overlap that define the space between clusters (in %) and the overlap between datasets (from -100: completely scattered to 100, completely overlapped)
|
|
58810
|
+
// see gapWidth : https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_gapWidth_topic_ID0EFVEQB.html#topic_ID0EFVEQB
|
|
58811
|
+
// see overlap : https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_overlap_topic_ID0ELYQQB.html#topic_ID0ELYQQB
|
|
58812
|
+
//
|
|
58813
|
+
// overlap and gapWitdh seems to be by default at -20 and 20 in chart.js.
|
|
58814
|
+
// See https://www.chartjs.org/docs/latest/charts/bar.html and https://www.chartjs.org/docs/latest/charts/bar.html#barpercentage-vs-categorypercentage
|
|
58815
|
+
const colors = new ChartColors();
|
|
58816
|
+
const dataSetsNodes = [];
|
|
58817
|
+
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
58818
|
+
const color = toXlsxHexColor(colors.next());
|
|
58819
|
+
const dataShapeProperty = shapeProperty({
|
|
58820
|
+
backgroundColor: color,
|
|
58821
|
+
line: { color },
|
|
58822
|
+
});
|
|
58823
|
+
dataSetsNodes.push(dsIndex === "0"
|
|
58824
|
+
? escapeXml /*xml*/ `
|
|
58825
|
+
<c:ser>
|
|
58826
|
+
<c:idx val="${dsIndex}"/>
|
|
58827
|
+
<c:order val="${dsIndex}"/>
|
|
58828
|
+
${dataset.label ? escapeXml /*xml*/ `<c:tx>${stringRef(dataset.label)}</c:tx>` : ""}
|
|
58829
|
+
${dataShapeProperty}
|
|
58830
|
+
${chart.labelRange ? escapeXml /*xml*/ `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
58831
|
+
<c:val> <!-- x-coordinate values -->
|
|
58832
|
+
${numberRef(dataset.range)}
|
|
58833
|
+
</c:val>
|
|
58834
|
+
</c:ser>
|
|
58835
|
+
`
|
|
58836
|
+
: escapeXml /*xml*/ `
|
|
58837
|
+
<c:ser>
|
|
58838
|
+
<c:idx val="${dsIndex}"/>
|
|
58839
|
+
<c:order val="${dsIndex}"/>
|
|
58840
|
+
<c:smooth val="0"/>
|
|
58841
|
+
<c:marker>
|
|
58842
|
+
<c:symbol val="circle" />
|
|
58843
|
+
<c:size val="5"/>
|
|
58844
|
+
</c:marker>
|
|
58845
|
+
${dataset.label ? escapeXml `<c:tx>${stringRef(dataset.label)}</c:tx>` : ""}
|
|
58846
|
+
${dataShapeProperty}
|
|
58847
|
+
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
58848
|
+
<c:val> <!-- x-coordinate values -->
|
|
58849
|
+
${numberRef(dataset.range)}
|
|
58850
|
+
</c:val>
|
|
58851
|
+
</c:ser>
|
|
58852
|
+
`);
|
|
58853
|
+
}
|
|
58854
|
+
// Excel does not support this feature
|
|
58855
|
+
const axisPos = chart.verticalAxisPosition === "left" ? "l" : "r";
|
|
58856
|
+
const overlap = chart.stacked ? 100 : -20;
|
|
58857
|
+
return escapeXml /*xml*/ `
|
|
58858
|
+
<c:barChart>
|
|
58859
|
+
<c:barDir val="col"/>
|
|
58860
|
+
<c:grouping val="clustered"/>
|
|
58861
|
+
<c:overlap val="${overlap}"/>
|
|
58862
|
+
<c:gapWidth val="70"/>
|
|
58863
|
+
<!-- each data marker in the series does not have a different color -->
|
|
58864
|
+
<c:varyColors val="0"/>
|
|
58865
|
+
${dataSetsNodes[0]}
|
|
58866
|
+
<c:axId val="${catAxId}" />
|
|
58867
|
+
<c:axId val="${valAxId}" />
|
|
58868
|
+
</c:barChart>
|
|
58869
|
+
<c:lineChart>
|
|
58870
|
+
<c:grouping val="standard"/>
|
|
58871
|
+
<!-- each data marker in the series does not have a different color -->
|
|
58872
|
+
<c:varyColors val="0"/>
|
|
58873
|
+
${joinXmlNodes(dataSetsNodes.slice(1))}
|
|
58874
|
+
<c:axId val="${catAxId}" />
|
|
58875
|
+
<c:axId val="${valAxId}" />
|
|
58876
|
+
</c:lineChart>
|
|
58877
|
+
${addAx("b", "c:catAx", catAxId, valAxId, { fontColor: chart.fontColor })}
|
|
58878
|
+
${addAx(axisPos, "c:valAx", valAxId, catAxId, { fontColor: chart.fontColor })}
|
|
58879
|
+
`;
|
|
58880
|
+
}
|
|
58092
58881
|
function addLineChart(chart) {
|
|
58093
58882
|
const colors = new ChartColors();
|
|
58094
58883
|
const dataSetsNodes = [];
|
|
@@ -58136,7 +58925,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58136
58925
|
}
|
|
58137
58926
|
function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
|
|
58138
58927
|
const colors = new ChartColors();
|
|
58139
|
-
const maxLength =
|
|
58928
|
+
const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
|
|
58140
58929
|
const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
|
|
58141
58930
|
const dataSetsNodes = [];
|
|
58142
58931
|
for (const [dsIndex, dataset] of Object.entries(chart.dataSets).reverse()) {
|
|
@@ -59014,7 +59803,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
59014
59803
|
const colHeaderXc = toXC(tableZone.left + i, tableZone.top);
|
|
59015
59804
|
const colName = sheetData.cells[colHeaderXc]?.content || `col${i}`;
|
|
59016
59805
|
const colAttributes = [
|
|
59017
|
-
["id", i + 1],
|
|
59806
|
+
["id", i + 1], // id cannot be 0
|
|
59018
59807
|
["name", colName],
|
|
59019
59808
|
];
|
|
59020
59809
|
columns.push(escapeXml /*xml*/ `<tableColumn ${formatAttributes(colAttributes)}/>`);
|
|
@@ -59230,6 +60019,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
59230
60019
|
* https://www.ecma-international.org/publications-and-standards/standards/ecma-376/
|
|
59231
60020
|
*/
|
|
59232
60021
|
function getXLSX(data) {
|
|
60022
|
+
data = fixLengthySheetNames(data);
|
|
59233
60023
|
const files = [];
|
|
59234
60024
|
const construct = getDefaultXLSXStructure();
|
|
59235
60025
|
files.push(createWorkbook(data, construct));
|
|
@@ -59477,6 +60267,40 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
59477
60267
|
`;
|
|
59478
60268
|
return createXMLFile(parseXML(xml), "_rels/.rels");
|
|
59479
60269
|
}
|
|
60270
|
+
/**
|
|
60271
|
+
* Excel sheet names are maximum 31 characters while o-spreadsheet do not have this limit.
|
|
60272
|
+
* This method converts the sheet names to be within the 31 characters limit.
|
|
60273
|
+
* The cells/charts referencing this sheet will be updated accordingly.
|
|
60274
|
+
*/
|
|
60275
|
+
function fixLengthySheetNames(data) {
|
|
60276
|
+
const nameMapping = {};
|
|
60277
|
+
const newNames = new Set();
|
|
60278
|
+
for (const sheet of data.sheets) {
|
|
60279
|
+
let newName = sheet.name.slice(0, 31);
|
|
60280
|
+
let i = 1;
|
|
60281
|
+
while (newNames.has(newName)) {
|
|
60282
|
+
newName = newName.slice(0, 31 - String(i).length) + i++;
|
|
60283
|
+
}
|
|
60284
|
+
newNames.add(newName);
|
|
60285
|
+
if (newName !== sheet.name) {
|
|
60286
|
+
nameMapping[sheet.name] = newName;
|
|
60287
|
+
sheet.name = newName;
|
|
60288
|
+
}
|
|
60289
|
+
}
|
|
60290
|
+
if (!Object.keys(nameMapping).length) {
|
|
60291
|
+
return data;
|
|
60292
|
+
}
|
|
60293
|
+
const sheetWithNewNames = Object.keys(nameMapping).sort((a, b) => b.length - a.length);
|
|
60294
|
+
let stringifiedData = JSON.stringify(data);
|
|
60295
|
+
for (const sheetName of sheetWithNewNames) {
|
|
60296
|
+
const regex = new RegExp(`'?${escapeRegExp(sheetName)}'?!`, "g");
|
|
60297
|
+
stringifiedData = stringifiedData.replaceAll(regex, (match) => {
|
|
60298
|
+
const newName = nameMapping[sheetName];
|
|
60299
|
+
return match.replace(sheetName, newName);
|
|
60300
|
+
});
|
|
60301
|
+
}
|
|
60302
|
+
return JSON.parse(stringifiedData);
|
|
60303
|
+
}
|
|
59480
60304
|
|
|
59481
60305
|
var Status;
|
|
59482
60306
|
(function (Status) {
|
|
@@ -60166,9 +60990,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60166
60990
|
exports.tokenize = tokenize;
|
|
60167
60991
|
|
|
60168
60992
|
|
|
60169
|
-
__info__.version = "17.3.0-alpha.
|
|
60170
|
-
__info__.date = "2024-
|
|
60171
|
-
__info__.hash = "
|
|
60993
|
+
__info__.version = "17.3.0-alpha.2";
|
|
60994
|
+
__info__.date = "2024-04-05T14:01:07.060Z";
|
|
60995
|
+
__info__.hash = "8c5a229";
|
|
60172
60996
|
|
|
60173
60997
|
|
|
60174
60998
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|