@odoo/o-spreadsheet 18.2.27 → 18.2.29

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.2.27
6
- * @date 2025-08-26T10:07:14.516Z
7
- * @hash fbf9445
5
+ * @version 18.2.29
6
+ * @date 2025-09-11T08:44:31.801Z
7
+ * @hash 665bc43
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -3477,6 +3477,7 @@
3477
3477
  "AUTOFILL_CELL",
3478
3478
  "SET_BORDER",
3479
3479
  "SET_ZONE_BORDERS",
3480
+ "SET_BORDERS_ON_TARGET",
3480
3481
  ]);
3481
3482
  const readonlyAllowedCommands = new Set([
3482
3483
  "START",
@@ -6903,7 +6904,7 @@
6903
6904
  this.getters = getters;
6904
6905
  this.dispatch = dispatch;
6905
6906
  }
6906
- copy(data) {
6907
+ copy(data, mode = "copyPaste") {
6907
6908
  return;
6908
6909
  }
6909
6910
  paste(target, clippedContent, options) { }
@@ -6922,7 +6923,7 @@
6922
6923
  }
6923
6924
 
6924
6925
  class AbstractCellClipboardHandler extends ClipboardHandler {
6925
- copy(data) {
6926
+ copy(data, mode = "copyPaste") {
6926
6927
  return;
6927
6928
  }
6928
6929
  pasteFromCopy(sheetId, target, content, options) {
@@ -7527,8 +7528,11 @@
7527
7528
  // (a) Swap 2 rows. This multiply the determinant by -1.
7528
7529
  // (b) Multiply a row by a scalar. This multiply the determinant by that scalar.
7529
7530
  // (c) Add to a row a multiple of another row. This does not change the determinant.
7531
+ if (M.length < 1 || M[0].length < 1) {
7532
+ throw new Error("invertMatrix: an empty matrix cannot be inverted.");
7533
+ }
7530
7534
  if (M.length !== M[0].length) {
7531
- throw new EvaluationError(_t("Function [[FUNCTION_NAME]] invert matrix error, only square matrices are invertible"));
7535
+ throw new Error("invertMatrix: only square matrices are invertible");
7532
7536
  }
7533
7537
  let determinant = 1;
7534
7538
  const dim = M.length;
@@ -7597,8 +7601,11 @@
7597
7601
  * Note: we use indexing [col][row] instead of the standard mathematical notation [row][col]
7598
7602
  */
7599
7603
  function multiplyMatrices(matrix1, matrix2) {
7604
+ if (matrix1.length < 1 || matrix2.length < 1) {
7605
+ throw new Error("multiplyMatrices: empty matrices cannot be multiplied.");
7606
+ }
7600
7607
  if (matrix1.length !== matrix2[0].length) {
7601
- throw new EvaluationError(_t("Cannot multiply matrices : incompatible matrices size."));
7608
+ throw new Error("multiplyMatrices: incompatible matrices size.");
7602
7609
  }
7603
7610
  const rowsM1 = matrix1[0].length;
7604
7611
  const colsM2 = matrix2.length;
@@ -7624,7 +7631,7 @@
7624
7631
  return arg;
7625
7632
  }
7626
7633
  if (!isSingleElementMatrix(arg)) {
7627
- throw new EvaluationError(_t("The value should be a scalar or a 1x1 matrix"));
7634
+ throw new Error("The value should be a scalar or a 1x1 matrix");
7628
7635
  }
7629
7636
  return arg[0][0];
7630
7637
  }
@@ -7861,6 +7868,16 @@
7861
7868
  }
7862
7869
  return values;
7863
7870
  }
7871
+ function assertNonEmptyMatrix(matrix, argName) {
7872
+ assert(() => matrix.length > 0 && matrix[0].length > 0, _t("[[FUNCTION_NAME]] expects the provided values of %(argName)s to be a non-empty matrix.", {
7873
+ argName,
7874
+ }));
7875
+ }
7876
+ function assertNonEmpty(...data) {
7877
+ if (data.length === 0 || data.some((arg) => arg.length === 0)) {
7878
+ throw new NotAvailableError(_t("[[FUNCTION_NAME]] has no valid input data."));
7879
+ }
7880
+ }
7864
7881
 
7865
7882
  const PREVIOUS_VALUE = "(previous)";
7866
7883
  const NEXT_VALUE = "(next)";
@@ -8623,7 +8640,7 @@
8623
8640
  }
