@odoo/o-spreadsheet 18.4.8 → 18.4.9

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.9
6
+ * @date 2025-09-05T07:38:32.126Z
7
+ * @hash a261873
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";
@@ -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
  }
@@ -11238,6 +11253,9 @@ const MMULT = {
11238
11253
  compute: function (matrix1, matrix2) {
11239
11254
  const _matrix1 = toNumberMatrix(matrix1, "matrix1");
11240
11255
  const _matrix2 = toNumberMatrix(matrix2, "matrix2");
11256
+ if (_matrix1.length === 0 || _matrix2.length === 0) {
11257
+ return new EvaluationError(_t("The first and second arguments of [[FUNCTION_NAME]] must be non-empty matrices."));
11258
+ }
11241
11259
  if (_matrix1.length !== _matrix2[0].length) {
11242
11260
  return new EvaluationError(_t("In [[FUNCTION_NAME]], the number of columns of the first matrix (%s) must be equal to the \
11243
11261
  number of rows of the second matrix (%s).", _matrix1.length.toString(), _matrix2[0].length.toString()));
@@ -12850,7 +12868,7 @@ function centile(data, percent, isInclusive, locale) {
12850
12868
  count++;
12851
12869
  }
12852
12870
  });
12853
- assert(count !== 0, _t("[[FUNCTION_NAME]] has no valid input data."));
12871
+ assert(count !== 0, noValidInputErrorMessage);
12854
12872
  if (!isInclusive) {
12855
12873
  // 2nd argument must be between 1/(n+1) and n/(n+1) with n the number of data
12856
12874
  assert(1 / (count + 1) <= _percent && _percent <= count / (count + 1), _t("Function [[FUNCTION_NAME]] parameter 2 value is out of range."));
@@ -13125,6 +13143,9 @@ const FORECAST = {
13125
13143
  ],
13126
13144
  compute: function (x, dataY, dataX) {
13127
13145
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13146
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13147
+ return new NotAvailableError(noValidInputErrorMessage);
13148
+ }
13128
13149
  return predictLinearValues([flatDataY], [flatDataX], matrixMap(toMatrix(x), (value) => toNumber(value, this.locale)), true);
13129
13150
  },
13130
13151
  isExported: true,
@@ -13141,6 +13162,9 @@ const GROWTH = {
13141
13162
  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
13163
  ],
13143
13164
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13165
+ if (knownDataY.length === 0 || knownDataY[0].length === 0) {
13166
+ return new EvaluationError(emptyDataErrorMessage("known_data_y"));
13167
+ }
13144
13168
  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
13169
  },
13146
13170
  };
@@ -13155,6 +13179,9 @@ const INTERCEPT = {
13155
13179
  ],
13156
13180
  compute: function (dataY, dataX) {
13157
13181
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13182
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13183
+ return new NotAvailableError(noValidInputErrorMessage);
13184
+ }
13158
13185
  const [[], [intercept]] = fullLinearRegression([flatDataX], [flatDataY]);
13159
13186
  return intercept;
13160
13187
  },
@@ -13187,7 +13214,7 @@ const LARGE = {
13187
13214
  });
13188
13215
  const result = largests.shift();
13189
13216
  if (result === undefined) {
13190
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
13217
+ return new EvaluationError(noValidInputErrorMessage);
13191
13218
  }
