@odoo/o-spreadsheet 17.4.2 → 17.4.4

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.
@@ -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 17.4.2
6
- * @date 2024-07-24T10:26:00.237Z
7
- * @hash f5ede5b
5
+ * @version 17.4.4
6
+ * @date 2024-08-09T12:24:07.798Z
7
+ * @hash a43e855
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -2766,13 +2766,16 @@
2766
2766
  }
2767
2767
  return new RegExp("^" + exp + "$", "i");
2768
2768
  });
2769
- function evaluatePredicate(value = "", criterion) {
2769
+ function evaluatePredicate(value = "", criterion, locale) {
2770
2770
  const { operator, operand } = criterion;
2771
2771
  if (operand === undefined || value === null || operand === null) {
2772
2772
  return false;
2773
2773
  }
2774
2774
  if (typeof operand === "number" && operator === "=") {
2775
- return value.toString() === operand.toString();
2775
+ if (typeof value === "string" && (isNumber(value, locale) || isDateTime(value, locale))) {
2776
+ return toNumber(value, locale) === operand;
2777
+ }
2778
+ return value === operand;
2776
2779
  }
2777
2780
  if (operator === "<>" || operator === "=") {
2778
2781
  let result;
@@ -2854,7 +2857,7 @@
2854
2857
  for (let k = 0; k < countArg - 1; k += 2) {
2855
2858
  const criteriaValue = toMatrix(args[k])[i][j].value;
2856
2859
  const criterion = predicates[k / 2];
2857
- validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2860
+ validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion, locale);
2858
2861
  if (!validatedPredicates) {
2859
2862
  break;
2860
2863
  }
@@ -6545,6 +6548,9 @@
6545
6548
  const groupValueString = typeof groupValue === "boolean"
6546
6549
  ? toString(groupValue).toLocaleLowerCase()
6547
6550
  : toString(groupValue);
6551
+ if (groupValueString === "null") {
6552
+ return null;
6553
+ }
6548
6554
  if (!pivotNormalizationValueRegistry.contains(dimension.type)) {
6549
6555
  throw new EvaluationError(_t("Field %(field)s is not supported because of its type (%(type)s)", {
6550
6556
  field: dimension.displayName,
@@ -6565,6 +6571,9 @@
6565
6571
  return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
6566
6572
  }
6567
6573
  function toFunctionPivotValue(value, dimension) {
6574
+ if (value === null) {
6575
+ return `"null"`;
6576
+ }
6568
6577
  if (!pivotToFunctionValueRegistry.contains(dimension.type)) {
6569
6578
  return `"${value}"`;
6570
6579
  }
@@ -10568,6 +10577,18 @@ stores.inject(MyMetaStore, storeInstance);
10568
10577
  useLeftAxis ||= !useRightAxis;
10569
10578
  return { useLeftAxis, useRightAxis };
10570
10579
  }
10580
+ function formatTickValue(localeFormat) {
10581
+ return (value) => {
10582
+ value = Number(value);
10583
+ if (isNaN(value))
10584
+ return value;
10585
+ const { locale, format } = localeFormat;
10586
+ return formatValue(value, {
10587
+ locale,
10588
+ format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
10589
+ });
10590
+ };
10591
+ }
10571
10592
 
10572
10593
  /** This is a chartJS plugin that will draw the values of each data next to the point/bar/pie slice */
10573
10594
  const chartShowValuesPlugin = {
@@ -19116,6 +19137,7 @@ stores.inject(MyMetaStore, storeInstance);
19116
19137
  const pivot = this.getters.getPivot(pivotId);
19117
19138
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
19118
19139
  addPivotDependencies(this, coreDefinition);
19140
+ pivot.init({ reload: pivot.needsReevaluation });
19119
19141
  const error = pivot.assertIsValid({ throwOnError: false });
19120
19142
  if (error) {
19121
19143
  return error;
@@ -19144,6 +19166,7 @@ stores.inject(MyMetaStore, storeInstance);
19144
19166
  const pivot = this.getters.getPivot(_pivotId);
19145
19167
  const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
19146
19168
  addPivotDependencies(this, coreDefinition);
19169
+ pivot.init({ reload: pivot.needsReevaluation });
19147
19170
  const error = pivot.assertIsValid({ throwOnError: false });
19148
19171
  if (error) {
19149
19172
  return error;
@@ -20361,14 +20384,6 @@ stores.inject(MyMetaStore, storeInstance);
20361
20384
  }
20362
20385
  const notAvailableError = new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
20363
20386
  function createComputeFunction(descr, functionName) {
20364
- function runtimeCompute(...args) {
20365
- try {
20366
- return vectorizedCompute.apply(this, args);
20367
- }
20368
- catch (e) {
20369
- return handleError(e, functionName);
20370
- }
20371
- }
20372
20387
  function vectorizedCompute(...args) {
20373
20388
  let countVectorizableCol = 1;
20374
20389
  let countVectorizableRow = 1;
@@ -20409,13 +20424,13 @@ stores.inject(MyMetaStore, storeInstance);
20409
20424
  }
20410
20425
  }
20411
20426
  if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
20412
- throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
20427
+ throw new BadExpressionError(_t("Function %s expects the parameter '%s' to be reference to a cell or range.", functionName, (i + 1).toString()));
20413
20428
  }
20414
20429
  }
20415
20430
  //#endregion
20416
20431
  if (countVectorizableCol === 1 && countVectorizableRow === 1) {
20417
20432
  // either this function is not vectorized or it ends up with a 1x1 dimension
20418
- return computeFunctionToObject.apply(this, args);
20433
+ return errorHandlingCompute.apply(this, args);
20419
20434
  }
20420
20435
  const getArgOffset = (i, j) => args.map((arg, index) => {
20421
20436
  switch (vectorArgsType?.[index]) {
@@ -20433,7 +20448,7 @@ stores.inject(MyMetaStore, storeInstance);
20433
20448
  if (col > vectorizableColLimit - 1 || row > vectorizableRowLimit - 1) {
20434
20449
  return notAvailableError;
20435
20450
  }
20436
- const singleCellComputeResult = computeFunctionToObject.apply(this, getArgOffset(col, row));
20451
+ const singleCellComputeResult = errorHandlingCompute.apply(this, getArgOffset(col, row));
20437
20452
  // In the case where the user tries to vectorize arguments of an array formula, we will get an
20438
20453
  // array for every combination of the vectorized arguments, which will lead to a 3D matrix and
20439
20454
  // we won't be able to return the values.
@@ -20448,6 +20463,14 @@ stores.inject(MyMetaStore, storeInstance);
20448
20463
  : singleCellComputeResult;
20449
20464
  });
20450
20465
  }
20466
+ function errorHandlingCompute(...args) {
20467
+ try {
20468
+ return computeFunctionToObject.apply(this, args);
20469
+ }
20470
+ catch (e) {
20471
+ return handleError(e, functionName);
20472
+ }
20473
+ }
20451
20474
  function computeFunctionToObject(...args) {
20452
20475
  const result = descr.compute.apply(this, args);
20453
20476
  if (!isMatrix(result)) {
@@ -20463,7 +20486,7 @@ stores.inject(MyMetaStore, storeInstance);
20463
20486
  }
20464
20487
  return matrixMap(result, (row) => ({ value: row }));
20465
20488
  }
20466
- return runtimeCompute;
20489
+ return vectorizedCompute;
20467
20490
  }
20468
20491
  function handleError(e, functionName) {
20469
20492
  // the error could be an user error (instance of EvaluationError)
@@ -20780,6 +20803,78 @@ stores.inject(MyMetaStore, storeInstance);
20780
20803
  return isMacOS() ? ev.metaKey : ev.ctrlKey;
20781
20804
  }
20782
20805
 
20806
+ /**
20807
+ * Return the o-spreadsheet element position relative
20808
+ * to the browser viewport.
20809
+ */
20810
+ function useSpreadsheetRect() {
20811
+ const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
20812
+ let spreadsheetElement = null;
20813
+ function updatePosition() {
20814
+ if (!spreadsheetElement) {
20815
+ spreadsheetElement = document.querySelector(".o-spreadsheet");
20816
+ }
20817
+ if (spreadsheetElement) {
20818
+ const { top, left, width, height } = spreadsheetElement.getBoundingClientRect();
20819
+ position.x = left;
20820
+ position.y = top;
20821
+ position.width = width;
20822
+ position.height = height;
20823
+ }
20824
+ }
20825
+ owl.onMounted(updatePosition);
20826
+ owl.onPatched(updatePosition);
20827
+ return position;
20828
+ }
20829
+ /**
20830
+ * Return the component (or ref's component) BoundingRect, relative
20831
+ * to the upper left corner of the screen (<body> element).
20832
+ *
20833
+ * Note: when used with a <Portal/> component, it will
20834
+ * return the portal position, not the teleported position.
20835
+ */
20836
+ function useAbsoluteBoundingRect(ref) {
20837
+ const rect = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
20838
+ function updateElRect() {
20839
+ const el = ref.el;
20840
+ if (el === null) {
20841
+ return;
20842
+ }
20843
+ const { top, left, width, height } = el.getBoundingClientRect();
20844
+ rect.x = left;
20845
+ rect.y = top;
20846
+ rect.width = width;
20847
+ rect.height = height;
20848
+ }
20849
+ owl.onMounted(updateElRect);
20850
+ owl.onPatched(updateElRect);
20851
+ return rect;
20852
+ }
20853
+ /**
20854
+ * Get the rectangle inside which a popover should stay when being displayed.
20855
+ * It's the value defined in `env.getPopoverContainerRect`, or the Rect of the "o-spreadsheet"
20856
+ * element by default.
20857
+ *
20858
+ * Coordinates are expressed expressed as absolute DOM position.
20859
+ */
20860
+ function usePopoverContainer() {
20861
+ const container = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
20862
+ const component = owl.useComponent();
20863
+ const spreadsheetRect = useSpreadsheetRect();
20864
+ function updateRect() {
20865
+ const env = component.env;
20866
+ const newRect = "getPopoverContainerRect" in env ? env.getPopoverContainerRect() : spreadsheetRect;
20867
+ container.x = newRect.x;
20868
+ container.y = newRect.y;
20869
+ container.width = newRect.width;
20870
+ container.height = newRect.height;
20871
+ }
20872
+ updateRect();
20873
+ owl.onMounted(updateRect);
20874
+ owl.onPatched(updateRect);
20875
+ return container;
20876
+ }
20877
+
20783
20878
  const arrowMap = {
20784
20879
  ArrowDown: "down",
20785
20880
  ArrowLeft: "left",
@@ -21369,7 +21464,9 @@ stores.inject(MyMetaStore, storeInstance);
21369
21464
  argToFocus: 0,
21370
21465
  });
21371
21466
  compositionActive = false;
21467
+ spreadsheetRect = useSpreadsheetRect();
21372
21468
  get assistantStyle() {
21469
+ const composerRect = this.composerRef.el.getBoundingClientRect();
21373
21470
  const assistantStyle = {};
21374
21471
  assistantStyle["min-width"] = `${this.props.rect?.width || ASSISTANT_WIDTH}px`;
21375
21472
  const proposals = this.autoCompleteState.provider?.proposals;
@@ -21396,6 +21493,9 @@ stores.inject(MyMetaStore, storeInstance);
21396
21493
  }
21397
21494
  else if (this.props.delimitation) {
21398
21495
  assistantStyle["max-height"] = `${this.props.delimitation.height}px`;
21496
+ if (composerRect.left + ASSISTANT_WIDTH > this.spreadsheetRect.width) {
21497
+ assistantStyle.right = `0px`;
21498
+ }
21399
21499
  }
21400
21500
  return cssPropertiesToCss(assistantStyle);
21401
21501
  }
@@ -23607,23 +23707,13 @@ stores.inject(MyMetaStore, storeInstance);
23607
23707
  padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
23608
23708
  };
23609
23709
  config.options.indexAxis = chart.horizontal ? "y" : "x";
23610
- const formatCallback = (value) => {
23611
- value = Number(value);
23612
- if (isNaN(value))
23613
- return value;
23614
- const { locale, format } = localeFormat;
23615
- return formatValue(value, {
23616
- locale,
23617
- format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
23618
- });
23619
- };
23620
23710
  config.options.scales = {};
23621
23711
  const labelsAxis = { ticks: { padding: 5, color: fontColor } };
23622
23712
  const valuesAxis = {
23623
23713
  beginAtZero: true, // the origin of the y axis is always zero
23624
23714
  ticks: {
23625
23715
  color: fontColor,
23626
- callback: formatCallback,
23716
+ callback: formatTickValue(localeFormat),
23627
23717
  },
23628
23718
  };
23629
23719
  const xAxis = chart.horizontal ? valuesAxis : labelsAxis;
@@ -23660,7 +23750,7 @@ stores.inject(MyMetaStore, storeInstance);
23660
23750
  showValues: chart.showValues,
23661
23751
  background: chart.background,
23662
23752
  horizontal: chart.horizontal,
23663
- callback: formatCallback,
23753
+ callback: formatTickValue(localeFormat),
23664
23754
  };
23665
23755
  return config;
23666
23756
  }
