@odoo/o-spreadsheet 19.0.4 → 19.0.6
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 +296 -204
- package/dist/o-spreadsheet.d.ts +227 -157
- package/dist/o-spreadsheet.esm.js +296 -204
- package/dist/o-spreadsheet.iife.js +296 -204
- package/dist/o-spreadsheet.iife.min.js +278 -285
- package/dist/o_spreadsheet.xml +66 -17
- 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.6
|
|
6
|
+
* @date 2025-10-16T06:39:36.282Z
|
|
7
|
+
* @hash 0d4315a
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -1383,9 +1383,7 @@
|
|
|
1383
1383
|
return newArray;
|
|
1384
1384
|
}
|
|
1385
1385
|
function insertItemsAtIndex(array, items, index) {
|
|
1386
|
-
|
|
1387
|
-
newArray.splice(index, 0, ...items);
|
|
1388
|
-
return newArray;
|
|
1386
|
+
return array.slice(0, index).concat(items).concat(array.slice(index));
|
|
1389
1387
|
}
|
|
1390
1388
|
function replaceItemAtIndex(array, newItem, index) {
|
|
1391
1389
|
const newArray = [...array];
|
|
@@ -4516,7 +4514,17 @@
|
|
|
4516
4514
|
return toMatrix(data).map((row) => {
|
|
4517
4515
|
return row.map((cell) => {
|
|
4518
4516
|
if (typeof cell.value !== "number") {
|
|
4519
|
-
|
|
4517
|
+
let message = "";
|
|
4518
|
+
if (typeof cell === "object") {
|
|
4519
|
+
message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got an empty value.", argName);
|
|
4520
|
+
}
|
|
4521
|
+
else if (typeof cell === "string") {
|
|
4522
|
+
message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got a string.", argName);
|
|
4523
|
+
}
|
|
4524
|
+
else if (typeof cell === "boolean") {
|
|
4525
|
+
message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got a boolean.", argName);
|
|
4526
|
+
}
|
|
4527
|
+
throw new EvaluationError(message);
|
|
4520
4528
|
}
|
|
4521
4529
|
return cell.value;
|
|
4522
4530
|
});
|
|
@@ -5635,7 +5643,7 @@
|
|
|
5635
5643
|
* Replace in place tokens "mm" and "m" that denote minutes in date format with "MM" to avoid confusion with months.
|
|
5636
5644
|
*
|
|
5637
5645
|
* As per OpenXML specification, in date formats if a date token "m" or "mm" is followed by a date token "s" or
|
|
5638
|
-
* preceded by a data token "h", then it's not a month but
|
|
5646
|
+
* preceded by a data token "h", then it's not a month but a minute.
|
|
5639
5647
|
*/
|
|
5640
5648
|
function convertTokensToMinutesInDateFormat(tokens) {
|
|
5641
5649
|
const dateParts = tokens.filter((token) => token.type === "DATE_PART");
|
|
@@ -5678,6 +5686,9 @@
|
|
|
5678
5686
|
case "REPEATED_CHAR":
|
|
5679
5687
|
format += "*" + token.value;
|
|
5680
5688
|
break;
|
|
5689
|
+
case "DATE_PART":
|
|
5690
|
+
format += token.value === "MM" ? "mm" : token.value; // Convert "MM" back to "mm" for minutes
|
|
5691
|
+
break;
|
|
5681
5692
|
default:
|
|
5682
5693
|
format += token.value;
|
|
5683
5694
|
}
|
|
@@ -9528,7 +9539,7 @@
|
|
|
9528
9539
|
pasteCell(origin, target, clipboardOption) {
|
|
9529
9540
|
const { sheetId, col, row } = target;
|
|
9530
9541
|
const targetCell = this.getters.getEvaluatedCell(target);
|
|
9531
|
-
const originFormat = origin?.format
|
|
9542
|
+
const originFormat = origin?.format || origin.evaluatedCell.format;
|
|
9532
9543
|
if (clipboardOption?.pasteOption === "asValue") {
|
|
9533
9544
|
this.dispatch("UPDATE_CELL", {
|
|
9534
9545
|
...target,
|
|
@@ -13901,7 +13912,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
13901
13912
|
if (knownDataY.length === 0 || knownDataY[0].length === 0) {
|
|
13902
13913
|
return new EvaluationError(emptyDataErrorMessage("known_data_y"));
|
|
13903
13914
|
}
|
|
13904
|
-
return expM(predictLinearValues(logM(toNumberMatrix(knownDataY, "
|
|
13915
|
+
return expM(predictLinearValues(logM(toNumberMatrix(knownDataY, "known_data_y")), toNumberMatrix(knownDataX, "known_data_x"), toNumberMatrix(newDataX, "new_data_y"), toBoolean(b)));
|
|
13905
13916
|
},
|
|
13906
13917
|
};
|
|
13907
13918
|
// -----------------------------------------------------------------------------
|
|
@@ -13974,7 +13985,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
13974
13985
|
if (dataY.length === 0 || dataY[0].length === 0) {
|
|
13975
13986
|
return new EvaluationError(emptyDataErrorMessage("data_y"));
|
|
13976
13987
|
}
|
|
13977
|
-
return fullLinearRegression(toNumberMatrix(dataX, "
|
|
13988
|
+
return fullLinearRegression(toNumberMatrix(dataX, "data_x"), toNumberMatrix(dataY, "data_y"), toBoolean(calculateB), toBoolean(verbose));
|
|
13978
13989
|
},
|
|
13979
13990
|
isExported: true,
|
|
13980
13991
|
};
|
|
@@ -13993,7 +14004,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
13993
14004
|
if (dataY.length === 0 || dataY[0].length === 0) {
|
|
13994
14005
|
return new EvaluationError(emptyDataErrorMessage("data_y"));
|
|
13995
14006
|
}
|
|
13996
|
-
const coeffs = fullLinearRegression(toNumberMatrix(dataX, "
|
|
14007
|
+
const coeffs = fullLinearRegression(toNumberMatrix(dataX, "data_x"), logM(toNumberMatrix(dataY, "data_y")), toBoolean(calculateB), toBoolean(verbose));
|
|
13997
14008
|
for (let i = 0; i < coeffs.length; i++) {
|
|
13998
14009
|
coeffs[i][0] = Math.exp(coeffs[i][0]);
|
|
13999
14010
|
}
|
|
@@ -14614,7 +14625,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
14614
14625
|
if (knownDataY.length === 0 || knownDataY[0].length === 0) {
|
|
14615
14626
|
return new EvaluationError(emptyDataErrorMessage("known_data_y"));
|
|
14616
14627
|
}
|
|
14617
|
-
return predictLinearValues(toNumberMatrix(knownDataY, "
|
|
14628
|
+
return predictLinearValues(toNumberMatrix(knownDataY, "known_data_y"), toNumberMatrix(knownDataX, "known_data_x"), toNumberMatrix(newDataX, "new_data_y"), toBoolean(b));
|
|
14618
14629
|
},
|
|
14619
14630
|
};
|
|
14620
14631
|
// -----------------------------------------------------------------------------
|
|
@@ -23135,6 +23146,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23135
23146
|
}
|
|
23136
23147
|
const ctx = chart.ctx;
|
|
23137
23148
|
ctx.save();
|
|
23149
|
+
const { left, top, height, width } = chart.chartArea;
|
|
23150
|
+
ctx.beginPath();
|
|
23151
|
+
ctx.rect(left, top, width, height);
|
|
23152
|
+
ctx.clip();
|
|
23138
23153
|
ctx.textAlign = "center";
|
|
23139
23154
|
ctx.textBaseline = "middle";
|
|
23140
23155
|
ctx.miterLimit = 1; // Avoid sharp artifacts on strokeText
|
|
@@ -24178,7 +24193,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24178
24193
|
this.chart.update();
|
|
24179
24194
|
}
|
|
24180
24195
|
hasChartDataChanged() {
|
|
24181
|
-
return !deepEquals(this.currentRuntime
|
|
24196
|
+
return !deepEquals(this.getChartDataInRuntime(this.currentRuntime), this.getChartDataInRuntime(this.chartRuntime));
|
|
24182
24197
|
}
|
|
24183
24198
|
enableAnimationInChartData(chartData) {
|
|
24184
24199
|
return {
|
|
@@ -24186,6 +24201,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24186
24201
|
options: { ...chartData.options, animation: { animateRotate: true } },
|
|
24187
24202
|
};
|
|
24188
24203
|
}
|
|
24204
|
+
getChartDataInRuntime(runtime) {
|
|
24205
|
+
const data = runtime.chartJsConfig.data;
|
|
24206
|
+
return {
|
|
24207
|
+
labels: data.labels,
|
|
24208
|
+
dataset: data.datasets.map((dataset) => ({
|
|
24209
|
+
data: dataset.data,
|
|
24210
|
+
label: dataset.label,
|
|
24211
|
+
tree: dataset.tree,
|
|
24212
|
+
})),
|
|
24213
|
+
};
|
|
24214
|
+
}
|
|
24189
24215
|
get animationChartId() {
|
|
24190
24216
|
return this.props.isFullScreen ? this.props.chartId + "-fullscreen" : this.props.chartId;
|
|
24191
24217
|
}
|
|
@@ -24853,6 +24879,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24853
24879
|
static template = "o-spreadsheet-ScorecardChart";
|
|
24854
24880
|
static props = {
|
|
24855
24881
|
chartId: String,
|
|
24882
|
+
isFullScreen: { type: Boolean, optional: true },
|
|
24856
24883
|
};
|
|
24857
24884
|
canvas = owl.useRef("chartContainer");
|
|
24858
24885
|
get runtime() {
|
|
@@ -25608,6 +25635,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25608
25635
|
parser: luxonFormat,
|
|
25609
25636
|
displayFormats,
|
|
25610
25637
|
unit: timeUnit ?? false,
|
|
25638
|
+
tooltipFormat: luxonFormat,
|
|
25611
25639
|
};
|
|
25612
25640
|
}
|
|
25613
25641
|
/**
|
|
@@ -26676,6 +26704,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
26676
26704
|
};
|
|
26677
26705
|
Object.assign(scales.x, axis);
|
|
26678
26706
|
scales.x.ticks.maxTicksLimit = 15;
|
|
26707
|
+
delete scales?.x?.ticks?.callback;
|
|
26679
26708
|
}
|
|
26680
26709
|
else if (axisType === "linear") {
|
|
26681
26710
|
scales.x.type = "linear";
|
|
@@ -27616,26 +27645,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27616
27645
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
27617
27646
|
}
|
|
27618
27647
|
|
|
27619
|
-
class FullScreenChartStore extends SpreadsheetStore {
|
|
27620
|
-
mutators = ["toggleFullScreenChart"];
|
|
27621
|
-
fullScreenFigure = undefined;
|
|
27622
|
-
toggleFullScreenChart(figureId) {
|
|
27623
|
-
if (this.fullScreenFigure?.id === figureId) {
|
|
27624
|
-
this.fullScreenFigure = undefined;
|
|
27625
|
-
}
|
|
27626
|
-
else {
|
|
27627
|
-
this.makeFullScreen(figureId);
|
|
27628
|
-
}
|
|
27629
|
-
}
|
|
27630
|
-
makeFullScreen(figureId) {
|
|
27631
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
27632
|
-
const figure = this.getters.getFigure(sheetId, figureId);
|
|
27633
|
-
if (figure) {
|
|
27634
|
-
this.fullScreenFigure = { ...figure, x: 0, y: 0, width: 0, height: 0 };
|
|
27635
|
-
}
|
|
27636
|
-
}
|
|
27637
|
-
}
|
|
27638
|
-
|
|
27639
27648
|
const TREND_LINE_AXES_IDS = [TREND_LINE_XAXIS_ID, MOVING_AVERAGE_TREND_LINE_XAXIS_ID];
|
|
27640
27649
|
const ZOOMABLE_AXIS_IDS = ["x", ...TREND_LINE_AXES_IDS];
|
|
27641
27650
|
class ZoomableChartStore extends SpreadsheetStore {
|
|
@@ -27807,7 +27816,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27807
27816
|
class ZoomableChartJsComponent extends ChartJsComponent {
|
|
27808
27817
|
static template = "o-spreadsheet-ZoomableChartJsComponent";
|
|
27809
27818
|
store;
|
|
27810
|
-
fullScreenChartStore;
|
|
27811
27819
|
masterChartCanvas = owl.useRef("masterChartCanvas");
|
|
27812
27820
|
masterChart;
|
|
27813
27821
|
mode;
|
|
@@ -27818,7 +27826,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27818
27826
|
removeEventListeners = () => { };
|
|
27819
27827
|
setup() {
|
|
27820
27828
|
this.store = useStore(ZoomableChartStore);
|
|
27821
|
-
this.fullScreenChartStore = useStore(FullScreenChartStore);
|
|
27822
27829
|
super.setup();
|
|
27823
27830
|
}
|
|
27824
27831
|
unmount() {
|
|
@@ -27833,12 +27840,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27833
27840
|
`;
|
|
27834
27841
|
}
|
|
27835
27842
|
get sliceable() {
|
|
27836
|
-
if (this.
|
|
27837
|
-
|
|
27838
|
-
const chartFigureId = this.env.model.getters.getFigureIdFromChartId(this.props.chartId);
|
|
27839
|
-
if (fullScreenFigureId === chartFigureId) {
|
|
27840
|
-
return true;
|
|
27841
|
-
}
|
|
27843
|
+
if (this.props.isFullScreen) {
|
|
27844
|
+
return true;
|
|
27842
27845
|
}
|
|
27843
27846
|
const definition = this.env.model.getters.getChartDefinition(this.props.chartId);
|
|
27844
27847
|
return ("zoomable" in definition && definition?.zoomable) ?? false;
|
|
@@ -27901,9 +27904,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27901
27904
|
const xMax = Math.max(...xValues);
|
|
27902
27905
|
return { xMin, xMax };
|
|
27903
27906
|
}
|
|
27904
|
-
get shouldAnimate() {
|
|
27905
|
-
return this.env.model.getters.isDashboard() && !this.sliceable;
|
|
27906
|
-
}
|
|
27907
27907
|
createChart(chartRuntime) {
|
|
27908
27908
|
const chartData = chartRuntime.chartJsConfig;
|
|
27909
27909
|
this.isBarChart = chartData.type === "bar";
|
|
@@ -27922,6 +27922,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27922
27922
|
const masterChartCtx = this.masterChartCanvas.el.getContext("2d");
|
|
27923
27923
|
this.masterChart = new window.Chart(masterChartCtx, this.getMasterChartConfiguration(chartRuntime["masterChartConfig"]));
|
|
27924
27924
|
this.resetAxesLimits();
|
|
27925
|
+
if (this.chart?.options) {
|
|
27926
|
+
this.chart.options.animation = false;
|
|
27927
|
+
}
|
|
27925
27928
|
}
|
|
27926
27929
|
updateChartJs(chartRuntime) {
|
|
27927
27930
|
const chartData = chartRuntime.chartJsConfig;
|
|
@@ -27955,6 +27958,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27955
27958
|
}
|
|
27956
27959
|
}
|
|
27957
27960
|
this.resetAxesLimits();
|
|
27961
|
+
if (this.chart?.options) {
|
|
27962
|
+
this.chart.options.animation = false;
|
|
27963
|
+
}
|
|
27958
27964
|
}
|
|
27959
27965
|
resetAxesLimits() {
|
|
27960
27966
|
if (!this.chart) {
|
|
@@ -28052,7 +28058,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28052
28058
|
onPointerDownInMasterChart(ev) {
|
|
28053
28059
|
this.removeEventListeners();
|
|
28054
28060
|
const position = ev.offsetX;
|
|
28055
|
-
if (!this.masterChart?.chartArea || !this.chart?.scales
|
|
28061
|
+
if (!this.masterChart?.chartArea || !this.chart?.scales?.x) {
|
|
28056
28062
|
return;
|
|
28057
28063
|
}
|
|
28058
28064
|
const { left, right, top, bottom } = this.masterChart.chartArea;
|
|
@@ -31610,6 +31616,26 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31610
31616
|
return matchedChart.displayName;
|
|
31611
31617
|
}
|
|
31612
31618
|
|
|
31619
|
+
class FullScreenFigureStore extends SpreadsheetStore {
|
|
31620
|
+
mutators = ["toggleFullScreenFigure"];
|
|
31621
|
+
fullScreenFigure = undefined;
|
|
31622
|
+
toggleFullScreenFigure(figureId) {
|
|
31623
|
+
if (this.fullScreenFigure?.id === figureId) {
|
|
31624
|
+
this.fullScreenFigure = undefined;
|
|
31625
|
+
}
|
|
31626
|
+
else {
|
|
31627
|
+
this.makeFullScreen(figureId);
|
|
31628
|
+
}
|
|
31629
|
+
}
|
|
31630
|
+
makeFullScreen(figureId) {
|
|
31631
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
31632
|
+
const figure = this.getters.getFigure(sheetId, figureId);
|
|
31633
|
+
if (figure) {
|
|
31634
|
+
this.fullScreenFigure = { ...figure, x: 0, y: 0, width: 0, height: 0 };
|
|
31635
|
+
}
|
|
31636
|
+
}
|
|
31637
|
+
}
|
|
31638
|
+
|
|
31613
31639
|
/**
|
|
31614
31640
|
* Repeatedly calls a callback function with a time delay between calls.
|
|
31615
31641
|
*/
|
|
@@ -32347,12 +32373,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32347
32373
|
class ChartDashboardMenu extends owl.Component {
|
|
32348
32374
|
static template = "o-spreadsheet-ChartDashboardMenu";
|
|
32349
32375
|
static components = { MenuPopover };
|
|
32350
|
-
static props = { chartId: String };
|
|
32376
|
+
static props = { chartId: String, hasFullScreenButton: { type: Boolean, optional: true } };
|
|
32377
|
+
static defaultProps = { hasFullScreenButton: true };
|
|
32351
32378
|
fullScreenFigureStore;
|
|
32352
32379
|
menuState = owl.useState({ isOpen: false, anchorRect: null, menuItems: [] });
|
|
32353
32380
|
setup() {
|
|
32354
32381
|
super.setup();
|
|
32355
|
-
this.fullScreenFigureStore = useStore(
|
|
32382
|
+
this.fullScreenFigureStore = useStore(FullScreenFigureStore);
|
|
32356
32383
|
}
|
|
32357
32384
|
getMenuItems() {
|
|
32358
32385
|
return [this.fullScreenMenuItem].filter(isDefined);
|
|
@@ -32363,11 +32390,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32363
32390
|
}
|
|
32364
32391
|
openContextMenu(ev) {
|
|
32365
32392
|
this.menuState.isOpen = true;
|
|
32366
|
-
this.menuState.anchorRect =
|
|
32393
|
+
this.menuState.anchorRect = getBoundingRectAsPOJO(ev.currentTarget);
|
|
32367
32394
|
const figureId = this.env.model.getters.getFigureIdFromChartId(this.props.chartId);
|
|
32368
32395
|
this.menuState.menuItems = getChartMenuActions(figureId, () => { }, this.env);
|
|
32369
32396
|
}
|
|
32370
32397
|
get fullScreenMenuItem() {
|
|
32398
|
+
if (!this.props.hasFullScreenButton) {
|
|
32399
|
+
return undefined;
|
|
32400
|
+
}
|
|
32371
32401
|
const definition = this.env.model.getters.getChartDefinition(this.props.chartId);
|
|
32372
32402
|
const figureId = this.env.model.getters.getFigureIdFromChartId(this.props.chartId);
|
|
32373
32403
|
if (definition.type === "scorecard") {
|
|
@@ -32379,7 +32409,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32379
32409
|
label: isFullScreen ? _t("Exit Full Screen") : _t("Full Screen"),
|
|
32380
32410
|
class: `text-muted fa ${isFullScreen ? "fa-compress" : "fa-expand"}`,
|
|
32381
32411
|
onClick: () => {
|
|
32382
|
-
this.fullScreenFigureStore.
|
|
32412
|
+
this.fullScreenFigureStore.toggleFullScreenFigure(figureId);
|
|
32383
32413
|
},
|
|
32384
32414
|
};
|
|
32385
32415
|
}
|
|
@@ -32391,6 +32421,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32391
32421
|
figureUI: Object,
|
|
32392
32422
|
onFigureDeleted: Function,
|
|
32393
32423
|
editFigureStyle: { type: Function, optional: true },
|
|
32424
|
+
isFullScreen: { type: Boolean, optional: true },
|
|
32425
|
+
openContextMenu: { type: Function, optional: true },
|
|
32394
32426
|
};
|
|
32395
32427
|
static components = { ChartDashboardMenu, MenuPopover };
|
|
32396
32428
|
carouselTabsRef = owl.useRef("carouselTabs");
|
|
@@ -32398,8 +32430,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32398
32430
|
menuState = owl.useState({ isOpen: false, anchorRect: null, menuItems: [] });
|
|
32399
32431
|
hiddenItems = [];
|
|
32400
32432
|
animationStore;
|
|
32433
|
+
fullScreenFigureStore;
|
|
32401
32434
|
setup() {
|
|
32402
32435
|
this.animationStore = useStore(ChartAnimationStore);
|
|
32436
|
+
this.fullScreenFigureStore = useStore(FullScreenFigureStore);
|
|
32403
32437
|
owl.useEffect(() => {
|
|
32404
32438
|
if (this.selectedCarouselItem?.type === "carouselDataView") {
|
|
32405
32439
|
this.props.editFigureStyle?.({ "pointer-events": "none" });
|
|
@@ -32446,7 +32480,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32446
32480
|
item,
|
|
32447
32481
|
});
|
|
32448
32482
|
if (item.type === "chart") {
|
|
32449
|
-
|
|
32483
|
+
const animationChartId = item.chartId + (this.props.isFullScreen ? "-fullscreen" : "");
|
|
32484
|
+
this.animationStore?.enableAnimationForChart(animationChartId);
|
|
32450
32485
|
}
|
|
32451
32486
|
}
|
|
32452
32487
|
get headerStyle() {
|
|
@@ -32510,6 +32545,23 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32510
32545
|
this.menuState.anchorRect = rect;
|
|
32511
32546
|
this.menuState.menuItems = createActions(menuItems);
|
|
32512
32547
|
}
|
|
32548
|
+
toggleFullScreen() {
|
|
32549
|
+
if (this.selectedCarouselItem?.type === "chart") {
|
|
32550
|
+
this.fullScreenFigureStore.toggleFullScreenFigure(this.props.figureUI.id);
|
|
32551
|
+
}
|
|
32552
|
+
}
|
|
32553
|
+
get fullScreenButtonTitle() {
|
|
32554
|
+
return this.props.isFullScreen ? _t("Exit Full Screen") : _t("Full Screen");
|
|
32555
|
+
}
|
|
32556
|
+
get visibleCarouselItems() {
|
|
32557
|
+
return this.carousel.items.filter((item) => item.type === "carouselDataView" && this.props.isFullScreen ? false : true);
|
|
32558
|
+
}
|
|
32559
|
+
openContextMenu(event) {
|
|
32560
|
+
const target = event.currentTarget;
|
|
32561
|
+
if (target) {
|
|
32562
|
+
this.props.openContextMenu?.(getBoundingRectAsPOJO(target));
|
|
32563
|
+
}
|
|
32564
|
+
}
|
|
32513
32565
|
}
|
|
32514
32566
|
|
|
32515
32567
|
class ChartFigure extends owl.Component {
|
|
@@ -32518,6 +32570,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32518
32570
|
figureUI: Object,
|
|
32519
32571
|
onFigureDeleted: Function,
|
|
32520
32572
|
editFigureStyle: { type: Function, optional: true },
|
|
32573
|
+
isFullScreen: { type: Boolean, optional: true },
|
|
32574
|
+
openContextMenu: { type: Function, optional: true },
|
|
32521
32575
|
};
|
|
32522
32576
|
static components = { ChartDashboardMenu };
|
|
32523
32577
|
onDoubleClick() {
|
|
@@ -32550,6 +32604,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32550
32604
|
figureUI: Object,
|
|
32551
32605
|
onFigureDeleted: Function,
|
|
32552
32606
|
editFigureStyle: { type: Function, optional: true },
|
|
32607
|
+
openContextMenu: { type: Function, optional: true },
|
|
32553
32608
|
};
|
|
32554
32609
|
static components = {};
|
|
32555
32610
|
// ---------------------------------------------------------------------------
|
|
@@ -34601,8 +34656,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34601
34656
|
}
|
|
34602
34657
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
34603
34658
|
this.props.composerStore.stopComposerRangeSelection();
|
|
34604
|
-
this.props.
|
|
34605
|
-
this.props.
|
|
34659
|
+
const isCurrentlyInactive = this.props.composerStore.editionMode === "inactive";
|
|
34660
|
+
this.props.onComposerContentFocused(newSelection);
|
|
34661
|
+
if (!isCurrentlyInactive) {
|
|
34662
|
+
this.props.composerStore.changeComposerCursorSelection(newSelection.start, newSelection.end);
|
|
34663
|
+
}
|
|
34606
34664
|
this.processTokenAtCursor();
|
|
34607
34665
|
}
|
|
34608
34666
|
onDblClick() {
|
|
@@ -35097,13 +35155,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35097
35155
|
}
|
|
35098
35156
|
}
|
|
35099
35157
|
startEdition(text, selection) {
|
|
35100
|
-
if (selection) {
|
|
35101
|
-
const content = text || this.getComposerContent(this.getters.getActivePosition());
|
|
35102
|
-
const validSelection = this.isSelectionValid(content.length, selection.start, selection.end);
|
|
35103
|
-
if (!validSelection) {
|
|
35104
|
-
return;
|
|
35105
|
-
}
|
|
35106
|
-
}
|
|
35107
35158
|
const { col, row } = this.getters.getActivePosition();
|
|
35108
35159
|
this.model.dispatch("SELECT_FIGURE", { figureId: null });
|
|
35109
35160
|
this.model.dispatch("SCROLL_TO_CELL", { col, row });
|
|
@@ -35160,7 +35211,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35160
35211
|
// ---------------------------------------------------------------------------
|
|
35161
35212
|
get currentContent() {
|
|
35162
35213
|
if (this.editionMode === "inactive") {
|
|
35163
|
-
return this.getComposerContent(this.getters.getActivePosition());
|
|
35214
|
+
return this.getComposerContent(this.getters.getActivePosition()).text;
|
|
35164
35215
|
}
|
|
35165
35216
|
return this._currentContent;
|
|
35166
35217
|
}
|
|
@@ -35359,8 +35410,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35359
35410
|
this.sheetId = sheetId;
|
|
35360
35411
|
this.row = row;
|
|
35361
35412
|
this.editionMode = "editing";
|
|
35362
|
-
|
|
35363
|
-
this.
|
|
35413
|
+
const { text, adjustedSelection } = this.getComposerContent({ sheetId, col, row }, selection);
|
|
35414
|
+
this.initialContent = text;
|
|
35415
|
+
this.setContent(str || this.initialContent, adjustedSelection ?? selection);
|
|
35364
35416
|
this.colorIndexByRange = {};
|
|
35365
35417
|
const zone = positionToZone({ col: this.col, row: this.row });
|
|
35366
35418
|
this.captureSelection(zone, col, row);
|
|
@@ -35837,7 +35889,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35837
35889
|
constructor(get, args) {
|
|
35838
35890
|
super(get);
|
|
35839
35891
|
this.args = args;
|
|
35840
|
-
this._currentContent = this.getComposerContent();
|
|
35892
|
+
this._currentContent = this.getComposerContent().text;
|
|
35841
35893
|
}
|
|
35842
35894
|
getAutoCompleteProviders() {
|
|
35843
35895
|
const providersDefinitions = super.getAutoCompleteProviders();
|
|
@@ -35874,7 +35926,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35874
35926
|
})
|
|
35875
35927
|
.join("");
|
|
35876
35928
|
}
|
|
35877
|
-
return localizeContent(content, this.getters.getLocale());
|
|
35929
|
+
return { text: localizeContent(content, this.getters.getLocale()) };
|
|
35878
35930
|
}
|
|
35879
35931
|
stopEdition() {
|
|
35880
35932
|
this._stopEdition();
|
|
@@ -39552,6 +39604,74 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
39552
39604
|
return path2D;
|
|
39553
39605
|
}
|
|
39554
39606
|
|
|
39607
|
+
/**
|
|
39608
|
+
* Get the relative path between two files
|
|
39609
|
+
*
|
|
39610
|
+
* Eg.:
|
|
39611
|
+
* from "folder1/file1.txt" to "folder2/file2.txt" => "../folder2/file2.txt"
|
|
39612
|
+
*/
|
|
39613
|
+
function getRelativePath(from, to) {
|
|
39614
|
+
const fromPathParts = from.split("/");
|
|
39615
|
+
const toPathParts = to.split("/");
|
|
39616
|
+
let relPath = "";
|
|
39617
|
+
let startIndex = 0;
|
|
39618
|
+
for (let i = 0; i < fromPathParts.length - 1; i++) {
|
|
39619
|
+
if (fromPathParts[i] === toPathParts[i]) {
|
|
39620
|
+
startIndex++;
|
|
39621
|
+
}
|
|
39622
|
+
else {
|
|
39623
|
+
relPath += "../";
|
|
39624
|
+
}
|
|
39625
|
+
}
|
|
39626
|
+
relPath += toPathParts.slice(startIndex).join("/");
|
|
39627
|
+
return relPath;
|
|
39628
|
+
}
|
|
39629
|
+
/**
|
|
39630
|
+
* Convert an array of element into an object where the objects keys were the elements position in the array.
|
|
39631
|
+
* Can give an offset as argument, and all the array indexes will we shifted by this offset in the returned object.
|
|
39632
|
+
*
|
|
39633
|
+
* eg. : ["a", "b"] => {0:"a", 1:"b"}
|
|
39634
|
+
*/
|
|
39635
|
+
function arrayToObject(array, indexOffset = 0) {
|
|
39636
|
+
const obj = {};
|
|
39637
|
+
for (let i = 0; i < array.length; i++) {
|
|
39638
|
+
if (array[i]) {
|
|
39639
|
+
obj[i + indexOffset] = array[i];
|
|
39640
|
+
}
|
|
39641
|
+
}
|
|
39642
|
+
return obj;
|
|
39643
|
+
}
|
|
39644
|
+
/**
|
|
39645
|
+
* In xlsx we can have string with unicode characters with the format _x00fa_.
|
|
39646
|
+
* Replace with characters understandable by JS
|
|
39647
|
+
*/
|
|
39648
|
+
function fixXlsxUnicode(str) {
|
|
39649
|
+
return str.replace(/_x([0-9a-zA-Z]{4})_/g, (match, code) => {
|
|
39650
|
+
return String.fromCharCode(parseInt(code, 16));
|
|
39651
|
+
});
|
|
39652
|
+
}
|
|
39653
|
+
/** Get a header in the SheetData. Create the header if it doesn't exist in the SheetData */
|
|
39654
|
+
function getSheetDataHeader(sheetData, dimension, index) {
|
|
39655
|
+
if (dimension === "COL") {
|
|
39656
|
+
if (!sheetData.cols[index]) {
|
|
39657
|
+
sheetData.cols[index] = {};
|
|
39658
|
+
}
|
|
39659
|
+
return sheetData.cols[index];
|
|
39660
|
+
}
|
|
39661
|
+
if (!sheetData.rows[index]) {
|
|
39662
|
+
sheetData.rows[index] = {};
|
|
39663
|
+
}
|
|
39664
|
+
return sheetData.rows[index];
|
|
39665
|
+
}
|
|
39666
|
+
/** Prefix the string by "=" if the string looks like a formula */
|
|
39667
|
+
function prefixFormulaWithEqual(formula) {
|
|
39668
|
+
if (formula[0] === "=") {
|
|
39669
|
+
return formula;
|
|
39670
|
+
}
|
|
39671
|
+
const tokens = tokenize(formula);
|
|
39672
|
+
return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
|
|
39673
|
+
}
|
|
39674
|
+
|
|
39555
39675
|
/**
|
|
39556
39676
|
* Map of the different types of conversions warnings and their name in error messages
|
|
39557
39677
|
*/
|
|
@@ -40074,66 +40194,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40074
40194
|
*/
|
|
40075
40195
|
const DEFAULT_SYSTEM_COLOR = "FF000000";
|
|
40076
40196
|
|
|
40077
|
-
/**
|
|
40078
|
-
* Get the relative path between two files
|
|
40079
|
-
*
|
|
40080
|
-
* Eg.:
|
|
40081
|
-
* from "folder1/file1.txt" to "folder2/file2.txt" => "../folder2/file2.txt"
|
|
40082
|
-
*/
|
|
40083
|
-
function getRelativePath(from, to) {
|
|
40084
|
-
const fromPathParts = from.split("/");
|
|
40085
|
-
const toPathParts = to.split("/");
|
|
40086
|
-
let relPath = "";
|
|
40087
|
-
let startIndex = 0;
|
|
40088
|
-
for (let i = 0; i < fromPathParts.length - 1; i++) {
|
|
40089
|
-
if (fromPathParts[i] === toPathParts[i]) {
|
|
40090
|
-
startIndex++;
|
|
40091
|
-
}
|
|
40092
|
-
else {
|
|
40093
|
-
relPath += "../";
|
|
40094
|
-
}
|
|
40095
|
-
}
|
|
40096
|
-
relPath += toPathParts.slice(startIndex).join("/");
|
|
40097
|
-
return relPath;
|
|
40098
|
-
}
|
|
40099
|
-
/**
|
|
40100
|
-
* Convert an array of element into an object where the objects keys were the elements position in the array.
|
|
40101
|
-
* Can give an offset as argument, and all the array indexes will we shifted by this offset in the returned object.
|
|
40102
|
-
*
|
|
40103
|
-
* eg. : ["a", "b"] => {0:"a", 1:"b"}
|
|
40104
|
-
*/
|
|
40105
|
-
function arrayToObject(array, indexOffset = 0) {
|
|
40106
|
-
const obj = {};
|
|
40107
|
-
for (let i = 0; i < array.length; i++) {
|
|
40108
|
-
if (array[i]) {
|
|
40109
|
-
obj[i + indexOffset] = array[i];
|
|
40110
|
-
}
|
|
40111
|
-
}
|
|
40112
|
-
return obj;
|
|
40113
|
-
}
|
|
40114
|
-
/**
|
|
40115
|
-
* In xlsx we can have string with unicode characters with the format _x00fa_.
|
|
40116
|
-
* Replace with characters understandable by JS
|
|
40117
|
-
*/
|
|
40118
|
-
function fixXlsxUnicode(str) {
|
|
40119
|
-
return str.replace(/_x([0-9a-zA-Z]{4})_/g, (match, code) => {
|
|
40120
|
-
return String.fromCharCode(parseInt(code, 16));
|
|
40121
|
-
});
|
|
40122
|
-
}
|
|
40123
|
-
/** Get a header in the SheetData. Create the header if it doesn't exist in the SheetData */
|
|
40124
|
-
function getSheetDataHeader(sheetData, dimension, index) {
|
|
40125
|
-
if (dimension === "COL") {
|
|
40126
|
-
if (!sheetData.cols[index]) {
|
|
40127
|
-
sheetData.cols[index] = {};
|
|
40128
|
-
}
|
|
40129
|
-
return sheetData.cols[index];
|
|
40130
|
-
}
|
|
40131
|
-
if (!sheetData.rows[index]) {
|
|
40132
|
-
sheetData.rows[index] = {};
|
|
40133
|
-
}
|
|
40134
|
-
return sheetData.rows[index];
|
|
40135
|
-
}
|
|
40136
|
-
|
|
40137
40197
|
const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/m|\s|-|\/|\.|:)+$/i;
|
|
40138
40198
|
/**
|
|
40139
40199
|
* Convert excel format to o_spreadsheet format
|
|
@@ -40348,9 +40408,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40348
40408
|
if (!rule.operator || !rule.formula || rule.formula.length === 0)
|
|
40349
40409
|
continue;
|
|
40350
40410
|
operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.operator];
|
|
40351
|
-
values.push(
|
|
40411
|
+
values.push(prefixFormulaWithEqual(rule.formula[0]));
|
|
40352
40412
|
if (rule.formula.length === 2) {
|
|
40353
|
-
values.push(
|
|
40413
|
+
values.push(prefixFormulaWithEqual(rule.formula[1]));
|
|
40354
40414
|
}
|
|
40355
40415
|
break;
|
|
40356
40416
|
}
|
|
@@ -40508,11 +40568,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40508
40568
|
? ICON_SETS[iconSet].neutral
|
|
40509
40569
|
: ICON_SETS[iconSet].good;
|
|
40510
40570
|
}
|
|
40511
|
-
/** Prefix the string by "=" if the string looks like a formula */
|
|
40512
|
-
function prefixFormula(formula) {
|
|
40513
|
-
const tokens = tokenize(formula);
|
|
40514
|
-
return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
|
|
40515
|
-
}
|
|
40516
40571
|
// ---------------------------------------------------------------------------
|
|
40517
40572
|
// Warnings
|
|
40518
40573
|
// ---------------------------------------------------------------------------
|
|
@@ -40988,7 +41043,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40988
41043
|
dvRules.push(decimalRule);
|
|
40989
41044
|
break;
|
|
40990
41045
|
case "list":
|
|
40991
|
-
const listRule =
|
|
41046
|
+
const listRule = convertListRule(dvId++, dv);
|
|
40992
41047
|
dvRules.push(listRule);
|
|
40993
41048
|
break;
|
|
40994
41049
|
case "date":
|
|
@@ -41008,9 +41063,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
41008
41063
|
return dvRules;
|
|
41009
41064
|
}
|
|
41010
41065
|
function convertDecimalRule(id, dv) {
|
|
41011
|
-
const values = [dv.formula1.toString()];
|
|
41066
|
+
const values = [prefixFormulaWithEqual(dv.formula1.toString())];
|
|
41012
41067
|
if (dv.formula2) {
|
|
41013
|
-
values.push(dv.formula2.toString());
|
|
41068
|
+
values.push(prefixFormulaWithEqual(dv.formula2.toString()));
|
|
41014
41069
|
}
|
|
41015
41070
|
return {
|
|
41016
41071
|
id: id.toString(),
|
|
@@ -41022,7 +41077,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
41022
41077
|
},
|
|
41023
41078
|
};
|
|
41024
41079
|
}
|
|
41025
|
-
function
|
|
41080
|
+
function convertListRule(id, dv) {
|
|
41026
41081
|
const formula1 = dv.formula1.toString();
|
|
41027
41082
|
const isRangeRule = rangeReference.test(formula1);
|
|
41028
41083
|
return {
|
|
@@ -41038,9 +41093,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
41038
41093
|
}
|
|
41039
41094
|
function convertDateRule(id, dv) {
|
|
41040
41095
|
let criterion;
|
|
41041
|
-
const values = [dv.formula1.toString()];
|
|
41096
|
+
const values = [prefixFormulaWithEqual(dv.formula1.toString())];
|
|
41042
41097
|
if (dv.formula2) {
|
|
41043
|
-
values.push(dv.formula2.toString());
|
|
41098
|
+
values.push(prefixFormulaWithEqual(dv.formula2.toString()));
|
|
41044
41099
|
criterion = {
|
|
41045
41100
|
type: XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[dv.operator],
|
|
41046
41101
|
values: getDateCriterionFormattedValues(values, DEFAULT_LOCALE),
|
|
@@ -41067,7 +41122,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
41067
41122
|
isBlocking: dv.errorStyle !== "warning",
|
|
41068
41123
|
criterion: {
|
|
41069
41124
|
type: "customFormula",
|
|
41070
|
-
values: [
|
|
41125
|
+
values: [prefixFormulaWithEqual(dv.formula1.toString())],
|
|
41071
41126
|
},
|
|
41072
41127
|
};
|
|
41073
41128
|
}
|
|
@@ -49731,39 +49786,63 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49731
49786
|
this.model.dispatch("AUTOFILL_TABLE_COLUMN", { ...this.currentEditedCell });
|
|
49732
49787
|
this.setContent("");
|
|
49733
49788
|
}
|
|
49734
|
-
getComposerContent(position) {
|
|
49789
|
+
getComposerContent(position, selection) {
|
|
49735
49790
|
const locale = this.getters.getLocale();
|
|
49736
49791
|
const cell = this.getters.getCell(position);
|
|
49737
49792
|
if (cell?.isFormula) {
|
|
49738
49793
|
const prettifiedContent = this.getPrettifiedFormula(cell);
|
|
49739
|
-
|
|
49794
|
+
// when a formula is prettified (multi lines, indented), adapt the cursor position
|
|
49795
|
+
// to take into account line breaks and tabs
|
|
49796
|
+
function adjustCursorIndex(targetIndex) {
|
|
49797
|
+
let adjustedIndex = 0;
|
|
49798
|
+
let originalIndex = 0;
|
|
49799
|
+
while (originalIndex < targetIndex) {
|
|
49800
|
+
adjustedIndex++;
|
|
49801
|
+
const char = prettifiedContent[adjustedIndex];
|
|
49802
|
+
if (char !== "\n" && char !== "\t") {
|
|
49803
|
+
originalIndex++;
|
|
49804
|
+
}
|
|
49805
|
+
}
|
|
49806
|
+
return adjustedIndex;
|
|
49807
|
+
}
|
|
49808
|
+
let adjustedSelection = selection;
|
|
49809
|
+
if (selection) {
|
|
49810
|
+
adjustedSelection = {
|
|
49811
|
+
start: adjustCursorIndex(selection.start),
|
|
49812
|
+
end: adjustCursorIndex(selection.end),
|
|
49813
|
+
};
|
|
49814
|
+
}
|
|
49815
|
+
return {
|
|
49816
|
+
text: localizeFormula(prettifiedContent, locale),
|
|
49817
|
+
adjustedSelection,
|
|
49818
|
+
};
|
|
49740
49819
|
}
|
|
49741
49820
|
const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
|
|
49742
49821
|
if (spreader) {
|
|
49743
|
-
return "";
|
|
49822
|
+
return { text: "" };
|
|
49744
49823
|
}
|
|
49745
49824
|
const { format, value, type, formattedValue } = this.getters.getEvaluatedCell(position);
|
|
49746
49825
|
switch (type) {
|
|
49747
49826
|
case CellValueType.empty:
|
|
49748
|
-
return "";
|
|
49827
|
+
return { text: "" };
|
|
49749
49828
|
case CellValueType.text:
|
|
49750
49829
|
case CellValueType.error:
|
|
49751
|
-
return value;
|
|
49830
|
+
return { text: value };
|
|
49752
49831
|
case CellValueType.boolean:
|
|
49753
|
-
return formattedValue;
|
|
49832
|
+
return { text: formattedValue };
|
|
49754
49833
|
case CellValueType.number:
|
|
49755
49834
|
if (format && isDateTimeFormat(format)) {
|
|
49756
49835
|
if (parseDateTime(formattedValue, locale) !== null) {
|
|
49757
49836
|
// formatted string can be parsed again
|
|
49758
|
-
return formattedValue;
|
|
49837
|
+
return { text: formattedValue };
|
|
49759
49838
|
}
|
|
49760
49839
|
// display a simplified and parsable string otherwise
|
|
49761
49840
|
const timeFormat = Number.isInteger(value)
|
|
49762
49841
|
? locale.dateFormat
|
|
49763
49842
|
: getDateTimeFormat(locale);
|
|
49764
|
-
return formatValue(value, { locale, format: timeFormat });
|
|
49843
|
+
return { text: formatValue(value, { locale, format: timeFormat }) };
|
|
49765
49844
|
}
|
|
49766
|
-
return this.numberComposerContent(value, format, locale);
|
|
49845
|
+
return { text: this.numberComposerContent(value, format, locale) };
|
|
49767
49846
|
}
|
|
49768
49847
|
}
|
|
49769
49848
|
getPrettifiedFormula(cell) {
|
|
@@ -49932,8 +50011,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49932
50011
|
},
|
|
49933
50012
|
focus: this.focus,
|
|
49934
50013
|
isDefaultFocus: true,
|
|
49935
|
-
onComposerContentFocused: () => this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
50014
|
+
onComposerContentFocused: (selection) => this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
49936
50015
|
focusMode: "contentFocus",
|
|
50016
|
+
selection,
|
|
49937
50017
|
}),
|
|
49938
50018
|
onComposerCellFocused: (content) => this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
49939
50019
|
focusMode: "cellFocus",
|
|
@@ -57339,12 +57419,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57339
57419
|
onCloseSidePanel: { type: Function, optional: true },
|
|
57340
57420
|
};
|
|
57341
57421
|
state = owl.useState({ rule: this.defaultDataValidationRule, errors: [] });
|
|
57422
|
+
editingSheetId;
|
|
57342
57423
|
setup() {
|
|
57424
|
+
this.editingSheetId = this.env.model.getters.getActiveSheetId();
|
|
57343
57425
|
if (this.props.rule) {
|
|
57344
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
57345
57426
|
this.state.rule = {
|
|
57346
57427
|
...this.props.rule,
|
|
57347
|
-
ranges: this.props.rule.ranges.map((range) => this.env.model.getters.getRangeString(range,
|
|
57428
|
+
ranges: this.props.rule.ranges.map((range) => this.env.model.getters.getRangeString(range, this.editingSheetId)),
|
|
57348
57429
|
};
|
|
57349
57430
|
this.state.rule.criterion.type = this.props.rule.criterion.type;
|
|
57350
57431
|
}
|
|
@@ -57378,7 +57459,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57378
57459
|
const locale = this.env.model.getters.getLocale();
|
|
57379
57460
|
const criterion = rule.criterion;
|
|
57380
57461
|
const criterionEvaluator = criterionEvaluatorRegistry.get(criterion.type);
|
|
57381
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
57382
57462
|
const values = criterion.values
|
|
57383
57463
|
.slice(0, criterionEvaluator.numberOfValues(criterion))
|
|
57384
57464
|
.map((value) => value?.trim())
|
|
@@ -57386,8 +57466,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57386
57466
|
.map((value) => canonicalizeContent(value, locale));
|
|
57387
57467
|
rule.criterion = { ...criterion, values };
|
|
57388
57468
|
return {
|
|
57389
|
-
sheetId,
|
|
57390
|
-
ranges: this.state.rule.ranges.map((xc) => this.env.model.getters.getRangeDataFromXc(
|
|
57469
|
+
sheetId: this.editingSheetId,
|
|
57470
|
+
ranges: this.state.rule.ranges.map((xc) => this.env.model.getters.getRangeDataFromXc(this.editingSheetId, xc)),
|
|
57391
57471
|
rule,
|
|
57392
57472
|
};
|
|
57393
57473
|
}
|
|
@@ -57914,6 +57994,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57914
57994
|
.o-button {
|
|
57915
57995
|
height: 19px;
|
|
57916
57996
|
width: 19px;
|
|
57997
|
+
box-sizing: content-box;
|
|
57917
57998
|
.o-icon {
|
|
57918
57999
|
height: 14px;
|
|
57919
58000
|
width: 14px;
|
|
@@ -58659,7 +58740,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58659
58740
|
return undefined;
|
|
58660
58741
|
}
|
|
58661
58742
|
get isCalculatedMeasureInvalid() {
|
|
58662
|
-
return
|
|
58743
|
+
return compile(this.props.measure.computedBy?.formula ?? "").isBadExpression;
|
|
58663
58744
|
}
|
|
58664
58745
|
}
|
|
58665
58746
|
|
|
@@ -61537,16 +61618,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
61537
61618
|
}
|
|
61538
61619
|
}
|
|
61539
61620
|
|
|
61540
|
-
class
|
|
61541
|
-
static template = "o-spreadsheet-
|
|
61621
|
+
class FullScreenFigure extends owl.Component {
|
|
61622
|
+
static template = "o-spreadsheet-FullScreenFigure";
|
|
61542
61623
|
static props = {};
|
|
61543
|
-
static components = {
|
|
61544
|
-
|
|
61545
|
-
ref = owl.useRef("
|
|
61624
|
+
static components = { ChartFigure };
|
|
61625
|
+
fullScreenFigureStore;
|
|
61626
|
+
ref = owl.useRef("fullScreenFigure");
|
|
61546
61627
|
spreadsheetRect = useSpreadsheetRect();
|
|
61547
61628
|
figureRegistry = figureRegistry;
|
|
61548
61629
|
setup() {
|
|
61549
|
-
this.
|
|
61630
|
+
this.fullScreenFigureStore = useStore(FullScreenFigureStore);
|
|
61550
61631
|
const animationStore = useStore(ChartAnimationStore);
|
|
61551
61632
|
let lastFigureId = undefined;
|
|
61552
61633
|
owl.onWillUpdateProps(() => {
|
|
@@ -61558,7 +61639,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
61558
61639
|
owl.useEffect((el) => el?.focus(), () => [this.ref.el]);
|
|
61559
61640
|
}
|
|
61560
61641
|
get figureUI() {
|
|
61561
|
-
return this.
|
|
61642
|
+
return this.fullScreenFigureStore.fullScreenFigure;
|
|
61562
61643
|
}
|
|
61563
61644
|
get chartId() {
|
|
61564
61645
|
if (!this.figureUI)
|
|
@@ -61567,7 +61648,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
61567
61648
|
}
|
|
61568
61649
|
exitFullScreen() {
|
|
61569
61650
|
if (this.figureUI) {
|
|
61570
|
-
this.
|
|
61651
|
+
this.fullScreenFigureStore.toggleFullScreenFigure(this.figureUI.id);
|
|
61571
61652
|
}
|
|
61572
61653
|
}
|
|
61573
61654
|
onKeyDown(ev) {
|
|
@@ -61575,15 +61656,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
61575
61656
|
this.exitFullScreen();
|
|
61576
61657
|
}
|
|
61577
61658
|
}
|
|
61578
|
-
get
|
|
61579
|
-
if (!this.
|
|
61659
|
+
get figureComponent() {
|
|
61660
|
+
if (!this.figureUI)
|
|
61580
61661
|
return undefined;
|
|
61581
|
-
|
|
61582
|
-
const component = chartComponentRegistry.get(type);
|
|
61583
|
-
if (!component) {
|
|
61584
|
-
throw new Error(`Component is not defined for type ${type}`);
|
|
61585
|
-
}
|
|
61586
|
-
return component;
|
|
61662
|
+
return figureRegistry.get(this.figureUI.tag).Component;
|
|
61587
61663
|
}
|
|
61588
61664
|
}
|
|
61589
61665
|
|
|
@@ -64323,11 +64399,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
64323
64399
|
break;
|
|
64324
64400
|
}
|
|
64325
64401
|
case "ADD_COLUMNS_ROWS": {
|
|
64326
|
-
const sizes =
|
|
64402
|
+
const sizes = this.sizes[cmd.sheetId][cmd.dimension];
|
|
64327
64403
|
const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
|
|
64328
64404
|
const baseSize = sizes[cmd.base];
|
|
64329
|
-
sizes
|
|
64330
|
-
this.history.update("sizes", cmd.sheetId, cmd.dimension,
|
|
64405
|
+
const newSizes = insertItemsAtIndex(sizes, Array(cmd.quantity).fill(baseSize), addIndex);
|
|
64406
|
+
this.history.update("sizes", cmd.sheetId, cmd.dimension, newSizes);
|
|
64331
64407
|
break;
|
|
64332
64408
|
}
|
|
64333
64409
|
case "RESIZE_COLUMNS_ROWS":
|
|
@@ -64478,9 +64554,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
64478
64554
|
break;
|
|
64479
64555
|
}
|
|
64480
64556
|
case "ADD_COLUMNS_ROWS": {
|
|
64481
|
-
const hiddenHeaders = [...this.hiddenHeaders[cmd.sheetId][cmd.dimension]];
|
|
64482
64557
|
const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
|
|
64483
|
-
hiddenHeaders.
|
|
64558
|
+
const hiddenHeaders = insertItemsAtIndex([...this.hiddenHeaders[cmd.sheetId][cmd.dimension]], Array(cmd.quantity).fill(false), addIndex);
|
|
64484
64559
|
this.history.update("hiddenHeaders", cmd.sheetId, cmd.dimension, hiddenHeaders);
|
|
64485
64560
|
break;
|
|
64486
64561
|
}
|
|
@@ -68664,12 +68739,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68664
68739
|
this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
|
|
68665
68740
|
}
|
|
68666
68741
|
rtreeItemComparer(left, right) {
|
|
68667
|
-
return (left.
|
|
68668
|
-
left.boundingBox.sheetId === right.boundingBox.sheetId &&
|
|
68742
|
+
return (left.boundingBox.sheetId === right.boundingBox.sheetId &&
|
|
68669
68743
|
left.boundingBox?.zone.left === right.boundingBox.zone.left &&
|
|
68670
68744
|
left.boundingBox?.zone.top === right.boundingBox.zone.top &&
|
|
68671
68745
|
left.boundingBox?.zone.right === right.boundingBox.zone.right &&
|
|
68672
|
-
left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom
|
|
68746
|
+
left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom &&
|
|
68747
|
+
deepEquals(left.data, right.data));
|
|
68673
68748
|
}
|
|
68674
68749
|
}
|
|
68675
68750
|
/**
|
|
@@ -68742,7 +68817,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68742
68817
|
* in the correct order they should be evaluated.
|
|
68743
68818
|
* This is called a topological ordering (excluding cycles)
|
|
68744
68819
|
*/
|
|
68745
|
-
getCellsDependingOn(ranges) {
|
|
68820
|
+
getCellsDependingOn(ranges, ignore) {
|
|
68746
68821
|
const visited = this.createEmptyPositionSet();
|
|
68747
68822
|
const queue = Array.from(ranges).reverse();
|
|
68748
68823
|
while (queue.length > 0) {
|
|
@@ -68757,7 +68832,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68757
68832
|
const impactedPositions = this.rTree.search(range).map((dep) => dep.data);
|
|
68758
68833
|
const nextInQueue = {};
|
|
68759
68834
|
for (const position of impactedPositions) {
|
|
68760
|
-
if (!visited.has(position)) {
|
|
68835
|
+
if (!visited.has(position) && !ignore.has(position)) {
|
|
68761
68836
|
if (!nextInQueue[position.sheetId]) {
|
|
68762
68837
|
nextInQueue[position.sheetId] = [];
|
|
68763
68838
|
}
|
|
@@ -69315,7 +69390,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
69315
69390
|
}
|
|
69316
69391
|
invalidatePositionsDependingOnSpread(sheetId, resultZone) {
|
|
69317
69392
|
// the result matrix is split in 2 zones to exclude the array formula position
|
|
69318
|
-
const invalidatedPositions = this.formulaDependencies().getCellsDependingOn(excludeTopLeft(resultZone).map((zone) => ({ sheetId, zone })));
|
|
69393
|
+
const invalidatedPositions = this.formulaDependencies().getCellsDependingOn(excludeTopLeft(resultZone).map((zone) => ({ sheetId, zone })), this.nextPositionsToUpdate);
|
|
69319
69394
|
invalidatedPositions.delete({ sheetId, col: resultZone.left, row: resultZone.top });
|
|
69320
69395
|
this.nextPositionsToUpdate.addMany(invalidatedPositions);
|
|
69321
69396
|
}
|
|
@@ -69433,7 +69508,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
69433
69508
|
for (const sheetId in zonesBySheetIds) {
|
|
69434
69509
|
ranges.push(...zonesBySheetIds[sheetId].map((zone) => ({ sheetId, zone })));
|
|
69435
69510
|
}
|
|
69436
|
-
return this.formulaDependencies().getCellsDependingOn(ranges);
|
|
69511
|
+
return this.formulaDependencies().getCellsDependingOn(ranges, this.nextPositionsToUpdate);
|
|
69437
69512
|
}
|
|
69438
69513
|
}
|
|
69439
69514
|
function forEachSpreadPositionInMatrix(nbColumns, nbRows, callback) {
|
|
@@ -70944,7 +71019,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
70944
71019
|
const topLeft = { col: unionZone.left, row: unionZone.top, sheetId };
|
|
70945
71020
|
const parentSpreadingCell = this.getters.getArrayFormulaSpreadingOn(topLeft);
|
|
70946
71021
|
if (!parentSpreadingCell) {
|
|
70947
|
-
|
|
71022
|
+
const evaluatedCell = this.getters.getEvaluatedCell(topLeft);
|
|
71023
|
+
return (evaluatedCell.value === CellErrorType.SpilledBlocked && !evaluatedCell.errorOriginPosition);
|
|
70948
71024
|
}
|
|
70949
71025
|
else if (deepEquals(parentSpreadingCell, topLeft) && getZoneArea(unionZone) === 1) {
|
|
70950
71026
|
return true;
|
|
@@ -82116,6 +82192,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82116
82192
|
static components = { Menu };
|
|
82117
82193
|
rootItems = topbarMenuRegistry.getMenuItems();
|
|
82118
82194
|
menuRef = owl.useRef("menu");
|
|
82195
|
+
containerRef = owl.useRef("container");
|
|
82119
82196
|
state = owl.useState({
|
|
82120
82197
|
menuItems: this.rootItems,
|
|
82121
82198
|
title: _t("Menu Bar"),
|
|
@@ -82123,6 +82200,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82123
82200
|
});
|
|
82124
82201
|
setup() {
|
|
82125
82202
|
owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
|
|
82203
|
+
owl.onMounted(this.updateShadows);
|
|
82126
82204
|
}
|
|
82127
82205
|
onExternalClick(ev) {
|
|
82128
82206
|
if (!this.menuRef.el?.contains(ev.target)) {
|
|
@@ -82135,6 +82213,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82135
82213
|
this.state.parentState = { ...this.state };
|
|
82136
82214
|
this.state.menuItems = children;
|
|
82137
82215
|
this.state.title = menu.name(this.env);
|
|
82216
|
+
this.containerRef.el?.scrollTo({ top: 0 });
|
|
82138
82217
|
}
|
|
82139
82218
|
else {
|
|
82140
82219
|
this.state.menuItems = this.rootItems;
|
|
@@ -82156,6 +82235,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82156
82235
|
height: `${this.props.height}px`,
|
|
82157
82236
|
});
|
|
82158
82237
|
}
|
|
82238
|
+
updateShadows() {
|
|
82239
|
+
if (!this.containerRef.el) {
|
|
82240
|
+
return;
|
|
82241
|
+
}
|
|
82242
|
+
this.containerRef.el.classList.remove("scroll-top", "scroll-bottom");
|
|
82243
|
+
const maxScroll = this.containerRef.el.scrollHeight - this.containerRef.el.clientHeight || 0;
|
|
82244
|
+
if (this.containerRef.el.scrollTop < maxScroll - 1) {
|
|
82245
|
+
this.containerRef.el.classList.add("scroll-bottom");
|
|
82246
|
+
}
|
|
82247
|
+
if (this.containerRef.el.scrollTop > 0) {
|
|
82248
|
+
this.containerRef.el.classList.add("scroll-top");
|
|
82249
|
+
}
|
|
82250
|
+
}
|
|
82159
82251
|
onClickBack() {
|
|
82160
82252
|
if (!this.state.parentState) {
|
|
82161
82253
|
this.props.onClose();
|
|
@@ -82164,6 +82256,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82164
82256
|
this.state.menuItems = this.state.parentState.menuItems;
|
|
82165
82257
|
this.state.title = this.state.parentState.title;
|
|
82166
82258
|
this.state.parentState = this.state.parentState.parentState;
|
|
82259
|
+
this.containerRef.el?.scrollTo({ top: 0 });
|
|
82167
82260
|
}
|
|
82168
82261
|
get backTitle() {
|
|
82169
82262
|
return this.state.parentState ? _t("Go to previous menu") : _t("Close menu bar");
|
|
@@ -82219,6 +82312,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82219
82312
|
? this.composerFocusStore.focusMode
|
|
82220
82313
|
: "inactive";
|
|
82221
82314
|
}
|
|
82315
|
+
get showFxIcon() {
|
|
82316
|
+
return (this.focus === "inactive" &&
|
|
82317
|
+
!this.composerStore.currentContent &&
|
|
82318
|
+
!this.composerStore.placeholder);
|
|
82319
|
+
}
|
|
82222
82320
|
get rect() {
|
|
82223
82321
|
return this.composerRef.el
|
|
82224
82322
|
? getBoundingRectAsPOJO(this.composerRef.el)
|
|
@@ -82234,8 +82332,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82234
82332
|
},
|
|
82235
82333
|
focus: this.focus,
|
|
82236
82334
|
composerStore: this.composerStore,
|
|
82237
|
-
onComposerContentFocused: () => this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
82335
|
+
onComposerContentFocused: (selection) => this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
82238
82336
|
focusMode: "contentFocus",
|
|
82337
|
+
selection,
|
|
82239
82338
|
}),
|
|
82240
82339
|
isDefaultFocus: false,
|
|
82241
82340
|
inputStyle: cssPropertiesToCss({
|
|
@@ -82243,6 +82342,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82243
82342
|
"max-height": `130px`,
|
|
82244
82343
|
}),
|
|
82245
82344
|
showAssistant: !isIOS(), // Hide assistant on iOS as it breaks visually
|
|
82345
|
+
placeholder: this.composerStore.placeholder,
|
|
82246
82346
|
};
|
|
82247
82347
|
}
|
|
82248
82348
|
get symbols() {
|
|
@@ -82261,12 +82361,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82261
82361
|
}
|
|
82262
82362
|
|
|
82263
82363
|
const COMPOSER_MAX_HEIGHT = 300;
|
|
82264
|
-
/* svg free of use from https://uxwing.com/formula-fx-icon/ */
|
|
82265
|
-
const FX_SVG = /*xml*/ `
|
|
82266
|
-
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 121.8 122.9' width='16' height='16' focusable='false'>
|
|
82267
|
-
<path d='m28 34-4 5v2h10l-6 40c-4 22-6 28-7 30-2 2-3 3-5 3-3 0-7-2-9-4H4c-2 2-4 4-4 7s4 6 8 6 9-2 15-8c8-7 13-17 18-39l7-35 13-1 3-6H49c4-23 7-27 11-27 2 0 5 2 8 6h4c1-1 4-4 4-7 0-2-3-6-9-6-5 0-13 4-20 10-6 7-9 14-11 24h-8zm41 16c4-5 7-7 8-7s2 1 5 9l3 12c-7 11-12 17-16 17l-3-1-2-1c-3 0-6 3-6 7s3 7 7 7c6 0 12-6 22-23l3 10c3 9 6 13 10 13 5 0 11-4 18-15l-3-4c-4 6-7 8-8 8-2 0-4-3-6-10l-5-15 8-10 6-4 3 1 3 2c2 0 6-3 6-7s-2-7-6-7c-6 0-11 5-21 20l-2-6c-3-9-5-14-9-14-5 0-12 6-18 15l3 3z' fill='#BDBDBD'/>
|
|
82268
|
-
</svg>
|
|
82269
|
-
`;
|
|
82270
82364
|
css /* scss */ `
|
|
82271
82365
|
.o-topbar-composer-container {
|
|
82272
82366
|
height: ${DESKTOP_TOPBAR_TOOLBAR_HEIGHT}px;
|
|
@@ -82278,14 +82372,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82278
82372
|
margin-bottom: -1px;
|
|
82279
82373
|
border: 1px solid;
|
|
82280
82374
|
font-family: ${DEFAULT_FONT};
|
|
82281
|
-
|
|
82282
|
-
/* In readonly we always show the fx icon if the composer is empty, not matter the focus */
|
|
82283
|
-
.o-composer:empty:not(:focus):not(.active)::before,
|
|
82284
|
-
&.o-topbar-composer-readonly .o-composer:empty::before {
|
|
82285
|
-
content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
|
|
82286
|
-
position: relative;
|
|
82287
|
-
top: 20%;
|
|
82288
|
-
}
|
|
82289
82375
|
}
|
|
82290
82376
|
|
|
82291
82377
|
.user-select-text {
|
|
@@ -82318,6 +82404,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82318
82404
|
? this.composerFocusStore.focusMode
|
|
82319
82405
|
: "inactive";
|
|
82320
82406
|
}
|
|
82407
|
+
get showFxIcon() {
|
|
82408
|
+
return (this.focus === "inactive" &&
|
|
82409
|
+
!this.composerStore.currentContent &&
|
|
82410
|
+
!this.composerStore.placeholder);
|
|
82411
|
+
}
|
|
82321
82412
|
get composerStyle() {
|
|
82322
82413
|
const style = {
|
|
82323
82414
|
padding: "5px 0px 5px 8px",
|
|
@@ -83669,7 +83760,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
83669
83760
|
SidePanels,
|
|
83670
83761
|
SpreadsheetDashboard,
|
|
83671
83762
|
HeaderGroupContainer,
|
|
83672
|
-
|
|
83763
|
+
FullScreenFigure,
|
|
83673
83764
|
};
|
|
83674
83765
|
sidePanel;
|
|
83675
83766
|
spreadsheetRef = owl.useRef("spreadsheet");
|
|
@@ -88393,6 +88484,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
88393
88484
|
Grid,
|
|
88394
88485
|
GridOverlay,
|
|
88395
88486
|
ScorecardChart,
|
|
88487
|
+
GaugeChartComponent,
|
|
88396
88488
|
LineConfigPanel,
|
|
88397
88489
|
BarConfigPanel,
|
|
88398
88490
|
PieChartDesignPanel,
|
|
@@ -88431,7 +88523,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
88431
88523
|
RadioSelection,
|
|
88432
88524
|
GeoChartRegionSelectSection,
|
|
88433
88525
|
ChartDashboardMenu,
|
|
88434
|
-
|
|
88526
|
+
FullScreenFigure,
|
|
88435
88527
|
};
|
|
88436
88528
|
const hooks = {
|
|
88437
88529
|
useDragAndDropListItems,
|
|
@@ -88531,9 +88623,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
88531
88623
|
exports.tokenize = tokenize;
|
|
88532
88624
|
|
|
88533
88625
|
|
|
88534
|
-
__info__.version = "19.0.
|
|
88535
|
-
__info__.date = "2025-
|
|
88536
|
-
__info__.hash = "
|
|
88626
|
+
__info__.version = "19.0.6";
|
|
88627
|
+
__info__.date = "2025-10-16T06:39:36.282Z";
|
|
88628
|
+
__info__.hash = "0d4315a";
|
|
88537
88629
|
|
|
88538
88630
|
|
|
88539
88631
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|