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