@@ -23939,21 +24029,11 @@ stores.inject(MyMetaStore, storeInstance);
23939
24029
  title: getChartAxisTitleRuntime(chart.axesDesign?.x),
23940
24030
  },
23941
24031
  };
23942
- const formatCallback = (value) => {
23943
- value = Number(value);
23944
- if (isNaN(value))
23945
- return value;
23946
- const { locale, format } = options;
23947
- return formatValue(value, {
23948
- locale,
23949
- format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
23950
- });
23951
- };
23952
24032
  const yAxis = {
23953
24033
  beginAtZero: true, // the origin of the y axis is always zero
23954
24034
  ticks: {
23955
24035
  color: fontColor,
23956
- callback: formatCallback,
24036
+ callback: formatTickValue(options),
23957
24037
  },
23958
24038
  };
23959
24039
  const { useLeftAxis, useRightAxis } = getDefinedAxis(chart.getDefinition());
@@ -23984,7 +24064,7 @@ stores.inject(MyMetaStore, storeInstance);
23984
24064
  config.options.plugins.chartShowValuesPlugin = {
23985
24065
  showValues: chart.showValues,
23986
24066
  background: chart.background,
23987
- callback: formatCallback,
24067
+ callback: formatTickValue(options),
23988
24068
  };
23989
24069
  return config;
