@odoo/o-spreadsheet 17.4.3 → 17.4.5

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.3
6
- * @date 2024-08-02T08:23:56.573Z
7
- * @hash 40ecd1e
5
+ * @version 17.4.5
6
+ * @date 2024-08-19T08:12:00.492Z
7
+ * @hash 28579ad
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';
@@ -2008,6 +2008,7 @@ const coreTypes = new Set([
2008
2008
  "UPDATE_CELL",
2009
2009
  "UPDATE_CELL_POSITION",
2010
2010
  "CLEAR_CELL",
2011
+ "CLEAR_CELLS",
2011
2012
  "DELETE_CONTENT",
2012
2013
  /** GRID SHAPE */
2013
2014
  "ADD_COLUMNS_ROWS",
@@ -6743,13 +6744,10 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6743
6744
  * Clear the clipped zones: remove the cells and clear the formatting
6744
6745
  */
6745
6746
  clearClippedZones(content) {
6746
- for (const row of content.cells) {
6747
- for (const cell of row) {
6748
- if (cell.cell) {
6749
- this.dispatch("CLEAR_CELL", cell.position);
6750
- }
6751
- }
6752
- }
6747
+ this.dispatch("CLEAR_CELLS", {
6748
+ sheetId: content.sheetId,
6749
+ target: content.zones,
6750
+ });
6753
6751
  this.dispatch("CLEAR_FORMATTING", {
6754
6752
  sheetId: content.sheetId,
6755
6753
  target: content.zones,
@@ -7717,7 +7715,7 @@ function parse(str) {
7717
7715
  }
7718
7716
  function parseTokens(tokens) {
7719
7717
  tokens = tokens.filter((x) => x.type !== "SPACE");
7720
- if (tokens[0].value === "=") {
7718
+ if (tokens[0]?.value === "=") {
7721
7719
  tokens.splice(0, 1);
7722
7720
  }
7723
7721
  const result = parseExpression(tokens);
@@ -9951,7 +9949,7 @@ class ComposerStore extends SpreadsheetStore {
9951
9949
  if (pivotId && pivotCell.type !== "EMPTY" && !cell?.isFormula) {
9952
9950
  const formulaPivotId = this.getters.getPivotFormulaId(pivotId);
9953
9951
  const formula = createPivotFormula(formulaPivotId, pivotCell);
9954
- return formula.slice(1); // strip leading =
9952
+ return localizeFormula(formula, this.getters.getLocale()).slice(1); // strip leading =
9955
9953
  }
9956
9954
  }
9957
9955
  const range = this.getters.getRangeFromZone(sheetId, zone);
@@ -10576,6 +10574,18 @@ function getDefinedAxis(definition) {
10576
10574
  useLeftAxis ||= !useRightAxis;
10577
10575
  return { useLeftAxis, useRightAxis };
10578
10576
  }
10577
+ function formatTickValue(localeFormat) {
10578
+ return (value) => {
10579
+ value = Number(value);
10580
+ if (isNaN(value))
10581
+ return value;
10582
+ const { locale, format } = localeFormat;
10583
+ return formatValue(value, {
10584
+ locale,
10585
+ format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
10586
+ });
10587
+ };
10588
+ }
10579
10589
 
10580
10590
  /** This is a chartJS plugin that will draw the values of each data next to the point/bar/pie slice */
10581
10591
  const chartShowValuesPlugin = {
@@ -19124,6 +19134,7 @@ const PIVOT_VALUE = {
19124
19134
  const pivot = this.getters.getPivot(pivotId);
19125
19135
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
19126
19136
  addPivotDependencies(this, coreDefinition);
19137
+ pivot.init({ reload: pivot.needsReevaluation });
19127
19138
  const error = pivot.assertIsValid({ throwOnError: false });
19128
19139
  if (error) {
19129
19140
  return error;
@@ -19152,6 +19163,7 @@ const PIVOT_HEADER = {
19152
19163
  const pivot = this.getters.getPivot(_pivotId);
19153
19164
  const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
19154
19165
  addPivotDependencies(this, coreDefinition);
19166
+ pivot.init({ reload: pivot.needsReevaluation });
19155
19167
  const error = pivot.assertIsValid({ throwOnError: false });
19156
19168
  if (error) {
19157
19169
  return error;
@@ -20369,14 +20381,6 @@ for (let category of categories) {
20369
20381
  }
20370
20382
  const notAvailableError = new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
20371
20383
  function createComputeFunction(descr, functionName) {
20372
- function runtimeCompute(...args) {
20373
- try {
20374
- return vectorizedCompute.apply(this, args);
20375
- }
20376
- catch (e) {
20377
- return handleError(e, functionName);
20378
- }
20379
- }
20380
20384
  function vectorizedCompute(...args) {
20381
20385
  let countVectorizableCol = 1;
20382
20386
  let countVectorizableRow = 1;
@@ -20417,13 +20421,13 @@ function createComputeFunction(descr, functionName) {
20417
20421
  }
20418
20422
  }
20419
20423
  if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
20420
- throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
20424
+ throw new BadExpressionError(_t("Function %s expects the parameter '%s' to be reference to a cell or range.", functionName, (i + 1).toString()));
20421
20425
  }
20422
20426
  }
20423
20427
  //#endregion
20424
20428
  if (countVectorizableCol === 1 && countVectorizableRow === 1) {
20425
20429
  // either this function is not vectorized or it ends up with a 1x1 dimension
20426
- return computeFunctionToObject.apply(this, args);
20430
+ return errorHandlingCompute.apply(this, args);
20427
20431
  }
20428
20432
  const getArgOffset = (i, j) => args.map((arg, index) => {
20429
20433
  switch (vectorArgsType?.[index]) {
@@ -20441,7 +20445,7 @@ function createComputeFunction(descr, functionName) {
20441
20445
  if (col > vectorizableColLimit - 1 || row > vectorizableRowLimit - 1) {
20442
20446
  return notAvailableError;
20443
20447
  }
20444
- const singleCellComputeResult = computeFunctionToObject.apply(this, getArgOffset(col, row));
20448
+ const singleCellComputeResult = errorHandlingCompute.apply(this, getArgOffset(col, row));
20445
20449
  // In the case where the user tries to vectorize arguments of an array formula, we will get an
20446
20450
  // array for every combination of the vectorized arguments, which will lead to a 3D matrix and
20447
20451
  // we won't be able to return the values.
@@ -20456,6 +20460,14 @@ function createComputeFunction(descr, functionName) {
20456
20460
  : singleCellComputeResult;
20457
20461
  });
20458
20462
  }
20463
+ function errorHandlingCompute(...args) {
20464
+ try {
20465
+ return computeFunctionToObject.apply(this, args);
20466
+ }
20467
+ catch (e) {
20468
+ return handleError(e, functionName);
20469
+ }
20470
+ }
20459
20471
  function computeFunctionToObject(...args) {
20460
20472
  const result = descr.compute.apply(this, args);
20461
20473
  if (!isMatrix(result)) {
@@ -20471,7 +20483,7 @@ function createComputeFunction(descr, functionName) {
20471
20483
  }
20472
20484
  return matrixMap(result, (row) => ({ value: row }));
20473
20485
  }
20474
- return runtimeCompute;
20486
+ return vectorizedCompute;
20475
20487
  }
20476
20488
  function handleError(e, functionName) {
20477
20489
  // the error could be an user error (instance of EvaluationError)
@@ -23692,23 +23704,13 @@ function getBarConfiguration(chart, labels, localeFormat) {
23692
23704
  padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
23693
23705
  };
23694
23706
  config.options.indexAxis = chart.horizontal ? "y" : "x";
23695
- const formatCallback = (value) => {
23696
- value = Number(value);
23697
- if (isNaN(value))
23698
- return value;
23699
- const { locale, format } = localeFormat;
23700
- return formatValue(value, {
23701
- locale,
23702
- format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
23703
- });
23704
- };
23705
23707
  config.options.scales = {};
23706
23708
  const labelsAxis = { ticks: { padding: 5, color: fontColor } };
23707
23709
  const valuesAxis = {
23708
23710
  beginAtZero: true, // the origin of the y axis is always zero
23709
23711
  ticks: {
23710
23712
  color: fontColor,
23711
- callback: formatCallback,
23713
+ callback: formatTickValue(localeFormat),
23712
23714
  },
23713
23715
  };
23714
23716
  const xAxis = chart.horizontal ? valuesAxis : labelsAxis;
@@ -23745,7 +23747,7 @@ function getBarConfiguration(chart, labels, localeFormat) {
23745
23747
  showValues: chart.showValues,
23746
23748
  background: chart.background,
23747
23749
  horizontal: chart.horizontal,
23748
- callback: formatCallback,
23750
+ callback: formatTickValue(localeFormat),
23749
23751
  };
23750
23752
  return config;
23751
23753
  }
@@ -24024,21 +24026,11 @@ function getLineOrScatterConfiguration(chart, labels, options) {
24024
24026
  title: getChartAxisTitleRuntime(chart.axesDesign?.x),
24025
24027
  },
24026
24028
  };
24027
- const formatCallback = (value) => {
24028
- value = Number(value);
24029
- if (isNaN(value))
24030
- return value;
24031
- const { locale, format } = options;
24032
- return formatValue(value, {
24033
- locale,
24034
- format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
24035
- });
24036
- };
24037
24029
  const yAxis = {
24038
24030
  beginAtZero: true, // the origin of the y axis is always zero
24039
24031
  ticks: {
24040
24032
  color: fontColor,
24041
- callback: formatCallback,
24033
+ callback: formatTickValue(options),
24042
24034
  },
24043
24035
  };
24044
24036
  const { useLeftAxis, useRightAxis } = getDefinedAxis(chart.getDefinition());
@@ -24069,7 +24061,7 @@ function getLineOrScatterConfiguration(chart, labels, options) {
24069
24061
  config.options.plugins.chartShowValuesPlugin = {
24070
24062
  showValues: chart.showValues,
24071
24063
  background: chart.background,
24072
- callback: formatCallback,
24064
+ callback: formatTickValue(options),
24073
24065
  };
24074
24066
  return config;
24075
24067
  }
@@ -24344,30 +24336,18 @@ function createComboChartRuntime(chart, getters) {
24344
24336
  title: getChartAxisTitleRuntime(chart.axesDesign?.x),
24345
24337
  },
24346
24338
  };
24347
- const formatCallback = (format) => {
24348
- return (value) => {
24349
- value = Number(value);
24350
- if (isNaN(value))
24351
- return value;
24352
- const { locale } = localeFormat;
24353
- return formatValue(value, {
24354
- locale,
24355
- format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
24356
- });
24357
- };
24358
- };
24359
24339
  const leftVerticalAxis = {
24360
24340
  beginAtZero: true, // the origin of the y axis is always zero
24361
24341
  ticks: {
24362
24342
  color: fontColor,
24363
- callback: formatCallback(mainDataSetFormat),
24343
+ callback: formatTickValue({ format: mainDataSetFormat, locale }),
24364
24344
  },
24365
24345
  };
24366
24346
  const rightVerticalAxis = {
24367
24347
  beginAtZero: true, // the origin of the y axis is always zero
24368
24348
  ticks: {
24369
24349
  color: fontColor,
24370
- callback: formatCallback(lineDataSetsFormat),
24350
+ callback: formatTickValue({ format: lineDataSetsFormat, locale }),
24371
24351
  },
24372
24352
  };
24373
24353
  const definition = chart.getDefinition();
@@ -24392,7 +24372,7 @@ function createComboChartRuntime(chart, getters) {
24392
24372
  config.options.plugins.chartShowValuesPlugin = {
24393
24373
  showValues: chart.showValues,
24394
24374
  background: chart.background,
24395
- callback: formatCallback(mainDataSetFormat),
24375
+ callback: formatTickValue({ format: mainDataSetFormat, locale }),
24396
24376
  };
24397
24377
  const colors = new ColorGenerator();
24398
24378
  for (let [index, { label, data }] of dataSetsValues.entries()) {
@@ -24924,7 +24904,10 @@ function getPieConfiguration(chart, labels, localeFormat) {
24924
24904
  const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
24925
24905
  return xLabel ? `${xLabel}: ${yLabelStr} (${percentage}%)` : `${yLabelStr} (${percentage}%)`;
24926
24906
  };
24927
- config.options.plugins.chartShowValuesPlugin = { showValues: chart.showValues };
24907
+ config.options.plugins.chartShowValuesPlugin = {
24908
+ showValues: chart.showValues,
24909
+ callback: formatTickValue(localeFormat),
24910
+ };
24928
24911
  return config;
24929
24912
  }
24930
24913
  function getPieColors(colors, dataSetsValues) {
@@ -25508,6 +25491,7 @@ function getWaterfallConfiguration(chart, labels, dataSeriesLabels, localeFormat
25508
25491
  config.options.plugins.chartShowValuesPlugin = {
25509
25492
  showValues: chart.showValues,
25510
25493
  background: chart.background,
25494
+ callback: formatTickValue(localeFormat),
25511
25495
  };
25512
25496
  return config;
25513
25497
  }
@@ -44368,6 +44352,7 @@ function convertChartData(chartData) {
44368
44352
  return {
44369
44353
  dataRange: convertExcelRangeToSheetXC(data.range, dataSetsHaveTitle),
44370
44354
  label,
44355
+ backgroundColor: data.backgroundColor,
44371
44356
  };
44372
44357
  });
44373
44358
  // For doughnut charts, in chartJS first dataset = outer dataset, in excel first dataset = inner dataset
@@ -45561,11 +45546,13 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
45561
45546
  label = { text };
45562
45547
  }
45563
45548
  }
45549
+ const color = this.extractChildAttr(chartDataElement, "c:spPr a:solidFill a:srgbClr", "val");
45564
45550
  return {
45565
45551
  label,
45566
45552
  range: this.extractChildTextContent(chartDataElement, "c:val c:f", {
45567
45553
  required: true,
45568
45554
  }),
45555
+ backgroundColor: color ? `${toHex(color.asString())}` : undefined,
45569
45556
  };
45570
45557
  });
45571
45558
  })
@@ -47771,6 +47758,9 @@ class CellPlugin extends CorePlugin {
47771
47758
  format: "",
47772
47759
  });
47773
47760
  break;
47761
+ case "CLEAR_CELLS":
47762
+ this.clearCells(cmd.sheetId, cmd.target);
47763
+ break;
47774
47764
  case "DELETE_CONTENT":
47775
47765
  this.clearZones(cmd.sheetId, cmd.target);
47776
47766
  break;
@@ -47829,6 +47819,25 @@ class CellPlugin extends CorePlugin {
47829
47819
  }
47830
47820
  }
47831
47821
  }
47822
+ /**
47823
+ * Clear the styles, the format and the content of zones
47824
+ */
47825
+ clearCells(sheetId, zones) {
47826
+ for (const zone of zones) {
47827
+ for (let col = zone.left; col <= zone.right; col++) {
47828
+ for (let row = zone.top; row <= zone.bottom; row++) {
47829
+ this.dispatch("UPDATE_CELL", {
47830
+ sheetId: sheetId,
47831
+ col,
47832
+ row,
47833
+ content: "",
47834
+ style: null,
47835
+ format: "",
47836
+ });
47837
+ }
47838
+ }
47839
+ }
47840
+ }
47832
47841
  /**
47833
47842
  * Copy the style of the reference column/row to the new columns/rows.
47834
47843
  */
@@ -50412,7 +50421,7 @@ class RangeAdapter {
50412
50421
  * @param sheetXC the string description of a range, in the form SheetName!XC:XC
50413
50422
  */
50414
50423
  getRangeFromSheetXC(defaultSheetId, sheetXC) {
50415
- if (!rangeReference.test(sheetXC)) {
50424
+ if (!rangeReference.test(sheetXC) || !this.getters.tryGetSheet(defaultSheetId)) {
50416
50425
  return new RangeImpl({
50417
50426
  sheetId: "",
50418
50427
  zone: { left: -1, top: -1, right: -1, bottom: -1 },
@@ -51289,19 +51298,23 @@ class SheetPlugin extends CorePlugin {
51289
51298
  }
51290
51299
  }
51291
51300
  moveCellOnColumnsDeletion(sheet, deletedColumn) {
51301
+ this.dispatch("CLEAR_CELLS", {
51302
+ sheetId: sheet.id,
51303
+ target: [
51304
+ {
51305
+ left: deletedColumn,
51306
+ top: 0,
51307
+ right: deletedColumn,
51308
+ bottom: sheet.rows.length - 1,
51309
+ },
51310
+ ],
51311
+ });
51292
51312
  for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
51293
51313
  const row = sheet.rows[rowIndex];
51294
51314
  for (let i in row.cells) {
51295
51315
  const colIndex = Number(i);
51296
51316
  const cellId = row.cells[i];
51297
51317
  if (cellId) {
51298
- if (colIndex === deletedColumn) {
51299
- this.dispatch("CLEAR_CELL", {
51300
- sheetId: sheet.id,
51301
- col: colIndex,
51302
- row: rowIndex,
51303
- });
51304
- }
51305
51318
  if (colIndex > deletedColumn) {
51306
51319
  this.setNewPosition(cellId, sheet.id, colIndex - 1, rowIndex);
51307
51320
  }
@@ -51347,22 +51360,20 @@ class SheetPlugin extends CorePlugin {
51347
51360
  *
51348
51361
  */
51349
51362
  moveCellOnRowsDeletion(sheet, deleteFromRow, deleteToRow) {
51363
+ this.dispatch("CLEAR_CELLS", {
51364
+ sheetId: sheet.id,
51365
+ target: [
51366
+ {
51367
+ left: 0,
51368
+ top: deleteFromRow,
51369
+ right: this.getters.getNumberCols(sheet.id),
51370
+ bottom: deleteToRow,
51371
+ },
51372
+ ],
51373
+ });
51350
51374
  const numberRows = deleteToRow - deleteFromRow + 1;
51351
51375
  for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
51352
51376
  const row = sheet.rows[rowIndex];
51353
- if (rowIndex >= deleteFromRow && rowIndex <= deleteToRow) {
51354
- for (let i in row.cells) {
51355
- const colIndex = Number(i);
51356
- const cellId = row.cells[i];
51357
- if (cellId) {
51358
- this.dispatch("CLEAR_CELL", {
51359
- sheetId: sheet.id,
51360
- col: colIndex,
51361
- row: rowIndex,
51362
- });
51363
- }
51364
- }
51365
- }
51366
51377
  if (rowIndex > deleteToRow) {
51367
51378
  for (let i in row.cells) {
51368
51379
  const colIndex = Number(i);
@@ -54065,18 +54076,23 @@ class Evaluator {
54065
54076
  this.evaluate(this.getAllCells());
54066
54077
  console.info("evaluate all cells", performance.now() - start, "ms");
54067
54078
  }
54068
- evaluateFormula(sheetId, formulaString) {
54069
- const compiledFormula = compile(formulaString);
54070
- const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
54071
- this.updateCompilationParameters();
54072
- const result = updateEvalContextAndExecute({ ...compiledFormula, dependencies: ranges }, this.compilationParams, sheetId);
54073
- if (isMatrix(result)) {
54074
- return matrixMap(result, (cell) => cell.value);
54079
+ evaluateFormulaResult(sheetId, formulaString) {
54080
+ try {
54081
+ const compiledFormula = compile(formulaString);
54082
+ const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
54083
+ this.updateCompilationParameters();
54084
+ const result = updateEvalContextAndExecute({ ...compiledFormula, dependencies: ranges }, this.compilationParams, sheetId);
54085
+ if (isMatrix(result)) {
54086
+ return result;
54087
+ }
54088
+ if (result.value === null) {
54089
+ return { value: 0, format: result.format };
54090
+ }
54091
+ return result;
54075
54092
  }
54076
- if (result.value === null) {
54077
- return 0;
54093
+ catch (error) {
54094
+ return handleError(error, "");
54078
54095
  }
54079
- return result.value;
54080
54096
  }
54081
54097
  getAllCells() {
54082
54098
  const positions = this.createEmptyPositionSet();
@@ -54439,6 +54455,7 @@ function updateEvalContextAndExecute(compiledFormula, compilationParams, sheetId
54439
54455
  class EvaluationPlugin extends UIPlugin {
54440
54456
  static getters = [
54441
54457
  "evaluateFormula",
54458
+ "evaluateFormulaResult",
54442
54459
  "getCorrespondingFormulaCell",
54443
54460
  "getRangeFormattedValues",
54444
54461
  "getRangeValues",
@@ -54498,12 +54515,14 @@ class EvaluationPlugin extends UIPlugin {
54498
54515
  // Getters
54499
54516
  // ---------------------------------------------------------------------------
54500
54517
  evaluateFormula(sheetId, formulaString) {
54501
- try {
54502
- return this.evaluator.evaluateFormula(sheetId, formulaString);
54503
- }
54504
- catch (error) {
54505
- return error.value || CellErrorType.GenericError;
54518
+ const result = this.evaluateFormulaResult(sheetId, formulaString);
54519
+ if (isMatrix(result)) {
54520
+ return matrixMap(result, (cell) => cell.value);
54506
54521
  }
54522
+ return result.value;
54523
+ }
54524
+ evaluateFormulaResult(sheetId, formulaString) {
54525
+ return this.evaluator.evaluateFormulaResult(sheetId, formulaString);
54507
54526
  }
54508
54527
  /**
54509
54528
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -55774,6 +55793,10 @@ class PivotUIPlugin extends UIPlugin {
55774
55793
  this.setupPivot(cmd.pivotId, { recreate: true });
55775
55794
  break;
55776
55795
  }
55796
+ case "REMOVE_PIVOT": {
55797
+ delete this.pivots[cmd.pivotId];
55798
+ break;
55799
+ }
55777
55800
  case "DELETE_SHEET":
55778
55801
  case "UPDATE_CELL": {
55779
55802
  this.unusedPivots = undefined;
@@ -55886,28 +55909,33 @@ class PivotUIPlugin extends UIPlugin {
55886
55909
  const pivotRow = position.row - mainPosition.row;
55887
55910
  return pivotCells[pivotCol][pivotRow];
55888
55911
  }
55889
- if (functionName === "PIVOT.HEADER" && args.at(-2) === "measure") {
55890
- const domain = pivot.parseArgsToPivotDomain(args.slice(1, -2).map((value) => ({ value })));
55912
+ try {
55913
+ if (functionName === "PIVOT.HEADER" && args.at(-2) === "measure") {
55914
+ const domain = pivot.parseArgsToPivotDomain(args.slice(1, -2).map((value) => ({ value })));
55915
+ return {
55916
+ type: "MEASURE_HEADER",
55917
+ domain,
55918
+ measure: args.at(-1)?.toString() || "",
55919
+ };
55920
+ }
55921
+ else if (functionName === "PIVOT.HEADER") {
55922
+ const domain = pivot.parseArgsToPivotDomain(args.slice(1).map((value) => ({ value })));
55923
+ return {
55924
+ type: "HEADER",
55925
+ domain,
55926
+ };
55927
+ }
55928
+ const [measure, ...domainArgs] = args.slice(1);
55929
+ const domain = pivot.parseArgsToPivotDomain(domainArgs.map((value) => ({ value })));
55891
55930
  return {
55892
- type: "MEASURE_HEADER",
55931
+ type: "VALUE",
55893
55932
  domain,
55894
- measure: args.at(-1)?.toString() || "",
55933
+ measure: measure?.toString() || "",
55895
55934
  };
55896
55935
  }
55897
- else if (functionName === "PIVOT.HEADER") {
55898
- const domain = pivot.parseArgsToPivotDomain(args.slice(1).map((value) => ({ value })));
55899
- return {
55900
- type: "HEADER",
55901
- domain,
55902
- };
55936
+ catch (_) {
55937
+ return EMPTY_PIVOT_CELL;
55903
55938
  }
55904
- const [measure, ...domainArgs] = args.slice(1);
55905
- const domain = pivot.parseArgsToPivotDomain(domainArgs.map((value) => ({ value })));
55906
- return {
55907
- type: "VALUE",
55908
- domain,
55909
- measure: measure?.toString() || "",
55910
- };
55911
55939
  }
55912
55940
  getPivot(pivotId) {
55913
55941
  return this.pivots[pivotId];
@@ -57203,7 +57231,7 @@ class Session extends EventBus {
57203
57231
  */
57204
57232
  leave(data) {
57205
57233
  if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
57206
- this.snapshot(data);
57234
+ this.snapshot(data());
57207
57235
  }
57208
57236
  delete this.clients[this.clientId];
57209
57237
  this.transportService.leave(this.clientId);
@@ -57625,9 +57653,7 @@ class DataCleanupPlugin extends UIPlugin {
57625
57653
  if (!data) {
57626
57654
  return;
57627
57655
  }
57628
- for (const { col, row } of positions(zone)) {
57629
- this.dispatch("CLEAR_CELL", { col, row, sheetId });
57630
- }
57656
+ this.dispatch("CLEAR_CELLS", { target: [zone], sheetId });
57631
57657
  const zonePasted = {
57632
57658
  left: zone.left,
57633
57659
  top: zone.top,
@@ -57775,6 +57801,7 @@ class FormatPlugin extends UIPlugin {
57775
57801
  * evaluated and updated with the number type.
57776
57802
  */
57777
57803
  setDecimal(sheetId, zones, step) {
57804
+ const positionsByFormat = {};
57778
57805
  // Find the each cell with a number value and get the format
57779
57806
  for (const zone of recomputeZones(zones)) {
57780
57807
  for (const position of positions(zone)) {
@@ -57784,15 +57811,20 @@ class FormatPlugin extends UIPlugin {
57784
57811
  // of the format
57785
57812
  this.getters.getLocale();
57786
57813
  const newFormat = changeDecimalPlaces(numberFormat, step);
57787
- // Apply the new format on the whole zone
57788
- this.dispatch("SET_FORMATTING", {
57789
- sheetId,
57790
- target: [positionToZone(position)],
57791
- format: newFormat,
57792
- });
57814
+ positionsByFormat[newFormat] = positionsByFormat[newFormat] || [];
57815
+ positionsByFormat[newFormat].push(position);
57793
57816
  }
57794
57817
  }
57795
57818
  }
57819
+ // consolidate all positions with the same format in bigger zones
57820
+ for (const newFormat in positionsByFormat) {
57821
+ const zones = recomputeZones(positionsByFormat[newFormat].map((position) => positionToZone(position)));
57822
+ this.dispatch("SET_FORMATTING", {
57823
+ sheetId,
57824
+ format: newFormat,
57825
+ target: zones,
57826
+ });
57827
+ }
57796
57828
  }
57797
57829
  /**
57798
57830
  * Take a range of cells and return the format of the first cell containing a
@@ -58294,6 +58326,9 @@ class SheetUIPlugin extends UIPlugin {
58294
58326
  if (showFormula && cell?.isFormula) {
58295
58327
  return localizeFormula(cell.content, this.getters.getLocale());
58296
58328
  }
58329
+ else if (showFormula && !cell?.content) {
58330
+ return "";
58331
+ }
58297
58332
  else {
58298
58333
  return this.getters.getEvaluatedCell(position).formattedValue;
58299
58334
  }
@@ -58792,6 +58827,7 @@ function repeatGroupHeadersCommand(getters, cmd) {
58792
58827
  const repeatCommandTransformRegistry = new Registry();
58793
58828
  repeatCommandTransformRegistry.add("UPDATE_CELL", genericRepeat);
58794
58829
  repeatCommandTransformRegistry.add("CLEAR_CELL", genericRepeat);
58830
+ repeatCommandTransformRegistry.add("CLEAR_CELLS", genericRepeat);
58795
58831
  repeatCommandTransformRegistry.add("DELETE_CONTENT", genericRepeat);
58796
58832
  repeatCommandTransformRegistry.add("ADD_MERGE", genericRepeat);
58797
58833
  repeatCommandTransformRegistry.add("REMOVE_MERGE", genericRepeat);
@@ -59416,9 +59452,10 @@ class ClipboardPlugin extends UIPlugin {
59416
59452
  case "DELETE_CELL": {
59417
59453
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
59418
59454
  if (!isZoneValid(cut[0])) {
59419
- for (const { col, row } of positions(cmd.zone)) {
59420
- this.dispatch("CLEAR_CELL", { col, row, sheetId: this.getters.getActiveSheetId() });
59421
- }
59455
+ this.dispatch("CLEAR_CELLS", {
59456
+ target: [cmd.zone],
59457
+ sheetId: this.getters.getActiveSheetId(),
59458
+ });
59422
59459
  break;
59423
59460
  }
59424
59461
  const copiedData = this.copy(cut);
@@ -67820,7 +67857,7 @@ class Model extends EventBus {
67820
67857
  this.session.join(this.config.client);
67821
67858
  }
67822
67859
  leaveSession() {
67823
- this.session.leave(this.exportData());
67860
+ this.session.leave(lazy(() => this.exportData()));
67824
67861
  }
67825
67862
  setupUiPlugin(Plugin) {
67826
67863
  const plugin = new Plugin(this.uiPluginConfig);
@@ -68379,6 +68416,6 @@ const constants = {
68379
68416
  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 };
68380
68417
 
68381
68418
 
68382
- __info__.version = "17.4.3";
68383
- __info__.date = "2024-08-02T08:23:56.573Z";
68384
- __info__.hash = "40ecd1e";
68419
+ __info__.version = "17.4.5";
68420
+ __info__.date = "2024-08-19T08:12:00.492Z";
68421
+ __info__.hash = "28579ad";