@odoo/o-spreadsheet 18.4.7 → 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.7
6
- * @date 2025-08-21T06:42:12.438Z
7
- * @hash d5eb3a6
5
+ * @version 18.4.9
6
+ * @date 2025-09-05T07:38:32.126Z
7
+ * @hash a261873
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, useExternalListener, onWillUpdateProps, onWillStart, onWillPatch, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -2643,6 +2643,7 @@ const invalidateBordersCommands = new Set([
2643
2643
  "AUTOFILL_CELL",
2644
2644
  "SET_BORDER",
2645
2645
  "SET_ZONE_BORDERS",
2646
+ "SET_BORDERS_ON_TARGET",
2646
2647
  ]);
2647
2648
  const readonlyAllowedCommands = new Set([
2648
2649
  "START",
@@ -3989,6 +3990,10 @@ function isDataNonEmpty(data) {
3989
3990
  }
3990
3991
  return true;
3991
3992
  }
3993
+ const noValidInputErrorMessage = _t("[[FUNCTION_NAME]] has no valid input data.");
3994
+ function emptyDataErrorMessage(argName) {
3995
+ return _t("[[FUNCTION_NAME]] expects the provided values of %(argName)s to be a non-empty matrix.", { argName });
3996
+ }
3992
3997
 
3993
3998
  function tokenizeFormat(str) {
3994
3999
  const chars = new TokenizingChars(str);
@@ -6590,40 +6595,44 @@ function orderRange(range) {
6590
6595
  };
6591
6596
  }
6592
6597
  function getRangeAdapter(cmd) {
6593
- switch (cmd.type) {
6594
- case "REMOVE_COLUMNS_ROWS":
6595
- return {
6596
- applyChange: getApplyRangeChangeRemoveColRow(cmd),
6597
- sheetId: cmd.sheetId,
6598
- sheetName: cmd.sheetName,
6599
- };
6600
- case "ADD_COLUMNS_ROWS":
6601
- return {
6602
- applyChange: getApplyRangeChangeAddColRow(cmd),
6603
- sheetId: cmd.sheetId,
6604
- sheetName: cmd.sheetName,
6605
- };
6606
- case "DELETE_SHEET":
6607
- return {
6608
- applyChange: getApplyRangeChangeDeleteSheet(cmd),
6609
- sheetId: cmd.sheetId,
6610
- sheetName: cmd.sheetName,
6611
- };
6612
- case "RENAME_SHEET":
6613
- return {
6614
- applyChange: getApplyRangeChangeRenameSheet(cmd),
6615
- sheetId: cmd.sheetId,
6616
- sheetName: cmd.oldName,
6617
- };
6618
- case "MOVE_RANGES":
6619
- return {
6620
- applyChange: getApplyRangeChangeMoveRange(cmd),
6621
- sheetId: cmd.sheetId,
6622
- sheetName: cmd.sheetName,
6623
- };
6598
+ return rangeAdapterRegistry.get(cmd.type)?.(cmd);
6599
+ }
6600
+ class RangeAdapterRegistry extends Registry {
6601
+ add(cmdType, fn) {
6602
+ super.add(cmdType, fn);
6603
+ return this;
6604
+ }
6605
+ get(cmdType) {
6606
+ return this.content[cmdType];
6624
6607
  }
6625
- return undefined;
6626
6608
  }
6609
+ const rangeAdapterRegistry = new RangeAdapterRegistry();
6610
+ rangeAdapterRegistry
6611
+ .add("REMOVE_COLUMNS_ROWS", (cmd) => ({
6612
+ applyChange: getApplyRangeChangeRemoveColRow(cmd),
6613
+ sheetId: cmd.sheetId,
6614
+ sheetName: { old: cmd.sheetName, current: cmd.sheetName },
6615
+ }))
6616
+ .add("ADD_COLUMNS_ROWS", (cmd) => ({
6617
+ applyChange: getApplyRangeChangeAddColRow(cmd),
6618
+ sheetId: cmd.sheetId,
6619
+ sheetName: { old: cmd.sheetName, current: cmd.sheetName },
6620
+ }))
6621
+ .add("DELETE_SHEET", (cmd) => ({
6622
+ applyChange: getApplyRangeChangeDeleteSheet(cmd),
6623
+ sheetId: cmd.sheetId,
6624
+ sheetName: { old: cmd.sheetName, current: cmd.sheetName },
6625
+ }))
6626
+ .add("RENAME_SHEET", (cmd) => ({
6627
+ applyChange: getApplyRangeChangeRenameSheet(cmd),
6628
+ sheetId: cmd.sheetId,
6629
+ sheetName: { old: cmd.oldName, current: cmd.newName },
6630
+ }))
6631
+ .add("MOVE_RANGES", (cmd) => ({
6632
+ applyChange: getApplyRangeChangeMoveRange(cmd),
6633
+ sheetId: cmd.sheetId,
6634
+ sheetName: { old: cmd.sheetName, current: cmd.sheetName },
6635
+ }));
6627
6636
  function getApplyRangeChangeRemoveColRow(cmd) {
6628
6637
  const start = cmd.dimension === "COL" ? "left" : "top";
6629
6638
  const end = cmd.dimension === "COL" ? "right" : "bottom";
@@ -7246,14 +7255,11 @@ function getPasteZones(target, content) {
7246
7255
  const width = content[0].length, height = content.length;
7247
7256
  return target.map((t) => splitZoneForPaste(t, width, height)).flat();
7248
7257
  }
7249
- function parseOSClipboardContent(content, clipboardId) {
7258
+ function parseOSClipboardContent(content) {
7250
7259
  let spreadsheetContent = undefined;
7251
7260
  if (content[ClipboardMIMEType.Html]) {
7252
7261
  const htmlDocument = new DOMParser().parseFromString(content[ClipboardMIMEType.Html], "text/html");
7253
- const oSheetClipboardData = htmlDocument
7254
- .querySelector("div")
7255
- ?.getAttribute("data-osheet-clipboard");
7256
- spreadsheetContent = oSheetClipboardData && JSON.parse(oSheetClipboardData);
7262
+ spreadsheetContent = getOSheetDataFromHTML(htmlDocument);
7257
7263
  }
7258
7264
  const textContent = content[ClipboardMIMEType.PlainText] || "";
7259
7265
  let imageBlob = undefined;
@@ -7272,6 +7278,17 @@ function parseOSClipboardContent(content, clipboardId) {
7272
7278
  };
7273
7279
  return osClipboardContent;
7274
7280
  }
7281
+ function getOSheetDataFromHTML(htmlDocument) {
7282
+ const attributes = [...htmlDocument.documentElement.attributes];
7283
+ // Check if it's a Microsoft Office clipboard data (it will have some namespaces defined in the root element)
7284
+ if (attributes.some((attr) => attr.value.includes("microsoft"))) {
7285
+ return undefined;
7286
+ }
7287
+ const oSheetClipboardData = htmlDocument
7288
+ .querySelector("div")
7289
+ ?.getAttribute("data-osheet-clipboard");
7290
+ return oSheetClipboardData && JSON.parse(oSheetClipboardData);
7291
+ }
7275
7292
  /**
7276
7293
  * Applies each clipboard handler to paste its corresponding data into the target.
7277
7294
  */
@@ -7992,8 +8009,11 @@ function invertMatrix(M) {
7992
8009
  // (a) Swap 2 rows. This multiply the determinant by -1.
7993
8010
  // (b) Multiply a row by a scalar. This multiply the determinant by that scalar.
7994
8011
  // (c) Add to a row a multiple of another row. This does not change the determinant.
8012
+ if (M.length < 1 || M[0].length < 1) {
8013
+ throw new Error("invertMatrix: an empty matrix cannot be inverted.");
8014
+ }
7995
8015
  if (M.length !== M[0].length) {
7996
- throw new EvaluationError(_t("Function [[FUNCTION_NAME]] invert matrix error, only square matrices are invertible"));
8016
+ throw new Error("invertMatrix: only square matrices are invertible");
7997
8017
  }
7998
8018
  let determinant = 1;
7999
8019
  const dim = M.length;
@@ -8062,8 +8082,11 @@ function swapMatrixRows(matrix, row1, row2) {
8062
8082
  * Note: we use indexing [col][row] instead of the standard mathematical notation [row][col]
8063
8083
  */
8064
8084
  function multiplyMatrices(matrix1, matrix2) {
8085
+ if (matrix1.length < 1 || matrix2.length < 1) {
8086
+ throw new Error("multiplyMatrices: empty matrices cannot be multiplied.");
8087
+ }
8065
8088
  if (matrix1.length !== matrix2[0].length) {
8066
- throw new EvaluationError(_t("Cannot multiply matrices : incompatible matrices size."));
8089
+ throw new Error("multiplyMatrices: incompatible matrices size.");
8067
8090
  }
8068
8091
  const rowsM1 = matrix1[0].length;
8069
8092
  const colsM2 = matrix2.length;
@@ -8089,7 +8112,7 @@ function toScalar(arg) {
8089
8112
  return arg;
8090
8113
  }
8091
8114
  if (!isSingleElementMatrix(arg)) {
8092
- throw new EvaluationError(_t("The value should be a scalar or a 1x1 matrix"));
8115
+ throw new Error("The value should be a scalar or a 1x1 matrix");
8093
8116
  }
8094
8117
  return arg[0][0];
8095
8118
  }
@@ -11228,6 +11251,9 @@ const MMULT = {
11228
11251
  compute: function (matrix1, matrix2) {
11229
11252
  const _matrix1 = toNumberMatrix(matrix1, "matrix1");
11230
11253
  const _matrix2 = toNumberMatrix(matrix2, "matrix2");
11254
+ if (_matrix1.length === 0 || _matrix2.length === 0) {
11255
+ return new EvaluationError(_t("The first and second arguments of [[FUNCTION_NAME]] must be non-empty matrices."));
11256
+ }
11231
11257
  if (_matrix1.length !== _matrix2[0].length) {
11232
11258
  return new EvaluationError(_t("In [[FUNCTION_NAME]], the number of columns of the first matrix (%s) must be equal to the \
11233
11259
  number of rows of the second matrix (%s).", _matrix1.length.toString(), _matrix2[0].length.toString()));
@@ -12840,7 +12866,7 @@ function centile(data, percent, isInclusive, locale) {
12840
12866
  count++;
12841
12867
  }
12842
12868
  });
12843
- assert(count !== 0, _t("[[FUNCTION_NAME]] has no valid input data."));
12869
+ assert(count !== 0, noValidInputErrorMessage);
12844
12870
  if (!isInclusive) {
12845
12871
  // 2nd argument must be between 1/(n+1) and n/(n+1) with n the number of data
12846
12872
  assert(1 / (count + 1) <= _percent && _percent <= count / (count + 1), _t("Function [[FUNCTION_NAME]] parameter 2 value is out of range."));
@@ -13115,6 +13141,9 @@ const FORECAST = {
13115
13141
  ],
13116
13142
  compute: function (x, dataY, dataX) {
13117
13143
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13144
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13145
+ return new NotAvailableError(noValidInputErrorMessage);
13146
+ }
13118
13147
  return predictLinearValues([flatDataY], [flatDataX], matrixMap(toMatrix(x), (value) => toNumber(value, this.locale)), true);
13119
13148
  },
13120
13149
  isExported: true,
@@ -13131,6 +13160,9 @@ const GROWTH = {
13131
13160
  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.")),
13132
13161
  ],
13133
13162
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13163
+ if (knownDataY.length === 0 || knownDataY[0].length === 0) {
13164
+ return new EvaluationError(emptyDataErrorMessage("known_data_y"));
13165
+ }
13134
13166
  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)));
13135
13167
  },
13136
13168
  };
@@ -13145,6 +13177,9 @@ const INTERCEPT = {
13145
13177
  ],
13146
13178
  compute: function (dataY, dataX) {
13147
13179
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13180
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13181
+ return new NotAvailableError(noValidInputErrorMessage);
13182
+ }
13148
13183
  const [[], [intercept]] = fullLinearRegression([flatDataX], [flatDataY]);
13149
13184
  return intercept;
13150
13185
  },
@@ -13177,7 +13212,7 @@ const LARGE = {
13177
13212
  });
13178
13213
  const result = largests.shift();
13179
13214
  if (result === undefined) {
13180
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
13215
+ return new EvaluationError(noValidInputErrorMessage);
13181
13216
  }
13182
13217
  if (count < _n) {
13183
13218
  return new EvaluationError(_t("Function [[FUNCTION_NAME]] parameter 2 value (%s) is out of range.", _n));
@@ -13198,6 +13233,9 @@ const LINEST = {
13198
13233
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13199
13234
  ],
13200
13235
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13236
+ if (dataY.length === 0 || dataY[0].length === 0) {
13237
+ return new EvaluationError(emptyDataErrorMessage("data_y"));
13238
+ }
13201
13239
  return fullLinearRegression(toNumberMatrix(dataX, "the first argument (data_y)"), toNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13202
13240
  },
13203
13241
  isExported: true,
@@ -13214,6 +13252,9 @@ const LOGEST = {
13214
13252
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13215
13253
  ],
13216
13254
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13255
+ if (dataY.length === 0 || dataY[0].length === 0) {
13256
+ return new EvaluationError(emptyDataErrorMessage("data_y"));
13257
+ }
13217
13258
  const coeffs = fullLinearRegression(toNumberMatrix(dataX, "the second argument (data_x)"), logM(toNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13218
13259
  for (let i = 0; i < coeffs.length; i++) {
13219
13260
  coeffs[i][0] = Math.exp(coeffs[i][0]);
@@ -13235,8 +13276,8 @@ const MATTHEWS = {
13235
13276
  const flatX = dataX.flat();
13236
13277
  const flatY = dataY.flat();
13237
13278
  assertSameNumberOfElements(flatX, flatY);
13238
- if (flatX.length === 0) {
13239
- return new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
13279
+ if (flatX.length === 0 || flatY.length === 0) {
13280
+ return new NotAvailableError(noValidInputErrorMessage);
13240
13281
  }
13241
13282
  const n = flatX.length;
13242
13283
  let trueN = 0, trueP = 0, falseP = 0, falseN = 0;
@@ -13401,11 +13442,8 @@ const MINIFS = {
13401
13442
  // -----------------------------------------------------------------------------
13402
13443
  function pearson(dataY, dataX) {
13403
13444
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13404
- if (flatDataX.length === 0) {
13405
- throw new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
13406
- }
13407
- if (flatDataX.length < 2) {
13408
- throw new EvaluationError(_t("[[FUNCTION_NAME]] needs at least two values for both parameters."));
13445
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13446
+ return new NotAvailableError(noValidInputErrorMessage);
13409
13447
  }
13410
13448
  const n = flatDataX.length;
13411
13449
  let sumX = 0, sumY = 0, sumXY = 0, sumXX = 0, sumYY = 0;
@@ -13495,6 +13533,9 @@ const POLYFIT_COEFFS = {
13495
13533
  ],
13496
13534
  compute: function (dataY, dataX, order, intercept = { value: true }) {
13497
13535
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13536
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13537
+ return new NotAvailableError(noValidInputErrorMessage);
13538
+ }
13498
13539
  return polynomialRegression(flatDataY, flatDataX, toNumber(order, this.locale), toBoolean(intercept));
13499
13540
  },
13500
13541
  isExported: false,
@@ -13514,6 +13555,9 @@ const POLYFIT_FORECAST = {
13514
13555
  compute: function (x, dataY, dataX, order, intercept = { value: true }) {
13515
13556
  const _order = toNumber(order, this.locale);
13516
13557
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13558
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13559
+ return new NotAvailableError(noValidInputErrorMessage);
13560
+ }
13517
13561
  const coeffs = polynomialRegression(flatDataY, flatDataX, _order, toBoolean(intercept)).flat();
13518
13562
  return matrixMap(toMatrix(x), (xij) => evaluatePolynomial(coeffs, toNumber(xij, this.locale), _order));
13519
13563
  },
@@ -13615,7 +13659,11 @@ const RSQ = {
13615
13659
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13616
13660
  ],
13617
13661
  compute: function (dataY, dataX) {
13618
- return Math.pow(pearson(dataX, dataY), 2.0);
13662
+ const value = pearson(dataY, dataX);
13663
+ if (value instanceof Error) {
13664
+ throw value;
13665
+ }
13666
+ return Math.pow(value, 2.0);
13619
13667
  },
13620
13668
  isExported: true,
13621
13669
  };
@@ -13630,6 +13678,9 @@ const SLOPE = {
13630
13678
  ],
13631
13679
  compute: function (dataY, dataX) {
13632
13680
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13681
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13682
+ return new NotAvailableError(noValidInputErrorMessage);
13683
+ }
13633
13684
  const [[slope]] = fullLinearRegression([flatDataX], [flatDataY]);
13634
13685
  return slope;
13635
13686
  },
@@ -13662,7 +13713,7 @@ const SMALL = {
13662
13713
  });
13663
13714
  const result = largests.pop();
13664
13715
  if (result === undefined) {
13665
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
13716
+ return new EvaluationError(noValidInputErrorMessage);
13666
13717
  }
13667
13718
  if (count < _n) {
13668
13719
  return new EvaluationError(_t("Function [[FUNCTION_NAME]] parameter 2 value (%s) is out of range.", _n));
@@ -13682,6 +13733,9 @@ const SPEARMAN = {
13682
13733
  ],
13683
13734
  compute: function (dataX, dataY) {
13684
13735
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13736
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13737
+ return new NotAvailableError(noValidInputErrorMessage);
13738
+ }
13685
13739
  const n = flatDataX.length;
13686
13740
  const order = flatDataX.map((e, i) => [e, flatDataY[i]]);
13687
13741
  order.sort((a, b) => a[0] - b[0]);
@@ -13792,6 +13846,9 @@ const STEYX = {
13792
13846
  ],
13793
13847
  compute: function (dataY, dataX) {
13794
13848
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13849
+ if (flatDataX.length === 0 || flatDataY.length === 0) {
13850
+ return new NotAvailableError(noValidInputErrorMessage);
13851
+ }
13795
13852
  const data = fullLinearRegression([flatDataX], [flatDataY], true, true);
13796
13853
  return data[1][2];
13797
13854
  },
@@ -13809,6 +13866,9 @@ const TREND = {
13809
13866
  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.")),
13810
13867
  ],
13811
13868
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13869
+ if (knownDataY.length === 0 || knownDataY[0].length === 0) {
13870
+ return new EvaluationError(emptyDataErrorMessage("known_data_y"));
13871
+ }
13812
13872
  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));
13813
13873
  },
13814
13874
  };
@@ -18724,7 +18784,7 @@ const AND = {
18724
18784
  compute: function (...logicalExpressions) {
18725
18785
  const { result, foundBoolean } = boolAnd(logicalExpressions);
18726
18786
  if (!foundBoolean) {
18727
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
18787
+ return new EvaluationError(noValidInputErrorMessage);
18728
18788
  }
18729
18789
  return result;
18730
18790
  },
@@ -18850,7 +18910,7 @@ const OR = {
18850
18910
  compute: function (...logicalExpressions) {
18851
18911
  const { result, foundBoolean } = boolOr(logicalExpressions);
18852
18912
  if (!foundBoolean) {
18853
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
18913
+ return new EvaluationError(noValidInputErrorMessage);
18854
18914
  }
18855
18915
  return result;
18856
18916
  },
@@ -18913,7 +18973,7 @@ const XOR = {
18913
18973
  return true; // no stop condition
18914
18974
  });
18915
18975
  if (!foundBoolean) {
18916
- return new EvaluationError(_t("[[FUNCTION_NAME]] has no valid input data."));
18976
+ return new EvaluationError(noValidInputErrorMessage);
18917
18977
  }
18918
18978
  return acc;
18919
18979
  },
@@ -21377,7 +21437,7 @@ function adaptFormulaStringRanges(defaultSheetId, formula, applyChange) {
21377
21437
  function adaptStringRange(defaultSheetId, sheetXC, applyChange) {
21378
21438
  const sheetName = splitReference(sheetXC).sheetName;
21379
21439
  if (sheetName
21380
- ? !isSheetNameEqual(sheetName, applyChange.sheetName)
21440
+ ? !isSheetNameEqual(sheetName, applyChange.sheetName.old)
21381
21441
  : defaultSheetId !== applyChange.sheetId) {
21382
21442
  return sheetXC;
21383
21443
  }
@@ -21394,7 +21454,7 @@ function adaptStringRange(defaultSheetId, sheetXC, applyChange) {
21394
21454
  }
21395
21455
  function getSheetNameGetter(applyChange) {
21396
21456
  return (sheetId) => {
21397
- return sheetId === applyChange.sheetId ? applyChange.sheetName : "";
21457
+ return sheetId === applyChange.sheetId ? applyChange.sheetName.current : "";
21398
21458
  };
21399
21459
  }
21400
21460
  function defaultGetSheetSize(sheetId) {
@@ -27012,10 +27072,6 @@ class ComboChart extends AbstractChart {
27012
27072
  };
27013
27073
  }
27014
27074
  getDefinitionForExcel() {
27015
- // Excel does not support aggregating labels
27016
- if (this.aggregated) {
27017
- return undefined;
27018
- }
27019
27075
  const dataSets = this.dataSets
27020
27076
  .map((ds) => toExcelDataset(this.getters, ds))
27021
27077
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -27389,9 +27445,13 @@ class GaugeChart extends AbstractChart {
27389
27445
  : undefined,
27390
27446
  };
27391
27447
  }
27392
- updateRanges(applyChange) {
27448
+ updateRanges(applyChange, sheetId, adaptSheetName) {
27393
27449
  const dataRange = adaptChartRange(this.dataRange, applyChange);
27394
- const adaptFormula = (formula) => this.getters.adaptFormulaStringDependencies(this.sheetId, formula, applyChange);
27450
+ const adaptFormula = (formula) => adaptFormulaStringRanges(this.sheetId, formula, {
27451
+ applyChange,
27452
+ sheetId,
27453
+ sheetName: adaptSheetName,
27454
+ });
27395
27455
  const sectionRule = adaptSectionRuleFormulas(this.sectionRule, adaptFormula);
27396
27456
  const definition = this.getDefinitionWithSpecificRanges(dataRange, sectionRule);
27397
27457
  return new GaugeChart(definition, this.sheetId, this.getters);
@@ -28330,10 +28390,6 @@ class ScatterChart extends AbstractChart {
28330
28390
  return new ScatterChart(definition, this.sheetId, this.getters);
28331
28391
  }
28332
28392
  getDefinitionForExcel() {
28333
- // Excel does not support aggregating labels
28334
- if (this.aggregated) {
28335
- return undefined;
28336
- }
28337
28393
  const dataSets = this.dataSets
28338
28394
  .map((ds) => toExcelDataset(this.getters, ds))
28339
28395
  .filter((ds) => ds.range !== "");
@@ -33718,6 +33774,9 @@ class Composer extends Component {
33718
33774
  this.contentHelper.removeSelection();
33719
33775
  }
33720
33776
  onMouseup() {
33777
+ if (this.env.model.getters.isReadonly()) {
33778
+ return;
33779
+ }
33721
33780
  const selection = this.contentHelper.getCurrentSelection();
33722
33781
  if (selection.start !== selection.end) {
33723
33782
  this.props.composerStore.hoverToken(undefined);
@@ -38181,9 +38240,9 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
38181
38240
  if (!rule.operator || !rule.formula || rule.formula.length === 0)
38182
38241
  continue;
38183
38242
  operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.operator];
38184
- values.push(rule.formula[0]);
38243
+ values.push(prefixFormula(rule.formula[0]));
38185
38244
  if (rule.formula.length === 2) {
38186
- values.push(rule.formula[1]);
38245
+ values.push(prefixFormula(rule.formula[1]));
38187
38246
  }
38188
38247
  break;
38189
38248
  }
@@ -38341,6 +38400,11 @@ function convertIcons(xlsxIconSet, index) {
38341
38400
  ? ICON_SETS[iconSet].neutral
38342
38401
  : ICON_SETS[iconSet].good;
38343
38402
  }
38403
+ /** Prefix the string by "=" if the string looks like a formula */
38404
+ function prefixFormula(formula) {
38405
+ const tokens = tokenize(formula);
38406
+ return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
38407
+ }
38344
38408
  // ---------------------------------------------------------------------------
38345
38409
  // Warnings
38346
38410
  // ---------------------------------------------------------------------------
@@ -38623,7 +38687,7 @@ function getColPosition(colIndex, sheetData) {
38623
38687
  function getRowPosition(rowIndex, sheetData) {
38624
38688
  let position = 0;
38625
38689
  for (let i = 0; i < rowIndex; i++) {
38626
- const rowAtIndex = sheetData.rows[i];
38690
+ const rowAtIndex = sheetData.rows.find((row) => row.index - 1 === i);
38627
38691
  if (rowAtIndex?.height) {
38628
38692
  position += rowAtIndex.height;
38629
38693
  }
@@ -38778,8 +38842,8 @@ function convertExcelTrendline(trend) {
38778
38842
  }
38779
38843
  function convertAnchor(XLSXanchor) {
38780
38844
  const offset = {
38781
- x: convertEMUToDotValue(XLSXanchor.colOffset),
38782
- y: convertEMUToDotValue(XLSXanchor.rowOffset),
38845
+ x: convertEMUToDotValue(XLSXanchor.colOffset) - FIGURE_BORDER_WIDTH,
38846
+ y: convertEMUToDotValue(XLSXanchor.rowOffset) - FIGURE_BORDER_WIDTH,
38783
38847
  };
38784
38848
  return { col: XLSXanchor.col, row: XLSXanchor.row, offset };
38785
38849
  }
@@ -39162,8 +39226,12 @@ function getSheetDims(sheet) {
39162
39226
  dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
39163
39227
  dims[1] = Math.max(dims[1], row.index);
39164
39228
  }
39165
- dims[0] = Math.max(dims[0], EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
39166
- dims[1] = Math.max(dims[1], EXCEL_IMPORT_DEFAULT_NUMBER_OF_ROWS);
39229
+ for (const fig of sheet.figures) {
39230
+ dims[0] = Math.max(dims[0], fig.anchors[fig.anchors.length - 1]?.col ?? 0);
39231
+ dims[1] = Math.max(dims[1], fig.anchors[fig.anchors.length - 1]?.row ?? 0);
39232
+ }
39233
+ dims[0] = Math.max(dims[0] + 5, EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
39234
+ dims[1] = Math.max(dims[1] + 5, EXCEL_IMPORT_DEFAULT_NUMBER_OF_ROWS);
39167
39235
  return dims;
39168
39236
  }
39169
39237
  /**
@@ -40866,7 +40934,7 @@ function getRelationFile(file, xmls) {
40866
40934
  return relsFile;
40867
40935
  }
40868
40936
 
40869
- const EXCEL_IMPORT_VERSION = "18.4.1";
40937
+ const EXCEL_IMPORT_VERSION = "18.4.2";
40870
40938
  class XlsxReader {
40871
40939
  warningManager;
40872
40940
  xmls;
@@ -44411,7 +44479,7 @@ const splitToColumns = {
44411
44479
  const reinsertDynamicPivotMenu = {
44412
44480
  id: "reinsert_dynamic_pivot",
44413
44481
  name: _t("Re-insert dynamic pivot"),
44414
- sequence: 1020,
44482
+ sequence: 60,
44415
44483
  icon: "o-spreadsheet-Icon.INSERT_PIVOT",
44416
44484
  children: [REINSERT_DYNAMIC_PIVOT_CHILDREN],
44417
44485
  isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
@@ -44419,7 +44487,7 @@ const reinsertDynamicPivotMenu = {
44419
44487
  const reinsertStaticPivotMenu = {
44420
44488
  id: "reinsert_static_pivot",
44421
44489
  name: _t("Re-insert static pivot"),
44422
- sequence: 1020,
44490
+ sequence: 70,
44423
44491
  icon: "o-spreadsheet-Icon.INSERT_PIVOT",
44424
44492
  children: [REINSERT_STATIC_PIVOT_CHILDREN],
44425
44493
  isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
@@ -58690,7 +58758,8 @@ class CorePlugin extends BasePlugin {
58690
58758
  * the type of change that occurred.
58691
58759
  *
58692
58760
  * @param applyChange a function that, when called, will adapt the range according to the change on the grid
58693
- * @param sheetId an optional sheetId to adapt either range of that sheet specifically, or ranges pointing to that sheet
58761
+ * @param sheetId an sheetId to adapt either range of that sheet specifically, or ranges pointing to that sheet
58762
+ * @param sheetName couple of old and new sheet names to adapt ranges pointing to that sheet
58694
58763
  */
58695
58764
  adaptRanges(applyChange, sheetId, sheetName) { }
58696
58765
  /**
@@ -59293,9 +59362,7 @@ class CellPlugin extends CorePlugin {
59293
59362
  for (const cell of Object.values(this.cells[sheet] || {})) {
59294
59363
  if (cell.isFormula) {
59295
59364
  for (const range of cell.compiledFormula.dependencies) {
59296
- if (!sheetId ||
59297
- range.sheetId === sheetId ||
59298
- (sheetName && range.invalidSheetName === sheetName)) {
59365
+ if (range.sheetId === sheetId || range.invalidSheetName === sheetName.old) {
59299
59366
  const change = applyChange(range);
59300
59367
  if (change.changeType !== "NONE") {
59301
59368
  this.history.update("cells", sheet, cell.id, "compiledFormula", "dependencies", cell.compiledFormula.dependencies.indexOf(range), change.range);
@@ -59911,9 +59978,9 @@ class ChartPlugin extends CorePlugin {
59911
59978
  charts = {};
59912
59979
  createChart = chartFactory(this.getters);
59913
59980
  validateChartDefinition = (cmd) => validateChartDefinition(this, cmd.definition);
59914
- adaptRanges(applyChange) {
59981
+ adaptRanges(applyChange, sheetId, adaptSheetName) {
59915
59982
  for (const [chartId, chart] of Object.entries(this.charts)) {
59916
- this.history.update("charts", chartId, chart?.updateRanges(applyChange));
59983
+ this.history.update("charts", chartId, chart?.updateRanges(applyChange, sheetId, adaptSheetName));
59917
59984
  }
59918
59985
  }
59919
59986
  // ---------------------------------------------------------------------------
@@ -60176,7 +60243,7 @@ class ConditionalFormatPlugin extends CorePlugin {
60176
60243
  }
60177
60244
  }
60178
60245
  }
60179
- adaptRanges(applyChange, sheetId, sheetName) {
60246
+ adaptRanges(applyChange, sheetId) {
60180
60247
  const sheetIds = sheetId ? [sheetId] : Object.keys(this.cfRules);
60181
60248
  for (const sheetId of sheetIds) {
60182
60249
  this.adaptCFRanges(sheetId, applyChange);
@@ -60558,11 +60625,8 @@ class DataValidationPlugin extends CorePlugin {
60558
60625
  "getValidationRuleForCell",
60559
60626
  ];
60560
60627
  rules = {};
60561
- adaptRanges(applyChange, sheetId, sheetName) {
60562
- const sheetIds = sheetId ? [sheetId] : Object.keys(this.rules);
60563
- for (const sheetId of sheetIds) {
60564
- this.adaptDVRanges(sheetId, applyChange);
60565
- }
60628
+ adaptRanges(applyChange, sheetId) {
60629
+ this.adaptDVRanges(sheetId, applyChange);
60566
60630
  this.adaptDVFormulas(applyChange);
60567
60631
  }
60568
60632
  adaptDVFormulas(applyChange) {
@@ -60852,9 +60916,6 @@ class FigurePlugin extends CorePlugin {
60852
60916
  // Command Handling
60853
60917
  // ---------------------------------------------------------------------------
60854
60918
  adaptRanges(applyChange, sheetId) {
60855
- if (!sheetId) {
60856
- return;
60857
- }
60858
60919
  for (const figure of this.getFigures(sheetId)) {
60859
60920
  const change = applyChange(this.getters.getRangeFromZone(sheetId, {
60860
60921
  left: figure.col,
@@ -61663,11 +61724,8 @@ class MergePlugin extends CorePlugin {
61663
61724
  break;
61664
61725
  }
61665
61726
  }
61666
- adaptRanges(applyChange, sheetId, sheetName) {
61667
- const sheetIds = sheetId ? [sheetId] : Object.keys(this.merges);
61668
- for (const sheetId of sheetIds) {
61669
- this.applyRangeChangeOnSheet(sheetId, applyChange);
61670
- }
61727
+ adaptRanges(applyChange, sheetId) {
61728
+ this.applyRangeChangeOnSheet(sheetId, applyChange);
61671
61729
  }
61672
61730
  // ---------------------------------------------------------------------------
61673
61731
  // Getters
@@ -63172,12 +63230,9 @@ class TablePlugin extends CorePlugin {
63172
63230
  static getters = ["getCoreTable", "getCoreTables", "getCoreTableMatchingTopLeft"];
63173
63231
  tables = {};
63174
63232
  nextTableId = 1;
63175
- adaptRanges(applyChange, sheetId, sheetName) {
63176
- const sheetIds = sheetId ? [sheetId] : this.getters.getSheetIds();
63177
- for (const sheetId of sheetIds) {
63178
- for (const table of this.getCoreTables(sheetId)) {
63179
- this.applyRangeChangeOnTable(sheetId, table, applyChange);
63180
- }
63233
+ adaptRanges(applyChange, sheetId) {
63234
+ for (const table of this.getCoreTables(sheetId)) {
63235
+ this.applyRangeChangeOnTable(sheetId, table, applyChange);
63181
63236
  }
63182
63237
  }
63183
63238
  allowDispatch(cmd) {
@@ -64140,7 +64195,7 @@ class PivotCorePlugin extends CorePlugin {
64140
64195
  }
64141
64196
  }
64142
64197
  }
64143
- adaptRanges(applyChange, sheetId, sheetName) {
64198
+ adaptRanges(applyChange) {
64144
64199
  for (const sheetId in this.compiledMeasureFormulas) {
64145
64200
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
64146
64201
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -68541,7 +68596,7 @@ class PivotUIPlugin extends CoreViewPlugin {
68541
68596
  if (!result) {
68542
68597
  return EMPTY_PIVOT_CELL;
68543
68598
  }
68544
- const { functionName, args } = result;
68599
+ let { functionName, args } = result;
68545
68600
  const formulaId = args[0];
68546
68601
  if (!formulaId) {
68547
68602
  return EMPTY_PIVOT_CELL;
@@ -68576,6 +68631,9 @@ class PivotUIPlugin extends CoreViewPlugin {
68576
68631
  return pivotCells[pivotCol][pivotRow];
68577
68632
  }
68578
68633
  try {
68634
+ const offsetRow = position.row - mainPosition.row;
68635
+ const offsetCol = position.col - mainPosition.col;
68636
+ args = args.map((arg) => (isMatrix(arg) ? arg[offsetCol][offsetRow] : arg));
68579
68637
  if (functionName === "PIVOT.HEADER" && args.at(-2) === "measure") {
68580
68638
  const domain = pivot.parseArgsToPivotDomain(args.slice(1, -2).map((value) => ({ value })));
68581
68639
  return {
@@ -70184,7 +70242,8 @@ function transformAll(toTransform, executed) {
70184
70242
  // If the executed command is not in the registry, we skip it
70185
70243
  // because we know there won't be any transformation impacting the
70186
70244
  // commands to transform.
70187
- if (possibleTransformations.has(executedCommand.type)) {
70245
+ if (possibleTransformations.has(executedCommand.type) ||
70246
+ rangeAdapterRegistry.contains(executedCommand.type)) {
70188
70247
  transformedCommands = transformedCommands.reduce((acc, cmd) => {
70189
70248
  const transformed = transform(cmd, executedCommand);
70190
70249
  if (transformed) {
@@ -76176,7 +76235,8 @@ const inverseCommandRegistry = new Registry()
76176
76235
  .add("HIDE_COLUMNS_ROWS", inverseHideColumnsRows)
76177
76236
  .add("UNHIDE_COLUMNS_ROWS", inverseUnhideColumnsRows)
76178
76237
  .add("CREATE_TABLE_STYLE", inverseCreateTableStyle)
76179
- .add("ADD_PIVOT", inverseAddPivot);
76238
+ .add("ADD_PIVOT", inverseAddPivot)
76239
+ .add("RENAME_SHEET", inverseRenameSheet);
76180
76240
  for (const cmd of coreTypes.values()) {
76181
76241
  if (!inverseCommandRegistry.contains(cmd)) {
76182
76242
  inverseCommandRegistry.add(cmd, identity);
@@ -76274,6 +76334,16 @@ function inverseUnhideColumnsRows(cmd) {
76274
76334
  function inverseCreateTableStyle(cmd) {
76275
76335
  return [{ type: "REMOVE_TABLE_STYLE", tableStyleId: cmd.tableStyleId }];
76276
76336
  }
76337
+ function inverseRenameSheet(cmd) {
76338
+ return [
76339
+ {
76340
+ type: "RENAME_SHEET",
76341
+ sheetId: cmd.sheetId,
76342
+ oldName: cmd.newName,
76343
+ newName: cmd.oldName,
76344
+ },
76345
+ ];
76346
+ }
76277
76347
 
76278
76348
  const numberFormatMenuRegistry = new Registry();
76279
76349
  numberFormatMenuRegistry
@@ -76872,8 +76942,9 @@ topbarMenuRegistry
76872
76942
  sequence: 40,
76873
76943
  separator: true,
76874
76944
  })
76875
- .addChild("data_sources_data", ["data"], (env) => {
76945
+ .addChild("pivot_data_sources", ["data"], (env) => {
76876
76946
  const sequence = 50;
76947
+ const numberOfPivots = env.model.getters.getPivotIds().length;
76877
76948
  return env.model.getters.getPivotIds().map((pivotId, index) => {
76878
76949
  const highlightProvider = {
76879
76950
  get highlights() {
@@ -76883,7 +76954,7 @@ topbarMenuRegistry
76883
76954
  return {
76884
76955
  id: `item_pivot_${env.model.getters.getPivotFormulaId(pivotId)}`,
76885
76956
  name: env.model.getters.getPivotDisplayName(pivotId),
76886
- sequence: sequence + index,
76957
+ sequence: sequence + index / numberOfPivots,
76887
76958
  isReadonlyAllowed: true,
76888
76959
  execute: (env) => env.openSidePanel("PivotSidePanel", { pivotId }),
76889
76960
  isEnabled: (env) => !env.isSmall,
@@ -83003,7 +83074,7 @@ function figureCoordinates(headers, anchor, offset) {
83003
83074
  for (const [headerIndex, header] of headers.slice(anchor).entries()) {
83004
83075
  if (currentPosition <= offset && offset < currentPosition + header.size) {
83005
83076
  return {
83006
- index: headerIndex,
83077
+ index: anchor + headerIndex,
83007
83078
  offset: convertDotValueToEMU(offset - currentPosition + FIGURE_BORDER_WIDTH),
83008
83079
  };
83009
83080
  }
@@ -83999,7 +84070,7 @@ class Model extends EventBus {
83999
84070
  handlers = [];
84000
84071
  uiHandlers = [];
84001
84072
  coreHandlers = [];
84002
- constructor(data = {}, config = {}, stateUpdateMessages = [], uuidGenerator = new UuidGenerator(), verboseImport = false) {
84073
+ constructor(data = {}, config = {}, stateUpdateMessages = [], uuidGenerator = new UuidGenerator(), verboseImport = true) {
84003
84074
  const start = performance.now();
84004
84075
  console.debug("##### Model creation #####");
84005
84076
  super();
@@ -84701,6 +84772,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
84701
84772
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, LocalTransportService, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
84702
84773
 
84703
84774
 
84704
- __info__.version = "18.4.7";
84705
- __info__.date = "2025-08-21T06:42:12.438Z";
84706
- __info__.hash = "d5eb3a6";
84775
+ __info__.version = "18.4.9";
84776
+ __info__.date = "2025-09-05T07:38:32.126Z";
84777
+ __info__.hash = "a261873";