@odoo/o-spreadsheet 18.4.8 → 18.4.10

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 18.4.8
6
- * @date 2025-08-26T10:14:08.954Z
7
- * @hash 746217a
5
+ * @version 18.4.10
6
+ * @date 2025-09-11T08:45:39.178Z
7
+ * @hash 15a11a4
8
8
  */
9
9
 
10
10
  'use strict';
@@ -2645,6 +2645,7 @@ const invalidateBordersCommands = new Set([
2645
2645
  "AUTOFILL_CELL",
2646
2646
  "SET_BORDER",
2647
2647
  "SET_ZONE_BORDERS",
2648
+ "SET_BORDERS_ON_TARGET",
2648
2649
  ]);
2649
2650
  const readonlyAllowedCommands = new Set([
2650
2651
  "START",
@@ -3991,6 +3992,10 @@ function isDataNonEmpty(data) {
3991
3992
  }
3992
3993
  return true;
3993
3994
  }
3995
+ const noValidInputErrorMessage = _t("[[FUNCTION_NAME]] has no valid input data.");
3996
+ function emptyDataErrorMessage(argName) {
3997
+ return _t("[[FUNCTION_NAME]] expects the provided values of %(argName)s to be a non-empty matrix.", { argName });
3998
+ }
3994
3999
 
3995
4000
  function tokenizeFormat(str) {
3996
4001
  const chars = new TokenizingChars(str);
@@ -6592,40 +6597,44 @@ function orderRange(range) {
6592
6597
  };
6593
6598
  }
6594
6599
  function getRangeAdapter(cmd) {
6595
- switch (cmd.type) {
6596
- case "REMOVE_COLUMNS_ROWS":
6597
- return {
6598
- applyChange: getApplyRangeChangeRemoveColRow(cmd),
6599
- sheetId: cmd.sheetId,
6600
- sheetName: cmd.sheetName,
6601
- };
6602
- case "ADD_COLUMNS_ROWS":
6603
- return {
6604
- applyChange: getApplyRangeChangeAddColRow(cmd),
6605
- sheetId: cmd.sheetId,
6606
- sheetName: cmd.sheetName,
6607
- };
6608
- case "DELETE_SHEET":
6609
- return {
6610
- applyChange: getApplyRangeChangeDeleteSheet(cmd),
6611
- sheetId: cmd.sheetId,
6612
- sheetName: cmd.sheetName,
6613
- };
6614
- case "RENAME_SHEET":
6615
- return {
6616
- applyChange: getApplyRangeChangeRenameSheet(cmd),
6617
- sheetId: cmd.sheetId,
6618
- sheetName: cmd.oldName,
6619
- };
6620
- case "MOVE_RANGES":
6621
- return {
6622
- applyChange: getApplyRangeChangeMoveRange(cmd),
6623
- sheetId: cmd.sheetId,
6624
- sheetName: cmd.sheetName,
6625
- };
6600
+ return rangeAdapterRegistry.get(cmd.type)?.(cmd);
6601
+ }
6602
+ class RangeAdapterRegistry extends Registry {
6603
+ add(cmdType, fn) {
6604
+ super.add(cmdType, fn);
6605
+ return this;
6606
+ }
6607
+ get(cmdType) {
6608
+ return this.content[cmdType];
6626
6609
  }
6627
- return undefined;
6628
6610
  }
6611
+ const rangeAdapterRegistry = new RangeAdapterRegistry();
6612
+ rangeAdapterRegistry
6613
+ .add("REMOVE_COLUMNS_ROWS", (cmd) => ({
6614
+ applyChange: getApplyRangeChangeRemoveColRow(cmd),
6615
+ sheetId: cmd.sheetId,
6616
+ sheetName: { old: cmd.sheetName, current: cmd.sheetName },
6617
+ }))
6618
+ .add("ADD_COLUMNS_ROWS", (cmd) => ({
6619
+ applyChange: getApplyRangeChangeAddColRow(cmd),
6620
+ sheetId: cmd.sheetId,
6621
+ sheetName: { old: cmd.sheetName, current: cmd.sheetName },
6622
+ }))
6623
+ .add("DELETE_SHEET", (cmd) => ({
6624
+ applyChange: getApplyRangeChangeDeleteSheet(cmd),
6625
+ sheetId: cmd.sheetId,
6626
+ sheetName: { old: cmd.sheetName, current: cmd.sheetName },
6627
+ }))
6628
+ .add("RENAME_SHEET", (cmd) => ({
6629
+ applyChange: getApplyRangeChangeRenameSheet(cmd),
6630
+ sheetId: cmd.sheetId,
6631
+ sheetName: { old: cmd.oldName, current: cmd.newName },
6632
+ }))
6633
+ .add("MOVE_RANGES", (cmd) => ({
6634
+ applyChange: getApplyRangeChangeMoveRange(cmd),
6635
+ sheetId: cmd.sheetId,
6636
+ sheetName: { old: cmd.sheetName, current: cmd.sheetName },
6637
+ }));
6629
6638
  function getApplyRangeChangeRemoveColRow(cmd) {
6630
6639
  const start = cmd.dimension === "COL" ? "left" : "top";
6631
6640
  const end = cmd.dimension === "COL" ? "right" : "bottom";
@@ -7347,7 +7356,7 @@ class ClipboardHandler {
7347
7356
  this.getters = getters;
7348
7357
  this.dispatch = dispatch;
7349
7358
  }
7350
- copy(data, isCutOperation) {
7359
+ copy(data, isCutOperation, mode = "copyPaste") {
7351
7360
  return;
7352
7361
  }
7353
7362
  paste(target, clippedContent, options) { }
@@ -7366,7 +7375,7 @@ class ClipboardHandler {
7366
7375
  }
7367
7376
 
7368
7377
  class AbstractCellClipboardHandler extends ClipboardHandler {
7369
- copy(data) {
7378
+ copy(data, isCutOperation, mode = "copyPaste") {
7370
7379
  return;
7371
7380
  }
7372
7381
  pasteFromCopy(sheetId, target, content, options) {
@@ -8002,8 +8011,11 @@ function invertMatrix(M) {
8002
8011
  // (a) Swap 2 rows. This multiply the determinant by -1.
8003
8012
  // (b) Multiply a row by a scalar. This multiply the determinant by that scalar.
8004
8013
  // (c) Add to a row a multiple of another row. This does not change the determinant.
8014
+ if (M.length < 1 || M[0].length < 1) {
8015
+ throw new Error("invertMatrix: an empty matrix cannot be inverted.");
8016
+ }
8005
8017
  if (M.length !== M[0].length) {
8006
- throw new EvaluationError(_t("Function [[FUNCTION_NAME]] invert matrix error, only square matrices are invertible"));
8018
+ throw new Error("invertMatrix: only square matrices are invertible");
8007
8019
  }
8008
8020
  let determinant = 1;
8009
8021
  const dim = M.length;
@@ -8072,8 +8084,11 @@ function swapMatrixRows(matrix, row1, row2) {
8072
8084
  * Note: we use indexing [col][row] instead of the standard mathematical notation [row][col]
8073
8085
  */
8074
8086
  function multiplyMatrices(matrix1, matrix2) {
8087
+ if (matrix1.length < 1 || matrix2.length < 1) {
8088
+ throw new Error("multiplyMatrices: empty matrices cannot be multiplied.");
8089
+ }
8075
8090
  if (matrix1.length !== matrix2[0].length) {
8076
- throw new EvaluationError(_t("Cannot multiply matrices : incompatible matrices size."));
8091
+ throw new Error("multiplyMatrices: incompatible matrices size.");
8077
8092
  }
8078
8093
  const rowsM1 = matrix1[0].length;
8079
8094
  const colsM2 = matrix2.length;
@@ -8099,7 +8114,7 @@ function toScalar(arg) {
8099
8114
  return arg;
8100
8115
  }
8101
8116
  if (!isSingleElementMatrix(arg)) {
8102
- throw new EvaluationError(_t("The value should be a scalar or a 1x1 matrix"));
8117
+ throw new Error("The value should be a scalar or a 1x1 matrix");
8103
8118
  }
8104
8119
  return arg[0][0];
8105
8120
  }
@@ -8890,7 +8905,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8890
8905
  }
8891
8906
  return "Success" /* CommandResult.Success */;
8892
8907
  }
8893
- copy(data) {
8908
+ copy(data, isCutOperation, mode = "copyPaste") {
8894
8909
  const sheetId = data.sheetId;
8895
8910
  const { clippedZones, rowsIndexes, columnsIndexes } = data;
8896
8911
  const clippedCells = [];
@@ -8903,7 +8918,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8903
8918
  const evaluatedCell = this.getters.getEvaluatedCell(position);
8904
8919
  const pivotId = this.getters.getPivotIdFromPosition(position);
8905
8920
  const spreader = this.getters.getArrayFormulaSpreadingOn(position);
8906
- if (pivotId && spreader) {
8921
+ if (mode !== "shiftCells" && pivotId && spreader) {
8907
8922
  const pivotZone = this.getters.getSpreadZone(spreader);
8908
8923
  if ((!deepEquals(spreader, position) || !isCopyingOneCell) &&
8909
8924
  pivotZone &&
@@ -8921,7 +8936,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8921
8936
  };
8922
8937
  }
8923
8938
  }
8924
- else {
8939
+ else if (mode !== "shiftCells") {
8925
8940
  if (spreader && !deepEquals(spreader, position)) {
8926
8941
  const isSpreaderCopied = rowsIndexes.includes(spreader.row) && columnsIndexes.includes(spreader.col);
8927
8942
  const content = isSpreaderCopied
@@ -9619,7 +9634,7 @@ class SheetClipboardHandler extends AbstractCellClipboardHandler {
9619
9634
  }
9620
9635
 
9621
9636
  class TableClipboardHandler extends AbstractCellClipboardHandler {
9622
- copy(data, isCutOperation) {
9637
+ copy(data, isCutOperation, mode = "copyPaste") {
9623
9638
  const sheetId = data.sheetId;
9624
9639
  const { rowsIndexes, columnsIndexes, zones } = data;
9625
9640
  const copiedTablesIds = new Set();
@@ -9657,11 +9672,13 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
9657
9672
  type: coreTable.type,
9658
9673
  };
9659
9674
  }
9660
- tableCellsInRow.push({
9661
- table: copiedTable,
9662
- style: this.getTableStyleToCopy(position),
9663
- isWholeTableCopied: copiedTablesIds.has(table.id),
9664
- });
9675
+ if (mode !== "shiftCells") {
9676
+ tableCellsInRow.push({
9677
+ table: copiedTable,
9678
+ style: this.getTableStyleToCopy(position),
9679
+ isWholeTableCopied: copiedTablesIds.has(table.id),
9680
+ });
9681
+ }
9665
9682
  }
9666
9683
  }
9667
9684
  return {
@@ -11238,6 +11255,9 @@ const MMULT = {
11238
11255
  compute: function (matrix1, matrix2) {
11239
11256
  const _matrix1 = toNumberMatrix(matrix1, "matrix1");
11240
11257
  const _matrix2 = toNumberMatrix(matrix2, "matrix2");
11258
+ if (_matrix1.length === 0 || _matrix2.length === 0) {
11259
+ return new EvaluationError(_t("The first and second arguments of [[FUNCTION_NAME]] must be non-empty matrices."));
11260
+ }
11241
11261
  if (_matrix1.length !== _matrix2[0].length) {
11242
11262
  return new EvaluationError(_t("In [[FUNCTION_NAME]], the number of columns of the first matrix (%s) must be equal to the \
11243
11263
  number of rows of the second matrix (%s).", _matrix1.length.toString(), _matrix2[0].length.toString()));
@@ -12850,7 +12870,7 @@ function centile(data, percent, isInclusive, locale) {
12850
12870
  count++;
12851
12871
  }
12852
12872
  });
12853
- assert(count !== 0, _t("[[FUNCTION_NAME]] has no valid input data."));
12873
+ assert(count !== 0, noValidInputErrorMessage);
12854
12874
  if (!isInclusive) {
12855
12875
  // 2nd argument must be between 1/(n+1) and n/(n+1) with n the number of data
12856
12876
  assert(1 / (count + 1) <= _percent && _percent <= count / (count + 1), _t("Function [[FUNCTION_NAME]] parameter 2 value is out of range."));
@@ -13125,6 +13145,9 @@ const FORECAST = {
13125
13145
  ],
13126
13146
  compute: function (x, dataY, dataX) {
13127
13147
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13148
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13149
+ return new NotAvailableError(noValidInputErrorMessage);
13150
+ }
13128
13151
  return predictLinearValues([flatDataY], [flatDataX], matrixMap(toMatrix(x), (value) => toNumber(value, this.locale)), true);
13129
13152
  },
13130
13153
  isExported: true,
@@ -13141,6 +13164,9 @@ const GROWTH = {
13141
13164
  arg("b (boolean, default=TRUE)", _t("Given a general exponential form of y = b*m^x for a curve fit, calculates b if TRUE or forces b to be 1 and only calculates the m values if FALSE.")),
13142
13165
  ],
13143
13166
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13167
+ if (knownDataY.length === 0 || knownDataY[0].length === 0) {
13168
+ return new EvaluationError(emptyDataErrorMessage("known_data_y"));
13169
+ }
13144
13170
  return expM(predictLinearValues(logM(toNumberMatrix(knownDataY, "the first argument (known_data_y)")), toNumberMatrix(knownDataX, "the second argument (known_data_x)"), toNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b)));
13145
13171
  },
13146
13172
  };
@@ -13155,6 +13181,9 @@ const INTERCEPT = {
13155
13181
  ],
13156
13182
  compute: function (dataY, dataX) {
13157
13183
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13184
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13185
+ return new NotAvailableError(noValidInputErrorMessage);
13186
+ }
13158
13187
  const [[], [intercept]] = fullLinearRegression([flatDataX], [flatDataY]);
13159
13188
  return intercept;
13160
13189
  },
@@ -13187,7 +13216,7 @@ const LARGE = {
13187
13216
  });
13188
13217
  const result = largests.shift();
13189
13218
  if (result === undefined) {
13190
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
13219
+ return new EvaluationError(noValidInputErrorMessage);
13191
13220
  }
13192
13221
  if (count < _n) {
13193
13222
  return new EvaluationError(_t("Function [[FUNCTION_NAME]] parameter 2 value (%s) is out of range.", _n));
@@ -13208,6 +13237,9 @@ const LINEST = {
13208
13237
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13209
13238
  ],
13210
13239
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13240
+ if (dataY.length === 0 || dataY[0].length === 0) {
13241
+ return new EvaluationError(emptyDataErrorMessage("data_y"));
13242
+ }
13211
13243
  return fullLinearRegression(toNumberMatrix(dataX, "the first argument (data_y)"), toNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13212
13244
  },
13213
13245
  isExported: true,
@@ -13224,6 +13256,9 @@ const LOGEST = {
13224
13256
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13225
13257
  ],
13226
13258
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13259
+ if (dataY.length === 0 || dataY[0].length === 0) {
13260
+ return new EvaluationError(emptyDataErrorMessage("data_y"));
13261
+ }
13227
13262
  const coeffs = fullLinearRegression(toNumberMatrix(dataX, "the second argument (data_x)"), logM(toNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13228
13263
  for (let i = 0; i < coeffs.length; i++) {
13229
13264
  coeffs[i][0] = Math.exp(coeffs[i][0]);
@@ -13245,8 +13280,8 @@ const MATTHEWS = {
13245
13280
  const flatX = dataX.flat();
13246
13281
  const flatY = dataY.flat();
13247
13282
  assertSameNumberOfElements(flatX, flatY);
13248
- if (flatX.length === 0) {
13249
- return new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
13283
+ if (flatX.length === 0 || flatY.length === 0) {
13284
+ return new NotAvailableError(noValidInputErrorMessage);
13250
13285
  }
13251
13286
  const n = flatX.length;
13252
13287
  let trueN = 0, trueP = 0, falseP = 0, falseN = 0;
@@ -13411,11 +13446,8 @@ const MINIFS = {
13411
13446
  // -----------------------------------------------------------------------------
13412
13447
  function pearson(dataY, dataX) {
13413
13448
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13414
- if (flatDataX.length === 0) {
13415
- throw new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
13416
- }
13417
- if (flatDataX.length < 2) {
13418
- throw new EvaluationError(_t("[[FUNCTION_NAME]] needs at least two values for both parameters."));
13449
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13450
+ return new NotAvailableError(noValidInputErrorMessage);
13419
13451
  }
13420
13452
  const n = flatDataX.length;
13421
13453
  let sumX = 0, sumY = 0, sumXY = 0, sumXX = 0, sumYY = 0;
@@ -13505,6 +13537,9 @@ const POLYFIT_COEFFS = {
13505
13537
  ],
13506
13538
  compute: function (dataY, dataX, order, intercept = { value: true }) {
13507
13539
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13540
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13541
+ return new NotAvailableError(noValidInputErrorMessage);
13542
+ }
13508
13543
  return polynomialRegression(flatDataY, flatDataX, toNumber(order, this.locale), toBoolean(intercept));
13509
13544
  },
13510
13545
  isExported: false,
@@ -13524,6 +13559,9 @@ const POLYFIT_FORECAST = {
13524
13559
  compute: function (x, dataY, dataX, order, intercept = { value: true }) {
13525
13560
  const _order = toNumber(order, this.locale);
13526
13561
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13562
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13563
+ return new NotAvailableError(noValidInputErrorMessage);
13564
+ }
13527
13565
  const coeffs = polynomialRegression(flatDataY, flatDataX, _order, toBoolean(intercept)).flat();
13528
13566
  return matrixMap(toMatrix(x), (xij) => evaluatePolynomial(coeffs, toNumber(xij, this.locale), _order));
13529
13567
  },
@@ -13625,7 +13663,11 @@ const RSQ = {
13625
13663
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13626
13664
  ],
13627
13665
  compute: function (dataY, dataX) {
13628
- return Math.pow(pearson(dataX, dataY), 2.0);
13666
+ const value = pearson(dataY, dataX);
13667
+ if (value instanceof Error) {
13668
+ throw value;
13669
+ }
13670
+ return Math.pow(value, 2.0);
13629
13671
  },
13630
13672
  isExported: true,
13631
13673
  };
@@ -13640,6 +13682,9 @@ const SLOPE = {
13640
13682
  ],
13641
13683
  compute: function (dataY, dataX) {
13642
13684
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13685
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13686
+ return new NotAvailableError(noValidInputErrorMessage);
13687
+ }
13643
13688
  const [[slope]] = fullLinearRegression([flatDataX], [flatDataY]);
13644
13689
  return slope;
13645
13690
  },
@@ -13672,7 +13717,7 @@ const SMALL = {
13672
13717
  });
13673
13718
  const result = largests.pop();
13674
13719
  if (result === undefined) {
13675
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
13720
+ return new EvaluationError(noValidInputErrorMessage);
13676
13721
  }
13677
13722
  if (count < _n) {
13678
13723
  return new EvaluationError(_t("Function [[FUNCTION_NAME]] parameter 2 value (%s) is out of range.", _n));
@@ -13692,6 +13737,9 @@ const SPEARMAN = {
13692
13737
  ],
13693
13738
  compute: function (dataX, dataY) {
13694
13739
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13740
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13741
+ return new NotAvailableError(noValidInputErrorMessage);
13742
+ }
13695
13743
  const n = flatDataX.length;
13696
13744
  const order = flatDataX.map((e, i) => [e, flatDataY[i]]);
13697
13745
  order.sort((a, b) => a[0] - b[0]);
@@ -13802,6 +13850,9 @@ const STEYX = {
13802
13850
  ],
13803
13851
  compute: function (dataY, dataX) {
13804
13852
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13853
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13854
+ return new NotAvailableError(noValidInputErrorMessage);
13855
+ }
13805
13856
  const data = fullLinearRegression([flatDataX], [flatDataY], true, true);
13806
13857
  return data[1][2];
13807
13858
  },
@@ -13819,6 +13870,9 @@ const TREND = {
13819
13870
  arg("b (boolean, optional, default=TRUE)", _t("Given a general linear form of y = m*x+b for a curve fit, calculates b if TRUE or forces b to be 0 and only calculates the m values if FALSE, i.e. forces the curve fit to pass through the origin.")),
13820
13871
  ],
13821
13872
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13873
+ if (knownDataY.length === 0 || knownDataY[0].length === 0) {
13874
+ return new EvaluationError(emptyDataErrorMessage("known_data_y"));
13875
+ }
13822
13876
  return predictLinearValues(toNumberMatrix(knownDataY, "the first argument (known_data_y)"), toNumberMatrix(knownDataX, "the second argument (known_data_x)"), toNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b));
13823
13877
  },
13824
13878
  };
@@ -18734,7 +18788,7 @@ const AND = {
18734
18788
  compute: function (...logicalExpressions) {
18735
18789
  const { result, foundBoolean } = boolAnd(logicalExpressions);
18736
18790
  if (!foundBoolean) {
18737
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
18791
+ return new EvaluationError(noValidInputErrorMessage);
18738
18792
  }
18739
18793
  return result;
18740
18794
  },
@@ -18860,7 +18914,7 @@ const OR = {
18860
18914
  compute: function (...logicalExpressions) {
18861
18915
  const { result, foundBoolean } = boolOr(logicalExpressions);
18862
18916
  if (!foundBoolean) {
18863
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
18917
+ return new EvaluationError(noValidInputErrorMessage);
18864
18918
  }
18865
18919
  return result;
18866
18920
  },
@@ -18923,7 +18977,7 @@ const XOR = {
18923
18977
  return true; // no stop condition
18924
18978
  });
18925
18979
  if (!foundBoolean) {
18926
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
18980
+ return new EvaluationError(noValidInputErrorMessage);
18927
18981
  }
18928
18982
  return acc;
18929
18983
  },
@@ -21387,7 +21441,7 @@ function adaptFormulaStringRanges(defaultSheetId, formula, applyChange) {
21387
21441
  function adaptStringRange(defaultSheetId, sheetXC, applyChange) {
21388
21442
  const sheetName = splitReference(sheetXC).sheetName;
21389
21443
  if (sheetName
21390
- ? !isSheetNameEqual(sheetName, applyChange.sheetName)
21444
+ ? !isSheetNameEqual(sheetName, applyChange.sheetName.old)
21391
21445
  : defaultSheetId !== applyChange.sheetId) {
21392
21446
  return sheetXC;
21393
21447
  }
@@ -21404,7 +21458,7 @@ function adaptStringRange(defaultSheetId, sheetXC, applyChange) {
21404
21458
  }
21405
21459
  function getSheetNameGetter(applyChange) {
21406
21460
  return (sheetId) => {
21407
- return sheetId === applyChange.sheetId ? applyChange.sheetName : "";
21461
+ return sheetId === applyChange.sheetId ? applyChange.sheetName.current : "";
21408
21462
  };
21409
21463
  }
21410
21464
  function defaultGetSheetSize(sheetId) {
@@ -27395,9 +27449,13 @@ class GaugeChart extends AbstractChart {
27395
27449
  : undefined,
27396
27450
  };
27397
27451
  }
27398
- updateRanges(applyChange) {
27452
+ updateRanges(applyChange, sheetId, adaptSheetName) {
27399
27453
  const dataRange = adaptChartRange(this.dataRange, applyChange);
27400
- const adaptFormula = (formula) => this.getters.adaptFormulaStringDependencies(this.sheetId, formula, applyChange);
27454
+ const adaptFormula = (formula) => adaptFormulaStringRanges(this.sheetId, formula, {
27455
+ applyChange,
27456
+ sheetId,
27457
+ sheetName: adaptSheetName,
27458
+ });
27401
27459
  const sectionRule = adaptSectionRuleFormulas(this.sectionRule, adaptFormula);
27402
27460
  const definition = this.getDefinitionWithSpecificRanges(dataRange, sectionRule);
27403
27461
  return new GaugeChart(definition, this.sheetId, this.getters);
@@ -33720,6 +33778,9 @@ class Composer extends owl.Component {
33720
33778
  this.contentHelper.removeSelection();
33721
33779
  }
33722
33780
  onMouseup() {
33781
+ if (this.env.model.getters.isReadonly()) {
33782
+ return;
33783
+ }
33723
33784
  const selection = this.contentHelper.getCurrentSelection();
33724
33785
  if (selection.start !== selection.end) {
33725
33786
  this.props.composerStore.hoverToken(undefined);
@@ -37455,7 +37516,7 @@ const SUPPORTED_HORIZONTAL_ALIGNMENTS = [
37455
37516
  ];
37456
37517
  const SUPPORTED_VERTICAL_ALIGNMENTS = ["top", "center", "bottom"];
37457
37518
  const SUPPORTED_FONTS = ["Arial"];
37458
- const SUPPORTED_FILL_PATTERNS = ["solid"];
37519
+ const SUPPORTED_FILL_PATTERNS = ["solid", "none"];
37459
37520
  const SUPPORTED_CF_TYPES = [
37460
37521
  "expression",
37461
37522
  "cellIs",
@@ -37655,7 +37716,7 @@ const SUBTOTAL_FUNCTION_CONVERSION_MAP = {
37655
37716
  };
37656
37717
  /** Mapping between Excel format indexes (see XLSX_FORMAT_MAP) and some supported formats */
37657
37718
  const XLSX_FORMATS_CONVERSION_MAP = {
37658
- 0: "",
37719
+ 0: "General",
37659
37720
  1: "0",
37660
37721
  2: "0.00",
37661
37722
  3: "#,#00",
@@ -37981,11 +38042,11 @@ const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/
37981
38042
  * Excel format are defined in openXML §18.8.31
37982
38043
  */
37983
38044
  function convertXlsxFormat(numFmtId, formats, warningManager) {
37984
- if (numFmtId === 0) {
37985
- return undefined;
37986
- }
37987
38045
  // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
37988
38046
  const format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || formats.find((f) => f.id === numFmtId)?.format;
38047
+ if (format === "General") {
38048
+ return undefined;
38049
+ }
37989
38050
  if (format) {
37990
38051
  try {
37991
38052
  let convertedFormat = format.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
@@ -38183,9 +38244,9 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
38183
38244
  if (!rule.operator || !rule.formula || rule.formula.length === 0)
38184
38245
  continue;
38185
38246
  operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.operator];
38186
- values.push(rule.formula[0]);
38247
+ values.push(prefixFormula(rule.formula[0]));
38187
38248
  if (rule.formula.length === 2) {
38188
- values.push(rule.formula[1]);
38249
+ values.push(prefixFormula(rule.formula[1]));
38189
38250
  }
38190
38251
  break;
38191
38252
  }
@@ -38343,6 +38404,11 @@ function convertIcons(xlsxIconSet, index) {
38343
38404
  ? ICON_SETS[iconSet].neutral
38344
38405
  : ICON_SETS[iconSet].good;
38345
38406
  }
38407
+ /** Prefix the string by "=" if the string looks like a formula */
38408
+ function prefixFormula(formula) {
38409
+ const tokens = tokenize(formula);
38410
+ return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
38411
+ }
38346
38412
  // ---------------------------------------------------------------------------
38347
38413
  // Warnings
38348
38414
  // ---------------------------------------------------------------------------
@@ -38625,7 +38691,7 @@ function getColPosition(colIndex, sheetData) {
38625
38691
  function getRowPosition(rowIndex, sheetData) {
38626
38692
  let position = 0;
38627
38693
  for (let i = 0; i < rowIndex; i++) {
38628
- const rowAtIndex = sheetData.rows[i];
38694
+ const rowAtIndex = sheetData.rows.find((row) => row.index - 1 === i);
38629
38695
  if (rowAtIndex?.height) {
38630
38696
  position += rowAtIndex.height;
38631
38697
  }
@@ -38780,8 +38846,8 @@ function convertExcelTrendline(trend) {
38780
38846
  }
38781
38847
  function convertAnchor(XLSXanchor) {
38782
38848
  const offset = {
38783
- x: convertEMUToDotValue(XLSXanchor.colOffset),
38784
- y: convertEMUToDotValue(XLSXanchor.rowOffset),
38849
+ x: convertEMUToDotValue(XLSXanchor.colOffset) - FIGURE_BORDER_WIDTH,
38850
+ y: convertEMUToDotValue(XLSXanchor.rowOffset) - FIGURE_BORDER_WIDTH,
38785
38851
  };
38786
38852
  return { col: XLSXanchor.col, row: XLSXanchor.row, offset };
38787
38853
  }
@@ -39164,8 +39230,12 @@ function getSheetDims(sheet) {
39164
39230
  dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
39165
39231
  dims[1] = Math.max(dims[1], row.index);
39166
39232
  }
39167
- dims[0] = Math.max(dims[0], EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
39168
- dims[1] = Math.max(dims[1], EXCEL_IMPORT_DEFAULT_NUMBER_OF_ROWS);
39233
+ for (const fig of sheet.figures) {
39234
+ dims[0] = Math.max(dims[0], fig.anchors[fig.anchors.length - 1]?.col ?? 0);
39235
+ dims[1] = Math.max(dims[1], fig.anchors[fig.anchors.length - 1]?.row ?? 0);
39236
+ }
39237
+ dims[0] = Math.max(dims[0] + 5, EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
39238
+ dims[1] = Math.max(dims[1] + 5, EXCEL_IMPORT_DEFAULT_NUMBER_OF_ROWS);
39169
39239
  return dims;
39170
39240
  }
39171
39241
  /**
@@ -40554,10 +40624,11 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
40554
40624
  });
40555
40625
  }
40556
40626
  extractRows(worksheet) {
40627
+ const spilledCells = new Set();
40557
40628
  return this.mapOnElements({ parent: worksheet, query: "sheetData row" }, (rowElement) => {
40558
40629
  return {
40559
40630
  index: this.extractAttr(rowElement, "r", { required: true })?.asNum(),
40560
- cells: this.extractCells(rowElement),
40631
+ cells: this.extractCells(rowElement, spilledCells),
40561
40632
  height: this.extractAttr(rowElement, "ht")?.asNum(),
40562
40633
  customHeight: this.extractAttr(rowElement, "customHeight")?.asBool(),
40563
40634
  hidden: this.extractAttr(rowElement, "hidden")?.asBool(),
@@ -40567,14 +40638,26 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
40567
40638
  };
40568
40639
  });
40569
40640
  }
40570
- extractCells(row) {
40641
+ extractCells(row, spilledCells) {
40571
40642
  return this.mapOnElements({ parent: row, query: "c" }, (cellElement) => {
40643
+ const xc = this.extractAttr(cellElement, "r", { required: true })?.asString();
40644
+ const formula = this.extractCellFormula(cellElement);
40645
+ if (formula?.ref && formula.sharedIndex === undefined) {
40646
+ const zone = toZone(formula.ref);
40647
+ for (const { col, row } of positions(zone)) {
40648
+ const followerXc = toXC(col, row);
40649
+ if (followerXc !== xc) {
40650
+ spilledCells.add(followerXc);
40651
+ }
40652
+ }
40653
+ }
40654
+ const isSpilled = spilledCells.has(xc);
40572
40655
  return {
40573
- xc: this.extractAttr(cellElement, "r", { required: true })?.asString(),
40656
+ xc,
40574
40657
  styleIndex: this.extractAttr(cellElement, "s")?.asNum(),
40575
40658
  type: CELL_TYPE_CONVERSION_MAP[this.extractAttr(cellElement, "t", { default: "n" })?.asString()],
40576
- value: this.extractChildTextContent(cellElement, "v"),
40577
- formula: this.extractCellFormula(cellElement),
40659
+ value: isSpilled ? undefined : this.extractChildTextContent(cellElement, "v") ?? undefined,
40660
+ formula: isSpilled ? undefined : formula,
40578
40661
  };
40579
40662
  });
40580
40663
  }
@@ -40582,11 +40665,14 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
40582
40665
  const formulaElement = this.querySelector(cellElement, "f");
40583
40666
  if (!formulaElement)
40584
40667
  return undefined;
40585
- return {
40586
- content: this.extractTextContent(formulaElement),
40587
- sharedIndex: this.extractAttr(formulaElement, "si")?.asNum(),
40588
- ref: this.extractAttr(formulaElement, "ref")?.asString(),
40589
- };
40668
+ const content = this.extractTextContent(formulaElement);
40669
+ const sharedIndex = this.extractAttr(formulaElement, "si")?.asNum();
40670
+ const ref = this.extractAttr(formulaElement, "ref")?.asString();
40671
+ // This is the case of spilled cells of array formulas where <f> is empty
40672
+ if ((content === undefined || content.trim() === "") && sharedIndex === undefined) {
40673
+ return undefined;
40674
+ }
40675
+ return { content, sharedIndex, ref };
40590
40676
  }
40591
40677
  extractHyperLinks(worksheet) {
40592
40678
  return this.mapOnElements({ parent: worksheet, query: "hyperlink" }, (linkElement) => {
@@ -40868,7 +40954,7 @@ function getRelationFile(file, xmls) {
40868
40954
  return relsFile;
40869
40955
  }
40870
40956
 
40871
- const EXCEL_IMPORT_VERSION = "18.4.1";
40957
+ const EXCEL_IMPORT_VERSION = "18.4.2";
40872
40958
  class XlsxReader {
40873
40959
  warningManager;
40874
40960
  xmls;
@@ -44413,7 +44499,7 @@ const splitToColumns = {
44413
44499
  const reinsertDynamicPivotMenu = {
44414
44500
  id: "reinsert_dynamic_pivot",
44415
44501
  name: _t("Re-insert dynamic pivot"),
44416
- sequence: 1020,
44502
+ sequence: 60,
44417
44503
  icon: "o-spreadsheet-Icon.INSERT_PIVOT",
44418
44504
  children: [REINSERT_DYNAMIC_PIVOT_CHILDREN],
44419
44505
  isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
@@ -44421,7 +44507,7 @@ const reinsertDynamicPivotMenu = {
44421
44507
  const reinsertStaticPivotMenu = {
44422
44508
  id: "reinsert_static_pivot",
44423
44509
  name: _t("Re-insert static pivot"),
44424
- sequence: 1020,
44510
+ sequence: 70,
44425
44511
  icon: "o-spreadsheet-Icon.INSERT_PIVOT",
44426
44512
  children: [REINSERT_STATIC_PIVOT_CHILDREN],
44427
44513
  isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
@@ -58692,7 +58778,8 @@ class CorePlugin extends BasePlugin {
58692
58778
  * the type of change that occurred.
58693
58779
  *
58694
58780
  * @param applyChange a function that, when called, will adapt the range according to the change on the grid
58695
- * @param sheetId an optional sheetId to adapt either range of that sheet specifically, or ranges pointing to that sheet
58781
+ * @param sheetId an sheetId to adapt either range of that sheet specifically, or ranges pointing to that sheet
58782
+ * @param sheetName couple of old and new sheet names to adapt ranges pointing to that sheet
58696
58783
  */
58697
58784
  adaptRanges(applyChange, sheetId, sheetName) { }
58698
58785
  /**
@@ -59295,9 +59382,7 @@ class CellPlugin extends CorePlugin {
59295
59382
  for (const cell of Object.values(this.cells[sheet] || {})) {
59296
59383
  if (cell.isFormula) {
59297
59384
  for (const range of cell.compiledFormula.dependencies) {
59298
- if (!sheetId ||
59299
- range.sheetId === sheetId ||
59300
- (sheetName && range.invalidSheetName === sheetName)) {
59385
+ if (range.sheetId === sheetId || range.invalidSheetName === sheetName.old) {
59301
59386
  const change = applyChange(range);
59302
59387
  if (change.changeType !== "NONE") {
59303
59388
  this.history.update("cells", sheet, cell.id, "compiledFormula", "dependencies", cell.compiledFormula.dependencies.indexOf(range), change.range);
@@ -59913,9 +59998,9 @@ class ChartPlugin extends CorePlugin {
59913
59998
  charts = {};
59914
59999
  createChart = chartFactory(this.getters);
59915
60000
  validateChartDefinition = (cmd) => validateChartDefinition(this, cmd.definition);
59916
- adaptRanges(applyChange) {
60001
+ adaptRanges(applyChange, sheetId, adaptSheetName) {
59917
60002
  for (const [chartId, chart] of Object.entries(this.charts)) {
59918
- this.history.update("charts", chartId, chart?.updateRanges(applyChange));
60003
+ this.history.update("charts", chartId, chart?.updateRanges(applyChange, sheetId, adaptSheetName));
59919
60004
  }
59920
60005
  }
59921
60006
  // ---------------------------------------------------------------------------
@@ -60178,7 +60263,7 @@ class ConditionalFormatPlugin extends CorePlugin {
60178
60263
  }
60179
60264
  }
60180
60265
  }
60181
- adaptRanges(applyChange, sheetId, sheetName) {
60266
+ adaptRanges(applyChange, sheetId) {
60182
60267
  const sheetIds = sheetId ? [sheetId] : Object.keys(this.cfRules);
60183
60268
  for (const sheetId of sheetIds) {
60184
60269
  this.adaptCFRanges(sheetId, applyChange);
@@ -60560,11 +60645,8 @@ class DataValidationPlugin extends CorePlugin {
60560
60645
  "getValidationRuleForCell",
60561
60646
  ];
60562
60647
  rules = {};
60563
- adaptRanges(applyChange, sheetId, sheetName) {
60564
- const sheetIds = sheetId ? [sheetId] : Object.keys(this.rules);
60565
- for (const sheetId of sheetIds) {
60566
- this.adaptDVRanges(sheetId, applyChange);
60567
- }
60648
+ adaptRanges(applyChange, sheetId) {
60649
+ this.adaptDVRanges(sheetId, applyChange);
60568
60650
  this.adaptDVFormulas(applyChange);
60569
60651
  }
60570
60652
  adaptDVFormulas(applyChange) {
@@ -60854,9 +60936,6 @@ class FigurePlugin extends CorePlugin {
60854
60936
  // Command Handling
60855
60937
  // ---------------------------------------------------------------------------
60856
60938
  adaptRanges(applyChange, sheetId) {
60857
- if (!sheetId) {
60858
- return;
60859
- }
60860
60939
  for (const figure of this.getFigures(sheetId)) {
60861
60940
  const change = applyChange(this.getters.getRangeFromZone(sheetId, {
60862
60941
  left: figure.col,
@@ -61665,11 +61744,8 @@ class MergePlugin extends CorePlugin {
61665
61744
  break;
61666
61745
  }
61667
61746
  }
61668
- adaptRanges(applyChange, sheetId, sheetName) {
61669
- const sheetIds = sheetId ? [sheetId] : Object.keys(this.merges);
61670
- for (const sheetId of sheetIds) {
61671
- this.applyRangeChangeOnSheet(sheetId, applyChange);
61672
- }
61747
+ adaptRanges(applyChange, sheetId) {
61748
+ this.applyRangeChangeOnSheet(sheetId, applyChange);
61673
61749
  }
61674
61750
  // ---------------------------------------------------------------------------
61675
61751
  // Getters
@@ -63174,12 +63250,9 @@ class TablePlugin extends CorePlugin {
63174
63250
  static getters = ["getCoreTable", "getCoreTables", "getCoreTableMatchingTopLeft"];
63175
63251
  tables = {};
63176
63252
  nextTableId = 1;
63177
- adaptRanges(applyChange, sheetId, sheetName) {
63178
- const sheetIds = sheetId ? [sheetId] : this.getters.getSheetIds();
63179
- for (const sheetId of sheetIds) {
63180
- for (const table of this.getCoreTables(sheetId)) {
63181
- this.applyRangeChangeOnTable(sheetId, table, applyChange);
63182
- }
63253
+ adaptRanges(applyChange, sheetId) {
63254
+ for (const table of this.getCoreTables(sheetId)) {
63255
+ this.applyRangeChangeOnTable(sheetId, table, applyChange);
63183
63256
  }
63184
63257
  }
63185
63258
  allowDispatch(cmd) {
@@ -64142,7 +64215,7 @@ class PivotCorePlugin extends CorePlugin {
64142
64215
  }
64143
64216
  }
64144
64217
  }
64145
- adaptRanges(applyChange, sheetId, sheetName) {
64218
+ adaptRanges(applyChange) {
64146
64219
  for (const sheetId in this.compiledMeasureFormulas) {
64147
64220
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
64148
64221
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -68543,7 +68616,7 @@ class PivotUIPlugin extends CoreViewPlugin {
68543
68616
  if (!result) {
68544
68617
  return EMPTY_PIVOT_CELL;
68545
68618
  }
68546
- const { functionName, args } = result;
68619
+ let { functionName, args } = result;
68547
68620
  const formulaId = args[0];
68548
68621
  if (!formulaId) {
68549
68622
  return EMPTY_PIVOT_CELL;
@@ -68578,6 +68651,9 @@ class PivotUIPlugin extends CoreViewPlugin {
68578
68651
  return pivotCells[pivotCol][pivotRow];
68579
68652
  }
68580
68653
  try {
68654
+ const offsetRow = position.row - mainPosition.row;
68655
+ const offsetCol = position.col - mainPosition.col;
68656
+ args = args.map((arg) => (isMatrix(arg) ? arg[offsetCol][offsetRow] : arg));
68581
68657
  if (functionName === "PIVOT.HEADER" && args.at(-2) === "measure") {
68582
68658
  const domain = pivot.parseArgsToPivotDomain(args.slice(1, -2).map((value) => ({ value })));
68583
68659
  return {
@@ -70186,7 +70262,8 @@ function transformAll(toTransform, executed) {
70186
70262
  // If the executed command is not in the registry, we skip it
70187
70263
  // because we know there won't be any transformation impacting the
70188
70264
  // commands to transform.
70189
- if (possibleTransformations.has(executedCommand.type)) {
70265
+ if (possibleTransformations.has(executedCommand.type) ||
70266
+ rangeAdapterRegistry.contains(executedCommand.type)) {
70190
70267
  transformedCommands = transformedCommands.reduce((acc, cmd) => {
70191
70268
  const transformed = transform(cmd, executedCommand);
70192
70269
  if (transformed) {
@@ -70933,7 +71010,7 @@ class DataCleanupPlugin extends UIPlugin {
70933
71010
  bottom: rowIndex,
70934
71011
  }));
70935
71012
  const handler = new CellClipboardHandler(this.getters, this.dispatch);
70936
- const data = handler.copy(getClipboardDataPositions(sheetId, rowsToKeep));
71013
+ const data = handler.copy(getClipboardDataPositions(sheetId, rowsToKeep), false);
70937
71014
  if (!data) {
70938
71015
  return;
70939
71016
  }
@@ -73018,12 +73095,12 @@ class ClipboardPlugin extends UIPlugin {
73018
73095
  }
73019
73096
  case "INSERT_CELL": {
73020
73097
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
73021
- const copiedData = this.copy(cut);
73098
+ const copiedData = this.copy(cut, "shiftCells");
73022
73099
  return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
73023
73100
  }
73024
73101
  case "DELETE_CELL": {
73025
73102
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
73026
- const copiedData = this.copy(cut);
73103
+ const copiedData = this.copy(cut, "shiftCells");
73027
73104
  return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
73028
73105
  }
73029
73106
  }
@@ -73134,13 +73211,13 @@ class ClipboardPlugin extends UIPlugin {
73134
73211
  });
73135
73212
  break;
73136
73213
  }
73137
- const copiedData = this.copy(cut);
73214
+ const copiedData = this.copy(cut, "shiftCells");
73138
73215
  this.paste(paste, copiedData, { isCutOperation: true });
73139
73216
  break;
73140
73217
  }
73141
73218
  case "INSERT_CELL": {
73142
73219
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
73143
- const copiedData = this.copy(cut);
73220
+ const copiedData = this.copy(cut, "shiftCells");
73144
73221
  this.paste(paste, copiedData, { isCutOperation: true });
73145
73222
  break;
73146
73223
  }
@@ -73255,11 +73332,11 @@ class ClipboardPlugin extends UIPlugin {
73255
73332
  }
73256
73333
  return false;
73257
73334
  }
73258
- copy(zones) {
73335
+ copy(zones, mode = "copyPaste") {
73259
73336
  const copiedData = {};
73260
73337
  const clipboardData = this.getClipboardData(zones);
73261
73338
  for (const { handlerName, handler } of this.selectClipboardHandlers(clipboardData)) {
73262
- const data = handler.copy(clipboardData, this._isCutOperation);
73339
+ const data = handler.copy(clipboardData, this._isCutOperation, mode);
73263
73340
  copiedData[handlerName] = data;
73264
73341
  const minimalKeys = ["sheetId", "cells", "zones", "figureId"];
73265
73342
  for (const key of minimalKeys) {
@@ -74273,7 +74350,7 @@ class GridSelectionPlugin extends UIPlugin {
74273
74350
  ];
74274
74351
  for (const Handler of clipboardHandlersRegistries.cellHandlers.getAll()) {
74275
74352
  const handler = new Handler(this.getters, this.dispatch);
74276
- const data = handler.copy(getClipboardDataPositions(sheetId, target));
74353
+ const data = handler.copy(getClipboardDataPositions(sheetId, target), false, "shiftCells");
74277
74354
  if (!data) {
74278
74355
  continue;
74279
74356
  }
@@ -76178,7 +76255,8 @@ const inverseCommandRegistry = new Registry()
76178
76255
  .add("HIDE_COLUMNS_ROWS", inverseHideColumnsRows)
76179
76256
  .add("UNHIDE_COLUMNS_ROWS", inverseUnhideColumnsRows)
76180
76257
  .add("CREATE_TABLE_STYLE", inverseCreateTableStyle)
76181
- .add("ADD_PIVOT", inverseAddPivot);
76258
+ .add("ADD_PIVOT", inverseAddPivot)
76259
+ .add("RENAME_SHEET", inverseRenameSheet);
76182
76260
  for (const cmd of coreTypes.values()) {
76183
76261
  if (!inverseCommandRegistry.contains(cmd)) {
76184
76262
  inverseCommandRegistry.add(cmd, identity);
@@ -76276,6 +76354,16 @@ function inverseUnhideColumnsRows(cmd) {
76276
76354
  function inverseCreateTableStyle(cmd) {
76277
76355
  return [{ type: "REMOVE_TABLE_STYLE", tableStyleId: cmd.tableStyleId }];
76278
76356
  }
76357
+ function inverseRenameSheet(cmd) {
76358
+ return [
76359
+ {
76360
+ type: "RENAME_SHEET",
76361
+ sheetId: cmd.sheetId,
76362
+ oldName: cmd.newName,
76363
+ newName: cmd.oldName,
76364
+ },
76365
+ ];
76366
+ }
76279
76367
 
76280
76368
  const numberFormatMenuRegistry = new Registry();
76281
76369
  numberFormatMenuRegistry
@@ -76874,8 +76962,9 @@ topbarMenuRegistry
76874
76962
  sequence: 40,
76875
76963
  separator: true,
76876
76964
  })
76877
- .addChild("data_sources_data", ["data"], (env) => {
76965
+ .addChild("pivot_data_sources", ["data"], (env) => {
76878
76966
  const sequence = 50;
76967
+ const numberOfPivots = env.model.getters.getPivotIds().length;
76879
76968
  return env.model.getters.getPivotIds().map((pivotId, index) => {
76880
76969
  const highlightProvider = {
76881
76970
  get highlights() {
@@ -76885,7 +76974,7 @@ topbarMenuRegistry
76885
76974
  return {
76886
76975
  id: `item_pivot_${env.model.getters.getPivotFormulaId(pivotId)}`,
76887
76976
  name: env.model.getters.getPivotDisplayName(pivotId),
76888
- sequence: sequence + index,
76977
+ sequence: sequence + index / numberOfPivots,
76889
76978
  isReadonlyAllowed: true,
76890
76979
  execute: (env) => env.openSidePanel("PivotSidePanel", { pivotId }),
76891
76980
  isEnabled: (env) => !env.isSmall,
@@ -83005,7 +83094,7 @@ function figureCoordinates(headers, anchor, offset) {
83005
83094
  for (const [headerIndex, header] of headers.slice(anchor).entries()) {
83006
83095
  if (currentPosition <= offset && offset < currentPosition + header.size) {
83007
83096
  return {
83008
- index: headerIndex,
83097
+ index: anchor + headerIndex,
83009
83098
  offset: convertDotValueToEMU(offset - currentPosition + FIGURE_BORDER_WIDTH),
83010
83099
  };
83011
83100
  }
@@ -84751,6 +84840,6 @@ exports.tokenColors = tokenColors;
84751
84840
  exports.tokenize = tokenize;
84752
84841
 
84753
84842
 
84754
- __info__.version = "18.4.8";
84755
- __info__.date = "2025-08-26T10:14:08.954Z";
84756
- __info__.hash = "746217a";
84843
+ __info__.version = "18.4.10";
84844
+ __info__.date = "2025-09-11T08:45:39.178Z";
84845
+ __info__.hash = "15a11a4";