13192
13219
  if (count < _n) {
13193
13220
  return new EvaluationError(_t("Function [[FUNCTION_NAME]] parameter 2 value (%s) is out of range.", _n));
@@ -13208,6 +13235,9 @@ const LINEST = {
13208
13235
  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
13236
  ],
13210
13237
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13238
+ if (dataY.length === 0 || dataY[0].length === 0) {
13239
+ return new EvaluationError(emptyDataErrorMessage("data_y"));
13240
+ }
13211
13241
  return fullLinearRegression(toNumberMatrix(dataX, "the first argument (data_y)"), toNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13212
13242
  },
13213
13243
  isExported: true,
@@ -13224,6 +13254,9 @@ const LOGEST = {
13224
13254
  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
13255
  ],
13226
13256
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13257
+ if (dataY.length === 0 || dataY[0].length === 0) {
13258
+ return new EvaluationError(emptyDataErrorMessage("data_y"));
13259
+ }
13227
13260
  const coeffs = fullLinearRegression(toNumberMatrix(dataX, "the second argument (data_x)"), logM(toNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13228
13261
  for (let i = 0; i < coeffs.length; i++) {
13229
13262
  coeffs[i][0] = Math.exp(coeffs[i][0]);
@@ -13245,8 +13278,8 @@ const MATTHEWS = {
13245
13278
  const flatX = dataX.flat();
13246
13279
  const flatY = dataY.flat();
13247
13280
  assertSameNumberOfElements(flatX, flatY);
13248
- if (flatX.length === 0) {
13249
- return new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
13281
+ if (flatX.length === 0 || flatY.length === 0) {
13282
+ return new NotAvailableError(noValidInputErrorMessage);
13250
13283
  }
13251
13284
  const n = flatX.length;
13252
13285
  let trueN = 0, trueP = 0, falseP = 0, falseN = 0;
@@ -13411,11 +13444,8 @@ const MINIFS = {
13411
13444
  // -----------------------------------------------------------------------------
13412
13445
  function pearson(dataY, dataX) {
13413
13446
  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."));
13447
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13448
+ return new NotAvailableError(noValidInputErrorMessage);
13419
13449
  }
13420
13450
  const n = flatDataX.length;
13421
13451
  let sumX = 0, sumY = 0, sumXY = 0, sumXX = 0, sumYY = 0;
@@ -13505,6 +13535,9 @@ const POLYFIT_COEFFS = {
13505
13535
  ],
13506
13536
  compute: function (dataY, dataX, order, intercept = { value: true }) {
13507
13537
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13538
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13539
+ return new NotAvailableError(noValidInputErrorMessage);
13540
+ }
13508
13541
  return polynomialRegression(flatDataY, flatDataX, toNumber(order, this.locale), toBoolean(intercept));
13509
13542
  },
13510
13543
  isExported: false,
@@ -13524,6 +13557,9 @@ const POLYFIT_FORECAST = {
13524
13557
  compute: function (x, dataY, dataX, order, intercept = { value: true }) {
13525
13558
  const _order = toNumber(order, this.locale);
13526
13559
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13560
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13561
+ return new NotAvailableError(noValidInputErrorMessage);
13562
+ }
13527
13563
  const coeffs = polynomialRegression(flatDataY, flatDataX, _order, toBoolean(intercept)).flat();
13528
13564
  return matrixMap(toMatrix(x), (xij) => evaluatePolynomial(coeffs, toNumber(xij, this.locale), _order));
13529
13565
  },
@@ -13625,7 +13661,11 @@ const RSQ = {
13625
13661
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13626
13662
  ],
13627
13663
  compute: function (dataY, dataX) {
13628
- return Math.pow(pearson(dataX, dataY), 2.0);
13664
+ const value = pearson(dataY, dataX);
13665
+ if (value instanceof Error) {
13666
+ throw value;
13667
+ }
13668
+ return Math.pow(value, 2.0);
13629
13669
  },
13630
13670
  isExported: true,
13631
13671
  };
@@ -13640,6 +13680,9 @@ const SLOPE = {
13640
13680
  ],
13641
13681
  compute: function (dataY, dataX) {
13642
13682
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13683
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13684
+ return new NotAvailableError(noValidInputErrorMessage);
13685
+ }
13643
13686
  const [[slope]] = fullLinearRegression([flatDataX], [flatDataY]);
13644
13687
  return slope;
13645
13688
  },
@@ -13672,7 +13715,7 @@ const SMALL = {
13672
13715
  });
13673
13716
  const result = largests.pop();
13674
13717
  if (result === undefined) {
13675
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
13718
+ return new EvaluationError(noValidInputErrorMessage);
13676
13719
  }
13677
13720
  if (count < _n) {
13678
13721
  return new EvaluationError(_t("Function [[FUNCTION_NAME]] parameter 2 value (%s) is out of range.", _n));
@@ -13692,6 +13735,9 @@ const SPEARMAN = {
13692
13735
  ],
13693
13736
  compute: function (dataX, dataY) {
13694
13737
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13738
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13739
+ return new NotAvailableError(noValidInputErrorMessage);
13740
+ }
13695
13741
  const n = flatDataX.length;
13696
13742
  const order = flatDataX.map((e, i) => [e, flatDataY[i]]);
13697
13743
  order.sort((a, b) => a[0] - b[0]);
@@ -13802,6 +13848,9 @@ const STEYX = {
13802
13848
  ],
13803
13849
  compute: function (dataY, dataX) {
13804
13850
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13851
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13852
+ return new NotAvailableError(noValidInputErrorMessage);
13853
+ }
13805
13854
  const data = fullLinearRegression([flatDataX], [flatDataY], true, true);
13806
13855
  return data[1][2];
13807
13856
  },
@@ -13819,6 +13868,9 @@ const TREND = {
13819
13868
  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
13869
  ],
13821
13870
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13871
+ if (knownDataY.length === 0 || knownDataY[0].length === 0) {
13872
+ return new EvaluationError(emptyDataErrorMessage("known_data_y"));
13873
+ }
13822
13874
  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
13875
  },
13824
13876
  };
@@ -18734,7 +18786,7 @@ const AND = {
18734
18786
  compute: function (...logicalExpressions) {
18735
18787
  const { result, foundBoolean } = boolAnd(logicalExpressions);
18736
18788
  if (!foundBoolean) {
18737
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
18789
+ return new EvaluationError(noValidInputErrorMessage);
18738
18790
  }
18739
18791
  return result;
18740
18792
  },
@@ -18860,7 +18912,7 @@ const OR = {
18860
18912
  compute: function (...logicalExpressions) {
18861
18913
  const { result, foundBoolean } = boolOr(logicalExpressions);
18862
18914
  if (!foundBoolean) {
18863
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
18915
+ return new EvaluationError(noValidInputErrorMessage);
18864
18916
  }
18865
18917
  return result;
18866
18918
  },
@@ -18923,7 +18975,7 @@ const XOR = {
18923
18975
  return true; // no stop condition
18924
18976
  });
18925
18977
  if (!foundBoolean) {
18926
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
18978
+ return new EvaluationError(noValidInputErrorMessage);
18927
18979
  }
18928
18980
  return acc;
18929
18981
  },
@@ -21387,7 +21439,7 @@ function adaptFormulaStringRanges(defaultSheetId, formula, applyChange) {
21387
21439
  function adaptStringRange(defaultSheetId, sheetXC, applyChange) {
21388
21440
  const sheetName = splitReference(sheetXC).sheetName;
21389
21441
  if (sheetName
21390
- ? !isSheetNameEqual(sheetName, applyChange.sheetName)
21442
+ ? !isSheetNameEqual(sheetName, applyChange.sheetName.old)
21391
21443
  : defaultSheetId !== applyChange.sheetId) {
21392
21444
  return sheetXC;
21393
21445
  }
@@ -21404,7 +21456,7 @@ function adaptStringRange(defaultSheetId, sheetXC, applyChange) {
21404
21456
  }
21405
21457
  function getSheetNameGetter(applyChange) {
21406
21458
  return (sheetId) => {
21407
- return sheetId === applyChange.sheetId ? applyChange.sheetName : "";
21459
+ return sheetId === applyChange.sheetId ? applyChange.sheetName.current : "";
21408
21460
  };
21409
21461
  }
21410
21462
  function defaultGetSheetSize(sheetId) {
@@ -27395,9 +27447,13 @@ class GaugeChart extends AbstractChart {
27395
27447
  : undefined,
27396
27448
  };
27397
27449
  }
27398
- updateRanges(applyChange) {
27450
+ updateRanges(applyChange, sheetId, adaptSheetName) {
27399
27451
  const dataRange = adaptChartRange(this.dataRange, applyChange);
27400
- const adaptFormula = (formula) => this.getters.adaptFormulaStringDependencies(this.sheetId, formula, applyChange);
27452
+ const adaptFormula = (formula) => adaptFormulaStringRanges(this.sheetId, formula, {
27453
+ applyChange,
27454
+ sheetId,
27455
+ sheetName: adaptSheetName,
27456
+ });
27401
27457
  const sectionRule = adaptSectionRuleFormulas(this.sectionRule, adaptFormula);
27402
27458
  const definition = this.getDefinitionWithSpecificRanges(dataRange, sectionRule);
27403
27459
  return new GaugeChart(definition, this.sheetId, this.getters);
@@ -33720,6 +33776,9 @@ class Composer extends owl.Component {
33720
33776
  this.contentHelper.removeSelection();
33721
33777
  }
33722
33778
  onMouseup() {
33779
+ if (this.env.model.getters.isReadonly()) {
33780
+ return;
33781
+ }
33723
33782
  const selection = this.contentHelper.getCurrentSelection();
33724
33783
  if (selection.start !== selection.end) {
33725
33784
  this.props.composerStore.hoverToken(undefined);
@@ -38183,9 +38242,9 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
38183
38242
  if (!rule.operator || !rule.formula || rule.formula.length === 0)
38184
38243
  continue;
38185
38244
  operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.operator];
38186
- values.push(rule.formula[0]);
38245
+ values.push(prefixFormula(rule.formula[0]));
38187
38246
  if (rule.formula.length === 2) {
38188
- values.push(rule.formula[1]);
38247
+ values.push(prefixFormula(rule.formula[1]));
38189
38248
  }
38190
38249
  break;
38191
38250
  }
@@ -38343,6 +38402,11 @@ function convertIcons(xlsxIconSet, index) {
38343
38402
  ? ICON_SETS[iconSet].neutral
38344
38403
  : ICON_SETS[iconSet].good;
38345
38404
  }
38405
+ /** Prefix the string by "=" if the string looks like a formula */
38406
+ function prefixFormula(formula) {
38407
+ const tokens = tokenize(formula);
38408
+ return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
38409
+ }
38346
38410
  // ---------------------------------------------------------------------------
38347
38411
  // Warnings
38348
38412
  // ---------------------------------------------------------------------------
@@ -38625,7 +38689,7 @@ function getColPosition(colIndex, sheetData) {
38625
38689
  function getRowPosition(rowIndex, sheetData) {
38626
38690
  let position = 0;
38627
38691
  for (let i = 0; i < rowIndex; i++) {
38628
- const rowAtIndex = sheetData.rows[i];
38692
+ const rowAtIndex = sheetData.rows.find((row) => row.index - 1 === i);
38629
38693
  if (rowAtIndex?.height) {
38630
38694
  position += rowAtIndex.height;
38631
38695
  }
@@ -38780,8 +38844,8 @@ function convertExcelTrendline(trend) {
38780
38844
  }
38781
38845
  function convertAnchor(XLSXanchor) {
38782
38846
  const offset = {
38783
- x: convertEMUToDotValue(XLSXanchor.colOffset),
38784
- y: convertEMUToDotValue(XLSXanchor.rowOffset),
38847
+ x: convertEMUToDotValue(XLSXanchor.colOffset) - FIGURE_BORDER_WIDTH,
38848
+ y: convertEMUToDotValue(XLSXanchor.rowOffset) - FIGURE_BORDER_WIDTH,
38785
38849
  };
38786
38850
  return { col: XLSXanchor.col, row: XLSXanchor.row, offset };
38787
38851
  }
@@ -39164,8 +39228,12 @@ function getSheetDims(sheet) {
39164
39228
  dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
39165
39229
  dims[1] = Math.max(dims[1], row.index);
39166
39230
  }
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);
39231
+ for (const fig of sheet.figures) {
39232
+ dims[0] = Math.max(dims[0], fig.anchors[fig.anchors.length - 1]?.col ?? 0);
39233
+ dims[1] = Math.max(dims[1], fig.anchors[fig.anchors.length - 1]?.row ?? 0);
39234
+ }
39235
+ dims[0] = Math.max(dims[0] + 5, EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
39236
+ dims[1] = Math.max(dims[1] + 5, EXCEL_IMPORT_DEFAULT_NUMBER_OF_ROWS);
39169
39237
  return dims;
39170
39238
  }
39171
39239
  /**
@@ -40868,7 +40936,7 @@ function getRelationFile(file, xmls) {
40868
40936
  return relsFile;
40869
40937
  }
40870
40938
 
40871
- const EXCEL_IMPORT_VERSION = "18.4.1";
40939
+ const EXCEL_IMPORT_VERSION = "18.4.2";
40872
40940
  class XlsxReader {
40873
40941
  warningManager;
40874
40942
  xmls;
@@ -44413,7 +44481,7 @@ const splitToColumns = {
44413
44481
  const reinsertDynamicPivotMenu = {
44414
44482
  id: "reinsert_dynamic_pivot",
44415
44483
  name: _t("Re-insert dynamic pivot"),
44416
- sequence: 1020,
44484
+ sequence: 60,
44417
44485
  icon: "o-spreadsheet-Icon.INSERT_PIVOT",
44418
44486
  children: [REINSERT_DYNAMIC_PIVOT_CHILDREN],
44419
44487
  isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
@@ -44421,7 +44489,7 @@ const reinsertDynamicPivotMenu = {
44421
44489
  const reinsertStaticPivotMenu = {
44422
44490
  id: "reinsert_static_pivot",
44423
44491
  name: _t("Re-insert static pivot"),
44424
- sequence: 1020,
44492
+ sequence: 70,
44425
44493
  icon: "o-spreadsheet-Icon.INSERT_PIVOT",
44426
44494
  children: [REINSERT_STATIC_PIVOT_CHILDREN],
44427
44495
  isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
@@ -58692,7 +58760,8 @@ class CorePlugin extends BasePlugin {
58692
58760
  * the type of change that occurred.
58693
58761
  *
58694
58762
  * @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
58763
+ * @param sheetId an sheetId to adapt either range of that sheet specifically, or ranges pointing to that sheet
58764
+ * @param sheetName couple of old and new sheet names to adapt ranges pointing to that sheet
58696
58765
  */
58697
58766
  adaptRanges(applyChange, sheetId, sheetName) { }
58698
58767
  /**
@@ -59295,9 +59364,7 @@ class CellPlugin extends CorePlugin {
59295
59364
  for (const cell of Object.values(this.cells[sheet] || {})) {
59296
59365
  if (cell.isFormula) {
59297
59366
  for (const range of cell.compiledFormula.dependencies) {
59298
- if (!sheetId ||
59299
- range.sheetId === sheetId ||
59300
- (sheetName && range.invalidSheetName === sheetName)) {
59367
+ if (range.sheetId === sheetId || range.invalidSheetName === sheetName.old) {
59301
59368
  const change = applyChange(range);
59302
59369
  if (change.changeType !== "NONE") {
59303
59370
  this.history.update("cells", sheet, cell.id, "compiledFormula", "dependencies", cell.compiledFormula.dependencies.indexOf(range), change.range);
@@ -59913,9 +59980,9 @@ class ChartPlugin extends CorePlugin {
59913
59980
  charts = {};
59914
59981
  createChart = chartFactory(this.getters);
59915
59982
  validateChartDefinition = (cmd) => validateChartDefinition(this, cmd.definition);
59916
- adaptRanges(applyChange) {
59983
+ adaptRanges(applyChange, sheetId, adaptSheetName) {
59917
59984
  for (const [chartId, chart] of Object.entries(this.charts)) {
59918
- this.history.update("charts", chartId, chart?.updateRanges(applyChange));
59985
+ this.history.update("charts", chartId, chart?.updateRanges(applyChange, sheetId, adaptSheetName));
59919
59986
  }
59920
59987
  }
59921
59988
  // ---------------------------------------------------------------------------
@@ -60178,7 +60245,7 @@ class ConditionalFormatPlugin extends CorePlugin {
60178
60245
  }
60179
60246
  }
60180
60247
  }
60181
- adaptRanges(applyChange, sheetId, sheetName) {
60248
+ adaptRanges(applyChange, sheetId) {
60182
60249
  const sheetIds = sheetId ? [sheetId] : Object.keys(this.cfRules);
60183
60250
  for (const sheetId of sheetIds) {
60184
60251
  this.adaptCFRanges(sheetId, applyChange);
@@ -60560,11 +60627,8 @@ class DataValidationPlugin extends CorePlugin {
60560
60627
  "getValidationRuleForCell",
60561
60628
  ];
60562
60629
  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
- }
60630
+ adaptRanges(applyChange, sheetId) {
60631
+ this.adaptDVRanges(sheetId, applyChange);
60568
60632
  this.adaptDVFormulas(applyChange);
60569
60633
  }
60570
60634
  adaptDVFormulas(applyChange) {
@@ -60854,9 +60918,6 @@ class FigurePlugin extends CorePlugin {
60854
60918
  // Command Handling
60855
60919
  // ---------------------------------------------------------------------------
60856
60920
  adaptRanges(applyChange, sheetId) {
60857
- if (!sheetId) {
60858
- return;
60859
- }
60860
60921
  for (const figure of this.getFigures(sheetId)) {
60861
60922
  const change = applyChange(this.getters.getRangeFromZone(sheetId, {
60862
60923
  left: figure.col,
@@ -61665,11 +61726,8 @@ class MergePlugin extends CorePlugin {
61665
61726
  break;
61666
61727
  }
61667
61728
  }
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
- }
61729
+ adaptRanges(applyChange, sheetId) {
61730
+ this.applyRangeChangeOnSheet(sheetId, applyChange);
61673
61731
  }
61674
61732
  // ---------------------------------------------------------------------------
61675
61733
  // Getters
@@ -63174,12 +63232,9 @@ class TablePlugin extends CorePlugin {
63174
63232
  static getters = ["getCoreTable", "getCoreTables", "getCoreTableMatchingTopLeft"];
63175
63233
  tables = {};
63176
63234
  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
- }
63235
+ adaptRanges(applyChange, sheetId) {
63236
+ for (const table of this.getCoreTables(sheetId)) {
63237
+ this.applyRangeChangeOnTable(sheetId, table, applyChange);
63183
63238
  }
63184
63239
  }
63185
63240
  allowDispatch(cmd) {
@@ -64142,7 +64197,7 @@ class PivotCorePlugin extends CorePlugin {
64142
64197
  }
64143
64198
  }
64144
64199
  }
64145
- adaptRanges(applyChange, sheetId, sheetName) {
64200
+ adaptRanges(applyChange) {
64146
64201
  for (const sheetId in this.compiledMeasureFormulas) {
64147
64202
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
64148
64203
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -68543,7 +68598,7 @@ class PivotUIPlugin extends CoreViewPlugin {
68543
68598
  if (!result) {
68544
68599
  return EMPTY_PIVOT_CELL;
68545
68600
  }
68546
- const { functionName, args } = result;
68601
+ let { functionName, args } = result;
68547
68602
  const formulaId = args[0];
68548
68603
  if (!formulaId) {
68549
68604
  return EMPTY_PIVOT_CELL;
@@ -68578,6 +68633,9 @@ class PivotUIPlugin extends CoreViewPlugin {
68578
68633
  return pivotCells[pivotCol][pivotRow];
68579
68634
  }
68580
68635
  try {
68636
+ const offsetRow = position.row - mainPosition.row;
68637
+ const offsetCol = position.col - mainPosition.col;
68638
+ args = args.map((arg) => (isMatrix(arg) ? arg[offsetCol][offsetRow] : arg));
68581
68639
  if (functionName === "PIVOT.HEADER" && args.at(-2) === "measure") {
68582
68640
  const domain = pivot.parseArgsToPivotDomain(args.slice(1, -2).map((value) => ({ value })));
68583
68641
  return {
@@ -70186,7 +70244,8 @@ function transformAll(toTransform, executed) {
70186
70244
  // If the executed command is not in the registry, we skip it
70187
70245
  // because we know there won't be any transformation impacting the
70188
70246
  // commands to transform.
70189
- if (possibleTransformations.has(executedCommand.type)) {
70247
+ if (possibleTransformations.has(executedCommand.type) ||
70248
+ rangeAdapterRegistry.contains(executedCommand.type)) {
70190
70249
  transformedCommands = transformedCommands.reduce((acc, cmd) => {
70191
70250
  const transformed = transform(cmd, executedCommand);
70192
70251
  if (transformed) {
@@ -76178,7 +76237,8 @@ const inverseCommandRegistry = new Registry()
76178
76237
  .add("HIDE_COLUMNS_ROWS", inverseHideColumnsRows)
76179
76238
  .add("UNHIDE_COLUMNS_ROWS", inverseUnhideColumnsRows)
76180
76239
  .add("CREATE_TABLE_STYLE", inverseCreateTableStyle)
76181
- .add("ADD_PIVOT", inverseAddPivot);
76240
+ .add("ADD_PIVOT", inverseAddPivot)
76241
+ .add("RENAME_SHEET", inverseRenameSheet);
76182
76242
  for (const cmd of coreTypes.values()) {
76183
76243
  if (!inverseCommandRegistry.contains(cmd)) {
76184
76244
  inverseCommandRegistry.add(cmd, identity);
@@ -76276,6 +76336,16 @@ function inverseUnhideColumnsRows(cmd) {
76276
76336
  function inverseCreateTableStyle(cmd) {
76277
76337
  return [{ type: "REMOVE_TABLE_STYLE", tableStyleId: cmd.tableStyleId }];
76278
76338
  }
76339
+ function inverseRenameSheet(cmd) {
76340
+ return [
76341
+ {
76342
+ type: "RENAME_SHEET",
76343
+ sheetId: cmd.sheetId,
76344
+ oldName: cmd.newName,
76345
+ newName: cmd.oldName,
76346
+ },
76347
+ ];
76348
+ }
76279
76349
 
76280
76350
  const numberFormatMenuRegistry = new Registry();
76281
76351
  numberFormatMenuRegistry
@@ -76874,8 +76944,9 @@ topbarMenuRegistry
76874
76944
  sequence: 40,
76875
76945
  separator: true,
76876
76946
  })
76877
- .addChild("data_sources_data", ["data"], (env) => {
76947
+ .addChild("pivot_data_sources", ["data"], (env) => {
76878
76948
  const sequence = 50;
76949
+ const numberOfPivots = env.model.getters.getPivotIds().length;
76879
76950
  return env.model.getters.getPivotIds().map((pivotId, index) => {
76880
76951
  const highlightProvider = {
76881
76952
  get highlights() {
@@ -76885,7 +76956,7 @@ topbarMenuRegistry
76885
76956
  return {
76886
76957
  id: `item_pivot_${env.model.getters.getPivotFormulaId(pivotId)}`,
76887
76958
  name: env.model.getters.getPivotDisplayName(pivotId),
76888
- sequence: sequence + index,
76959
+ sequence: sequence + index / numberOfPivots,
76889
76960
  isReadonlyAllowed: true,
76890
76961
  execute: (env) => env.openSidePanel("PivotSidePanel", { pivotId }),
76891
76962
  isEnabled: (env) => !env.isSmall,
@@ -83005,7 +83076,7 @@ function figureCoordinates(headers, anchor, offset) {
83005
83076
  for (const [headerIndex, header] of headers.slice(anchor).entries()) {
83006
83077
  if (currentPosition <= offset && offset < currentPosition + header.size) {
83007
83078
  return {
83008
- index: headerIndex,
83079
+ index: anchor + headerIndex,
83009
83080
  offset: convertDotValueToEMU(offset - currentPosition + FIGURE_BORDER_WIDTH),
83010
83081
  };
83011
83082
  }
@@ -84001,7 +84072,7 @@ class Model extends EventBus {
84001
84072
  handlers = [];
84002
84073
  uiHandlers = [];
84003
84074
  coreHandlers = [];
84004
- constructor(data = {}, config = {}, stateUpdateMessages = [], uuidGenerator = new UuidGenerator(), verboseImport = false) {
84075
+ constructor(data = {}, config = {}, stateUpdateMessages = [], uuidGenerator = new UuidGenerator(), verboseImport = true) {
84005
84076
  const start = performance.now();
84006
84077
  console.debug("##### Model creation #####");
84007
84078
  super();
@@ -84751,6 +84822,6 @@ exports.tokenColors = tokenColors;
84751
84822
  exports.tokenize = tokenize;
84752
84823
 
84753
84824
 
84754
- __info__.version = "18.4.8";
84755
- __info__.date = "2025-08-26T10:14:08.954Z";
84756
- __info__.hash = "746217a";
84825
+ __info__.version = "18.4.9";
84826
+ __info__.date = "2025-09-05T07:38:32.126Z";
84827
+ __info__.hash = "a261873";