23990
24070
  }
@@ -24259,30 +24339,18 @@ stores.inject(MyMetaStore, storeInstance);
24259
24339
  title: getChartAxisTitleRuntime(chart.axesDesign?.x),
24260
24340
  },
24261
24341
  };
24262
- const formatCallback = (format) => {
24263
- return (value) => {
24264
- value = Number(value);
24265
- if (isNaN(value))
24266
- return value;
24267
- const { locale } = localeFormat;
24268
- return formatValue(value, {
24269
- locale,
24270
- format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
24271
- });
24272
- };
24273
- };
24274
24342
  const leftVerticalAxis = {
24275
24343
  beginAtZero: true, // the origin of the y axis is always zero
24276
24344
  ticks: {
24277
24345
  color: fontColor,
24278
- callback: formatCallback(mainDataSetFormat),
24346
+ callback: formatTickValue({ format: mainDataSetFormat, locale }),
24279
24347
  },
24280
24348
  };
24281
24349
  const rightVerticalAxis = {
24282
24350
  beginAtZero: true, // the origin of the y axis is always zero
24283
24351
  ticks: {
24284
24352
  color: fontColor,
24285
- callback: formatCallback(lineDataSetsFormat),
24353
+ callback: formatTickValue({ format: lineDataSetsFormat, locale }),
24286
24354
  },
24287
24355
  };