8624
8641
  return "Success" /* CommandResult.Success */;
8625
8642
  }
8626
- copy(data) {
8643
+ copy(data, mode = "copyPaste") {
8627
8644
  const sheetId = data.sheetId;
8628
8645
  const { clippedZones, rowsIndexes, columnsIndexes } = data;
8629
8646
  const clippedCells = [];
@@ -8636,7 +8653,7 @@
8636
8653
  const evaluatedCell = this.getters.getEvaluatedCell(position);
8637
8654
  const pivotId = this.getters.getPivotIdFromPosition(position);
8638
8655
  const spreader = this.getters.getArrayFormulaSpreadingOn(position);
8639
- if (pivotId && spreader) {
8656
+ if (mode !== "shiftCells" && pivotId && spreader) {
8640
8657
  const pivotZone = this.getters.getSpreadZone(spreader);
8641
8658
  if ((!deepEquals(spreader, position) || !isCopyingOneCell) &&
8642
8659
  pivotZone &&
@@ -8654,7 +8671,7 @@
8654
8671
  };
8655
8672
  }
8656
8673
  }
8657
- else {
8674
+ else if (mode !== "shiftCells") {
8658
8675
  if (spreader && !deepEquals(spreader, position)) {
8659
8676
  const isSpreaderCopied = rowsIndexes.includes(spreader.row) && columnsIndexes.includes(spreader.col);
8660
8677
  const content = isSpreaderCopied
@@ -9347,7 +9364,7 @@
9347
9364
  }
9348
9365
 
9349
9366
  class TableClipboardHandler extends AbstractCellClipboardHandler {
9350
- copy(data) {
9367
+ copy(data, mode = "copyPaste") {
9351
9368
  const sheetId = data.sheetId;
9352
9369
  const { rowsIndexes, columnsIndexes, zones } = data;
9353
9370
  const copiedTablesIds = new Set();
@@ -9377,11 +9394,13 @@
9377
9394
  type: coreTable.type,
9378
9395
  };
9379
9396
  }
9380
- tableCellsInRow.push({
9381
- table: copiedTable,
9382
- style: this.getTableStyleToCopy(position),
9383
- isWholeTableCopied: copiedTablesIds.has(table.id),
9384
- });
9397
+ if (mode !== "shiftCells") {
9398
+ tableCellsInRow.push({
9399
+ table: copiedTable,
9400
+ style: this.getTableStyleToCopy(position),
9401
+ isWholeTableCopied: copiedTablesIds.has(table.id),
9402
+ });
9403
+ }
9385
9404
  }
9386
9405
  }
9387
9406
  return {
@@ -11798,6 +11817,7 @@ stores.inject(MyMetaStore, storeInstance);
11798
11817
  compute: function (matrix1, matrix2) {
11799
11818
  const _matrix1 = toNumberMatrix(matrix1, "matrix1");
11800
11819
  const _matrix2 = toNumberMatrix(matrix2, "matrix2");
11820
+ assert(() => _matrix1.length > 0 && _matrix2.length > 0, _t("The first and second arguments of [[FUNCTION_NAME]] must be non-empty matrices."));
11801
11821
  assert(() => _matrix1.length === _matrix2[0].length, _t("In [[FUNCTION_NAME]], the number of columns of the first matrix (%s) must be equal to the \
11802
11822
  number of rows of the second matrix (%s).", _matrix1.length.toString(), _matrix2[0].length.toString()));
11803
11823
  return multiplyMatrices(_matrix1, _matrix2);
@@ -13593,6 +13613,7 @@ stores.inject(MyMetaStore, storeInstance);
13593
13613
  ],
13594
13614
  compute: function (x, dataY, dataX) {
13595
13615
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13616
+ assertNonEmpty(flatDataX, flatDataY);
13596
13617
  return predictLinearValues([flatDataY], [flatDataX], matrixMap(toMatrix(x), (value) => toNumber(value, this.locale)), true);
13597
13618
  },
13598
13619
  isExported: true,
@@ -13609,6 +13630,7 @@ stores.inject(MyMetaStore, storeInstance);
13609
13630
  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.")),
13610
13631
  ],
13611
13632
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13633
+ assertNonEmptyMatrix(knownDataY, "known_data_y");
13612
13634
  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)));
13613
13635
  },
13614
13636
  };
