@odoo/o-spreadsheet 19.0.10 → 19.0.12
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 +344 -220
- package/dist/o-spreadsheet.d.ts +47 -14
- package/dist/o-spreadsheet.esm.js +344 -220
- package/dist/o-spreadsheet.iife.js +344 -220
- package/dist/o-spreadsheet.iife.min.js +432 -432
- package/dist/o_spreadsheet.xml +50 -10
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 19.0.
|
|
6
|
-
* @date 2025-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 19.0.12
|
|
6
|
+
* @date 2025-12-02T05:34:17.495Z
|
|
7
|
+
* @hash 32203f1
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -183,7 +183,6 @@ const invalidateEvaluationCommands = new Set([
|
|
|
183
183
|
"REDO",
|
|
184
184
|
"ADD_MERGE",
|
|
185
185
|
"REMOVE_MERGE",
|
|
186
|
-
"DUPLICATE_SHEET",
|
|
187
186
|
"UPDATE_LOCALE",
|
|
188
187
|
"ADD_PIVOT",
|
|
189
188
|
"UPDATE_PIVOT",
|
|
@@ -864,7 +863,7 @@ const PIVOT_TABLE_CONFIG = {
|
|
|
864
863
|
};
|
|
865
864
|
const PIVOT_INDENT = 15;
|
|
866
865
|
const PIVOT_COLLAPSE_ICON_SIZE = 12;
|
|
867
|
-
const PIVOT_MAX_NUMBER_OF_CELLS =
|
|
866
|
+
const PIVOT_MAX_NUMBER_OF_CELLS = 5e5;
|
|
868
867
|
const DEFAULT_CURRENCY = {
|
|
869
868
|
symbol: "$",
|
|
870
869
|
position: "before",
|
|
@@ -13350,7 +13349,7 @@ const SUBTOTAL = {
|
|
|
13350
13349
|
if (!acceptHiddenCells && this.getters.isRowHiddenByUser(sheetId, row))
|
|
13351
13350
|
continue;
|
|
13352
13351
|
for (let col = left; col <= right; col++) {
|
|
13353
|
-
const cell = this.getters.
|
|
13352
|
+
const cell = this.getters.getCorrespondingFormulaCell({ sheetId, col, row });
|
|
13354
13353
|
if (!cell || !isSubtotalCell(cell)) {
|
|
13355
13354
|
evaluatedCellToKeep.push(this.getters.getEvaluatedCell({ sheetId, col, row }));
|
|
13356
13355
|
}
|
|
@@ -19346,7 +19345,7 @@ function getTokenNextReferenceType(xc) {
|
|
|
19346
19345
|
function setXcToFixedReferenceType(xc, referenceType) {
|
|
19347
19346
|
let sheetName;
|
|
19348
19347
|
({ sheetName, xc } = splitReference(xc));
|
|
19349
|
-
sheetName = sheetName ? sheetName + "!" : "";
|
|
19348
|
+
sheetName = sheetName ? getCanonicalSymbolName(sheetName) + "!" : "";
|
|
19350
19349
|
xc = xc.replace(/\$/g, "");
|
|
19351
19350
|
const splitIndex = xc.indexOf(":");
|
|
19352
19351
|
if (splitIndex >= 0) {
|
|
@@ -23879,6 +23878,9 @@ function getTreeMapGroupColors(definition, tree) {
|
|
|
23879
23878
|
}));
|
|
23880
23879
|
}
|
|
23881
23880
|
function getTreeMapColorScale(tree, coloringOption) {
|
|
23881
|
+
if (tree.length === 0) {
|
|
23882
|
+
return undefined;
|
|
23883
|
+
}
|
|
23882
23884
|
const treeNodesByLevel = pyramidizeTree(tree);
|
|
23883
23885
|
const nodes = treeNodesByLevel[treeNodesByLevel.length - 1];
|
|
23884
23886
|
const minValue = Math.min(...nodes.map((node) => node.value));
|
|
@@ -25564,11 +25566,18 @@ function chartToImageUrl(runtime, figure, type) {
|
|
|
25564
25566
|
// we have to add the canvas to the DOM otherwise it won't be rendered
|
|
25565
25567
|
document.body.append(div);
|
|
25566
25568
|
if ("chartJsConfig" in runtime) {
|
|
25569
|
+
const extensionsLoaded = areChartJSExtensionsLoaded();
|
|
25570
|
+
if (!extensionsLoaded) {
|
|
25571
|
+
registerChartJSExtensions();
|
|
25572
|
+
}
|
|
25567
25573
|
const config = deepCopy(runtime.chartJsConfig);
|
|
25568
25574
|
config.plugins = [backgroundColorChartJSPlugin];
|
|
25569
25575
|
const chart = new window.Chart(canvas, config);
|
|
25570
25576
|
imageContent = chart.toBase64Image();
|
|
25571
25577
|
chart.destroy();
|
|
25578
|
+
if (!extensionsLoaded) {
|
|
25579
|
+
unregisterChartJsExtensions();
|
|
25580
|
+
}
|
|
25572
25581
|
}
|
|
25573
25582
|
else if (type === "scorecard") {
|
|
25574
25583
|
const design = getScorecardConfiguration(figure, runtime);
|
|
@@ -25598,11 +25607,18 @@ async function chartToImageFile(runtime, figure, type) {
|
|
|
25598
25607
|
document.body.append(div);
|
|
25599
25608
|
let chartBlob = null;
|
|
25600
25609
|
if ("chartJsConfig" in runtime) {
|
|
25610
|
+
const extensionsLoaded = areChartJSExtensionsLoaded();
|
|
25611
|
+
if (!extensionsLoaded) {
|
|
25612
|
+
registerChartJSExtensions();
|
|
25613
|
+
}
|
|
25601
25614
|
const config = deepCopy(runtime.chartJsConfig);
|
|
25602
25615
|
config.plugins = [backgroundColorChartJSPlugin];
|
|
25603
25616
|
const chart = new window.Chart(canvas, config);
|
|
25604
25617
|
chartBlob = await new Promise((resolve) => canvas.toBlob(resolve, "image/png"));
|
|
25605
25618
|
chart.destroy();
|
|
25619
|
+
if (!extensionsLoaded) {
|
|
25620
|
+
unregisterChartJsExtensions();
|
|
25621
|
+
}
|
|
25606
25622
|
}
|
|
25607
25623
|
else if (type === "scorecard") {
|
|
25608
25624
|
const design = getScorecardConfiguration(figure, runtime);
|
|
@@ -27728,29 +27744,19 @@ class ZoomableChartStore extends SpreadsheetStore {
|
|
|
27728
27744
|
}
|
|
27729
27745
|
resetAxisLimits(chartId, limits) {
|
|
27730
27746
|
for (const axisId of ZOOMABLE_AXIS_IDS) {
|
|
27731
|
-
if (limits
|
|
27732
|
-
|
|
27733
|
-
this.originalAxisLimits[chartId]
|
|
27734
|
-
|
|
27735
|
-
|
|
27736
|
-
};
|
|
27737
|
-
}
|
|
27738
|
-
this.originalAxisLimits[chartId][axisId]["min"] = limits[axisId].min;
|
|
27739
|
-
this.originalAxisLimits[chartId][axisId]["max"] = limits[axisId].max;
|
|
27747
|
+
if (limits[axisId]) {
|
|
27748
|
+
this.originalAxisLimits[chartId] = {
|
|
27749
|
+
...this.originalAxisLimits[chartId],
|
|
27750
|
+
[axisId]: { ...limits[axisId] },
|
|
27751
|
+
};
|
|
27740
27752
|
}
|
|
27741
|
-
else {
|
|
27742
|
-
|
|
27743
|
-
delete this.originalAxisLimits[chartId][axisId];
|
|
27744
|
-
}
|
|
27753
|
+
else if (this.originalAxisLimits[chartId]?.[axisId]) {
|
|
27754
|
+
delete this.originalAxisLimits[chartId][axisId];
|
|
27745
27755
|
}
|
|
27746
27756
|
}
|
|
27747
27757
|
return "noStateChange";
|
|
27748
27758
|
}
|
|
27749
27759
|
updateAxisLimits(chartId, limits) {
|
|
27750
|
-
if (limits === undefined) {
|
|
27751
|
-
delete this.currentAxesLimits[chartId];
|
|
27752
|
-
return "noStateChange";
|
|
27753
|
-
}
|
|
27754
27760
|
let { min, max } = limits;
|
|
27755
27761
|
if (min > max) {
|
|
27756
27762
|
[min, max] = [max, min];
|
|
@@ -27766,26 +27772,14 @@ class ZoomableChartStore extends SpreadsheetStore {
|
|
|
27766
27772
|
* for the current trend line axes.
|
|
27767
27773
|
*/
|
|
27768
27774
|
updateTrendLineConfiguration(chartId) {
|
|
27769
|
-
if (!this.originalAxisLimits[chartId]) {
|
|
27775
|
+
if (!this.originalAxisLimits[chartId]?.x || !this.currentAxesLimits[chartId]?.x) {
|
|
27770
27776
|
return "noStateChange";
|
|
27771
27777
|
}
|
|
27772
27778
|
const chartLimits = this.originalAxisLimits[chartId].x;
|
|
27773
|
-
if (chartLimits === undefined) {
|
|
27774
|
-
return "noStateChange";
|
|
27775
|
-
}
|
|
27776
27779
|
for (const axisId of TREND_LINE_AXES_IDS) {
|
|
27777
27780
|
if (!this.originalAxisLimits[chartId][axisId]) {
|
|
27778
27781
|
continue;
|
|
27779
27782
|
}
|
|
27780
|
-
if (!this.currentAxesLimits[chartId]?.[axisId]) {
|
|
27781
|
-
this.currentAxesLimits[chartId] = {
|
|
27782
|
-
...this.currentAxesLimits[chartId],
|
|
27783
|
-
[axisId]: {},
|
|
27784
|
-
};
|
|
27785
|
-
}
|
|
27786
|
-
if (this.currentAxesLimits[chartId]?.x === undefined) {
|
|
27787
|
-
return "noStateChange";
|
|
27788
|
-
}
|
|
27789
27783
|
const realRange = chartLimits.max - chartLimits.min;
|
|
27790
27784
|
const trendingLimits = this.originalAxisLimits[chartId][axisId];
|
|
27791
27785
|
const trendingRange = trendingLimits.max - trendingLimits.min;
|
|
@@ -27793,8 +27787,10 @@ class ZoomableChartStore extends SpreadsheetStore {
|
|
|
27793
27787
|
const intercept = trendingLimits.min - chartLimits.min * slope;
|
|
27794
27788
|
const newXMin = this.currentAxesLimits[chartId].x.min;
|
|
27795
27789
|
const newXMax = this.currentAxesLimits[chartId].x.max;
|
|
27796
|
-
this.currentAxesLimits[chartId][axisId]
|
|
27797
|
-
|
|
27790
|
+
this.currentAxesLimits[chartId][axisId] = {
|
|
27791
|
+
min: newXMin * slope + intercept,
|
|
27792
|
+
max: newXMax * slope + intercept,
|
|
27793
|
+
};
|
|
27798
27794
|
}
|
|
27799
27795
|
return "noStateChange";
|
|
27800
27796
|
}
|
|
@@ -27863,8 +27859,9 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
27863
27859
|
hasLinearScale;
|
|
27864
27860
|
isBarChart;
|
|
27865
27861
|
chartId = "";
|
|
27866
|
-
datasetBoundaries = {
|
|
27862
|
+
datasetBoundaries = { min: 0, max: 0 };
|
|
27867
27863
|
removeEventListeners = () => { };
|
|
27864
|
+
isMasterChartAllowed = false;
|
|
27868
27865
|
setup() {
|
|
27869
27866
|
this.store = useStore(ZoomableChartStore);
|
|
27870
27867
|
super.setup();
|
|
@@ -27880,12 +27877,19 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
27880
27877
|
height:${height};
|
|
27881
27878
|
`;
|
|
27882
27879
|
}
|
|
27880
|
+
get masterChartContainerStyle() {
|
|
27881
|
+
const runtime = this.env.model.getters.getChartRuntime(this.props.chartId);
|
|
27882
|
+
if (runtime && !runtime.chartJsConfig.data.datasets.some((ds) => ds.data.length > 1)) {
|
|
27883
|
+
return "opacity: 0.3;";
|
|
27884
|
+
}
|
|
27885
|
+
return "";
|
|
27886
|
+
}
|
|
27883
27887
|
get sliceable() {
|
|
27884
27888
|
if (this.props.isFullScreen) {
|
|
27885
27889
|
return true;
|
|
27886
27890
|
}
|
|
27887
27891
|
const definition = this.env.model.getters.getChartDefinition(this.props.chartId);
|
|
27888
|
-
return ("zoomable" in definition && definition
|
|
27892
|
+
return ("zoomable" in definition && definition.zoomable) ?? false;
|
|
27889
27893
|
}
|
|
27890
27894
|
get axisOffset() {
|
|
27891
27895
|
return !this.hasLinearScale && this.isBarChart ? 0.5 : 0;
|
|
@@ -27910,15 +27914,13 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
27910
27914
|
if (!this.sliceable) {
|
|
27911
27915
|
return chartData;
|
|
27912
27916
|
}
|
|
27913
|
-
|
|
27914
|
-
const
|
|
27915
|
-
|
|
27916
|
-
|
|
27917
|
-
|
|
27918
|
-
|
|
27919
|
-
|
|
27920
|
-
if (xAxis?.max !== undefined) {
|
|
27921
|
-
xScale.max = this.hasLinearScale ? xAxis.max : Math.floor(xAxis.max) - this.axisOffset;
|
|
27917
|
+
let x = chartData.options.scales.x;
|
|
27918
|
+
const limits = this.store.currentAxesLimits[this.chartId]?.x;
|
|
27919
|
+
if (limits) {
|
|
27920
|
+
x = {
|
|
27921
|
+
...x,
|
|
27922
|
+
...this.getStoredBoundaries(),
|
|
27923
|
+
};
|
|
27922
27924
|
}
|
|
27923
27925
|
return {
|
|
27924
27926
|
...chartData,
|
|
@@ -27926,7 +27928,7 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
27926
27928
|
...chartData.options,
|
|
27927
27929
|
scales: {
|
|
27928
27930
|
...chartData.options.scales,
|
|
27929
|
-
x
|
|
27931
|
+
x,
|
|
27930
27932
|
},
|
|
27931
27933
|
layout: {
|
|
27932
27934
|
...chartData.options.layout,
|
|
@@ -27941,9 +27943,19 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
27941
27943
|
getAxisLimitsFromDataset(chartData) {
|
|
27942
27944
|
const data = chartData.data.datasets.map((ds) => ds.data).flat();
|
|
27943
27945
|
const xValues = data.map((d, i) => (typeof d === "object" && d !== null ? d.x : i));
|
|
27944
|
-
const
|
|
27945
|
-
const
|
|
27946
|
-
return {
|
|
27946
|
+
const min = Math.min(...xValues);
|
|
27947
|
+
const max = Math.max(...xValues);
|
|
27948
|
+
return { min, max };
|
|
27949
|
+
}
|
|
27950
|
+
setMasterChartCursor(runtime) {
|
|
27951
|
+
const masterElement = this.masterChartCanvas?.el;
|
|
27952
|
+
if (runtime && !runtime.chartJsConfig.data.datasets.some((ds) => ds.data.length > 1)) {
|
|
27953
|
+
masterElement.style.cursor = "not-allowed";
|
|
27954
|
+
this.isMasterChartAllowed = false;
|
|
27955
|
+
return;
|
|
27956
|
+
}
|
|
27957
|
+
masterElement.style.cursor = "default";
|
|
27958
|
+
this.isMasterChartAllowed = true;
|
|
27947
27959
|
}
|
|
27948
27960
|
createChart(chartRuntime) {
|
|
27949
27961
|
const chartData = chartRuntime.chartJsConfig;
|
|
@@ -27955,12 +27967,14 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
27955
27967
|
chartRuntime.chartJsConfig = updatedData;
|
|
27956
27968
|
}
|
|
27957
27969
|
super.createChart(chartRuntime);
|
|
27958
|
-
this.hasLinearScale = this.chart?.scales?.x
|
|
27970
|
+
this.hasLinearScale = this.chart?.scales?.x?.type === "linear";
|
|
27959
27971
|
if (!this.sliceable || !("masterChartConfig" in chartRuntime)) {
|
|
27972
|
+
this.isMasterChartAllowed = false;
|
|
27960
27973
|
return;
|
|
27961
27974
|
}
|
|
27962
27975
|
this.masterChart?.destroy();
|
|
27963
|
-
const masterChartCtx = this.masterChartCanvas
|
|
27976
|
+
const masterChartCtx = (this.masterChartCanvas?.el).getContext("2d");
|
|
27977
|
+
this.setMasterChartCursor(chartRuntime);
|
|
27964
27978
|
this.masterChart = new window.Chart(masterChartCtx, this.getMasterChartConfiguration(chartRuntime["masterChartConfig"]));
|
|
27965
27979
|
this.resetAxesLimits();
|
|
27966
27980
|
if (this.chart?.options) {
|
|
@@ -27969,11 +27983,10 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
27969
27983
|
}
|
|
27970
27984
|
updateChartJs(chartRuntime) {
|
|
27971
27985
|
const chartData = chartRuntime.chartJsConfig;
|
|
27972
|
-
const
|
|
27973
|
-
if (this.datasetBoundaries.
|
|
27974
|
-
this.datasetBoundaries.xMax !== newDatasetBoundaries.xMax) {
|
|
27986
|
+
const { min, max } = this.getAxisLimitsFromDataset(chartData);
|
|
27987
|
+
if (this.datasetBoundaries.min !== min || this.datasetBoundaries.max !== max) {
|
|
27975
27988
|
this.store.clearAxisLimits(this.chartId);
|
|
27976
|
-
this.datasetBoundaries =
|
|
27989
|
+
this.datasetBoundaries = { min, max };
|
|
27977
27990
|
}
|
|
27978
27991
|
this.isBarChart = chartData?.type === "bar";
|
|
27979
27992
|
this.chartId = `${chartData.type}-${this.props.chartId}`;
|
|
@@ -27982,9 +27995,10 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
27982
27995
|
chartRuntime.chartJsConfig = updatedData;
|
|
27983
27996
|
}
|
|
27984
27997
|
super.updateChartJs(chartRuntime);
|
|
27985
|
-
this.hasLinearScale = this.chart?.scales?.x
|
|
27998
|
+
this.hasLinearScale = this.chart?.scales?.x?.type === "linear";
|
|
27986
27999
|
if (!this.sliceable || !("masterChartConfig" in chartRuntime)) {
|
|
27987
28000
|
this.masterChart = undefined;
|
|
28001
|
+
this.isMasterChartAllowed = false;
|
|
27988
28002
|
}
|
|
27989
28003
|
else {
|
|
27990
28004
|
const masterChartConfig = this.getMasterChartConfiguration(chartRuntime["masterChartConfig"]);
|
|
@@ -27997,6 +28011,7 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
27997
28011
|
this.masterChart.config.options = masterChartConfig.options;
|
|
27998
28012
|
this.masterChart.update();
|
|
27999
28013
|
}
|
|
28014
|
+
this.setMasterChartCursor(chartRuntime);
|
|
28000
28015
|
}
|
|
28001
28016
|
this.resetAxesLimits();
|
|
28002
28017
|
if (this.chart?.options) {
|
|
@@ -28007,18 +28022,15 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
28007
28022
|
if (!this.chart) {
|
|
28008
28023
|
return;
|
|
28009
28024
|
}
|
|
28010
|
-
const
|
|
28011
|
-
if (
|
|
28025
|
+
const storedLimits = this.store.originalAxisLimits[this.chartId]?.x;
|
|
28026
|
+
if (!storedLimits) {
|
|
28012
28027
|
let scales = this.masterChart
|
|
28013
28028
|
? this.masterChart.scales
|
|
28014
28029
|
: this.chart.scales;
|
|
28015
|
-
if (!this.hasLinearScale && scales
|
|
28030
|
+
if (!this.hasLinearScale && scales.x) {
|
|
28016
28031
|
scales = {
|
|
28017
28032
|
...scales,
|
|
28018
|
-
x:
|
|
28019
|
-
min: Math.ceil(scales.x.min) - this.axisOffset,
|
|
28020
|
-
max: Math.floor(scales.x.max) + this.axisOffset,
|
|
28021
|
-
},
|
|
28033
|
+
x: this.adjustBoundaries(scales.x),
|
|
28022
28034
|
};
|
|
28023
28035
|
}
|
|
28024
28036
|
this.store.resetAxisLimits(this.chartId, scales);
|
|
@@ -28033,13 +28045,13 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
28033
28045
|
}
|
|
28034
28046
|
updateTrendingLineAxes() {
|
|
28035
28047
|
this.store.updateTrendLineConfiguration(this.chartId);
|
|
28036
|
-
const
|
|
28048
|
+
const limits = this.store.currentAxesLimits[this.chartId];
|
|
28037
28049
|
for (const axisId of [TREND_LINE_XAXIS_ID, MOVING_AVERAGE_TREND_LINE_XAXIS_ID]) {
|
|
28038
|
-
if (!this.chart?.config
|
|
28050
|
+
if (!this.chart?.config?.options?.scales?.[axisId] || !limits?.[axisId]) {
|
|
28039
28051
|
continue;
|
|
28040
28052
|
}
|
|
28041
|
-
this.chart.config.options.scales[axisId].min =
|
|
28042
|
-
this.chart.config.options.scales[axisId].max =
|
|
28053
|
+
this.chart.config.options.scales[axisId].min = limits[axisId].min;
|
|
28054
|
+
this.chart.config.options.scales[axisId].max = limits[axisId].max;
|
|
28043
28055
|
}
|
|
28044
28056
|
}
|
|
28045
28057
|
get upperBound() {
|
|
@@ -28082,29 +28094,71 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
28082
28094
|
offset +
|
|
28083
28095
|
((scale.max + 2 * offset - scale.min) * (position - left)) / (right - left));
|
|
28084
28096
|
}
|
|
28085
|
-
|
|
28097
|
+
/**
|
|
28098
|
+
* Compute min and max from the store, adjusting them if needed for non linear scales.
|
|
28099
|
+
* Getting the value from the store, we have to ensure that the values are integers for
|
|
28100
|
+
* non linear scales (bar and category). To select a bar in the chart, we have to include
|
|
28101
|
+
* the whole bar, which means that for the i-th bar, the selected min should be <= i and
|
|
28102
|
+
* the selected max should be >= i, so using the Math.floor and Math.ceil functions is
|
|
28103
|
+
* the right way to do it.
|
|
28104
|
+
* Sometimes, we can get a minimal value > the maximal value, which arise when the user
|
|
28105
|
+
* select a very small area in the master chart, and hasn't selected the middle of a bar
|
|
28106
|
+
* or a group of bars (in case of more than one data series).
|
|
28107
|
+
* Assuming we have to select the middle of a bar/a groupe of bars, we will reject the
|
|
28108
|
+
* coming value afterward. In this case, we do not update the chart because it would lead
|
|
28109
|
+
* to an empty chart.
|
|
28110
|
+
*/
|
|
28111
|
+
getStoredBoundaries() {
|
|
28112
|
+
let { min, max } = this.store.currentAxesLimits[this.chartId].x;
|
|
28086
28113
|
if (!this.hasLinearScale) {
|
|
28087
|
-
|
|
28088
|
-
|
|
28114
|
+
min = Math.ceil(min);
|
|
28115
|
+
max = Math.floor(max);
|
|
28089
28116
|
}
|
|
28090
|
-
|
|
28091
|
-
|
|
28092
|
-
|
|
28117
|
+
return { min, max };
|
|
28118
|
+
}
|
|
28119
|
+
/**
|
|
28120
|
+
* Adjust the min and max values of an axis if needed for non linear scales.
|
|
28121
|
+
* Here, after rounding (see docstring of getStoredBoundaries), we adjust the min by
|
|
28122
|
+
* substracting the axis offset, and we add it to the max, because when computing from the
|
|
28123
|
+
* scale, chartJs use integer values as the limits for non linear scales. If we have a min
|
|
28124
|
+
* value of 1, it means we want to start displaying from 0.5, and if we have a max value of
|
|
28125
|
+
* 4, it means we want to display until 4.5.
|
|
28126
|
+
* Here, we don't have to check if min > max because we are computing from the scale, and
|
|
28127
|
+
* chartJs ensures that this won't happen, even after our adjustments.
|
|
28128
|
+
*/
|
|
28129
|
+
adjustBoundaries({ min, max }) {
|
|
28130
|
+
if (!this.hasLinearScale) {
|
|
28131
|
+
min = Math.ceil(min) - this.axisOffset;
|
|
28132
|
+
max = Math.floor(max) + this.axisOffset;
|
|
28133
|
+
}
|
|
28134
|
+
return { min, max };
|
|
28135
|
+
}
|
|
28136
|
+
updateAxisLimits(xMin, xMax) {
|
|
28137
|
+
if (xMin === xMax) {
|
|
28138
|
+
return;
|
|
28139
|
+
}
|
|
28140
|
+
if (!this.chart) {
|
|
28141
|
+
return;
|
|
28093
28142
|
}
|
|
28094
28143
|
this.store.updateAxisLimits(this.chartId, { min: xMin, max: xMax });
|
|
28095
|
-
this.
|
|
28144
|
+
const { min, max } = this.getStoredBoundaries();
|
|
28145
|
+
if (max > min || (this.isBarChart && max === min)) {
|
|
28146
|
+
this.chart.config.options.scales.x.min = min;
|
|
28147
|
+
this.chart.config.options.scales.x.max = max;
|
|
28148
|
+
this.updateTrendingLineAxes();
|
|
28149
|
+
this.chart.update();
|
|
28150
|
+
}
|
|
28096
28151
|
this.masterChart?.update();
|
|
28097
|
-
this.chart?.update();
|
|
28098
28152
|
}
|
|
28099
|
-
|
|
28153
|
+
onMasterChartPointerDown(ev) {
|
|
28100
28154
|
this.removeEventListeners();
|
|
28101
28155
|
const position = ev.offsetX;
|
|
28102
28156
|
if (!this.masterChart?.chartArea || !this.chart?.scales?.x) {
|
|
28103
28157
|
return;
|
|
28104
28158
|
}
|
|
28105
28159
|
const { left, right, top, bottom } = this.masterChart.chartArea;
|
|
28106
|
-
const
|
|
28107
|
-
const
|
|
28160
|
+
const upperBound = this.upperBound ?? right;
|
|
28161
|
+
const lowerBound = this.lowerBound ?? left;
|
|
28108
28162
|
if (position < left - 5 || position > right + 5 || ev.offsetY < top || ev.offsetY > bottom) {
|
|
28109
28163
|
return;
|
|
28110
28164
|
}
|
|
@@ -28112,8 +28166,10 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
28112
28166
|
ev.stopPropagation();
|
|
28113
28167
|
let startingPositionOnChart, windowSize, startX;
|
|
28114
28168
|
const startingEventPosition = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
|
|
28115
|
-
if ((
|
|
28116
|
-
|
|
28169
|
+
if ((lowerBound !== left || upperBound !== right) &&
|
|
28170
|
+
position > lowerBound + 5 &&
|
|
28171
|
+
position < upperBound - 5) {
|
|
28172
|
+
startingPositionOnChart = ev.offsetX - lowerBound;
|
|
28117
28173
|
this.mode = "moveInMaster";
|
|
28118
28174
|
const currentLimits = this.store.currentAxesLimits[this.chartId]?.x;
|
|
28119
28175
|
windowSize =
|
|
@@ -28122,31 +28178,29 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
28122
28178
|
}
|
|
28123
28179
|
else {
|
|
28124
28180
|
this.mode = "selectInMaster";
|
|
28125
|
-
if (Math.abs(position -
|
|
28126
|
-
startingPositionOnChart =
|
|
28181
|
+
if (Math.abs(position - lowerBound) < 5) {
|
|
28182
|
+
startingPositionOnChart = upperBound;
|
|
28127
28183
|
}
|
|
28128
|
-
else if (Math.abs(position -
|
|
28129
|
-
startingPositionOnChart =
|
|
28184
|
+
else if (Math.abs(position - upperBound) < 5) {
|
|
28185
|
+
startingPositionOnChart = lowerBound;
|
|
28130
28186
|
}
|
|
28131
28187
|
else {
|
|
28132
28188
|
startingPositionOnChart = clip(position, left, right);
|
|
28133
28189
|
}
|
|
28134
28190
|
startX = this.computeCoordinate(startingPositionOnChart);
|
|
28135
28191
|
}
|
|
28136
|
-
const
|
|
28137
|
-
const
|
|
28192
|
+
const storedMin = this.store.originalAxisLimits[this.chartId].x.min;
|
|
28193
|
+
const storedMax = this.store.originalAxisLimits[this.chartId].x.max;
|
|
28138
28194
|
const computeNewAxisLimits = (position) => {
|
|
28139
|
-
let xMin, xMax;
|
|
28140
|
-
const { left, right } = this.masterChart.chartArea;
|
|
28141
28195
|
if (this.mode === "moveInMaster") {
|
|
28142
|
-
|
|
28143
|
-
if (
|
|
28144
|
-
|
|
28196
|
+
let min = this.computeCoordinate(position - startingPositionOnChart);
|
|
28197
|
+
if (min < storedMin) {
|
|
28198
|
+
min = storedMin;
|
|
28145
28199
|
}
|
|
28146
|
-
else if (
|
|
28147
|
-
|
|
28200
|
+
else if (min > storedMax - windowSize) {
|
|
28201
|
+
min = storedMax - windowSize;
|
|
28148
28202
|
}
|
|
28149
|
-
|
|
28203
|
+
return { min, max: min + windowSize };
|
|
28150
28204
|
}
|
|
28151
28205
|
else if (this.mode === "selectInMaster") {
|
|
28152
28206
|
const upperBound = clip(position, left, right);
|
|
@@ -28155,54 +28209,52 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
28155
28209
|
if (startX === undefined || endX === undefined) {
|
|
28156
28210
|
return {};
|
|
28157
28211
|
}
|
|
28158
|
-
|
|
28159
|
-
|
|
28212
|
+
return {
|
|
28213
|
+
min: Math.min(startX, endX),
|
|
28214
|
+
max: Math.max(startX, endX),
|
|
28215
|
+
};
|
|
28160
28216
|
}
|
|
28161
28217
|
}
|
|
28162
|
-
return {
|
|
28218
|
+
return {};
|
|
28163
28219
|
};
|
|
28164
|
-
const
|
|
28220
|
+
const onMasterChartDrag = (ev) => {
|
|
28165
28221
|
const position = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
|
|
28166
28222
|
if (Math.abs(position - startingEventPosition) < 5) {
|
|
28167
28223
|
return;
|
|
28168
28224
|
}
|
|
28169
|
-
const { min
|
|
28170
|
-
if (
|
|
28171
|
-
this.updateAxisLimits(
|
|
28225
|
+
const { min, max } = computeNewAxisLimits(position);
|
|
28226
|
+
if (min !== undefined && max !== undefined) {
|
|
28227
|
+
this.updateAxisLimits(min, max);
|
|
28172
28228
|
}
|
|
28173
28229
|
};
|
|
28174
|
-
const
|
|
28230
|
+
const onMasterChartPointerUp = (ev) => {
|
|
28175
28231
|
this.removeEventListeners();
|
|
28176
|
-
|
|
28177
|
-
if (
|
|
28178
|
-
|
|
28179
|
-
|
|
28180
|
-
|
|
28181
|
-
|
|
28182
|
-
|
|
28183
|
-
|
|
28184
|
-
}
|
|
28185
|
-
else {
|
|
28186
|
-
xMin = Math.ceil(xMin) - this.axisOffset;
|
|
28187
|
-
xMax = Math.floor(xMax) + this.axisOffset;
|
|
28188
|
-
}
|
|
28189
|
-
}
|
|
28190
|
-
this.updateAxisLimits(xMin, xMax);
|
|
28232
|
+
let { min, max } = this.chart.scales.x;
|
|
28233
|
+
if (!this.hasLinearScale) {
|
|
28234
|
+
if (this.mode === "moveInMaster") {
|
|
28235
|
+
min = Math.round(min) - this.axisOffset;
|
|
28236
|
+
max = min + windowSize;
|
|
28237
|
+
}
|
|
28238
|
+
else {
|
|
28239
|
+
({ min, max } = this.adjustBoundaries({ min, max }));
|
|
28191
28240
|
}
|
|
28192
28241
|
}
|
|
28242
|
+
this.updateAxisLimits(min, max);
|
|
28193
28243
|
this.mode = undefined;
|
|
28194
28244
|
};
|
|
28195
28245
|
this.removeEventListeners = () => {
|
|
28196
|
-
window.removeEventListener("pointermove",
|
|
28197
|
-
window.removeEventListener("pointerup",
|
|
28246
|
+
window.removeEventListener("pointermove", onMasterChartDrag, true);
|
|
28247
|
+
window.removeEventListener("pointerup", onMasterChartPointerUp, true);
|
|
28198
28248
|
};
|
|
28199
|
-
window.addEventListener("pointermove",
|
|
28200
|
-
window.addEventListener("pointerup",
|
|
28249
|
+
window.addEventListener("pointermove", onMasterChartDrag, true);
|
|
28250
|
+
window.addEventListener("pointerup", onMasterChartPointerUp, true);
|
|
28201
28251
|
}
|
|
28202
|
-
|
|
28203
|
-
const { offsetX: x, offsetY: y } = ev;
|
|
28252
|
+
onMasterChartPointerMove(ev) {
|
|
28253
|
+
const { offsetX: x, offsetY: y, target } = ev;
|
|
28254
|
+
if (!target || !this.isMasterChartAllowed) {
|
|
28255
|
+
return;
|
|
28256
|
+
}
|
|
28204
28257
|
if (this.mode === undefined) {
|
|
28205
|
-
const target = ev.target;
|
|
28206
28258
|
if (!this.masterChart?.chartArea) {
|
|
28207
28259
|
target["style"].cursor = "default";
|
|
28208
28260
|
return;
|
|
@@ -28224,14 +28276,14 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
28224
28276
|
}
|
|
28225
28277
|
}
|
|
28226
28278
|
}
|
|
28227
|
-
|
|
28279
|
+
onMasterChartMouseLeave(ev) {
|
|
28228
28280
|
const target = ev.target;
|
|
28229
|
-
if (!target) {
|
|
28281
|
+
if (!target || !this.isMasterChartAllowed) {
|
|
28230
28282
|
return;
|
|
28231
28283
|
}
|
|
28232
28284
|
target["style"].cursor = "default";
|
|
28233
28285
|
}
|
|
28234
|
-
|
|
28286
|
+
onMasterChartDoubleClick(ev) {
|
|
28235
28287
|
this.mode = undefined;
|
|
28236
28288
|
const position = ev.offsetX;
|
|
28237
28289
|
if (!this.masterChart?.chartArea || !this.chart?.scales.x) {
|
|
@@ -28248,33 +28300,25 @@ class ZoomableChartJsComponent extends ChartJsComponent {
|
|
|
28248
28300
|
}
|
|
28249
28301
|
ev.preventDefault();
|
|
28250
28302
|
ev.stopPropagation();
|
|
28251
|
-
let { min
|
|
28303
|
+
let { min, max } = this.store.currentAxesLimits[this.chartId]?.x ?? this.chart.scales.x;
|
|
28252
28304
|
const originalAxisLimits = this.store.originalAxisLimits[this.chartId].x;
|
|
28253
28305
|
if (!originalAxisLimits) {
|
|
28254
28306
|
return;
|
|
28255
28307
|
}
|
|
28256
|
-
let originalXMin = originalAxisLimits.min;
|
|
28257
|
-
let originalXMax = originalAxisLimits.max;
|
|
28258
|
-
if (this.hasLinearScale) {
|
|
28259
|
-
originalXMin = Math.ceil(originalXMin) - this.axisOffset;
|
|
28260
|
-
originalXMax = Math.floor(originalXMax) + this.axisOffset;
|
|
28261
|
-
}
|
|
28262
28308
|
if (Math.abs(position - lowerBound) < 5) {
|
|
28263
|
-
|
|
28264
|
-
xMin = originalXMin;
|
|
28309
|
+
min = originalAxisLimits.min;
|
|
28265
28310
|
}
|
|
28266
28311
|
else if (Math.abs(position - upperBound) < 5) {
|
|
28267
|
-
|
|
28312
|
+
max = originalAxisLimits.max;
|
|
28268
28313
|
}
|
|
28269
28314
|
else if (lowerBound < position && position < upperBound) {
|
|
28270
|
-
|
|
28271
|
-
|
|
28272
|
-
xMax = originalXMax;
|
|
28315
|
+
min = originalAxisLimits.min;
|
|
28316
|
+
max = originalAxisLimits.max;
|
|
28273
28317
|
}
|
|
28274
28318
|
else {
|
|
28275
28319
|
return;
|
|
28276
28320
|
}
|
|
28277
|
-
this.updateAxisLimits(
|
|
28321
|
+
this.updateAxisLimits(min, max);
|
|
28278
28322
|
}
|
|
28279
28323
|
}
|
|
28280
28324
|
|
|
@@ -34405,7 +34449,8 @@ class Composer extends owl.Component {
|
|
|
34405
34449
|
assistantStyle["max-height"] = `${availableSpaceAbove - CLOSE_ICON_RADIUS}px`;
|
|
34406
34450
|
// render top
|
|
34407
34451
|
// We compensate 2 px of margin on the assistant style + 1px for design reasons
|
|
34408
|
-
assistantStyle.
|
|
34452
|
+
assistantStyle.top = `-3px`;
|
|
34453
|
+
assistantStyle.transform = `translate(0, -100%)`;
|
|
34409
34454
|
}
|
|
34410
34455
|
if (cellX + ASSISTANT_WIDTH > this.props.delimitation.width) {
|
|
34411
34456
|
// render left
|
|
@@ -34525,16 +34570,12 @@ class Composer extends owl.Component {
|
|
|
34525
34570
|
processTabKey(ev, direction) {
|
|
34526
34571
|
ev.preventDefault();
|
|
34527
34572
|
ev.stopPropagation();
|
|
34528
|
-
|
|
34529
|
-
this.props.composerStore.autoCompleteOrStop(direction);
|
|
34530
|
-
}
|
|
34573
|
+
this.props.composerStore.autoCompleteOrStop(direction, this.assistant.forcedClosed);
|
|
34531
34574
|
}
|
|
34532
34575
|
processEnterKey(ev, direction) {
|
|
34533
34576
|
ev.preventDefault();
|
|
34534
34577
|
ev.stopPropagation();
|
|
34535
|
-
|
|
34536
|
-
this.props.composerStore.autoCompleteOrStop(direction);
|
|
34537
|
-
}
|
|
34578
|
+
this.props.composerStore.autoCompleteOrStop(direction, this.assistant.forcedClosed);
|
|
34538
34579
|
}
|
|
34539
34580
|
processNewLineEvent(ev) {
|
|
34540
34581
|
ev.preventDefault();
|
|
@@ -34710,7 +34751,6 @@ class Composer extends owl.Component {
|
|
|
34710
34751
|
return;
|
|
34711
34752
|
}
|
|
34712
34753
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
34713
|
-
this.props.composerStore.stopComposerRangeSelection();
|
|
34714
34754
|
const isCurrentlyInactive = this.props.composerStore.editionMode === "inactive";
|
|
34715
34755
|
this.props.onComposerContentFocused(newSelection);
|
|
34716
34756
|
if (!isCurrentlyInactive) {
|
|
@@ -35201,6 +35241,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
35201
35241
|
}
|
|
35202
35242
|
this.selectionStart = start;
|
|
35203
35243
|
this.selectionEnd = end;
|
|
35244
|
+
this.stopComposerRangeSelection();
|
|
35204
35245
|
this.computeFormulaCursorContext();
|
|
35205
35246
|
this.computeParenthesisRelatedToCursor();
|
|
35206
35247
|
this.updateAutoCompleteProvider();
|
|
@@ -35871,10 +35912,13 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
35871
35912
|
hideHelp() {
|
|
35872
35913
|
this.autoComplete.hide();
|
|
35873
35914
|
}
|
|
35874
|
-
autoCompleteOrStop(direction) {
|
|
35915
|
+
autoCompleteOrStop(direction, assistantForcedClosed = false) {
|
|
35875
35916
|
if (this.editionMode !== "inactive") {
|
|
35876
35917
|
const autoComplete = this.autoComplete;
|
|
35877
|
-
|
|
35918
|
+
const suppressAutocomplete = assistantForcedClosed && this.canBeToggled;
|
|
35919
|
+
if (!suppressAutocomplete &&
|
|
35920
|
+
autoComplete.provider &&
|
|
35921
|
+
autoComplete.selectedIndex !== undefined) {
|
|
35878
35922
|
const autoCompleteValue = autoComplete.provider.proposals[autoComplete.selectedIndex]?.text;
|
|
35879
35923
|
if (autoCompleteValue) {
|
|
35880
35924
|
this.autoComplete.provider?.selectProposal(autoCompleteValue);
|
|
@@ -44194,18 +44238,22 @@ function dropCommands(initialMessages, commandType) {
|
|
|
44194
44238
|
return messages;
|
|
44195
44239
|
}
|
|
44196
44240
|
function fixChartDefinitions(data, initialMessages) {
|
|
44241
|
+
/**
|
|
44242
|
+
* Revisions created after version 18.5.1 contain the full chart definition in the command
|
|
44243
|
+
* if the data was alreay updated to 18.5.1, then those older revision cannot (by definition) be reaplied
|
|
44244
|
+
* and should not be replayed.
|
|
44245
|
+
* FIXME: every command should be versionned when upgraded to allow finer tuning.
|
|
44246
|
+
*/
|
|
44247
|
+
if (!data.version || compareVersions(String(data.version), "18.5.1") >= 0) {
|
|
44248
|
+
return initialMessages;
|
|
44249
|
+
}
|
|
44197
44250
|
const messages = [];
|
|
44198
44251
|
const map = {};
|
|
44199
44252
|
for (const sheet of data.sheets || []) {
|
|
44200
44253
|
sheet.figures?.forEach((figure) => {
|
|
44201
44254
|
if (figure.tag === "chart") {
|
|
44202
44255
|
// chart definition
|
|
44203
|
-
|
|
44204
|
-
map[figure.data.chartId] = figure.data;
|
|
44205
|
-
}
|
|
44206
|
-
else {
|
|
44207
|
-
map[figure.id] = figure.data;
|
|
44208
|
-
}
|
|
44256
|
+
map[figure.id] = figure.data;
|
|
44209
44257
|
}
|
|
44210
44258
|
});
|
|
44211
44259
|
}
|
|
@@ -47788,7 +47836,6 @@ const dateGranularities = [
|
|
|
47788
47836
|
pivotRegistry.add("SPREADSHEET", {
|
|
47789
47837
|
ui: SpreadsheetPivot,
|
|
47790
47838
|
definition: SpreadsheetPivotRuntimeDefinition,
|
|
47791
|
-
externalData: false,
|
|
47792
47839
|
dateGranularities: [...dateGranularities],
|
|
47793
47840
|
datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
|
|
47794
47841
|
isMeasureCandidate: (field) => field.type !== "boolean",
|
|
@@ -51565,10 +51612,11 @@ class AbstractResizer extends owl.Component {
|
|
|
51565
51612
|
this.state.waitingForMove = false;
|
|
51566
51613
|
}
|
|
51567
51614
|
onMouseMove(ev) {
|
|
51568
|
-
if (this.env.isMobile()
|
|
51569
|
-
|
|
51570
|
-
|
|
51571
|
-
|
|
51615
|
+
if (this.env.isMobile() ||
|
|
51616
|
+
this.env.model.getters.isReadonly() ||
|
|
51617
|
+
this.state.isResizing ||
|
|
51618
|
+
this.state.isMoving ||
|
|
51619
|
+
this.state.isSelecting) {
|
|
51572
51620
|
return;
|
|
51573
51621
|
}
|
|
51574
51622
|
this._computeHandleDisplay(ev);
|
|
@@ -51635,6 +51683,10 @@ class AbstractResizer extends owl.Component {
|
|
|
51635
51683
|
if (index < 0) {
|
|
51636
51684
|
return;
|
|
51637
51685
|
}
|
|
51686
|
+
if (this.env.model.getters.isReadonly()) {
|
|
51687
|
+
this._selectElement(index, false);
|
|
51688
|
+
return;
|
|
51689
|
+
}
|
|
51638
51690
|
if (this.state.waitingForMove) {
|
|
51639
51691
|
if (!this.env.model.getters.isGridSelectionActive()) {
|
|
51640
51692
|
this._selectElement(index, false);
|
|
@@ -52996,7 +53048,7 @@ const friction = 0.95;
|
|
|
52996
53048
|
const verticalScrollFactor = 1;
|
|
52997
53049
|
const horizontalScrollFactor = 1;
|
|
52998
53050
|
const resetTimeoutDuration = 100;
|
|
52999
|
-
function useTouchScroll(ref, updateScroll, canMoveUp) {
|
|
53051
|
+
function useTouchScroll(ref, updateScroll, canMoveUp, canMoveDown) {
|
|
53000
53052
|
let lastX = 0;
|
|
53001
53053
|
let lastY = 0;
|
|
53002
53054
|
let velocityX = 0;
|
|
@@ -53033,7 +53085,7 @@ function useTouchScroll(ref, updateScroll, canMoveUp) {
|
|
|
53033
53085
|
lastX = clientX;
|
|
53034
53086
|
lastY = clientY;
|
|
53035
53087
|
lastTime = currentTime;
|
|
53036
|
-
if (canMoveUp()) {
|
|
53088
|
+
if ((deltaY < 0 && canMoveUp()) || (deltaY > 0 && canMoveDown())) {
|
|
53037
53089
|
if (event.cancelable) {
|
|
53038
53090
|
event.preventDefault();
|
|
53039
53091
|
}
|
|
@@ -53819,7 +53871,9 @@ class FontSizeEditor extends owl.Component {
|
|
|
53819
53871
|
inputRef = owl.useRef("inputFontSize");
|
|
53820
53872
|
rootEditorRef = owl.useRef("FontSizeEditor");
|
|
53821
53873
|
fontSizeListRef = owl.useRef("fontSizeList");
|
|
53874
|
+
DOMFocusableElementStore;
|
|
53822
53875
|
setup() {
|
|
53876
|
+
this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
|
|
53823
53877
|
owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
|
|
53824
53878
|
}
|
|
53825
53879
|
get popoverProps() {
|
|
@@ -53873,6 +53927,13 @@ class FontSizeEditor extends owl.Component {
|
|
|
53873
53927
|
}
|
|
53874
53928
|
this.props.onToggle?.();
|
|
53875
53929
|
}
|
|
53930
|
+
if (ev.key === "Tab") {
|
|
53931
|
+
ev.preventDefault();
|
|
53932
|
+
ev.stopPropagation();
|
|
53933
|
+
this.closeFontList();
|
|
53934
|
+
this.DOMFocusableElementStore.focus();
|
|
53935
|
+
return;
|
|
53936
|
+
}
|
|
53876
53937
|
}
|
|
53877
53938
|
}
|
|
53878
53939
|
|
|
@@ -55208,19 +55269,6 @@ class ChartWithAxisDesignPanel extends owl.Component {
|
|
|
55208
55269
|
}
|
|
55209
55270
|
}
|
|
55210
55271
|
|
|
55211
|
-
class ChartShowDataMarkers extends owl.Component {
|
|
55212
|
-
static template = "o-spreadsheet-ChartShowDataMarkers";
|
|
55213
|
-
static components = {
|
|
55214
|
-
Checkbox,
|
|
55215
|
-
};
|
|
55216
|
-
static props = {
|
|
55217
|
-
chartId: String,
|
|
55218
|
-
definition: Object,
|
|
55219
|
-
updateChart: Function,
|
|
55220
|
-
canUpdateChart: Function,
|
|
55221
|
-
};
|
|
55222
|
-
}
|
|
55223
|
-
|
|
55224
55272
|
class GenericZoomableChartDesignPanel extends ChartWithAxisDesignPanel {
|
|
55225
55273
|
static template = "o-spreadsheet-GenericZoomableChartDesignPanel";
|
|
55226
55274
|
static components = {
|
|
@@ -55234,6 +55282,26 @@ class GenericZoomableChartDesignPanel extends ChartWithAxisDesignPanel {
|
|
|
55234
55282
|
}
|
|
55235
55283
|
}
|
|
55236
55284
|
|
|
55285
|
+
class BarChartDesignPanel extends GenericZoomableChartDesignPanel {
|
|
55286
|
+
static template = "o-spreadsheet-BarChartDesignPanel";
|
|
55287
|
+
get isZoomable() {
|
|
55288
|
+
return !this.props.definition.horizontal;
|
|
55289
|
+
}
|
|
55290
|
+
}
|
|
55291
|
+
|
|
55292
|
+
class ChartShowDataMarkers extends owl.Component {
|
|
55293
|
+
static template = "o-spreadsheet-ChartShowDataMarkers";
|
|
55294
|
+
static components = {
|
|
55295
|
+
Checkbox,
|
|
55296
|
+
};
|
|
55297
|
+
static props = {
|
|
55298
|
+
chartId: String,
|
|
55299
|
+
definition: Object,
|
|
55300
|
+
updateChart: Function,
|
|
55301
|
+
canUpdateChart: Function,
|
|
55302
|
+
};
|
|
55303
|
+
}
|
|
55304
|
+
|
|
55237
55305
|
class ComboChartDesignPanel extends GenericZoomableChartDesignPanel {
|
|
55238
55306
|
static template = "o-spreadsheet-ComboChartDesignPanel";
|
|
55239
55307
|
static components = {
|
|
@@ -56162,7 +56230,7 @@ chartSidePanelComponentRegistry
|
|
|
56162
56230
|
})
|
|
56163
56231
|
.add("bar", {
|
|
56164
56232
|
configuration: BarConfigPanel,
|
|
56165
|
-
design:
|
|
56233
|
+
design: BarChartDesignPanel,
|
|
56166
56234
|
})
|
|
56167
56235
|
.add("combo", {
|
|
56168
56236
|
configuration: GenericChartConfigPanel,
|
|
@@ -59271,7 +59339,6 @@ function insertTokenAfterArgSeparator(tokenAtCursor, value) {
|
|
|
59271
59339
|
// replace the whole token
|
|
59272
59340
|
start = tokenAtCursor.start;
|
|
59273
59341
|
}
|
|
59274
|
-
this.composer.stopComposerRangeSelection();
|
|
59275
59342
|
this.composer.changeComposerCursorSelection(start, end);
|
|
59276
59343
|
this.composer.replaceComposerCursorSelection(value);
|
|
59277
59344
|
}
|
|
@@ -59289,7 +59356,6 @@ function insertTokenAfterLeftParenthesis(tokenAtCursor, value) {
|
|
|
59289
59356
|
// replace the whole token
|
|
59290
59357
|
start = tokenAtCursor.start;
|
|
59291
59358
|
}
|
|
59292
|
-
this.composer.stopComposerRangeSelection();
|
|
59293
59359
|
this.composer.changeComposerCursorSelection(start, end);
|
|
59294
59360
|
this.composer.replaceComposerCursorSelection(value);
|
|
59295
59361
|
}
|
|
@@ -60750,6 +60816,7 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
60750
60816
|
getPanelProps(panelInfo) {
|
|
60751
60817
|
const state = this.computeState(panelInfo);
|
|
60752
60818
|
if (state.isOpen) {
|
|
60819
|
+
panelInfo.currentPanelProps = state.props ?? panelInfo.currentPanelProps;
|
|
60753
60820
|
return state.props ?? {};
|
|
60754
60821
|
}
|
|
60755
60822
|
return {};
|
|
@@ -60761,11 +60828,11 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
60761
60828
|
}
|
|
60762
60829
|
return undefined;
|
|
60763
60830
|
}
|
|
60764
|
-
open(componentTag,
|
|
60831
|
+
open(componentTag, currentPanelProps = {}) {
|
|
60765
60832
|
if (this.screenWidthStore.isSmall) {
|
|
60766
60833
|
return;
|
|
60767
60834
|
}
|
|
60768
|
-
const newPanelInfo = {
|
|
60835
|
+
const newPanelInfo = { currentPanelProps, componentTag, size: DEFAULT_SIDE_PANEL_SIZE };
|
|
60769
60836
|
const state = this.computeState(newPanelInfo);
|
|
60770
60837
|
if (!state.isOpen) {
|
|
60771
60838
|
return;
|
|
@@ -60789,8 +60856,8 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
60789
60856
|
}
|
|
60790
60857
|
this._openPanel("secondaryPanel", newPanelInfo, state);
|
|
60791
60858
|
}
|
|
60792
|
-
replace(componentTag, currentPanelKey,
|
|
60793
|
-
const newPanelInfo = {
|
|
60859
|
+
replace(componentTag, currentPanelKey, currentPanelProps = {}) {
|
|
60860
|
+
const newPanelInfo = { currentPanelProps, componentTag, size: DEFAULT_SIDE_PANEL_SIZE };
|
|
60794
60861
|
const state = this.computeState(newPanelInfo);
|
|
60795
60862
|
if (!state.isOpen) {
|
|
60796
60863
|
return;
|
|
@@ -60820,10 +60887,10 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
60820
60887
|
_openPanel(panel, newPanel, state) {
|
|
60821
60888
|
const currentPanel = this[panel];
|
|
60822
60889
|
if (currentPanel && newPanel.componentTag !== currentPanel.componentTag) {
|
|
60823
|
-
currentPanel.
|
|
60890
|
+
currentPanel.currentPanelProps?.onCloseSidePanel?.();
|
|
60824
60891
|
}
|
|
60825
60892
|
this[panel] = {
|
|
60826
|
-
|
|
60893
|
+
currentPanelProps: state.props ?? {},
|
|
60827
60894
|
componentTag: newPanel.componentTag,
|
|
60828
60895
|
size: currentPanel?.size || DEFAULT_SIDE_PANEL_SIZE,
|
|
60829
60896
|
isCollapsed: currentPanel?.isCollapsed || false,
|
|
@@ -60845,16 +60912,16 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
60845
60912
|
close() {
|
|
60846
60913
|
if (this.mainPanel?.isPinned) {
|
|
60847
60914
|
if (this.secondaryPanel) {
|
|
60848
|
-
this.secondaryPanel.
|
|
60915
|
+
this.secondaryPanel.currentPanelProps.onCloseSidePanel?.();
|
|
60849
60916
|
this.secondaryPanel = undefined;
|
|
60850
60917
|
}
|
|
60851
60918
|
return;
|
|
60852
60919
|
}
|
|
60853
|
-
this.mainPanel?.
|
|
60920
|
+
this.mainPanel?.currentPanelProps.onCloseSidePanel?.();
|
|
60854
60921
|
this.mainPanel = undefined;
|
|
60855
60922
|
}
|
|
60856
60923
|
closeMainPanel() {
|
|
60857
|
-
this.mainPanel?.
|
|
60924
|
+
this.mainPanel?.currentPanelProps.onCloseSidePanel?.();
|
|
60858
60925
|
this.mainPanel = this.secondaryPanel || undefined;
|
|
60859
60926
|
this.secondaryPanel = undefined;
|
|
60860
60927
|
}
|
|
@@ -60886,7 +60953,7 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
60886
60953
|
}
|
|
60887
60954
|
this.mainPanel.isPinned = !this.mainPanel.isPinned;
|
|
60888
60955
|
if (!this.mainPanel.isPinned && this.secondaryPanel) {
|
|
60889
|
-
this.secondaryPanel?.
|
|
60956
|
+
this.secondaryPanel?.currentPanelProps.onCloseSidePanel?.();
|
|
60890
60957
|
this.mainPanel = this.secondaryPanel;
|
|
60891
60958
|
this.secondaryPanel = undefined;
|
|
60892
60959
|
}
|
|
@@ -60905,7 +60972,7 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
60905
60972
|
panelInfo.size = COLLAPSED_SIDE_PANEL_SIZE;
|
|
60906
60973
|
}
|
|
60907
60974
|
}
|
|
60908
|
-
computeState({ componentTag, initialPanelProps }) {
|
|
60975
|
+
computeState({ componentTag, currentPanelProps: initialPanelProps, }) {
|
|
60909
60976
|
const customComputeState = sidePanelRegistry.get(componentTag).computeState;
|
|
60910
60977
|
const state = customComputeState
|
|
60911
60978
|
? customComputeState(this.getters, initialPanelProps)
|
|
@@ -60915,7 +60982,7 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
60915
60982
|
changeSpreadsheetWidth(width) {
|
|
60916
60983
|
this.availableWidth = width - MIN_SHEET_VIEW_WIDTH;
|
|
60917
60984
|
if (this.secondaryPanel && width - this.totalPanelSize < MIN_SHEET_VIEW_WIDTH) {
|
|
60918
|
-
this.secondaryPanel?.
|
|
60985
|
+
this.secondaryPanel?.currentPanelProps.onCloseSidePanel?.();
|
|
60919
60986
|
this.secondaryPanel = undefined;
|
|
60920
60987
|
}
|
|
60921
60988
|
if (this.mainPanel && width - this.totalPanelSize < MIN_SHEET_VIEW_WIDTH) {
|
|
@@ -61075,6 +61142,10 @@ class Grid extends owl.Component {
|
|
|
61075
61142
|
useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
|
|
61076
61143
|
const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
61077
61144
|
return scrollY > 0;
|
|
61145
|
+
}, () => {
|
|
61146
|
+
const { maxOffsetY } = this.env.model.getters.getMaximumSheetOffset();
|
|
61147
|
+
const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
61148
|
+
return scrollY < maxOffsetY;
|
|
61078
61149
|
});
|
|
61079
61150
|
}
|
|
61080
61151
|
get highlights() {
|
|
@@ -62367,22 +62438,34 @@ class BordersPlugin extends CorePlugin {
|
|
|
62367
62438
|
addBorder(sheetId, zone, newBorder, force = false) {
|
|
62368
62439
|
const borders = [];
|
|
62369
62440
|
const plannedBorder = newBorder ? { zone, style: newBorder } : undefined;
|
|
62370
|
-
|
|
62371
|
-
|
|
62372
|
-
|
|
62373
|
-
|
|
62374
|
-
|
|
62441
|
+
// For each side, decide if we must clear the border on the *adjacent*
|
|
62442
|
+
// existing cell when we draw on the opposite side of the new zone.
|
|
62443
|
+
//
|
|
62444
|
+
// Example:
|
|
62445
|
+
// - newBorder.right is set → we draw border on the RIGHT side of `zone`
|
|
62446
|
+
// - the cell on the right may already have a LEFT border on that edge
|
|
62447
|
+
// In that case we clear that LEFT border, so only the new RIGHT border
|
|
62448
|
+
// remains on the shared edge.
|
|
62449
|
+
//
|
|
62450
|
+
// existingBorderSideToClear[side] = true means we should clear the border on that
|
|
62451
|
+
// side of the existing adjacent zone before adding the new border.
|
|
62452
|
+
const existingBorderSideToClear = {
|
|
62453
|
+
left: force || !!newBorder?.right,
|
|
62454
|
+
right: force || !!newBorder?.left,
|
|
62455
|
+
top: force || !!newBorder?.bottom,
|
|
62456
|
+
bottom: force || !!newBorder?.top,
|
|
62375
62457
|
};
|
|
62376
62458
|
let editingZone = [zone];
|
|
62377
62459
|
for (const existingBorder of this.borders[sheetId] ?? []) {
|
|
62378
62460
|
const inter = intersection(existingBorder.zone, zone);
|
|
62379
62461
|
if (!inter) {
|
|
62380
|
-
//
|
|
62462
|
+
// Check if the existing border is adjacent to the new zone
|
|
62381
62463
|
const adjacentEdge = adjacent(existingBorder.zone, zone);
|
|
62382
|
-
if (adjacentEdge &&
|
|
62464
|
+
if (adjacentEdge && existingBorderSideToClear[adjacentEdge.position]) {
|
|
62383
62465
|
for (const newZone of splitIfAdjacent(existingBorder.zone, zone)) {
|
|
62384
62466
|
const border = this.computeBorderFromZone(newZone, existingBorder);
|
|
62385
62467
|
const adjacentEdge = adjacent(newZone, zone);
|
|
62468
|
+
// Clear the existing border on the side that touches the new zone
|
|
62386
62469
|
switch (adjacentEdge?.position) {
|
|
62387
62470
|
case "left":
|
|
62388
62471
|
border.style.left = undefined;
|
|
@@ -64239,7 +64322,8 @@ class FigurePlugin extends CorePlugin {
|
|
|
64239
64322
|
}
|
|
64240
64323
|
break;
|
|
64241
64324
|
case "DUPLICATE_SHEET": {
|
|
64242
|
-
for (const
|
|
64325
|
+
for (const figure of this.getFigures(cmd.sheetId)) {
|
|
64326
|
+
const figureId = figure.id;
|
|
64243
64327
|
const fig = this.figures[cmd.sheetId]?.[figureId];
|
|
64244
64328
|
if (!fig) {
|
|
64245
64329
|
continue;
|
|
@@ -67717,10 +67801,17 @@ class PivotCorePlugin extends CorePlugin {
|
|
|
67717
67801
|
if (!pivot) {
|
|
67718
67802
|
continue;
|
|
67719
67803
|
}
|
|
67720
|
-
|
|
67804
|
+
const def = deepCopy(pivot.definition);
|
|
67805
|
+
for (const measure of def.measures) {
|
|
67721
67806
|
if (measure.computedBy?.formula === formulaString) {
|
|
67722
|
-
const measureIndex =
|
|
67723
|
-
|
|
67807
|
+
const measureIndex = def.measures.indexOf(measure);
|
|
67808
|
+
if (measureIndex !== -1) {
|
|
67809
|
+
def.measures[measureIndex].computedBy = {
|
|
67810
|
+
formula: newFormulaString,
|
|
67811
|
+
sheetId,
|
|
67812
|
+
};
|
|
67813
|
+
}
|
|
67814
|
+
this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
|
|
67724
67815
|
}
|
|
67725
67816
|
}
|
|
67726
67817
|
}
|
|
@@ -67881,6 +67972,9 @@ class SpreadsheetPivotCorePlugin extends CorePlugin {
|
|
|
67881
67972
|
const { sheetId, zone } = definition.dataSet;
|
|
67882
67973
|
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
67883
67974
|
const adaptedRange = adaptPivotRange(range, applyChange);
|
|
67975
|
+
if (adaptedRange === range) {
|
|
67976
|
+
return;
|
|
67977
|
+
}
|
|
67884
67978
|
const dataSet = adaptedRange && {
|
|
67885
67979
|
sheetId: adaptedRange.sheetId,
|
|
67886
67980
|
zone: adaptedRange.zone,
|
|
@@ -72200,9 +72294,7 @@ class PivotUIPlugin extends CoreViewPlugin {
|
|
|
72200
72294
|
handle(cmd) {
|
|
72201
72295
|
if (invalidateEvaluationCommands.has(cmd.type)) {
|
|
72202
72296
|
for (const pivotId of this.getters.getPivotIds()) {
|
|
72203
|
-
|
|
72204
|
-
this.setupPivot(pivotId, { recreate: true });
|
|
72205
|
-
}
|
|
72297
|
+
this.setupPivot(pivotId, { recreate: true });
|
|
72206
72298
|
}
|
|
72207
72299
|
}
|
|
72208
72300
|
switch (cmd.type) {
|
|
@@ -72424,7 +72516,7 @@ class PivotUIPlugin extends CoreViewPlugin {
|
|
|
72424
72516
|
pivot.init({ reload: true });
|
|
72425
72517
|
}
|
|
72426
72518
|
setupPivot(pivotId, { recreate } = { recreate: false }) {
|
|
72427
|
-
const definition = this.getters.getPivotCoreDefinition(pivotId);
|
|
72519
|
+
const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
|
|
72428
72520
|
if (!(pivotId in this.pivots)) {
|
|
72429
72521
|
const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
|
|
72430
72522
|
this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
|
|
@@ -78676,6 +78768,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
78676
78768
|
"getFigureUI",
|
|
78677
78769
|
"getPositionAnchorOffset",
|
|
78678
78770
|
"getGridOffset",
|
|
78771
|
+
"getMaximumSheetOffset",
|
|
78679
78772
|
];
|
|
78680
78773
|
viewports = {};
|
|
78681
78774
|
/**
|
|
@@ -81930,16 +82023,18 @@ class ClickableCellsStore extends SpreadsheetStore {
|
|
|
81930
82023
|
get clickableCells() {
|
|
81931
82024
|
const cells = [];
|
|
81932
82025
|
const getters = this.getters;
|
|
81933
|
-
const sheetId = getters.getActiveSheetId();
|
|
81934
82026
|
for (const position of this.getters.getVisibleCellPositions()) {
|
|
81935
82027
|
const item = this.getClickableItem(position);
|
|
81936
82028
|
if (!item) {
|
|
81937
82029
|
continue;
|
|
81938
82030
|
}
|
|
81939
82031
|
const title = typeof item.title === "function" ? item.title(position, getters) : item.title;
|
|
81940
|
-
const
|
|
82032
|
+
const rect = this.getClickableCellRect(position);
|
|
82033
|
+
if (!rect) {
|
|
82034
|
+
continue;
|
|
82035
|
+
}
|
|
81941
82036
|
cells.push({
|
|
81942
|
-
coordinates:
|
|
82037
|
+
coordinates: rect,
|
|
81943
82038
|
position,
|
|
81944
82039
|
action: item.execute,
|
|
81945
82040
|
title: title || "",
|
|
@@ -81949,6 +82044,31 @@ class ClickableCellsStore extends SpreadsheetStore {
|
|
|
81949
82044
|
}
|
|
81950
82045
|
return cells;
|
|
81951
82046
|
}
|
|
82047
|
+
getClickableCellRect(position) {
|
|
82048
|
+
const zone = this.getters.expandZone(position.sheetId, positionToZone(position));
|
|
82049
|
+
const clickableRect = this.getters.getVisibleRect(zone);
|
|
82050
|
+
const icons = this.getters.getCellIcons(position);
|
|
82051
|
+
const iconsAtPosition = {
|
|
82052
|
+
center: icons.find((icon) => icon.horizontalAlign === "center"),
|
|
82053
|
+
left: icons.find((icon) => icon.horizontalAlign === "left"),
|
|
82054
|
+
right: icons.find((icon) => icon.horizontalAlign === "right"),
|
|
82055
|
+
};
|
|
82056
|
+
if (iconsAtPosition.center?.onClick) {
|
|
82057
|
+
return undefined;
|
|
82058
|
+
}
|
|
82059
|
+
if (iconsAtPosition.right?.onClick) {
|
|
82060
|
+
const cellRect = this.getters.getRect(zone);
|
|
82061
|
+
const iconRect = this.getters.getCellIconRect(iconsAtPosition.right, cellRect);
|
|
82062
|
+
clickableRect.width -= iconRect.width + iconsAtPosition.right.margin;
|
|
82063
|
+
}
|
|
82064
|
+
if (iconsAtPosition.left?.onClick) {
|
|
82065
|
+
const cellRect = this.getters.getRect(zone);
|
|
82066
|
+
const iconRect = this.getters.getCellIconRect(iconsAtPosition.left, cellRect);
|
|
82067
|
+
clickableRect.x += iconRect.width + iconsAtPosition.left.margin;
|
|
82068
|
+
clickableRect.width -= iconRect.width + iconsAtPosition.left.margin;
|
|
82069
|
+
}
|
|
82070
|
+
return clickableRect;
|
|
82071
|
+
}
|
|
81952
82072
|
}
|
|
81953
82073
|
|
|
81954
82074
|
css /* scss */ `
|
|
@@ -81987,6 +82107,10 @@ class SpreadsheetDashboard extends owl.Component {
|
|
|
81987
82107
|
useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
|
|
81988
82108
|
const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
81989
82109
|
return scrollY > 0;
|
|
82110
|
+
}, () => {
|
|
82111
|
+
const { maxOffsetY } = this.env.model.getters.getMaximumSheetOffset();
|
|
82112
|
+
const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
82113
|
+
return scrollY < maxOffsetY;
|
|
81990
82114
|
});
|
|
81991
82115
|
}
|
|
81992
82116
|
get gridContainer() {
|
|
@@ -82702,7 +82826,7 @@ class SmallBottomBar extends owl.Component {
|
|
|
82702
82826
|
height: this.focus === "inactive" ? "26px" : "fit-content",
|
|
82703
82827
|
"max-height": `130px`,
|
|
82704
82828
|
}),
|
|
82705
|
-
showAssistant:
|
|
82829
|
+
showAssistant: false, // Hide assistant in small composer as it gets cropped ATM
|
|
82706
82830
|
placeholder: this.composerStore.placeholder,
|
|
82707
82831
|
};
|
|
82708
82832
|
}
|
|
@@ -84031,7 +84155,7 @@ css /* scss */ `
|
|
|
84031
84155
|
border-radius: 4px;
|
|
84032
84156
|
font-weight: 500;
|
|
84033
84157
|
font-size: 14px;
|
|
84034
|
-
height: 32px;
|
|
84158
|
+
min-height: 32px;
|
|
84035
84159
|
line-height: 16px;
|
|
84036
84160
|
flex-grow: 1;
|
|
84037
84161
|
background-color: ${BUTTON_BG};
|
|
@@ -88984,6 +89108,6 @@ exports.tokenColors = tokenColors;
|
|
|
88984
89108
|
exports.tokenize = tokenize;
|
|
88985
89109
|
|
|
88986
89110
|
|
|
88987
|
-
__info__.version = "19.0.
|
|
88988
|
-
__info__.date = "2025-
|
|
88989
|
-
__info__.hash = "
|
|
89111
|
+
__info__.version = "19.0.12";
|
|
89112
|
+
__info__.date = "2025-12-02T05:34:17.495Z";
|
|
89113
|
+
__info__.hash = "32203f1";
|