24288
24356
  const definition = chart.getDefinition();
@@ -24307,7 +24375,7 @@ stores.inject(MyMetaStore, storeInstance);
24307
24375
  config.options.plugins.chartShowValuesPlugin = {
24308
24376
  showValues: chart.showValues,
24309
24377
  background: chart.background,
24310
- callback: formatCallback(mainDataSetFormat),
24378
+ callback: formatTickValue({ format: mainDataSetFormat, locale }),
24311
24379
  };
24312
24380
  const colors = new ColorGenerator();
24313
24381
  for (let [index, { label, data }] of dataSetsValues.entries()) {
@@ -24839,7 +24907,10 @@ stores.inject(MyMetaStore, storeInstance);
24839
24907
  const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
24840
24908
  return xLabel ? `${xLabel}: ${yLabelStr} (${percentage}%)` : `${yLabelStr} (${percentage}%)`;
24841
24909
  };
24842
- config.options.plugins.chartShowValuesPlugin = { showValues: chart.showValues };
24910
+ config.options.plugins.chartShowValuesPlugin = {
24911
+ showValues: chart.showValues,
24912
+ callback: formatTickValue(localeFormat),
24913
+ };
24843
24914
  return config;
24844
24915
  }
24845
24916
  function getPieColors(colors, dataSetsValues) {
@@ -25423,6 +25494,7 @@ stores.inject(MyMetaStore, storeInstance);
25423
25494
  config.options.plugins.chartShowValuesPlugin = {
25424
25495
  showValues: chart.showValues,
25425
25496
  background: chart.background,
25497
+ callback: formatTickValue(localeFormat),
25426
25498
  };
25427
25499
  return config;
25428
25500
  }