@@ -13623,6 +13645,7 @@ stores.inject(MyMetaStore, storeInstance);
13623
13645
  ],
13624
13646
  compute: function (dataY, dataX) {
13625
13647
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13648
+ assertNonEmpty(flatDataX, flatDataY);
13626
13649
  const [[], [intercept]] = fullLinearRegression([flatDataX], [flatDataY]);
13627
13650
  return intercept;
13628
13651
  },
@@ -13672,6 +13695,7 @@ stores.inject(MyMetaStore, storeInstance);
13672
13695
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13673
13696
  ],
13674
13697
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13698
+ assertNonEmptyMatrix(dataY, "data_y");
13675
13699
  return fullLinearRegression(toNumberMatrix(dataX, "the first argument (data_y)"), toNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13676
13700
  },
13677
13701
  isExported: true,
@@ -13688,6 +13712,7 @@ stores.inject(MyMetaStore, storeInstance);
13688
13712
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13689
13713
  ],
13690
13714
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13715
+ assertNonEmptyMatrix(dataY, "data_y");
13691
13716
  const coeffs = fullLinearRegression(toNumberMatrix(dataX, "the second argument (data_x)"), logM(toNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13692
13717
  for (let i = 0; i < coeffs.length; i++) {
13693
13718
  coeffs[i][0] = Math.exp(coeffs[i][0]);
@@ -13709,9 +13734,7 @@ stores.inject(MyMetaStore, storeInstance);
13709
13734
  const flatX = dataX.flat();
13710
13735
  const flatY = dataY.flat();
13711
13736
  assertSameNumberOfElements(flatX, flatY);
13712
- if (flatX.length === 0) {
13713
- return new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
13714
- }
13737
+ assertNonEmpty(flatX, flatY);
13715
13738
  const n = flatX.length;
13716
13739
  let trueN = 0, trueP = 0, falseP = 0, falseN = 0;
13717
13740
  for (let i = 0; i < n; ++i) {
@@ -13875,12 +13898,7 @@ stores.inject(MyMetaStore, storeInstance);
13875
13898
  // -----------------------------------------------------------------------------
13876
13899
  function pearson(dataY, dataX) {
13877
13900
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13878
- if (flatDataX.length === 0) {
13879
- throw new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
13880
- }
13881
- if (flatDataX.length < 2) {
13882
- throw new EvaluationError(_t("[[FUNCTION_NAME]] needs at least two values for both parameters."));
13883
- }
13901
+ assertNonEmpty(flatDataX, flatDataY);
13884
13902
  const n = flatDataX.length;
13885
13903
  let sumX = 0, sumY = 0, sumXY = 0, sumXX = 0, sumYY = 0;
13886
13904
  for (let i = 0; i < n; i++) {
@@ -13969,6 +13987,7 @@ stores.inject(MyMetaStore, storeInstance);
13969
13987
  ],
13970
13988
  compute: function (dataY, dataX, order, intercept = { value: true }) {
13971
13989
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13990
+ assertNonEmpty(flatDataX, flatDataY);
13972
13991
  return polynomialRegression(flatDataY, flatDataX, toNumber(order, this.locale), toBoolean(intercept));
13973
13992
  },
13974
13993
  isExported: false,
@@ -13988,6 +14007,7 @@ stores.inject(MyMetaStore, storeInstance);
13988
14007
  compute: function (x, dataY, dataX, order, intercept = { value: true }) {
13989
14008
  const _order = toNumber(order, this.locale);
13990
14009
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14010
+ assertNonEmpty(flatDataX, flatDataY);
13991
14011
  const coeffs = polynomialRegression(flatDataY, flatDataX, _order, toBoolean(intercept)).flat();
13992
14012
  return matrixMap(toMatrix(x), (xij) => evaluatePolynomial(coeffs, toNumber(xij, this.locale), _order));
13993
14013
  },
@@ -14104,6 +14124,7 @@ stores.inject(MyMetaStore, storeInstance);
14104
14124
  ],
14105
14125
  compute: function (dataY, dataX) {
14106
14126
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14127
+ assertNonEmpty(flatDataX, flatDataY);
14107
14128
  const [[slope]] = fullLinearRegression([flatDataX], [flatDataY]);
14108
14129
  return slope;
14109
14130
  },
@@ -14152,6 +14173,7 @@ stores.inject(MyMetaStore, storeInstance);
14152
14173
  ],
14153
14174
  compute: function (dataX, dataY) {
14154
14175
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14176
+ assertNonEmpty(flatDataX, flatDataY);
14155
14177
  const n = flatDataX.length;
14156
14178
  const order = flatDataX.map((e, i) => [e, flatDataY[i]]);
14157
14179
  order.sort((a, b) => a[0] - b[0]);
@@ -14262,6 +14284,7 @@ stores.inject(MyMetaStore, storeInstance);
14262
14284
  ],
14263
14285
  compute: function (dataY, dataX) {
14264
14286
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14287
+ assertNonEmpty(flatDataX, flatDataY);
14265
14288
  const data = fullLinearRegression([flatDataX], [flatDataY], true, true);
14266
14289
  return data[1][2];
14267
14290
  },
@@ -14279,6 +14302,7 @@ stores.inject(MyMetaStore, storeInstance);
14279
14302
  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.")),
14280
14303
  ],
14281
14304
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
14305
+ assertNonEmptyMatrix(knownDataY, "known_data_y");
14282
14306
  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));
