@odoo/o-spreadsheet 17.3.0-alpha.1 → 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 +941 -414
- package/dist/o-spreadsheet.d.ts +66 -55
- package/dist/o-spreadsheet.esm.js +941 -414
- package/dist/o-spreadsheet.iife.js +941 -414
- package/dist/o-spreadsheet.iife.min.js +315 -275
- package/dist/o_spreadsheet.xml +107 -44
- 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) {
|
|
@@ -465,7 +465,7 @@
|
|
|
465
465
|
}
|
|
466
466
|
// Generate new Id if the item didn't exist in the dictionary
|
|
467
467
|
const ids = Object.keys(itemsDic);
|
|
468
|
-
const maxId = ids.length === 0 ? 0 :
|
|
468
|
+
const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
|
|
469
469
|
itemsDic[maxId + 1] = item;
|
|
470
470
|
return maxId + 1;
|
|
471
471
|
}
|
|
@@ -483,7 +483,7 @@
|
|
|
483
483
|
let timeout = undefined;
|
|
484
484
|
const debounced = function () {
|
|
485
485
|
const context = this;
|
|
486
|
-
const args = arguments;
|
|
486
|
+
const args = Array.from(arguments);
|
|
487
487
|
function later() {
|
|
488
488
|
timeout = undefined;
|
|
489
489
|
if (!immediate) {
|
|
@@ -685,6 +685,34 @@
|
|
|
685
685
|
}
|
|
686
686
|
return RegExp(searchValue, flags);
|
|
687
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
|
+
}
|
|
688
716
|
|
|
689
717
|
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
690
718
|
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
|
|
@@ -2087,6 +2115,7 @@
|
|
|
2087
2115
|
CommandResult["InvalidCopyPasteSelection"] = "InvalidCopyPasteSelection";
|
|
2088
2116
|
CommandResult["NoChanges"] = "NoChanges";
|
|
2089
2117
|
CommandResult["InvalidInputId"] = "InvalidInputId";
|
|
2118
|
+
CommandResult["SheetIsHidden"] = "SheetIsHidden";
|
|
2090
2119
|
})(exports.CommandResult || (exports.CommandResult = {}));
|
|
2091
2120
|
|
|
2092
2121
|
const PLAIN_TEXT_FORMAT = "@"; // see OpenXML spec §18.8.31
|
|
@@ -4558,8 +4587,9 @@
|
|
|
4558
4587
|
* Get the default height of the cell given its style.
|
|
4559
4588
|
*/
|
|
4560
4589
|
function getDefaultCellHeight(ctx, cell, colSize) {
|
|
4561
|
-
if (!cell || !cell.content)
|
|
4590
|
+
if (!cell || (!cell.isFormula && !cell.content)) {
|
|
4562
4591
|
return DEFAULT_CELL_HEIGHT;
|
|
4592
|
+
}
|
|
4563
4593
|
const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
|
|
4564
4594
|
const numberOfLines = cell.isFormula
|
|
4565
4595
|
? 1
|
|
@@ -6993,10 +7023,17 @@
|
|
|
6993
7023
|
},
|
|
6994
7024
|
open(url, env) {
|
|
6995
7025
|
const sheetId = parseSheetUrl(url);
|
|
6996
|
-
env.model.dispatch("ACTIVATE_SHEET", {
|
|
7026
|
+
const result = env.model.dispatch("ACTIVATE_SHEET", {
|
|
6997
7027
|
sheetIdFrom: env.model.getters.getActiveSheetId(),
|
|
6998
7028
|
sheetIdTo: sheetId,
|
|
6999
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
|
+
}
|
|
7000
7037
|
},
|
|
7001
7038
|
sequence: 0,
|
|
7002
7039
|
});
|
|
@@ -7112,7 +7149,7 @@
|
|
|
7112
7149
|
}
|
|
7113
7150
|
function numberCell(value, format, formattedValue) {
|
|
7114
7151
|
return {
|
|
7115
|
-
value: value || 0,
|
|
7152
|
+
value: value || 0, // necessary to avoid "-0" and NaN values,
|
|
7116
7153
|
format,
|
|
7117
7154
|
formattedValue,
|
|
7118
7155
|
type: CellValueType.number,
|
|
@@ -9956,11 +9993,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9956
9993
|
}
|
|
9957
9994
|
else {
|
|
9958
9995
|
const range = this.getters.getRangeFromSheetXC(position.sheetId, rule.criterion.values[0]);
|
|
9959
|
-
values = this.getters
|
|
9996
|
+
values = Array.from(new Set(this.getters
|
|
9960
9997
|
.getRangeValues(range)
|
|
9961
9998
|
.filter(isNotNull)
|
|
9962
9999
|
.map((value) => value.toString())
|
|
9963
|
-
.filter((val) => val !== "");
|
|
10000
|
+
.filter((val) => val !== "")));
|
|
9964
10001
|
}
|
|
9965
10002
|
return values.map((value) => ({ text: value }));
|
|
9966
10003
|
},
|
|
@@ -19407,10 +19444,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19407
19444
|
}
|
|
19408
19445
|
}
|
|
19409
19446
|
return {
|
|
19410
|
-
labels:
|
|
19447
|
+
labels: Array.from(labelSet),
|
|
19411
19448
|
dataSetsValues: datasets.map((dataset, indexOfDataset) => ({
|
|
19412
19449
|
...dataset,
|
|
19413
|
-
data:
|
|
19450
|
+
data: Array.from(labelSet).map((label) => labelMap[label][indexOfDataset]),
|
|
19414
19451
|
})),
|
|
19415
19452
|
};
|
|
19416
19453
|
}
|
|
@@ -19429,8 +19466,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19429
19466
|
function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale }) {
|
|
19430
19467
|
const options = {
|
|
19431
19468
|
// https://www.chartjs.org/docs/latest/general/responsive.html
|
|
19432
|
-
responsive: true,
|
|
19433
|
-
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
|
|
19434
19471
|
layout: {
|
|
19435
19472
|
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
|
|
19436
19473
|
},
|
|
@@ -19476,7 +19513,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19476
19513
|
labels: labels.map(truncateLabel),
|
|
19477
19514
|
datasets: [],
|
|
19478
19515
|
},
|
|
19479
|
-
platform: undefined,
|
|
19516
|
+
platform: undefined, // This key is optional and will be set by chart.js
|
|
19480
19517
|
plugins: [],
|
|
19481
19518
|
};
|
|
19482
19519
|
}
|
|
@@ -19753,7 +19790,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19753
19790
|
},
|
|
19754
19791
|
y: {
|
|
19755
19792
|
position: chart.verticalAxisPosition,
|
|
19756
|
-
beginAtZero: true,
|
|
19793
|
+
beginAtZero: true, // the origin of the y axis is always zero
|
|
19757
19794
|
ticks: {
|
|
19758
19795
|
color: fontColor,
|
|
19759
19796
|
callback: (value) => {
|
|
@@ -19804,6 +19841,204 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19804
19841
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
19805
19842
|
}
|
|
19806
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
|
+
|
|
19807
20042
|
function isDataRangeValid(definition) {
|
|
19808
20043
|
return definition.dataRange && !rangeReference.test(definition.dataRange)
|
|
19809
20044
|
? "InvalidGaugeDataRange" /* CommandResult.InvalidGaugeDataRange */
|
|
@@ -20142,7 +20377,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20142
20377
|
return undefined;
|
|
20143
20378
|
}
|
|
20144
20379
|
const labelsTimestamps = labelDates.map((date) => date.getTime());
|
|
20145
|
-
const period =
|
|
20380
|
+
const period = largeMax(labelsTimestamps) - largeMin(labelsTimestamps);
|
|
20146
20381
|
const minUnit = getFormatMinDisplayUnit(format);
|
|
20147
20382
|
if (UNIT_LENGTH.second >= UNIT_LENGTH[minUnit] && Milliseconds.inSeconds(period) < 180) {
|
|
20148
20383
|
return "second";
|
|
@@ -20274,7 +20509,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20274
20509
|
},
|
|
20275
20510
|
y: {
|
|
20276
20511
|
position: chart.verticalAxisPosition,
|
|
20277
|
-
beginAtZero: true,
|
|
20512
|
+
beginAtZero: true, // the origin of the y axis is always zero
|
|
20278
20513
|
ticks: {
|
|
20279
20514
|
color: fontColor,
|
|
20280
20515
|
callback: (value) => {
|
|
@@ -20360,7 +20595,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20360
20595
|
const dataset = {
|
|
20361
20596
|
label,
|
|
20362
20597
|
data,
|
|
20363
|
-
tension: 0,
|
|
20598
|
+
tension: 0, // 0 -> render straight lines, which is much faster
|
|
20364
20599
|
borderColor: color,
|
|
20365
20600
|
backgroundColor,
|
|
20366
20601
|
pointBackgroundColor: color,
|
|
@@ -20582,7 +20817,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20582
20817
|
...this.getDefinition(),
|
|
20583
20818
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
20584
20819
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
20585
|
-
verticalAxisPosition: "left",
|
|
20820
|
+
verticalAxisPosition: "left", //TODO ExcelChartDefinition should be adapted, but can be done later
|
|
20586
20821
|
dataSets,
|
|
20587
20822
|
labelRange,
|
|
20588
20823
|
};
|
|
@@ -20630,7 +20865,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20630
20865
|
}
|
|
20631
20866
|
function getPieColors(colors, dataSetsValues) {
|
|
20632
20867
|
const pieColors = [];
|
|
20633
|
-
const maxLength =
|
|
20868
|
+
const maxLength = largeMax(dataSetsValues.map((ds) => ds.data.length));
|
|
20634
20869
|
for (let i = 0; i <= maxLength; i++) {
|
|
20635
20870
|
pieColors.push(colors.next());
|
|
20636
20871
|
}
|
|
@@ -20799,7 +21034,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20799
21034
|
configOptions.elements = {
|
|
20800
21035
|
point: {
|
|
20801
21036
|
radius: 3,
|
|
20802
|
-
hoverRadius: 3,
|
|
21037
|
+
hoverRadius: 3, // chartJS seems bugged, the point starts with the "hoverRadius" value
|
|
20803
21038
|
hitRadius: 8,
|
|
20804
21039
|
},
|
|
20805
21040
|
};
|
|
@@ -20839,6 +21074,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20839
21074
|
name: _t("Bar"),
|
|
20840
21075
|
sequence: 10,
|
|
20841
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
|
+
});
|
|
20842
21087
|
chartRegistry.add("line", {
|
|
20843
21088
|
match: (type) => type === "line",
|
|
20844
21089
|
createChart: (definition, sheetId, getters) => new LineChart(definition, sheetId, getters),
|
|
@@ -20892,6 +21137,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20892
21137
|
const chartComponentRegistry = new Registry();
|
|
20893
21138
|
chartComponentRegistry.add("line", ChartJsComponent);
|
|
20894
21139
|
chartComponentRegistry.add("bar", ChartJsComponent);
|
|
21140
|
+
chartComponentRegistry.add("combo", ChartJsComponent);
|
|
20895
21141
|
chartComponentRegistry.add("pie", ChartJsComponent);
|
|
20896
21142
|
chartComponentRegistry.add("gauge", GaugeChartComponent);
|
|
20897
21143
|
chartComponentRegistry.add("scatter", ChartJsComponent);
|
|
@@ -23150,7 +23396,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23150
23396
|
style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
|
|
23151
23397
|
border: { bottom: { color: colorSet.highlight, style: "thin" } },
|
|
23152
23398
|
},
|
|
23153
|
-
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
|
|
23399
|
+
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
|
|
23154
23400
|
firstRowStripe: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
|
|
23155
23401
|
secondRowStripe: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
|
|
23156
23402
|
});
|
|
@@ -23168,7 +23414,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23168
23414
|
},
|
|
23169
23415
|
},
|
|
23170
23416
|
headerRow: { border: { bottom: { color: colorSet.highlight, style: "medium" } } },
|
|
23171
|
-
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
|
|
23417
|
+
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
|
|
23172
23418
|
firstRowStripe: { style: { fillColor: colorSet.light } },
|
|
23173
23419
|
firstColumnStripe: { style: { fillColor: colorSet.light } },
|
|
23174
23420
|
});
|
|
@@ -23187,7 +23433,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23187
23433
|
headerRow: {
|
|
23188
23434
|
style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
|
|
23189
23435
|
},
|
|
23190
|
-
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
|
|
23436
|
+
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
|
|
23191
23437
|
firstRowStripe: { style: { fillColor: colorSet.light } },
|
|
23192
23438
|
firstColumnStripe: { style: { fillColor: colorSet.light } },
|
|
23193
23439
|
});
|
|
@@ -23223,7 +23469,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23223
23469
|
bottom: { color: "#000000", style: "medium" },
|
|
23224
23470
|
},
|
|
23225
23471
|
},
|
|
23226
|
-
totalRow: { border: { top: { color: "#000000", style: "medium" } } },
|
|
23472
|
+
totalRow: { border: { top: { color: "#000000", style: "medium" } } }, // @compatibility: should be double line
|
|
23227
23473
|
headerRow: {
|
|
23228
23474
|
style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
|
|
23229
23475
|
border: { bottom: { color: "#000000", style: "medium" } },
|
|
@@ -23247,7 +23493,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23247
23493
|
},
|
|
23248
23494
|
style: { fillColor: colorSet.light },
|
|
23249
23495
|
},
|
|
23250
|
-
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } },
|
|
23496
|
+
totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
|
|
23251
23497
|
firstRowStripe: { style: { fillColor: colorSet.medium } },
|
|
23252
23498
|
firstColumnStripe: { style: { fillColor: colorSet.medium } },
|
|
23253
23499
|
});
|
|
@@ -23278,7 +23524,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23278
23524
|
category: "dark",
|
|
23279
23525
|
colorName: colorSet.name,
|
|
23280
23526
|
wholeTable: { style: { fillColor: colorSet.light } },
|
|
23281
|
-
totalRow: { border: { top: { color: "#000000", style: "medium" } } },
|
|
23527
|
+
totalRow: { border: { top: { color: "#000000", style: "medium" } } }, // @compatibility: should be double line
|
|
23282
23528
|
headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
|
|
23283
23529
|
firstRowStripe: { style: { fillColor: colorSet.medium } },
|
|
23284
23530
|
firstColumnStripe: { style: { fillColor: colorSet.medium } },
|
|
@@ -23443,8 +23689,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23443
23689
|
let last;
|
|
23444
23690
|
const activesRows = env.model.getters.getActiveRows();
|
|
23445
23691
|
if (activesRows.size !== 0) {
|
|
23446
|
-
first =
|
|
23447
|
-
last =
|
|
23692
|
+
first = largeMin([...activesRows]);
|
|
23693
|
+
last = largeMax([...activesRows]);
|
|
23448
23694
|
}
|
|
23449
23695
|
else {
|
|
23450
23696
|
const zone = env.model.getters.getSelectedZones()[0];
|
|
@@ -23472,8 +23718,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23472
23718
|
let last;
|
|
23473
23719
|
const activeCols = env.model.getters.getActiveCols();
|
|
23474
23720
|
if (activeCols.size !== 0) {
|
|
23475
|
-
first =
|
|
23476
|
-
last =
|
|
23721
|
+
first = largeMin([...activeCols]);
|
|
23722
|
+
last = largeMax([...activeCols]);
|
|
23477
23723
|
}
|
|
23478
23724
|
else {
|
|
23479
23725
|
const zone = env.model.getters.getSelectedZones()[0];
|
|
@@ -23501,8 +23747,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23501
23747
|
let last;
|
|
23502
23748
|
const activesRows = env.model.getters.getActiveRows();
|
|
23503
23749
|
if (activesRows.size !== 0) {
|
|
23504
|
-
first =
|
|
23505
|
-
last =
|
|
23750
|
+
first = largeMin([...activesRows]);
|
|
23751
|
+
last = largeMax([...activesRows]);
|
|
23506
23752
|
}
|
|
23507
23753
|
else {
|
|
23508
23754
|
const zone = env.model.getters.getSelectedZones()[0];
|
|
@@ -23543,8 +23789,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23543
23789
|
let last;
|
|
23544
23790
|
const activeCols = env.model.getters.getActiveCols();
|
|
23545
23791
|
if (activeCols.size !== 0) {
|
|
23546
|
-
first =
|
|
23547
|
-
last =
|
|
23792
|
+
first = largeMin([...activeCols]);
|
|
23793
|
+
last = largeMax([...activeCols]);
|
|
23548
23794
|
}
|
|
23549
23795
|
else {
|
|
23550
23796
|
const zone = env.model.getters.getSelectedZones()[0];
|
|
@@ -23585,7 +23831,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23585
23831
|
let row;
|
|
23586
23832
|
let quantity;
|
|
23587
23833
|
if (activeRows.size) {
|
|
23588
|
-
row =
|
|
23834
|
+
row = largeMin([...activeRows]);
|
|
23589
23835
|
quantity = activeRows.size;
|
|
23590
23836
|
}
|
|
23591
23837
|
else {
|
|
@@ -23606,7 +23852,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23606
23852
|
let row;
|
|
23607
23853
|
let quantity;
|
|
23608
23854
|
if (activeRows.size) {
|
|
23609
|
-
row =
|
|
23855
|
+
row = largeMax([...activeRows]);
|
|
23610
23856
|
quantity = activeRows.size;
|
|
23611
23857
|
}
|
|
23612
23858
|
else {
|
|
@@ -23627,7 +23873,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23627
23873
|
let column;
|
|
23628
23874
|
let quantity;
|
|
23629
23875
|
if (activeCols.size) {
|
|
23630
|
-
column =
|
|
23876
|
+
column = largeMin([...activeCols]);
|
|
23631
23877
|
quantity = activeCols.size;
|
|
23632
23878
|
}
|
|
23633
23879
|
else {
|
|
@@ -23648,7 +23894,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23648
23894
|
let column;
|
|
23649
23895
|
let quantity;
|
|
23650
23896
|
if (activeCols.size) {
|
|
23651
|
-
column =
|
|
23897
|
+
column = largeMax([...activeCols]);
|
|
23652
23898
|
quantity = activeCols.size;
|
|
23653
23899
|
}
|
|
23654
23900
|
else {
|
|
@@ -27254,6 +27500,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27254
27500
|
static template = "o-spreadsheet-BarChartDesignPanel";
|
|
27255
27501
|
}
|
|
27256
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
|
+
|
|
27257
27519
|
class GaugeChartConfigPanel extends owl.Component {
|
|
27258
27520
|
static template = "o-spreadsheet-GaugeChartConfigPanel";
|
|
27259
27521
|
static components = { ChartErrorSection, ChartDataSeries };
|
|
@@ -27611,6 +27873,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27611
27873
|
.add("bar", {
|
|
27612
27874
|
configuration: BarConfigPanel,
|
|
27613
27875
|
design: BarChartDesignPanel,
|
|
27876
|
+
})
|
|
27877
|
+
.add("combo", {
|
|
27878
|
+
configuration: ComboChartConfigPanel,
|
|
27879
|
+
design: ComboChartDesignPanel,
|
|
27614
27880
|
})
|
|
27615
27881
|
.add("pie", {
|
|
27616
27882
|
configuration: LineBarPieConfigPanel,
|
|
@@ -30251,7 +30517,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30251
30517
|
const composerStore = useStore(ComposerStore);
|
|
30252
30518
|
// The feature makes no sense if we are editing a cell, because then the selection isn't active
|
|
30253
30519
|
// Stop the edition when the panel is mounted, and close the panel if the user start editing a cell
|
|
30254
|
-
owl.useEffect(
|
|
30520
|
+
owl.useEffect((editionMode) => {
|
|
30521
|
+
if (editionMode !== "inactive") {
|
|
30522
|
+
this.props.onCloseSidePanel();
|
|
30523
|
+
}
|
|
30524
|
+
}, () => [composerStore.editionMode]);
|
|
30255
30525
|
owl.onMounted(() => {
|
|
30256
30526
|
composerStore.stopEdition();
|
|
30257
30527
|
});
|
|
@@ -31960,6 +32230,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31960
32230
|
this.assistantState.allowCellSelectionBehind = false;
|
|
31961
32231
|
}, 2000);
|
|
31962
32232
|
}
|
|
32233
|
+
get formulaArgSeparator() {
|
|
32234
|
+
return this.env.model.getters.getLocale().formulaArgSeparator + " ";
|
|
32235
|
+
}
|
|
31963
32236
|
}
|
|
31964
32237
|
|
|
31965
32238
|
const functions$2 = functionRegistry.content;
|
|
@@ -32119,6 +32392,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32119
32392
|
owl.useEffect(() => {
|
|
32120
32393
|
this.processContent();
|
|
32121
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
|
+
});
|
|
32122
32401
|
}
|
|
32123
32402
|
// ---------------------------------------------------------------------------
|
|
32124
32403
|
// Handlers
|
|
@@ -34098,11 +34377,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34098
34377
|
height: 10000px;
|
|
34099
34378
|
background-color: ${SELECTION_BORDER_COLOR};
|
|
34100
34379
|
}
|
|
34101
|
-
.o-unhide-buttons {
|
|
34102
|
-
width: fit-content;
|
|
34103
|
-
gap: 5px;
|
|
34104
|
-
transform: translate(-50%, 0);
|
|
34105
|
-
}
|
|
34106
34380
|
.o-unhide:hover {
|
|
34107
34381
|
z-index: ${ComponentsImportance.Grid + 1};
|
|
34108
34382
|
background-color: lightgrey;
|
|
@@ -34264,10 +34538,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34264
34538
|
height: 1px;
|
|
34265
34539
|
background-color: ${SELECTION_BORDER_COLOR};
|
|
34266
34540
|
}
|
|
34267
|
-
.o-unhide-buttons {
|
|
34268
|
-
height: fit-content;
|
|
34269
|
-
transform: translate(0, -50%);
|
|
34270
|
-
}
|
|
34271
34541
|
.o-unhide:hover {
|
|
34272
34542
|
z-index: ${ComponentsImportance.Grid + 1};
|
|
34273
34543
|
background-color: lightgrey;
|
|
@@ -35475,7 +35745,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35475
35745
|
onScroll(offset) {
|
|
35476
35746
|
const { scrollX } = this.env.model.getters.getActiveSheetDOMScrollInfo();
|
|
35477
35747
|
this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
|
|
35478
|
-
offsetX: scrollX,
|
|
35748
|
+
offsetX: scrollX, // offsetX is the same
|
|
35479
35749
|
offsetY: offset,
|
|
35480
35750
|
});
|
|
35481
35751
|
}
|
|
@@ -35763,8 +36033,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35763
36033
|
"Ctrl+Shift+L": () => this.setHorizontalAlign("left"),
|
|
35764
36034
|
"Ctrl+Shift+R": () => this.setHorizontalAlign("right"),
|
|
35765
36035
|
"Ctrl+Shift+V": () => PASTE_AS_VALUE_ACTION(this.env),
|
|
35766
|
-
"Ctrl+Shift+<": () => this.clearFormatting(),
|
|
35767
|
-
"Ctrl+<": () => this.clearFormatting(),
|
|
36036
|
+
"Ctrl+Shift+<": () => this.clearFormatting(), // for qwerty
|
|
36037
|
+
"Ctrl+<": () => this.clearFormatting(), // for azerty
|
|
35768
36038
|
"Ctrl+Shift+ ": () => {
|
|
35769
36039
|
this.env.model.selection.selectAll();
|
|
35770
36040
|
},
|
|
@@ -36200,6 +36470,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36200
36470
|
"surfaceChart",
|
|
36201
36471
|
"surface3DChart",
|
|
36202
36472
|
"bubbleChart",
|
|
36473
|
+
"comboChart",
|
|
36203
36474
|
];
|
|
36204
36475
|
|
|
36205
36476
|
/** In XLSX color format (no #) */
|
|
@@ -36531,10 +36802,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36531
36802
|
const CF_TYPE_CONVERSION_MAP = {
|
|
36532
36803
|
aboveAverage: undefined,
|
|
36533
36804
|
expression: undefined,
|
|
36534
|
-
cellIs: undefined,
|
|
36535
|
-
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
|
|
36536
36807
|
dataBar: undefined,
|
|
36537
|
-
iconSet: undefined,
|
|
36808
|
+
iconSet: undefined, // exist but isn't an operator in o_spreadsheet
|
|
36538
36809
|
top10: undefined,
|
|
36539
36810
|
uniqueValues: undefined,
|
|
36540
36811
|
duplicateValues: undefined,
|
|
@@ -36611,6 +36882,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36611
36882
|
surfaceChart: undefined,
|
|
36612
36883
|
surface3DChart: undefined,
|
|
36613
36884
|
bubbleChart: undefined,
|
|
36885
|
+
comboChart: "combo",
|
|
36614
36886
|
};
|
|
36615
36887
|
/** Conversion map for the SUBTOTAL(index, formula) function in xlsx, index <=> actual function*/
|
|
36616
36888
|
const SUBTOTAL_FUNCTION_CONVERSION_MAP = {
|
|
@@ -36769,7 +37041,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36769
37041
|
61: "993366",
|
|
36770
37042
|
62: "333399",
|
|
36771
37043
|
63: "333333",
|
|
36772
|
-
64: "000000",
|
|
37044
|
+
64: "000000", // system foreground
|
|
36773
37045
|
65: "FFFFFF", // system background
|
|
36774
37046
|
};
|
|
36775
37047
|
const IMAGE_MIMETYPE_TO_EXTENSION_MAPPING = {
|
|
@@ -37961,7 +38233,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37961
38233
|
function getSheetDims(sheet) {
|
|
37962
38234
|
const dims = [0, 0];
|
|
37963
38235
|
for (let row of sheet.rows) {
|
|
37964
|
-
dims[0] = Math.max(dims[0],
|
|
38236
|
+
dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
|
|
37965
38237
|
dims[1] = Math.max(dims[1], row.index);
|
|
37966
38238
|
}
|
|
37967
38239
|
dims[0] = Math.max(dims[0], EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
|
|
@@ -38827,6 +39099,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38827
39099
|
if (!CHART_TYPE_CONVERSION_MAP[chartType]) {
|
|
38828
39100
|
throw new Error(`Unsupported chart type ${chartType}`);
|
|
38829
39101
|
}
|
|
39102
|
+
if (CHART_TYPE_CONVERSION_MAP[chartType] === "combo") {
|
|
39103
|
+
return this.extractComboChart(rootChartElement);
|
|
39104
|
+
}
|
|
38830
39105
|
// Title can be separated into multiple xml elements (for styling and such), we only import the text
|
|
38831
39106
|
const chartTitle = this.mapOnElements({ parent: rootChartElement, query: "c:title a:t" }, (textElement) => {
|
|
38832
39107
|
return textElement.textContent || "";
|
|
@@ -38855,6 +39130,37 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38855
39130
|
};
|
|
38856
39131
|
})[0];
|
|
38857
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
|
+
}
|
|
38858
39164
|
extractChartDatasets(chartElement) {
|
|
38859
39165
|
return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
|
|
38860
39166
|
return {
|
|
@@ -38872,12 +39178,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38872
39178
|
if (!plotAreaElement) {
|
|
38873
39179
|
throw new Error("Missing plot area in the chart definition.");
|
|
38874
39180
|
}
|
|
39181
|
+
let globalTag = undefined;
|
|
38875
39182
|
for (let child of plotAreaElement.children) {
|
|
38876
39183
|
const tag = removeTagEscapedNamespaces(child.tagName);
|
|
38877
39184
|
if (XLSX_CHART_TYPES.some((chartType) => chartType === tag)) {
|
|
38878
|
-
|
|
39185
|
+
if (!globalTag) {
|
|
39186
|
+
globalTag = tag;
|
|
39187
|
+
}
|
|
39188
|
+
else if (globalTag !== tag) {
|
|
39189
|
+
globalTag = "comboChart";
|
|
39190
|
+
}
|
|
38879
39191
|
}
|
|
38880
39192
|
}
|
|
39193
|
+
if (globalTag) {
|
|
39194
|
+
return globalTag;
|
|
39195
|
+
}
|
|
38881
39196
|
throw new Error("Unknown chart type");
|
|
38882
39197
|
}
|
|
38883
39198
|
}
|
|
@@ -42468,6 +42783,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42468
42783
|
if (newRule.criterion.type === "isBoolean") {
|
|
42469
42784
|
this.setCenterStyleToBooleanCells(newRule);
|
|
42470
42785
|
}
|
|
42786
|
+
else if (newRule.criterion.type === "isValueInList") {
|
|
42787
|
+
newRule.criterion.values = Array.from(new Set(newRule.criterion.values));
|
|
42788
|
+
}
|
|
42471
42789
|
const adaptedRules = this.removeRangesFromRules(sheetId, newRule.ranges, rules);
|
|
42472
42790
|
const ruleIndex = adaptedRules.findIndex((rule) => rule.id === newRule.id);
|
|
42473
42791
|
if (ruleIndex !== -1) {
|
|
@@ -42864,7 +43182,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42864
43182
|
if (hiddenElements.size >= elements) {
|
|
42865
43183
|
return "TooManyHiddenElements" /* CommandResult.TooManyHiddenElements */;
|
|
42866
43184
|
}
|
|
42867
|
-
else if (
|
|
43185
|
+
else if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
|
|
42868
43186
|
return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
|
|
42869
43187
|
}
|
|
42870
43188
|
else {
|
|
@@ -43193,7 +43511,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43193
43511
|
"isInSameMerge",
|
|
43194
43512
|
"isMergeHidden",
|
|
43195
43513
|
"getMainCellPosition",
|
|
43196
|
-
"getBottomLeftCell",
|
|
43197
43514
|
"expandZone",
|
|
43198
43515
|
"doesIntersectMerge",
|
|
43199
43516
|
"doesColumnsHaveCommonMerges",
|
|
@@ -43375,13 +43692,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43375
43692
|
const mergeTopLeftPos = this.getMerge(position).topLeft;
|
|
43376
43693
|
return { sheetId: position.sheetId, col: mergeTopLeftPos.col, row: mergeTopLeftPos.row };
|
|
43377
43694
|
}
|
|
43378
|
-
getBottomLeftCell(position) {
|
|
43379
|
-
if (!this.isInMerge(position)) {
|
|
43380
|
-
return position;
|
|
43381
|
-
}
|
|
43382
|
-
const { bottom, left } = this.getMerge(position);
|
|
43383
|
-
return { sheetId: position.sheetId, col: left, row: bottom };
|
|
43384
|
-
}
|
|
43385
43695
|
isMergeHidden(sheetId, merge) {
|
|
43386
43696
|
const hiddenColsGroups = this.getters.getHiddenColsGroups(sheetId);
|
|
43387
43697
|
const hiddenRowsGroups = this.getters.getHiddenRowsGroups(sheetId);
|
|
@@ -43682,8 +43992,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43682
43992
|
let newRange = range;
|
|
43683
43993
|
let changeType = "NONE";
|
|
43684
43994
|
for (let group of groups) {
|
|
43685
|
-
const min =
|
|
43686
|
-
const max =
|
|
43995
|
+
const min = largeMin(group);
|
|
43996
|
+
const max = largeMax(group);
|
|
43687
43997
|
if (range.zone[start] <= min && min <= range.zone[end]) {
|
|
43688
43998
|
const toRemove = Math.min(range.zone[end], max) - min + 1;
|
|
43689
43999
|
changeType = "RESIZE";
|
|
@@ -44065,7 +44375,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44065
44375
|
"getSheetIds",
|
|
44066
44376
|
"getVisibleSheetIds",
|
|
44067
44377
|
"isSheetVisible",
|
|
44068
|
-
"getEvaluationSheets",
|
|
44069
44378
|
"doesHeaderExist",
|
|
44070
44379
|
"doesHeadersExist",
|
|
44071
44380
|
"getCell",
|
|
@@ -44132,8 +44441,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44132
44441
|
}
|
|
44133
44442
|
return "Success" /* CommandResult.Success */;
|
|
44134
44443
|
case "REMOVE_COLUMNS_ROWS": {
|
|
44135
|
-
const min =
|
|
44136
|
-
const max =
|
|
44444
|
+
const min = largeMin(cmd.elements);
|
|
44445
|
+
const max = largeMax(cmd.elements);
|
|
44137
44446
|
if (min < 0 || !this.doesHeaderExist(cmd.sheetId, cmd.dimension, max)) {
|
|
44138
44447
|
return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
|
|
44139
44448
|
}
|
|
@@ -44324,9 +44633,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44324
44633
|
getVisibleSheetIds() {
|
|
44325
44634
|
return this.orderedSheetIds.filter(this.isSheetVisible.bind(this));
|
|
44326
44635
|
}
|
|
44327
|
-
getEvaluationSheets() {
|
|
44328
|
-
return this.sheets;
|
|
44329
|
-
}
|
|
44330
44636
|
doesHeaderExist(sheetId, dimension, index) {
|
|
44331
44637
|
return dimension === "COL"
|
|
44332
44638
|
? index >= 0 && index < this.getNumberCols(sheetId)
|
|
@@ -44335,13 +44641,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44335
44641
|
doesHeadersExist(sheetId, dimension, headerIndexes) {
|
|
44336
44642
|
return headerIndexes.every((index) => this.doesHeaderExist(sheetId, dimension, index));
|
|
44337
44643
|
}
|
|
44338
|
-
getRow(sheetId, index) {
|
|
44339
|
-
const row = this.getSheet(sheetId).rows[index];
|
|
44340
|
-
if (!row) {
|
|
44341
|
-
throw new Error(`Row ${row} not found.`);
|
|
44342
|
-
}
|
|
44343
|
-
return row;
|
|
44344
|
-
}
|
|
44345
44644
|
getCell({ sheetId, col, row }) {
|
|
44346
44645
|
const sheet = this.tryGetSheet(sheetId);
|
|
44347
44646
|
const cellId = sheet?.rows[row]?.cells[col];
|
|
@@ -45910,12 +46209,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45910
46209
|
: _t("Function %s expects its parameters to be single values or single cell references, not ranges.", functionName.toString()));
|
|
45911
46210
|
}
|
|
45912
46211
|
const position = { sheetId: range.sheetId, col: range.zone.left, row: range.zone.top };
|
|
45913
|
-
return this.readCell(position);
|
|
45914
|
-
}
|
|
45915
|
-
readCell(position) {
|
|
45916
|
-
if (!this.getters.tryGetSheet(position.sheetId)) {
|
|
45917
|
-
throw new EvaluationError(_t("Invalid sheet name"));
|
|
45918
|
-
}
|
|
45919
46212
|
return this.computeCell(position);
|
|
45920
46213
|
}
|
|
45921
46214
|
/**
|
|
@@ -45951,7 +46244,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45951
46244
|
matrix[colIndex] = new Array(height);
|
|
45952
46245
|
for (let row = _zone.top; row <= _zone.bottom; row++) {
|
|
45953
46246
|
const rowIndex = row - _zone.top;
|
|
45954
|
-
matrix[colIndex][rowIndex] = this.
|
|
46247
|
+
matrix[colIndex][rowIndex] = this.computeCell({ sheetId, col, row });
|
|
45955
46248
|
}
|
|
45956
46249
|
}
|
|
45957
46250
|
this.rangeCache[cacheKey] = matrix;
|
|
@@ -47059,15 +47352,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47059
47352
|
getEvaluatedCell(position) {
|
|
47060
47353
|
return this.evaluatedCells.get(position) || EMPTY_CELL;
|
|
47061
47354
|
}
|
|
47062
|
-
|
|
47355
|
+
getSpreadZone(position) {
|
|
47063
47356
|
if (!this.spreadingRelations.isArrayFormula(position)) {
|
|
47064
|
-
return
|
|
47357
|
+
return undefined;
|
|
47065
47358
|
}
|
|
47066
47359
|
if (this.evaluatedCells.get(position)?.type === CellValueType.error) {
|
|
47067
|
-
return
|
|
47360
|
+
return positionToZone(position);
|
|
47068
47361
|
}
|
|
47069
47362
|
const spreadPositions = Array.from(this.spreadingRelations.getArrayResultPositions(position));
|
|
47070
|
-
return
|
|
47363
|
+
return union(positionToZone(position), unionPositionsToZone(spreadPositions));
|
|
47071
47364
|
}
|
|
47072
47365
|
getEvaluatedPositions() {
|
|
47073
47366
|
return this.evaluatedCells.keys();
|
|
@@ -47472,7 +47765,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47472
47765
|
"getEvaluatedCell",
|
|
47473
47766
|
"getEvaluatedCells",
|
|
47474
47767
|
"getEvaluatedCellsInZone",
|
|
47475
|
-
"
|
|
47768
|
+
"getSpreadZone",
|
|
47476
47769
|
"getArrayFormulaSpreadingOn",
|
|
47477
47770
|
"isEmpty",
|
|
47478
47771
|
];
|
|
@@ -47578,8 +47871,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47578
47871
|
getEvaluatedCellsInZone(sheetId, zone) {
|
|
47579
47872
|
return positions(zone).map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }));
|
|
47580
47873
|
}
|
|
47581
|
-
|
|
47582
|
-
|
|
47874
|
+
/**
|
|
47875
|
+
* Return the spread zone the position is part of, if any
|
|
47876
|
+
*/
|
|
47877
|
+
getSpreadZone(position) {
|
|
47878
|
+
return this.evaluator.getSpreadZone(position);
|
|
47583
47879
|
}
|
|
47584
47880
|
getArrayFormulaSpreadingOn(position) {
|
|
47585
47881
|
return this.evaluator.getArrayFormulaSpreadingOn(position);
|
|
@@ -47619,7 +47915,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47619
47915
|
? getItemId(newFormat, data.formats)
|
|
47620
47916
|
: exportedCellData.format;
|
|
47621
47917
|
let content;
|
|
47622
|
-
if (formulaCell instanceof FormulaCellWithDependencies) {
|
|
47918
|
+
if (isFormula && formulaCell instanceof FormulaCellWithDependencies) {
|
|
47623
47919
|
content = formulaCell.contentWithFixedReferences;
|
|
47624
47920
|
}
|
|
47625
47921
|
else {
|
|
@@ -47667,17 +47963,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47667
47963
|
*/
|
|
47668
47964
|
function sortWithClusters(colorsToSort) {
|
|
47669
47965
|
const clusters = [
|
|
47670
|
-
{ leadColor: rgba(255, 0, 0), colors: [] },
|
|
47671
|
-
{ leadColor: rgba(255, 128, 0), colors: [] },
|
|
47672
|
-
{ leadColor: rgba(128, 128, 0), colors: [] },
|
|
47673
|
-
{ leadColor: rgba(128, 255, 0), colors: [] },
|
|
47674
|
-
{ leadColor: rgba(0, 255, 0), colors: [] },
|
|
47675
|
-
{ leadColor: rgba(0, 255, 128), colors: [] },
|
|
47676
|
-
{ leadColor: rgba(0, 255, 255), colors: [] },
|
|
47677
|
-
{ leadColor: rgba(0, 127, 255), colors: [] },
|
|
47678
|
-
{ leadColor: rgba(0, 0, 255), colors: [] },
|
|
47679
|
-
{ leadColor: rgba(127, 0, 255), colors: [] },
|
|
47680
|
-
{ 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
|
|
47681
47977
|
{ leadColor: rgba(255, 0, 128), colors: [] }, // rose
|
|
47682
47978
|
];
|
|
47683
47979
|
for (const color of colorsToSort.map(colorToRGBA)) {
|
|
@@ -48068,13 +48364,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48068
48364
|
.map((cell) => cell.value);
|
|
48069
48365
|
switch (threshold.type) {
|
|
48070
48366
|
case "value":
|
|
48071
|
-
const result = functionName === "max" ?
|
|
48367
|
+
const result = functionName === "max" ? largeMax(rangeValues) : largeMin(rangeValues);
|
|
48072
48368
|
return result;
|
|
48073
48369
|
case "number":
|
|
48074
48370
|
return Number(threshold.value);
|
|
48075
48371
|
case "percentage":
|
|
48076
|
-
const min =
|
|
48077
|
-
const max =
|
|
48372
|
+
const min = largeMin(rangeValues);
|
|
48373
|
+
const max = largeMax(rangeValues);
|
|
48078
48374
|
const delta = max - min;
|
|
48079
48375
|
return min + (delta * Number(threshold.value)) / 100;
|
|
48080
48376
|
case "percentile":
|
|
@@ -48541,8 +48837,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48541
48837
|
else if (deepEquals(parentSpreadingCell, topLeft) && getZoneArea(unionZone) === 1) {
|
|
48542
48838
|
return true;
|
|
48543
48839
|
}
|
|
48544
|
-
const
|
|
48545
|
-
return deepEquals(unionZone,
|
|
48840
|
+
const zone = this.getters.getSpreadZone(parentSpreadingCell);
|
|
48841
|
+
return deepEquals(unionZone, zone);
|
|
48546
48842
|
}
|
|
48547
48843
|
coreTableToTable(sheetId, table) {
|
|
48548
48844
|
if (table.type !== "dynamic") {
|
|
@@ -48550,8 +48846,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48550
48846
|
}
|
|
48551
48847
|
const tableZone = table.range.zone;
|
|
48552
48848
|
const tablePosition = { sheetId, col: tableZone.left, row: tableZone.top };
|
|
48553
|
-
const
|
|
48554
|
-
const zone = spreadPositions.length ? unionPositionsToZone(spreadPositions) : table.range.zone;
|
|
48849
|
+
const zone = this.getters.getSpreadZone(tablePosition) ?? table.range.zone;
|
|
48555
48850
|
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
48556
48851
|
const filters = this.getDynamicTableFilters(sheetId, table, zone);
|
|
48557
48852
|
return { id: table.id, range, filters, config: table.config };
|
|
@@ -49001,8 +49296,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49001
49296
|
let row = zone.bottom;
|
|
49002
49297
|
if (col > 0) {
|
|
49003
49298
|
let leftPosition = { sheetId, col: col - 1, row };
|
|
49004
|
-
while (this.getters.
|
|
49005
|
-
this.getters.getCell(leftPosition)?.content) {
|
|
49299
|
+
while (this.getters.getEvaluatedCell(leftPosition).type !== CellValueType.empty) {
|
|
49006
49300
|
row += 1;
|
|
49007
49301
|
leftPosition = { sheetId, col: col - 1, row };
|
|
49008
49302
|
}
|
|
@@ -49011,8 +49305,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49011
49305
|
col = zone.right;
|
|
49012
49306
|
if (col <= this.getters.getNumberCols(sheetId)) {
|
|
49013
49307
|
let rightPosition = { sheetId, col: col + 1, row };
|
|
49014
|
-
while (this.getters.
|
|
49015
|
-
this.getters.getCell(rightPosition)?.content) {
|
|
49308
|
+
while (this.getters.getEvaluatedCell(rightPosition).type !== CellValueType.empty) {
|
|
49016
49309
|
row += 1;
|
|
49017
49310
|
rightPosition = { sheetId, col: col + 1, row };
|
|
49018
49311
|
}
|
|
@@ -49322,13 +49615,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49322
49615
|
const cells = this.getters.getEvaluatedCellsInZone(sheet.id, zone);
|
|
49323
49616
|
const cellPositions = range(end, -1, -1);
|
|
49324
49617
|
const invalidCells = cellPositions.filter((position) => cells[position] && !cells[position].isAutoSummable);
|
|
49325
|
-
const maxValidPosition =
|
|
49618
|
+
const maxValidPosition = largeMax(invalidCells);
|
|
49326
49619
|
const numberSequences = groupConsecutive(cellPositions.filter((position) => this.isNumber(cells[position])));
|
|
49327
49620
|
const firstSequence = numberSequences[0] || [];
|
|
49328
|
-
if (
|
|
49621
|
+
if (largeMax(firstSequence) < maxValidPosition) {
|
|
49329
49622
|
return Infinity;
|
|
49330
49623
|
}
|
|
49331
|
-
return
|
|
49624
|
+
return largeMin(firstSequence);
|
|
49332
49625
|
}
|
|
49333
49626
|
shouldFindData(sheetId, zone) {
|
|
49334
49627
|
return this.getters.isEmpty(sheetId, zone) || this.getters.isSingleCellOrMerge(sheetId, zone);
|
|
@@ -50903,8 +51196,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
50903
51196
|
static getters = [
|
|
50904
51197
|
"doesCellHaveGridIcon",
|
|
50905
51198
|
"getCellWidth",
|
|
50906
|
-
"getCellComputedBorder",
|
|
50907
|
-
"getCellComputedStyle",
|
|
50908
51199
|
"getTextWidth",
|
|
50909
51200
|
"getCellText",
|
|
50910
51201
|
"getCellMultiLineText",
|
|
@@ -50948,7 +51239,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
50948
51239
|
// Getters
|
|
50949
51240
|
// ---------------------------------------------------------------------------
|
|
50950
51241
|
getCellWidth(position) {
|
|
50951
|
-
const style = this.getCellComputedStyle(position);
|
|
51242
|
+
const style = this.getters.getCellComputedStyle(position);
|
|
50952
51243
|
let contentWidth = 0;
|
|
50953
51244
|
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
50954
51245
|
if (content) {
|
|
@@ -51041,35 +51332,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51041
51332
|
*/
|
|
51042
51333
|
isCellEmpty(position) {
|
|
51043
51334
|
const mainPosition = this.getters.getMainCellPosition(position);
|
|
51044
|
-
return
|
|
51045
|
-
this.getters.getCell(mainPosition)?.content);
|
|
51046
|
-
}
|
|
51047
|
-
getCellComputedBorder(position) {
|
|
51048
|
-
const cellBorder = this.getters.getCellBorder(position) || {};
|
|
51049
|
-
const cellTableBorder = this.getters.getCellTableBorder(position) || {};
|
|
51050
|
-
// Use removeFalsyAttributes to avoid overwriting borders with undefined values
|
|
51051
|
-
const border = { ...cellTableBorder, ...removeFalsyAttributes(cellBorder) };
|
|
51052
|
-
return isObjectEmptyRecursive(border) ? null : border;
|
|
51053
|
-
}
|
|
51054
|
-
getCellComputedStyle(position) {
|
|
51055
|
-
const cell = this.getters.getCell(position);
|
|
51056
|
-
const cfStyle = this.getters.getCellConditionalFormatStyle(position);
|
|
51057
|
-
const tableStyle = this.getters.getCellTableStyle(position);
|
|
51058
|
-
const computedStyle = {
|
|
51059
|
-
...removeFalsyAttributes(tableStyle),
|
|
51060
|
-
...removeFalsyAttributes(cell?.style),
|
|
51061
|
-
...removeFalsyAttributes(cfStyle),
|
|
51062
|
-
};
|
|
51063
|
-
const evaluatedCell = this.getters.getEvaluatedCell(position);
|
|
51064
|
-
if (evaluatedCell.link && !computedStyle.textColor) {
|
|
51065
|
-
computedStyle.textColor = LINK_COLOR;
|
|
51066
|
-
}
|
|
51067
|
-
return computedStyle;
|
|
51335
|
+
return this.getters.getEvaluatedCell(mainPosition).type === CellValueType.empty;
|
|
51068
51336
|
}
|
|
51069
51337
|
getColMaxWidth(sheetId, index) {
|
|
51070
51338
|
const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
|
|
51071
51339
|
const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
|
|
51072
|
-
return Math.max(0,
|
|
51340
|
+
return Math.max(0, largeMax(sizes));
|
|
51073
51341
|
}
|
|
51074
51342
|
/**
|
|
51075
51343
|
* Check that any "sheetId" in the command matches an existing
|
|
@@ -51098,6 +51366,236 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51098
51366
|
}
|
|
51099
51367
|
}
|
|
51100
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
|
+
|
|
51101
51599
|
const genericRepeatsTransforms = [
|
|
51102
51600
|
repeatSheetDependantCommand,
|
|
51103
51601
|
repeatTargetDependantCommand,
|
|
@@ -51675,148 +52173,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51675
52173
|
}
|
|
51676
52174
|
}
|
|
51677
52175
|
|
|
51678
|
-
class TableStylePlugin extends UIPlugin {
|
|
51679
|
-
static getters = ["getCellTableStyle", "getCellTableBorder"];
|
|
51680
|
-
tableStyles = {};
|
|
51681
|
-
handle(cmd) {
|
|
51682
|
-
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
51683
|
-
(cmd.type === "UPDATE_CELL" && "content" in cmd) ||
|
|
51684
|
-
cmd.type === "EVALUATE_CELLS") {
|
|
51685
|
-
this.tableStyles = {};
|
|
51686
|
-
return;
|
|
51687
|
-
}
|
|
51688
|
-
switch (cmd.type) {
|
|
51689
|
-
case "HIDE_COLUMNS_ROWS":
|
|
51690
|
-
case "UNHIDE_COLUMNS_ROWS":
|
|
51691
|
-
case "UNFOLD_HEADER_GROUP":
|
|
51692
|
-
case "FOLD_HEADER_GROUP":
|
|
51693
|
-
case "FOLD_ALL_HEADER_GROUPS":
|
|
51694
|
-
case "UNFOLD_ALL_HEADER_GROUPS":
|
|
51695
|
-
case "UPDATE_TABLE":
|
|
51696
|
-
case "UPDATE_FILTER":
|
|
51697
|
-
delete this.tableStyles[cmd.sheetId];
|
|
51698
|
-
break;
|
|
51699
|
-
}
|
|
51700
|
-
}
|
|
51701
|
-
finalize() {
|
|
51702
|
-
for (const sheetId of this.getters.getSheetIds()) {
|
|
51703
|
-
if (!this.tableStyles[sheetId]) {
|
|
51704
|
-
this.tableStyles[sheetId] = {};
|
|
51705
|
-
}
|
|
51706
|
-
for (const table of this.getters.getTables(sheetId)) {
|
|
51707
|
-
if (!this.tableStyles[sheetId][table.id]) {
|
|
51708
|
-
this.tableStyles[sheetId][table.id] = this.computeTableStyle(sheetId, table);
|
|
51709
|
-
}
|
|
51710
|
-
}
|
|
51711
|
-
}
|
|
51712
|
-
}
|
|
51713
|
-
getCellTableStyle(position) {
|
|
51714
|
-
const table = this.getters.getTable(position);
|
|
51715
|
-
if (!table) {
|
|
51716
|
-
return undefined;
|
|
51717
|
-
}
|
|
51718
|
-
return this.tableStyles[position.sheetId][table.id]().styles[position.col]?.[position.row];
|
|
51719
|
-
}
|
|
51720
|
-
getCellTableBorder(position) {
|
|
51721
|
-
const table = this.getters.getTable(position);
|
|
51722
|
-
if (!table) {
|
|
51723
|
-
return undefined;
|
|
51724
|
-
}
|
|
51725
|
-
return this.tableStyles[position.sheetId][table.id]().borders[position.col]?.[position.row];
|
|
51726
|
-
}
|
|
51727
|
-
computeTableStyle(sheetId, table) {
|
|
51728
|
-
return lazy(() => {
|
|
51729
|
-
const { config, numberOfCols, numberOfRows } = this.getTableRuntimeConfig(sheetId, table);
|
|
51730
|
-
const relativeTableStyle = getComputedTableStyle(config, numberOfCols, numberOfRows);
|
|
51731
|
-
// Return the style with sheet coordinates instead of tables coordinates
|
|
51732
|
-
const mapping = this.getTableMapping(sheetId, table);
|
|
51733
|
-
const absoluteTableStyle = { borders: {}, styles: {} };
|
|
51734
|
-
for (let col = 0; col < numberOfCols; col++) {
|
|
51735
|
-
const colInSheet = mapping.colMapping[col];
|
|
51736
|
-
absoluteTableStyle.borders[colInSheet] = {};
|
|
51737
|
-
absoluteTableStyle.styles[colInSheet] = {};
|
|
51738
|
-
for (let row = 0; row < numberOfRows; row++) {
|
|
51739
|
-
const rowInSheet = mapping.rowMapping[row];
|
|
51740
|
-
absoluteTableStyle.borders[colInSheet][rowInSheet] = relativeTableStyle.borders[col][row];
|
|
51741
|
-
absoluteTableStyle.styles[colInSheet][rowInSheet] = relativeTableStyle.styles[col][row];
|
|
51742
|
-
}
|
|
51743
|
-
}
|
|
51744
|
-
return absoluteTableStyle;
|
|
51745
|
-
});
|
|
51746
|
-
}
|
|
51747
|
-
/**
|
|
51748
|
-
* Get the actual table config that will be used to compute the table style. It is different from
|
|
51749
|
-
* the config of the table because of hidden rows and columns in the sheet. For example remove the
|
|
51750
|
-
* hidden rows from config.numberOfHeaders.
|
|
51751
|
-
*/
|
|
51752
|
-
getTableRuntimeConfig(sheetId, table) {
|
|
51753
|
-
const tableZone = table.range.zone;
|
|
51754
|
-
const config = { ...table.config };
|
|
51755
|
-
let numberOfCols = tableZone.right - tableZone.left + 1;
|
|
51756
|
-
let numberOfRows = tableZone.bottom - tableZone.top + 1;
|
|
51757
|
-
for (let row = tableZone.top; row <= tableZone.bottom; row++) {
|
|
51758
|
-
if (!this.getters.isRowHidden(sheetId, row)) {
|
|
51759
|
-
continue;
|
|
51760
|
-
}
|
|
51761
|
-
numberOfRows--;
|
|
51762
|
-
if (row - tableZone.top < table.config.numberOfHeaders) {
|
|
51763
|
-
config.numberOfHeaders--;
|
|
51764
|
-
if (config.numberOfHeaders < 0) {
|
|
51765
|
-
config.numberOfHeaders = 0;
|
|
51766
|
-
}
|
|
51767
|
-
}
|
|
51768
|
-
if (row === tableZone.bottom) {
|
|
51769
|
-
config.totalRow = false;
|
|
51770
|
-
}
|
|
51771
|
-
}
|
|
51772
|
-
for (let col = tableZone.left; col <= tableZone.right; col++) {
|
|
51773
|
-
if (!this.getters.isColHidden(sheetId, col)) {
|
|
51774
|
-
continue;
|
|
51775
|
-
}
|
|
51776
|
-
numberOfCols--;
|
|
51777
|
-
if (col === tableZone.left) {
|
|
51778
|
-
config.firstColumn = false;
|
|
51779
|
-
}
|
|
51780
|
-
if (col === tableZone.right) {
|
|
51781
|
-
config.lastColumn = false;
|
|
51782
|
-
}
|
|
51783
|
-
}
|
|
51784
|
-
return {
|
|
51785
|
-
config,
|
|
51786
|
-
numberOfCols,
|
|
51787
|
-
numberOfRows,
|
|
51788
|
-
};
|
|
51789
|
-
}
|
|
51790
|
-
/**
|
|
51791
|
-
* Get a mapping: relative col/row position in the table <=> col/row in the sheet
|
|
51792
|
-
*/
|
|
51793
|
-
getTableMapping(sheetId, table) {
|
|
51794
|
-
const colMapping = {};
|
|
51795
|
-
const rowMapping = {};
|
|
51796
|
-
let colOffset = 0;
|
|
51797
|
-
let rowOffset = 0;
|
|
51798
|
-
const tableZone = table.range.zone;
|
|
51799
|
-
for (let col = tableZone.left; col <= tableZone.right; col++) {
|
|
51800
|
-
if (this.getters.isColHidden(sheetId, col)) {
|
|
51801
|
-
continue;
|
|
51802
|
-
}
|
|
51803
|
-
colMapping[colOffset] = col;
|
|
51804
|
-
colOffset++;
|
|
51805
|
-
for (let row = tableZone.top; row <= tableZone.bottom; row++) {
|
|
51806
|
-
if (this.getters.isRowHidden(sheetId, row)) {
|
|
51807
|
-
continue;
|
|
51808
|
-
}
|
|
51809
|
-
rowMapping[rowOffset] = row;
|
|
51810
|
-
rowOffset++;
|
|
51811
|
-
}
|
|
51812
|
-
}
|
|
51813
|
-
return {
|
|
51814
|
-
colMapping,
|
|
51815
|
-
rowMapping,
|
|
51816
|
-
};
|
|
51817
|
-
}
|
|
51818
|
-
}
|
|
51819
|
-
|
|
51820
52176
|
/**
|
|
51821
52177
|
* Clipboard Plugin
|
|
51822
52178
|
*
|
|
@@ -52526,38 +52882,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52526
52882
|
}
|
|
52527
52883
|
}
|
|
52528
52884
|
|
|
52529
|
-
const selectionStatisticFunctions = [
|
|
52530
|
-
{
|
|
52531
|
-
name: _t("Sum"),
|
|
52532
|
-
types: [CellValueType.number],
|
|
52533
|
-
compute: (values, locale) => sum([[values]], locale),
|
|
52534
|
-
},
|
|
52535
|
-
{
|
|
52536
|
-
name: _t("Avg"),
|
|
52537
|
-
types: [CellValueType.number],
|
|
52538
|
-
compute: (values, locale) => average([[values]], locale),
|
|
52539
|
-
},
|
|
52540
|
-
{
|
|
52541
|
-
name: _t("Min"),
|
|
52542
|
-
types: [CellValueType.number],
|
|
52543
|
-
compute: (values, locale) => min([[values]], locale),
|
|
52544
|
-
},
|
|
52545
|
-
{
|
|
52546
|
-
name: _t("Max"),
|
|
52547
|
-
types: [CellValueType.number],
|
|
52548
|
-
compute: (values, locale) => max([[values]], locale),
|
|
52549
|
-
},
|
|
52550
|
-
{
|
|
52551
|
-
name: _t("Count"),
|
|
52552
|
-
types: [CellValueType.number, CellValueType.text, CellValueType.boolean, CellValueType.error],
|
|
52553
|
-
compute: (values) => countAny([[values]]),
|
|
52554
|
-
},
|
|
52555
|
-
{
|
|
52556
|
-
name: _t("Count Numbers"),
|
|
52557
|
-
types: [CellValueType.number, CellValueType.text, CellValueType.boolean, CellValueType.error],
|
|
52558
|
-
compute: (values, locale) => countNumbers([[values]], locale),
|
|
52559
|
-
},
|
|
52560
|
-
];
|
|
52561
52885
|
/**
|
|
52562
52886
|
* SelectionPlugin
|
|
52563
52887
|
*/
|
|
@@ -52573,8 +52897,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52573
52897
|
"getSelectedZones",
|
|
52574
52898
|
"getSelectedZone",
|
|
52575
52899
|
"getSelectedCells",
|
|
52576
|
-
"getStatisticFnResults",
|
|
52577
|
-
"getAggregate",
|
|
52578
52900
|
"getSelectedFigureId",
|
|
52579
52901
|
"getSelection",
|
|
52580
52902
|
"getActivePosition",
|
|
@@ -52609,7 +52931,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52609
52931
|
switch (cmd.type) {
|
|
52610
52932
|
case "ACTIVATE_SHEET":
|
|
52611
52933
|
try {
|
|
52612
|
-
this.getters.getSheet(cmd.sheetIdTo);
|
|
52934
|
+
const sheet = this.getters.getSheet(cmd.sheetIdTo);
|
|
52935
|
+
if (!sheet.isVisible) {
|
|
52936
|
+
return "SheetIsHidden" /* CommandResult.SheetIsHidden */;
|
|
52937
|
+
}
|
|
52613
52938
|
break;
|
|
52614
52939
|
}
|
|
52615
52940
|
catch (error) {
|
|
@@ -52858,52 +53183,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52858
53183
|
: this.getters.getNextVisibleCellPosition({ sheetId, col: 0, row: 0 });
|
|
52859
53184
|
}
|
|
52860
53185
|
}
|
|
52861
|
-
getStatisticFnResults() {
|
|
52862
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
52863
|
-
const cells = new Set();
|
|
52864
|
-
for (const zone of this.gridSelection.zones) {
|
|
52865
|
-
for (const { col, row } of positions(zone)) {
|
|
52866
|
-
if (this.getters.isRowHidden(sheetId, row) || this.getters.isColHidden(sheetId, col)) {
|
|
52867
|
-
continue; // Skip hidden cells
|
|
52868
|
-
}
|
|
52869
|
-
const evaluatedCell = this.getters.getEvaluatedCell({ sheetId, col, row });
|
|
52870
|
-
if (evaluatedCell.type !== CellValueType.empty) {
|
|
52871
|
-
cells.add(evaluatedCell);
|
|
52872
|
-
}
|
|
52873
|
-
}
|
|
52874
|
-
}
|
|
52875
|
-
const locale = this.getters.getLocale();
|
|
52876
|
-
let statisticFnResults = {};
|
|
52877
|
-
for (let fn of selectionStatisticFunctions) {
|
|
52878
|
-
// We don't want to display statistical information when there is no interest:
|
|
52879
|
-
// We set the statistical result to undefined if the data handled by the selection
|
|
52880
|
-
// does not match the data handled by the function.
|
|
52881
|
-
// Ex: if there are only texts in the selection, we prefer that the SUM result
|
|
52882
|
-
// be displayed as undefined rather than 0.
|
|
52883
|
-
let fnResult = undefined;
|
|
52884
|
-
const evaluatedCells = [...cells].filter((c) => fn.types.includes(c.type));
|
|
52885
|
-
if (evaluatedCells.length) {
|
|
52886
|
-
fnResult = fn.compute(evaluatedCells, locale);
|
|
52887
|
-
}
|
|
52888
|
-
statisticFnResults[fn.name] = fnResult;
|
|
52889
|
-
}
|
|
52890
|
-
return statisticFnResults;
|
|
52891
|
-
}
|
|
52892
|
-
getAggregate() {
|
|
52893
|
-
let aggregate = 0;
|
|
52894
|
-
let n = 0;
|
|
52895
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
52896
|
-
const cellPositions = this.gridSelection.zones.map(positions).flat();
|
|
52897
|
-
for (const { col, row } of cellPositions) {
|
|
52898
|
-
const cell = this.getters.getEvaluatedCell({ sheetId, col, row });
|
|
52899
|
-
if (cell.type === CellValueType.number) {
|
|
52900
|
-
n++;
|
|
52901
|
-
aggregate += cell.value;
|
|
52902
|
-
}
|
|
52903
|
-
}
|
|
52904
|
-
const locale = this.getters.getLocale();
|
|
52905
|
-
return n < 2 ? null : formatValue(aggregate, { locale });
|
|
52906
|
-
}
|
|
52907
53186
|
isSelected(zone) {
|
|
52908
53187
|
return !!this.getters.getSelectedZones().find((z) => isEqual(z, zone));
|
|
52909
53188
|
}
|
|
@@ -52945,9 +53224,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52945
53224
|
// Other
|
|
52946
53225
|
// ---------------------------------------------------------------------------
|
|
52947
53226
|
activateSheet(sheetIdFrom, sheetIdTo) {
|
|
52948
|
-
if (!this.getters.isSheetVisible(sheetIdTo)) {
|
|
52949
|
-
this.dispatch("SHOW_SHEET", { sheetId: sheetIdTo });
|
|
52950
|
-
}
|
|
52951
53227
|
this.setActiveSheet(sheetIdTo);
|
|
52952
53228
|
this.sheetsData[sheetIdFrom] = {
|
|
52953
53229
|
gridSelection: deepCopy(this.gridSelection),
|
|
@@ -53954,7 +54230,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
53954
54230
|
* column of the current viewport
|
|
53955
54231
|
*/
|
|
53956
54232
|
getColDimensionsInViewport(sheetId, col) {
|
|
53957
|
-
const left =
|
|
54233
|
+
const left = largeMin(this.getters.getSheetViewVisibleCols());
|
|
53958
54234
|
const start = this.getters.getColRowOffsetInViewport("COL", left, col);
|
|
53959
54235
|
const size = this.getters.getColSize(sheetId, col);
|
|
53960
54236
|
const isColHidden = this.getters.isColHidden(sheetId, col);
|
|
@@ -53969,7 +54245,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
53969
54245
|
* of the current viewport
|
|
53970
54246
|
*/
|
|
53971
54247
|
getRowDimensionsInViewport(sheetId, row) {
|
|
53972
|
-
const top =
|
|
54248
|
+
const top = largeMin(this.getters.getSheetViewVisibleRows());
|
|
53973
54249
|
const start = this.getters.getColRowOffsetInViewport("ROW", top, row);
|
|
53974
54250
|
const size = this.getters.getRowSize(sheetId, row);
|
|
53975
54251
|
const isRowHidden = this.getters.isRowHidden(sheetId, row);
|
|
@@ -54321,6 +54597,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54321
54597
|
.add("evaluation_filter", FilterEvaluationPlugin)
|
|
54322
54598
|
.add("header_visibility_ui", HeaderVisibilityUIPlugin)
|
|
54323
54599
|
.add("table_style", TableStylePlugin)
|
|
54600
|
+
.add("cell_computed_style", CellComputedStylePlugin)
|
|
54324
54601
|
.add("header_positions", HeaderPositionsUIPlugin)
|
|
54325
54602
|
.add("viewport", SheetViewPlugin)
|
|
54326
54603
|
.add("clipboard", ClipboardPlugin);
|
|
@@ -54381,6 +54658,38 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54381
54658
|
}
|
|
54382
54659
|
}
|
|
54383
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
|
+
|
|
54384
54693
|
const RIPPLE_KEY_FRAMES = [
|
|
54385
54694
|
{ transform: "scale(0)" },
|
|
54386
54695
|
{ transform: "scale(0.8)", offset: 0.33 },
|
|
@@ -54683,12 +54992,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54683
54992
|
this.editionState = "initializing";
|
|
54684
54993
|
}
|
|
54685
54994
|
stopEdition() {
|
|
54686
|
-
|
|
54995
|
+
const input = this.sheetNameRef.el;
|
|
54996
|
+
if (!this.state.isEditing || !input)
|
|
54687
54997
|
return;
|
|
54688
54998
|
this.state.isEditing = false;
|
|
54689
54999
|
this.editionState = "initializing";
|
|
54690
|
-
|
|
55000
|
+
input.blur();
|
|
54691
55001
|
const inputValue = this.getInputContent() || "";
|
|
55002
|
+
input.innerText = inputValue;
|
|
54692
55003
|
interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
|
|
54693
55004
|
}
|
|
54694
55005
|
cancelEdition() {
|
|
@@ -54732,6 +55043,115 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54732
55043
|
}
|
|
54733
55044
|
}
|
|
54734
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
|
+
|
|
54735
55155
|
// -----------------------------------------------------------------------------
|
|
54736
55156
|
// SpreadSheet
|
|
54737
55157
|
// -----------------------------------------------------------------------------
|
|
@@ -54747,40 +55167,38 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54747
55167
|
}
|
|
54748
55168
|
`;
|
|
54749
55169
|
class BottomBarStatistic extends owl.Component {
|
|
54750
|
-
static template = "o-spreadsheet-
|
|
55170
|
+
static template = "o-spreadsheet-BottomBarStatistic";
|
|
54751
55171
|
static props = {
|
|
54752
55172
|
openContextMenu: Function,
|
|
54753
55173
|
closeContextMenu: Function,
|
|
54754
55174
|
};
|
|
54755
55175
|
static components = { Ripple };
|
|
54756
55176
|
selectedStatisticFn = "";
|
|
54757
|
-
|
|
55177
|
+
store;
|
|
54758
55178
|
setup() {
|
|
54759
|
-
this.
|
|
55179
|
+
this.store = useStore(AggregateStatisticsStore);
|
|
54760
55180
|
owl.onWillUpdateProps(() => {
|
|
54761
|
-
|
|
54762
|
-
if (!deepEquals(newStatisticFnResults, this.statisticFnResults)) {
|
|
55181
|
+
if (Object.values(this.store.statisticFnResults).every((result) => result === undefined)) {
|
|
54763
55182
|
this.props.closeContextMenu();
|
|
54764
55183
|
}
|
|
54765
|
-
this.statisticFnResults = newStatisticFnResults;
|
|
54766
55184
|
});
|
|
54767
55185
|
}
|
|
54768
55186
|
getSelectedStatistic() {
|
|
54769
55187
|
// don't display button if no function has a result
|
|
54770
|
-
if (Object.values(this.statisticFnResults).every((result) => result === undefined)) {
|
|
55188
|
+
if (Object.values(this.store.statisticFnResults).every((result) => result === undefined)) {
|
|
54771
55189
|
return undefined;
|
|
54772
55190
|
}
|
|
54773
55191
|
if (this.selectedStatisticFn === "") {
|
|
54774
|
-
this.selectedStatisticFn = Object.keys(this.statisticFnResults)[0];
|
|
55192
|
+
this.selectedStatisticFn = Object.keys(this.store.statisticFnResults)[0];
|
|
54775
55193
|
}
|
|
54776
|
-
return this.getComposedFnName(this.selectedStatisticFn
|
|
55194
|
+
return this.getComposedFnName(this.selectedStatisticFn);
|
|
54777
55195
|
}
|
|
54778
55196
|
listSelectionStatistics(ev) {
|
|
54779
55197
|
const registry = new MenuItemRegistry();
|
|
54780
55198
|
let i = 0;
|
|
54781
|
-
for (let [fnName
|
|
55199
|
+
for (let [fnName] of Object.entries(this.store.statisticFnResults)) {
|
|
54782
55200
|
registry.add(fnName, {
|
|
54783
|
-
name: this.getComposedFnName(fnName
|
|
55201
|
+
name: () => this.getComposedFnName(fnName),
|
|
54784
55202
|
sequence: i,
|
|
54785
55203
|
isReadonlyAllowed: true,
|
|
54786
55204
|
execute: () => {
|
|
@@ -54793,8 +55211,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54793
55211
|
const { top, left, width } = target.getBoundingClientRect();
|
|
54794
55212
|
this.props.openContextMenu(left + width, top, registry);
|
|
54795
55213
|
}
|
|
54796
|
-
getComposedFnName(fnName
|
|
55214
|
+
getComposedFnName(fnName) {
|
|
54797
55215
|
const locale = this.env.model.getters.getLocale();
|
|
55216
|
+
const fnValue = this.store.statisticFnResults[fnName];
|
|
54798
55217
|
return fnName + ": " + (fnValue !== undefined ? formatValue(fnValue, { locale }) : "__");
|
|
54799
55218
|
}
|
|
54800
55219
|
}
|
|
@@ -54903,10 +55322,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54903
55322
|
name: sheet.name,
|
|
54904
55323
|
sequence: i,
|
|
54905
55324
|
isReadonlyAllowed: true,
|
|
54906
|
-
textColor: sheet.isVisible ? undefined : "
|
|
55325
|
+
textColor: sheet.isVisible ? undefined : "#808080",
|
|
54907
55326
|
execute: (env) => {
|
|
55327
|
+
if (!this.env.model.getters.isSheetVisible(sheetId)) {
|
|
55328
|
+
this.env.model.dispatch("SHOW_SHEET", { sheetId });
|
|
55329
|
+
}
|
|
54908
55330
|
env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: from, sheetIdTo: sheetId });
|
|
54909
55331
|
},
|
|
55332
|
+
isEnabled: (env) => (env.model.getters.isReadonly() ? sheet.isVisible : true),
|
|
54910
55333
|
});
|
|
54911
55334
|
i++;
|
|
54912
55335
|
}
|
|
@@ -54979,7 +55402,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54979
55402
|
this.sheetListRef.el.scrollTo({ top: 0, left: scroll, behavior: "smooth" });
|
|
54980
55403
|
}
|
|
54981
55404
|
onSheetMouseDown(sheetId, event) {
|
|
54982
|
-
if (event.button !== 0)
|
|
55405
|
+
if (event.button !== 0 || this.env.model.getters.isReadonly())
|
|
54983
55406
|
return;
|
|
54984
55407
|
this.closeMenu();
|
|
54985
55408
|
const visibleSheets = this.getVisibleSheets();
|
|
@@ -55015,7 +55438,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55015
55438
|
.map((sheetEl) => sheetEl.getBoundingClientRect())
|
|
55016
55439
|
.map((rect) => ({
|
|
55017
55440
|
x: rect.x,
|
|
55018
|
-
width: rect.width - 1,
|
|
55441
|
+
width: rect.width - 1, // -1 to compensate negative margin
|
|
55019
55442
|
y: rect.y,
|
|
55020
55443
|
height: rect.height,
|
|
55021
55444
|
}));
|
|
@@ -55242,7 +55665,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55242
55665
|
}
|
|
55243
55666
|
return cssPropertiesToCss({
|
|
55244
55667
|
top: `${groupBox.headerRect.height / 2}px`,
|
|
55245
|
-
left: `calc(50% - 1px)`,
|
|
55668
|
+
left: `calc(50% - 1px)`, // -1px: we want the border to be on the center
|
|
55246
55669
|
width: `30%`,
|
|
55247
55670
|
height: `calc(100% - ${groupBox.headerRect.height / 2}px)`,
|
|
55248
55671
|
"border-left": `1px solid ${HEADER_GROUPING_BORDER_COLOR}`,
|
|
@@ -55294,7 +55717,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55294
55717
|
return "";
|
|
55295
55718
|
}
|
|
55296
55719
|
return cssPropertiesToCss({
|
|
55297
|
-
top: `calc(50% - 1px)`,
|
|
55720
|
+
top: `calc(50% - 1px)`, // -1px: we want the border to be on the center
|
|
55298
55721
|
left: `${groupBox.headerRect.width / 2}px`,
|
|
55299
55722
|
width: `calc(100% - ${groupBox.headerRect.width / 2}px)`,
|
|
55300
55723
|
height: `30%`,
|
|
@@ -56385,7 +56808,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56385
56808
|
}
|
|
56386
56809
|
.o-disabled {
|
|
56387
56810
|
opacity: 0.4;
|
|
56388
|
-
|
|
56811
|
+
cursor: default;
|
|
56389
56812
|
pointer-events: none;
|
|
56390
56813
|
}
|
|
56391
56814
|
|
|
@@ -56551,7 +56974,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56551
56974
|
|
|
56552
56975
|
.o-number-input {
|
|
56553
56976
|
/* Remove number input arrows */
|
|
56554
|
-
|
|
56977
|
+
appearance: textfield;
|
|
56555
56978
|
&::-webkit-outer-spin-button,
|
|
56556
56979
|
&::-webkit-inner-spin-button {
|
|
56557
56980
|
-webkit-appearance: none;
|
|
@@ -56594,6 +57017,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56594
57017
|
this.notificationStore = useStore(NotificationStore);
|
|
56595
57018
|
this.composerFocusStore = useStore(ComposerFocusStore);
|
|
56596
57019
|
this.sidePanel = useStore(SidePanelStore);
|
|
57020
|
+
useStore(ArrayFormulaHighlight);
|
|
56597
57021
|
this.keyDownMapping = {
|
|
56598
57022
|
"CTRL+H": () => this.sidePanel.toggle("FindAndReplace", {}),
|
|
56599
57023
|
"CTRL+F": () => this.sidePanel.toggle("FindAndReplace", {}),
|
|
@@ -56696,7 +57120,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56696
57120
|
const gridColSize = GROUP_LAYER_WIDTH * this.rowLayers.length;
|
|
56697
57121
|
const gridRowSize = GROUP_LAYER_WIDTH * this.colLayers.length;
|
|
56698
57122
|
return cssPropertiesToCss({
|
|
56699
|
-
"grid-template-columns": `${gridColSize ? gridColSize + 2 : 0}px auto`,
|
|
57123
|
+
"grid-template-columns": `${gridColSize ? gridColSize + 2 : 0}px auto`, // +2: margins
|
|
56700
57124
|
"grid-template-rows": `${gridRowSize ? gridRowSize + 2 : 0}px auto`,
|
|
56701
57125
|
});
|
|
56702
57126
|
}
|
|
@@ -57428,14 +57852,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57428
57852
|
this.revertBefore(operationId);
|
|
57429
57853
|
this.tree.drop(operationId);
|
|
57430
57854
|
}
|
|
57431
|
-
getRevertedExecution() {
|
|
57432
|
-
const data = [];
|
|
57433
|
-
const operations = this.tree.revertedExecution(this.HEAD_BRANCH);
|
|
57434
|
-
for (const { operation } of operations) {
|
|
57435
|
-
data.push(operation.data);
|
|
57436
|
-
}
|
|
57437
|
-
return data;
|
|
57438
|
-
}
|
|
57439
57855
|
/**
|
|
57440
57856
|
* Revert the state as it was *before* the given operation was executed.
|
|
57441
57857
|
*/
|
|
@@ -58224,6 +58640,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58224
58640
|
case "bar":
|
|
58225
58641
|
plot = addBarChart(chart.data);
|
|
58226
58642
|
break;
|
|
58643
|
+
case "combo":
|
|
58644
|
+
plot = addComboChart(chart.data);
|
|
58645
|
+
break;
|
|
58227
58646
|
case "line":
|
|
58228
58647
|
plot = addLineChart(chart.data);
|
|
58229
58648
|
break;
|
|
@@ -58386,6 +58805,79 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58386
58805
|
${addAx(axisPos, "c:valAx", valAxId, catAxId, { fontColor: chart.fontColor })}
|
|
58387
58806
|
`;
|
|
58388
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
|
+
}
|
|
58389
58881
|
function addLineChart(chart) {
|
|
58390
58882
|
const colors = new ChartColors();
|
|
58391
58883
|
const dataSetsNodes = [];
|
|
@@ -58433,7 +58925,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58433
58925
|
}
|
|
58434
58926
|
function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
|
|
58435
58927
|
const colors = new ChartColors();
|
|
58436
|
-
const maxLength =
|
|
58928
|
+
const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
|
|
58437
58929
|
const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
|
|
58438
58930
|
const dataSetsNodes = [];
|
|
58439
58931
|
for (const [dsIndex, dataset] of Object.entries(chart.dataSets).reverse()) {
|
|
@@ -59311,7 +59803,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
59311
59803
|
const colHeaderXc = toXC(tableZone.left + i, tableZone.top);
|
|
59312
59804
|
const colName = sheetData.cells[colHeaderXc]?.content || `col${i}`;
|
|
59313
59805
|
const colAttributes = [
|
|
59314
|
-
["id", i + 1],
|
|
59806
|
+
["id", i + 1], // id cannot be 0
|
|
59315
59807
|
["name", colName],
|
|
59316
59808
|
];
|
|
59317
59809
|
columns.push(escapeXml /*xml*/ `<tableColumn ${formatAttributes(colAttributes)}/>`);
|
|
@@ -59527,6 +60019,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
59527
60019
|
* https://www.ecma-international.org/publications-and-standards/standards/ecma-376/
|
|
59528
60020
|
*/
|
|
59529
60021
|
function getXLSX(data) {
|
|
60022
|
+
data = fixLengthySheetNames(data);
|
|
59530
60023
|
const files = [];
|
|
59531
60024
|
const construct = getDefaultXLSXStructure();
|
|
59532
60025
|
files.push(createWorkbook(data, construct));
|
|
@@ -59774,6 +60267,40 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
59774
60267
|
`;
|
|
59775
60268
|
return createXMLFile(parseXML(xml), "_rels/.rels");
|
|
59776
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
|
+
}
|
|
59777
60304
|
|
|
59778
60305
|
var Status;
|
|
59779
60306
|
(function (Status) {
|
|
@@ -60463,9 +60990,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60463
60990
|
exports.tokenize = tokenize;
|
|
60464
60991
|
|
|
60465
60992
|
|
|
60466
|
-
__info__.version = "17.3.0-alpha.
|
|
60467
|
-
__info__.date = "2024-
|
|
60468
|
-
__info__.hash = "
|
|
60993
|
+
__info__.version = "17.3.0-alpha.2";
|
|
60994
|
+
__info__.date = "2024-04-05T14:01:07.060Z";
|
|
60995
|
+
__info__.hash = "8c5a229";
|
|
60469
60996
|
|
|
60470
60997
|
|
|
60471
60998
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|