@@ -26238,78 +26310,6 @@ stores.inject(MyMetaStore, storeInstance);
26238
26310
  };
26239
26311
  }
26240
26312
 
26241
- /**
26242
- * Return the o-spreadsheet element position relative
26243
- * to the browser viewport.
26244
- */
26245
- function useSpreadsheetRect() {
26246
- const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
26247
- let spreadsheetElement = null;
26248
- function updatePosition() {
26249
- if (!spreadsheetElement) {
26250
- spreadsheetElement = document.querySelector(".o-spreadsheet");
26251
- }
26252
- if (spreadsheetElement) {
26253
- const { top, left, width, height } = spreadsheetElement.getBoundingClientRect();
26254
- position.x = left;
26255
- position.y = top;
26256
- position.width = width;
26257
- position.height = height;
26258
- }
26259
- }
26260
- owl.onMounted(updatePosition);
26261
- owl.onPatched(updatePosition);
26262
- return position;
26263
- }
26264
- /**
26265
- * Return the component (or ref's component) BoundingRect, relative
26266
- * to the upper left corner of the screen (<body> element).
26267
- *
26268
- * Note: when used with a <Portal/> component, it will
26269
- * return the portal position, not the teleported position.
26270
- */
26271
- function useAbsoluteBoundingRect(ref) {
26272
- const rect = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
26273
- function updateElRect() {
26274
- const el = ref.el;
26275
- if (el === null) {
26276
- return;
26277
- }
26278
- const { top, left, width, height } = el.getBoundingClientRect();
26279
- rect.x = left;
26280
- rect.y = top;
26281
- rect.width = width;
26282
- rect.height = height;
26283
- }
26284
- owl.onMounted(updateElRect);
26285
- owl.onPatched(updateElRect);
26286
- return rect;
26287
- }
26288
- /**
26289
- * Get the rectangle inside which a popover should stay when being displayed.
26290
- * It's the value defined in `env.getPopoverContainerRect`, or the Rect of the "o-spreadsheet"
26291
- * element by default.
26292
- *
26293
- * Coordinates are expressed expressed as absolute DOM position.
26294
- */
26295
- function usePopoverContainer() {
26296
- const container = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
26297
- const component = owl.useComponent();
26298
- const spreadsheetRect = useSpreadsheetRect();
26299
- function updateRect() {
26300
- const env = component.env;
26301
- const newRect = "getPopoverContainerRect" in env ? env.getPopoverContainerRect() : spreadsheetRect;
26302
- container.x = newRect.x;
26303
- container.y = newRect.y;
26304
- container.width = newRect.width;
26305
- container.height = newRect.height;
26306
- }
26307
- updateRect();
26308
- owl.onMounted(updateRect);
26309
- owl.onPatched(updateRect);
26310
- return container;
26311
- }
26312
-
26313
26313
  css /* scss */ `
26314
26314
  .o-popover {
26315
26315
  position: absolute;
@@ -35808,6 +35808,14 @@ stores.inject(MyMetaStore, storeInstance);
35808
35808
  .pivot-dim-operator-label {
35809
35809
  min-width: 120px;
35810
35810
  }
35811
+
35812
+ &.pivot-dimension-invalid {
35813
+ background-color: #ffdddd;
35814
+ border-color: red !important;
35815
+ select {
35816
+ background-color: #ffdddd;
35817
+ }
35818
+ }
35811
35819
  }
35812
35820
  `;
