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