14283
14307
  },
14284
14308
  };
@@ -23772,7 +23796,7 @@ stores.inject(MyMetaStore, storeInstance);
23772
23796
  ];
23773
23797
  const SUPPORTED_VERTICAL_ALIGNMENTS = ["top", "center", "bottom"];
23774
23798
  const SUPPORTED_FONTS = ["Arial"];
23775
- const SUPPORTED_FILL_PATTERNS = ["solid"];
23799
+ const SUPPORTED_FILL_PATTERNS = ["solid", "none"];
23776
23800
  const SUPPORTED_CF_TYPES = [
23777
23801
  "expression",
23778
23802
  "cellIs",
@@ -23957,7 +23981,7 @@ stores.inject(MyMetaStore, storeInstance);
23957
23981
  };
23958
23982
  /** Mapping between Excel format indexes (see XLSX_FORMAT_MAP) and some supported formats */
23959
23983
  const XLSX_FORMATS_CONVERSION_MAP = {
23960
- 0: "",
23984
+ 0: "General",
23961
23985
  1: "0",
23962
23986
  2: "0.00",
23963
23987
  3: "#,#00",
@@ -24283,11 +24307,11 @@ stores.inject(MyMetaStore, storeInstance);
24283
24307
  * Excel format are defined in openXML §18.8.31
24284
24308
  */
24285
24309
  function convertXlsxFormat(numFmtId, formats, warningManager) {
24286
- if (numFmtId === 0) {
24287
- return undefined;
24288
- }
24289
24310
  // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
24290
24311
  let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || formats.find((f) => f.id === numFmtId)?.format;
24312
+ if (format === "General") {
24313
+ return undefined;
24314
+ }
24291
24315
  if (format) {
24292
24316
  try {
24293
24317
  let convertedFormat = format.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
@@ -24485,9 +24509,9 @@ stores.inject(MyMetaStore, storeInstance);
24485
24509
  if (!rule.operator || !rule.formula || rule.formula.length === 0)
24486
24510
  continue;
24487
24511
  operator = convertCFCellIsOperator(rule.operator);
24488
- values.push(rule.formula[0]);
24512
+ values.push(prefixFormula(rule.formula[0]));
24489
24513
  if (rule.formula.length === 2) {
24490
- values.push(rule.formula[1]);
24514
+ values.push(prefixFormula(rule.formula[1]));
24491
24515
  }
24492
24516
  break;
24493
24517
  }
@@ -24645,6 +24669,11 @@ stores.inject(MyMetaStore, storeInstance);
24645
24669
  ? ICON_SETS[iconSet].neutral
24646
24670
  : ICON_SETS[iconSet].good;
24647
24671
  }
24672
+ /** Prefix the string by "=" if the string looks like a formula */
24673
+ function prefixFormula(formula) {
24674
+ const tokens = tokenize(formula);
24675
+ return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
24676
+ }
24648
24677
  // ---------------------------------------------------------------------------
24649
24678
  // Warnings
24650
24679
  // ---------------------------------------------------------------------------
@@ -27243,10 +27272,11 @@ stores.inject(MyMetaStore, storeInstance);
27243
27272
  });