35813
35821
  class PivotDimension extends owl.Component {
@@ -47215,12 +47223,13 @@ stores.inject(MyMetaStore, storeInstance);
47215
47223
  this.clearBorders(cmd.sheetId, cmd.target);
47216
47224
  break;
47217
47225
  case "REMOVE_COLUMNS_ROWS":
47218
- for (let el of [...cmd.elements].sort((a, b) => b - a)) {
47226
+ const elements = [...cmd.elements].sort((a, b) => b - a);
47227
+ for (const group of groupConsecutive(elements)) {
47219
47228
  if (cmd.dimension === "COL") {
47220
- this.shiftBordersHorizontally(cmd.sheetId, el + 1, -1);
47229
+ this.shiftBordersHorizontally(cmd.sheetId, group[group.length - 1] + 1, -group.length);
47221
47230
  }
47222
47231
  else {
47223
- this.shiftBordersVertically(cmd.sheetId, el + 1, -1);
47232
+ this.shiftBordersVertically(cmd.sheetId, group[group.length - 1] + 1, -group.length);
47224
47233
  }
47225
47234
  }
47226
47235
  break;
@@ -50390,7 +50399,7 @@ stores.inject(MyMetaStore, storeInstance);
50390
50399
  * @param sheetXC the string description of a range, in the form SheetName!XC:XC
50391
50400
  */
50392
50401
  getRangeFromSheetXC(defaultSheetId, sheetXC) {
50393
- if (!rangeReference.test(sheetXC)) {
50402
+ if (!rangeReference.test(sheetXC) || !this.getters.tryGetSheet(defaultSheetId)) {
50394
50403
  return new RangeImpl({
50395
50404
  sheetId: "",
50396
50405
  zone: { left: -1, top: -1, right: -1, bottom: -1 },
@@ -51281,12 +51290,7 @@ stores.inject(MyMetaStore, storeInstance);
51281
51290
  });
51282
51291
  }
51283
51292
  if (colIndex > deletedColumn) {
51284
- this.dispatch("UPDATE_CELL_POSITION", {
51285
- sheetId: sheet.id,
51286
- cellId: cellId,
51287
- col: colIndex - 1,
51288
- row: rowIndex,
51289
- });
51293
+ this.setNewPosition(cellId, sheet.id, colIndex - 1, rowIndex);
51290
51294
  }
51291
51295
  }
51292
51296
  }
@@ -51296,7 +51300,7 @@ stores.inject(MyMetaStore, storeInstance);
51296
51300
  * Move the cells after a column or rows insertion
51297
51301
  */
51298
51302
  moveCellsOnAddition(sheet, addedElement, quantity, dimension) {
51299
- const commands = [];
51303
+ const updates = [];
51300
51304
  for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
51301
51305
  const row = sheet.rows[rowIndex];
51302
51306
  if (dimension !== "rows" || rowIndex >= addedElement) {
@@ -51305,20 +51309,20 @@ stores.inject(MyMetaStore, storeInstance);
51305
51309
  const cellId = row.cells[i];
51306
51310
  if (cellId) {
51307
51311
  if (dimension === "rows" || colIndex >= addedElement) {
51308
- commands.push({
51309
- type: "UPDATE_CELL_POSITION",
51312
+ updates.push({
51310
51313
  sheetId: sheet.id,
51311
51314
  cellId: cellId,
51312
51315
  col: colIndex + (dimension === "columns" ? quantity : 0),
51313
51316
  row: rowIndex + (dimension === "rows" ? quantity : 0),
51317
+ type: "UPDATE_CELL_POSITION",
51314
51318
  });
51315
51319
  }
51316
51320
  }
51317
51321
  }
51318
51322
  }
51319
51323
  }
51320
- for (let cmd of commands.reverse()) {
51321
- this.dispatch(cmd.type, cmd);
51324
+ for (let update of updates.reverse()) {
51325
+ this.updateCellPosition(update);
51322
51326
  }
51323
51327
  }
51324
51328
  /**
@@ -51351,12 +51355,7 @@ stores.inject(MyMetaStore, storeInstance);
51351
51355
  const colIndex = Number(i);
51352
51356
  const cellId = row.cells[i];
51353
51357
  if (cellId) {
51354
- this.dispatch("UPDATE_CELL_POSITION", {
51355
- sheetId: sheet.id,
51356
- cellId: cellId,
51357
- col: colIndex,
51358
- row: rowIndex - numberRows,
51359
- });
51358
+ this.setNewPosition(cellId, sheet.id, colIndex, rowIndex - numberRows);
51360
51359
  }
51361
51360
  }
51362
51361
  }
@@ -54053,18 +54052,23 @@ stores.inject(MyMetaStore, storeInstance);
54053
54052
  this.evaluate(this.getAllCells());
54054
54053
  console.info("evaluate all cells", performance.now() - start, "ms");
54055
54054
  }
54056
- evaluateFormula(sheetId, formulaString) {
54057
- const compiledFormula = compile(formulaString);
54058
- const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
54059
- this.updateCompilationParameters();
54060
- const result = updateEvalContextAndExecute({ ...compiledFormula, dependencies: ranges }, this.compilationParams, sheetId);
54061
- if (isMatrix(result)) {
54062
- return matrixMap(result, (cell) => cell.value);
54055
+ evaluateFormulaResult(sheetId, formulaString) {
54056
+ try {
54057
+ const compiledFormula = compile(formulaString);
54058
+ const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
54059
+ this.updateCompilationParameters();
54060
+ const result = updateEvalContextAndExecute({ ...compiledFormula, dependencies: ranges }, this.compilationParams, sheetId);
54061
+ if (isMatrix(result)) {
54062
+ return result;
54063
+ }
54064
+ if (result.value === null) {
54065
+ return { value: 0, format: result.format };
54066
+ }
54067
+ return result;
54063
54068
  }
54064
- if (result.value === null) {
54065
- return 0;
54069
+ catch (error) {
54070
+ return handleError(error, "");
54066
54071
  }
54067
- return result.value;
54068
54072
  }
54069
54073
  getAllCells() {
54070
54074
  const positions = this.createEmptyPositionSet();
@@ -54122,6 +54126,9 @@ stores.inject(MyMetaStore, storeInstance);
54122
54126
  if (!this.blockedArrayFormulas.has(position)) {
54123
54127
  this.invalidateSpreading(position);
54124
54128
  }
54129
+ if (this.spreadingRelations.isArrayFormula(position)) {
54130
+ this.spreadingRelations.removeNode(position);
54131
+ }
54125
54132
  const cell = this.getters.getCell(position);
54126
54133
  if (cell === undefined) {
54127
54134
  return EMPTY_CELL;
@@ -54164,7 +54171,6 @@ stores.inject(MyMetaStore, storeInstance);
54164
54171
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
54165
54172
  const nbColumns = formulaReturn.length;
54166
54173
  const nbRows = formulaReturn[0].length;
54167
- this.spreadingRelations.removeNode(formulaPosition);
54168
54174
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.updateSpreadRelation(formulaPosition));
54169
54175
  this.assertNoMergedCellsInSpreadZone(formulaPosition, formulaReturn);
54170
54176
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.checkCollision(formulaPosition));
@@ -54425,6 +54431,7 @@ stores.inject(MyMetaStore, storeInstance);
54425
54431
  class EvaluationPlugin extends UIPlugin {
54426
54432
  static getters = [
54427
54433
  "evaluateFormula",
54434
+ "evaluateFormulaResult",
54428
54435
  "getCorrespondingFormulaCell",
54429
54436
  "getRangeFormattedValues",
54430
54437
  "getRangeValues",
@@ -54484,12 +54491,14 @@ stores.inject(MyMetaStore, storeInstance);
54484
54491
  // Getters
54485
54492
  // ---------------------------------------------------------------------------
54486
54493
  evaluateFormula(sheetId, formulaString) {
54487
- try {
54488
- return this.evaluator.evaluateFormula(sheetId, formulaString);
54489
- }
54490
- catch (error) {
54491
- return error.value || CellErrorType.GenericError;
54494
+ const result = this.evaluateFormulaResult(sheetId, formulaString);
54495
+ if (isMatrix(result)) {
54496
+ return matrixMap(result, (cell) => cell.value);
54492
54497
  }
54498
+ return result.value;
54499
+ }
54500
+ evaluateFormulaResult(sheetId, formulaString) {
54501
+ return this.evaluator.evaluateFormulaResult(sheetId, formulaString);
54493
54502
  }
54494
54503
  /**
54495
54504
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -55872,28 +55881,33 @@ stores.inject(MyMetaStore, storeInstance);
55872
55881
  const pivotRow = position.row - mainPosition.row;
55873
55882
  return pivotCells[pivotCol][pivotRow];
55874
55883
  }
55875
- if (functionName === "PIVOT.HEADER" && args.at(-2) === "measure") {
55876
- const domain = pivot.parseArgsToPivotDomain(args.slice(1, -2).map((value) => ({ value })));
55884
+ try {
55885
+ if (functionName === "PIVOT.HEADER" && args.at(-2) === "measure") {
55886
+ const domain = pivot.parseArgsToPivotDomain(args.slice(1, -2).map((value) => ({ value })));
55887
+ return {
55888
+ type: "MEASURE_HEADER",
55889
+ domain,
55890
+ measure: args.at(-1)?.toString() || "",
55891
+ };
55892
+ }
55893
+ else if (functionName === "PIVOT.HEADER") {
55894
+ const domain = pivot.parseArgsToPivotDomain(args.slice(1).map((value) => ({ value })));
55895
+ return {
55896
+ type: "HEADER",
55897
+ domain,
55898
+ };
55899
+ }
55900
+ const [measure, ...domainArgs] = args.slice(1);
55901
+ const domain = pivot.parseArgsToPivotDomain(domainArgs.map((value) => ({ value })));
55877
55902
  return {
55878
- type: "MEASURE_HEADER",
55903
+ type: "VALUE",
55879
55904
  domain,
55880
- measure: args.at(-1)?.toString() || "",
55905
+ measure: measure?.toString() || "",
55881
55906
  };
55882
55907
  }
55883
- else if (functionName === "PIVOT.HEADER") {
55884
- const domain = pivot.parseArgsToPivotDomain(args.slice(1).map((value) => ({ value })));
55885
- return {
55886
- type: "HEADER",
55887
- domain,
55888
- };
55908
+ catch (_) {
55909
+ return EMPTY_PIVOT_CELL;
55889
55910
  }
55890
- const [measure, ...domainArgs] = args.slice(1);
55891
- const domain = pivot.parseArgsToPivotDomain(domainArgs.map((value) => ({ value })));
55892
- return {
55893
- type: "VALUE",
55894
- domain,
55895
- measure: measure?.toString() || "",
55896
- };
55897
55911
  }
55898
55912
  getPivot(pivotId) {
55899
55913
  return this.pivots[pivotId];
@@ -57761,6 +57775,7 @@ stores.inject(MyMetaStore, storeInstance);
57761
57775
  * evaluated and updated with the number type.
57762
57776
  */
57763
57777
  setDecimal(sheetId, zones, step) {
57778
+ const positionsByFormat = {};
57764
57779
  // Find the each cell with a number value and get the format
57765
57780
  for (const zone of recomputeZones(zones)) {
57766
57781
  for (const position of positions(zone)) {
@@ -57770,15 +57785,20 @@ stores.inject(MyMetaStore, storeInstance);
57770
57785
  // of the format
57771
57786
  this.getters.getLocale();
57772
57787
  const newFormat = changeDecimalPlaces(numberFormat, step);
57773
- // Apply the new format on the whole zone
57774
- this.dispatch("SET_FORMATTING", {
57775
- sheetId,
57776
- target: [positionToZone(position)],
57777
- format: newFormat,
57778
- });
57788
+ positionsByFormat[newFormat] = positionsByFormat[newFormat] || [];
57789
+ positionsByFormat[newFormat].push(position);
57779
57790
  }
57780
57791
  }
57781
57792
  }
57793
+ // consolidate all positions with the same format in bigger zones
57794
+ for (const newFormat in positionsByFormat) {
57795
+ const zones = recomputeZones(positionsByFormat[newFormat].map((position) => positionToZone(position)));
57796
+ this.dispatch("SET_FORMATTING", {
57797
+ sheetId,
57798
+ format: newFormat,
57799
+ target: zones,
57800
+ });
57801
+ }
57782
57802
  }
57783
57803
  /**
57784
57804
  * Take a range of cells and return the format of the first cell containing a
@@ -63089,6 +63109,8 @@ stores.inject(MyMetaStore, storeInstance);
63089
63109
 
63090
63110
  .o-sidePanel-handle-container {
63091
63111
  width: 8px;
63112
+ position: fixed;
63113
+ top: 50%;
63092
63114
  }
63093
63115
  .o-sidePanel-handle {
63094
63116
  cursor: col-resize;
@@ -65708,7 +65730,7 @@ stores.inject(MyMetaStore, storeInstance);
65708
65730
  }
65709
65731
 
65710
65732
  class StateObserver {
65711
- changes = [];
65733
+ changes;
65712
65734
  commands = [];
65713
65735
  /**
65714
65736
  * Record the changes which could happen in the given callback, save them in a
@@ -65740,7 +65762,7 @@ stores.inject(MyMetaStore, storeInstance);
65740
65762
  if (value[key] === val) {
65741
65763
  return;
65742
65764
  }
65743
- this.changes.push({
65765
+ this.changes?.push({
65744
65766
  key,
65745
65767
  target: value,
65746
65768
  before: value[key],
@@ -68406,9 +68428,9 @@ stores.inject(MyMetaStore, storeInstance);
68406
68428
  exports.tokenize = tokenize;
68407
68429
 
68408
68430
 
68409
- __info__.version = "17.4.2";
68410
- __info__.date = "2024-07-24T10:26:00.237Z";
68411
- __info__.hash = "f5ede5b";
68431
+ __info__.version = "17.4.4";
68432
+ __info__.date = "2024-08-09T12:24:07.798Z";
68433
+ __info__.hash = "a43e855";
68412
68434
 
68413
68435
 
68414
68436
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);