27244
27273
  }
27245
27274
  extractRows(worksheet) {
27275
+ const spilledCells = new Set();
27246
27276
  return this.mapOnElements({ parent: worksheet, query: "sheetData row" }, (rowElement) => {
27247
27277
  return {
27248
27278
  index: this.extractAttr(rowElement, "r", { required: true })?.asNum(),
27249
- cells: this.extractCells(rowElement),
27279
+ cells: this.extractCells(rowElement, spilledCells),
27250
27280
  height: this.extractAttr(rowElement, "ht")?.asNum(),
27251
27281
  customHeight: this.extractAttr(rowElement, "customHeight")?.asBool(),
27252
27282
  hidden: this.extractAttr(rowElement, "hidden")?.asBool(),
@@ -27256,14 +27286,26 @@ stores.inject(MyMetaStore, storeInstance);
27256
27286
  };
27257
27287
  });
27258
27288
  }
27259
- extractCells(row) {
27289
+ extractCells(row, spilledCells) {
27260
27290
  return this.mapOnElements({ parent: row, query: "c" }, (cellElement) => {
27291
+ const xc = this.extractAttr(cellElement, "r", { required: true })?.asString();
27292
+ const formula = this.extractCellFormula(cellElement);
27293
+ if (formula?.ref && formula.sharedIndex === undefined) {
27294
+ const zone = toZone(formula.ref);
27295
+ for (const { col, row } of positions(zone)) {
27296
+ const followerXc = toXC(col, row);
27297
+ if (followerXc !== xc) {
27298
+ spilledCells.add(followerXc);
27299
+ }
27300
+ }
27301
+ }
27302
+ const isSpilled = spilledCells.has(xc);
27261
27303
  return {
27262
- xc: this.extractAttr(cellElement, "r", { required: true })?.asString(),
27304
+ xc,
27263
27305
  styleIndex: this.extractAttr(cellElement, "s")?.asNum(),
27264
27306
  type: CELL_TYPE_CONVERSION_MAP[this.extractAttr(cellElement, "t", { default: "n" })?.asString()],
27265
- value: this.extractChildTextContent(cellElement, "v"),
27266
- formula: this.extractCellFormula(cellElement),
27307
+ value: isSpilled ? undefined : this.extractChildTextContent(cellElement, "v") ?? undefined,
27308
+ formula: isSpilled ? undefined : formula,
27267
27309
  };
27268
27310
  });
27269
27311
  }
@@ -27271,11 +27313,14 @@ stores.inject(MyMetaStore, storeInstance);
27271
27313
  const formulaElement = this.querySelector(cellElement, "f");
27272
27314
  if (!formulaElement)
27273
27315
  return undefined;
27274
- return {
27275
- content: this.extractTextContent(formulaElement),
27276
- sharedIndex: this.extractAttr(formulaElement, "si")?.asNum(),
27277
- ref: this.extractAttr(formulaElement, "ref")?.asString(),
27278
- };
27316
+ const content = this.extractTextContent(formulaElement);
27317
+ const sharedIndex = this.extractAttr(formulaElement, "si")?.asNum();
27318
+ const ref = this.extractAttr(formulaElement, "ref")?.asString();
27319
+ // This is the case of spilled cells of array formulas where <f> is empty
27320
+ if ((content === undefined || content.trim() === "") && sharedIndex === undefined) {
27321
+ return undefined;
27322
+ }
27323
+ return { content, sharedIndex, ref };
27279
27324
  }
27280
27325
  extractHyperLinks(worksheet) {
27281
27326
  return this.mapOnElements({ parent: worksheet, query: "hyperlink" }, (linkElement) => {
@@ -36169,7 +36214,7 @@ stores.inject(MyMetaStore, storeInstance);
36169
36214
  const reinsertDynamicPivotMenu = {
36170
36215
  id: "reinsert_dynamic_pivot",
36171
36216
  name: _t("Re-insert dynamic pivot"),
36172
- sequence: 1020,
36217
+ sequence: 60,
36173
36218
  icon: "o-spreadsheet-Icon.INSERT_PIVOT",
36174
36219
  children: [REINSERT_DYNAMIC_PIVOT_CHILDREN],
36175
36220
  isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
@@ -36177,7 +36222,7 @@ stores.inject(MyMetaStore, storeInstance);
36177
36222
  const reinsertStaticPivotMenu = {
36178
36223
  id: "reinsert_static_pivot",
36179
36224
  name: _t("Re-insert static pivot"),
36180
- sequence: 1020,
36225
+ sequence: 70,
36181
36226
  icon: "o-spreadsheet-Icon.INSERT_PIVOT",
36182
36227
  children: [REINSERT_STATIC_PIVOT_CHILDREN],
36183
36228
  isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
@@ -37915,8 +37960,9 @@ stores.inject(MyMetaStore, storeInstance);
37915
37960
  sequence: 40,
37916
37961
  separator: true,
37917
37962
  })
37918
- .addChild("data_sources_data", ["data"], (env) => {
37963
+ .addChild("pivot_data_sources", ["data"], (env) => {
37919
37964
  const sequence = 50;
37965
+ const numberOfPivots = env.model.getters.getPivotIds().length;
37920
37966
  return env.model.getters.getPivotIds().map((pivotId, index) => {
37921
37967
  const highlightProvider = {
37922
37968
  get highlights() {
@@ -37926,7 +37972,7 @@ stores.inject(MyMetaStore, storeInstance);
37926
37972
  return {
37927
37973
  id: `item_pivot_${env.model.getters.getPivotFormulaId(pivotId)}`,
37928
37974
  name: env.model.getters.getPivotDisplayName(pivotId),
37929
- sequence: sequence + index,
37975
+ sequence: sequence + index / numberOfPivots,
37930
37976
  isReadonlyAllowed: true,
37931
37977
  execute: (env) => env.openSidePanel("PivotSidePanel", { pivotId }),
37932
37978
  onStartHover: (env) => env.getStore(HighlightStore).register(highlightProvider),
@@ -63898,7 +63944,7 @@ stores.inject(MyMetaStore, storeInstance);
63898
63944
  if (!result) {
63899
63945
  return EMPTY_PIVOT_CELL;
63900
63946
  }
63901
- const { functionName, args } = result;
63947
+ let { functionName, args } = result;
63902
63948
  const formulaId = args[0];
63903
63949
  if (!formulaId) {
63904
63950
  return EMPTY_PIVOT_CELL;
@@ -63928,6 +63974,9 @@ stores.inject(MyMetaStore, storeInstance);
63928
63974
  return pivotCells[pivotCol][pivotRow];
63929
63975
  }
63930
63976
  try {
63977
+ const offsetRow = position.row - mainPosition.row;
63978
+ const offsetCol = position.col - mainPosition.col;
63979
+ args = args.map((arg) => (isMatrix(arg) ? arg[offsetCol][offsetRow] : arg));
63931
63980
  if (functionName === "PIVOT.HEADER" && args.at(-2) === "measure") {
63932
63981
  const domain = pivot.parseArgsToPivotDomain(args.slice(1, -2).map((value) => ({ value })));
63933
63982
  return {
@@ -67776,12 +67825,12 @@ stores.inject(MyMetaStore, storeInstance);
67776
67825
  }
67777
67826
  case "INSERT_CELL": {
67778
67827
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
67779
- const copiedData = this.copy(cut);
67828
+ const copiedData = this.copy(cut, "shiftCells");
67780
67829
  return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
67781
67830
  }
67782
67831
  case "DELETE_CELL": {
67783
67832
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
67784
- const copiedData = this.copy(cut);
67833
+ const copiedData = this.copy(cut, "shiftCells");
67785
67834
  return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
67786
67835
  }
67787
67836
  }
@@ -67871,13 +67920,13 @@ stores.inject(MyMetaStore, storeInstance);
67871
67920
  });
67872
67921
  break;
67873
67922
  }
67874
- const copiedData = this.copy(cut);
67923
+ const copiedData = this.copy(cut, "shiftCells");
67875
67924
  this.paste(paste, copiedData, { isCutOperation: true });
67876
67925
  break;
67877
67926
  }
67878
67927
  case "INSERT_CELL": {
67879
67928
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
67880
- const copiedData = this.copy(cut);
67929
+ const copiedData = this.copy(cut, "shiftCells");
67881
67930
  this.paste(paste, copiedData, { isCutOperation: true });
67882
67931
  break;
67883
67932
  }
@@ -67992,11 +68041,11 @@ stores.inject(MyMetaStore, storeInstance);
67992
68041
  }
67993
68042
  return false;
67994
68043
  }
67995
- copy(zones) {
68044
+ copy(zones, mode = "copyPaste") {
67996
68045
  let copiedData = {};
67997
68046
  const clipboardData = this.getClipboardData(zones);
67998
68047
  for (const { handlerName, handler } of this.selectClipboardHandlers(clipboardData)) {
67999
- const data = handler.copy(clipboardData);
68048
+ const data = handler.copy(clipboardData, mode);
68000
68049
  copiedData[handlerName] = data;
68001
68050
  const minimalKeys = ["sheetId", "cells", "zones", "figureId"];
68002
68051
  for (const key of minimalKeys) {
@@ -68860,7 +68909,7 @@ stores.inject(MyMetaStore, storeInstance);
68860
68909
  ];
68861
68910
  for (const Handler of clipboardHandlersRegistries.cellHandlers.getAll()) {
68862
68911
  const handler = new Handler(this.getters, this.dispatch);
68863
- const data = handler.copy(getClipboardDataPositions(sheetId, target));
68912
+ const data = handler.copy(getClipboardDataPositions(sheetId, target), "shiftCells");
68864
68913
  if (!data) {
68865
68914
  continue;
68866
68915
  }
@@ -77284,9 +77333,9 @@ stores.inject(MyMetaStore, storeInstance);
77284
77333
  exports.tokenize = tokenize;
77285
77334
 
77286
77335
 
77287
- __info__.version = "18.2.27";
77288
- __info__.date = "2025-08-26T10:07:14.516Z";
77289
- __info__.hash = "fbf9445";
77336
+ __info__.version = "18.2.29";
77337
+ __info__.date = "2025-09-11T08:44:31.801Z";
77338
+ __info__.hash = "665bc43";
77290
77339
 
77291
77340
 
77292
77341
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);