@odoo/o-spreadsheet 18.3.19 → 18.3.21

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.3.19
6
- * @date 2025-09-05T07:38:30.661Z
7
- * @hash 77fd307
5
+ * @version 18.3.21
6
+ * @date 2025-09-19T07:25:12.089Z
7
+ * @hash b64ee85
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -862,8 +862,19 @@ function memoize(func) {
862
862
  },
863
863
  }[funcName];
864
864
  }
865
+ /**
866
+ * Removes the specified indexes from the array.
867
+ * Sparse (empty) elements are transformed to undefined (unless their index is explicitly removed).
868
+ */
865
869
  function removeIndexesFromArray(array, indexes) {
866
- return array.filter((_, index) => !indexes.includes(index));
870
+ const toRemove = new Set(indexes);
871
+ const newArray = [];
872
+ for (let i = 0; i < array.length; i++) {
873
+ if (!toRemove.has(i)) {
874
+ newArray.push(array[i]);
875
+ }
876
+ }
877
+ return newArray;
867
878
  }
868
879
  function insertItemsAtIndex(array, items, index) {
869
880
  const newArray = [...array];
@@ -7207,7 +7218,7 @@ class ClipboardHandler {
7207
7218
  this.getters = getters;
7208
7219
  this.dispatch = dispatch;
7209
7220
  }
7210
- copy(data, isCutOperation) {
7221
+ copy(data, isCutOperation, mode = "copyPaste") {
7211
7222
  return;
7212
7223
  }
7213
7224
  paste(target, clippedContent, options) { }
@@ -7226,7 +7237,7 @@ class ClipboardHandler {
7226
7237
  }
7227
7238
 
7228
7239
  class AbstractCellClipboardHandler extends ClipboardHandler {
7229
- copy(data) {
7240
+ copy(data, isCutOperation, mode = "copyPaste") {
7230
7241
  return;
7231
7242
  }
7232
7243
  pasteFromCopy(sheetId, target, content, options) {
@@ -8949,7 +8960,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8949
8960
  }
8950
8961
  return "Success" /* CommandResult.Success */;
8951
8962
  }
8952
- copy(data) {
8963
+ copy(data, isCutOperation, mode = "copyPaste") {
8953
8964
  const sheetId = data.sheetId;
8954
8965
  const { clippedZones, rowsIndexes, columnsIndexes } = data;
8955
8966
  const clippedCells = [];
@@ -8962,7 +8973,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8962
8973
  const evaluatedCell = this.getters.getEvaluatedCell(position);
8963
8974
  const pivotId = this.getters.getPivotIdFromPosition(position);
8964
8975
  const spreader = this.getters.getArrayFormulaSpreadingOn(position);
8965
- if (pivotId && spreader) {
8976
+ if (mode !== "shiftCells" && pivotId && spreader) {
8966
8977
  const pivotZone = this.getters.getSpreadZone(spreader);
8967
8978
  if ((!deepEquals(spreader, position) || !isCopyingOneCell) &&
8968
8979
  pivotZone &&
@@ -8980,7 +8991,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8980
8991
  };
8981
8992
  }
8982
8993
  }
8983
- else {
8994
+ else if (mode !== "shiftCells") {
8984
8995
  if (spreader && !deepEquals(spreader, position)) {
8985
8996
  const isSpreaderCopied = rowsIndexes.includes(spreader.row) && columnsIndexes.includes(spreader.col);
8986
8997
  const content = isSpreaderCopied
@@ -9680,7 +9691,7 @@ class SheetClipboardHandler extends AbstractCellClipboardHandler {
9680
9691
  }
9681
9692
 
9682
9693
  class TableClipboardHandler extends AbstractCellClipboardHandler {
9683
- copy(data, isCutOperation) {
9694
+ copy(data, isCutOperation, mode = "copyPaste") {
9684
9695
  const sheetId = data.sheetId;
9685
9696
  const { rowsIndexes, columnsIndexes, zones } = data;
9686
9697
  const copiedTablesIds = new Set();
@@ -9718,11 +9729,13 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
9718
9729
  type: coreTable.type,
9719
9730
  };
9720
9731
  }
9721
- tableCellsInRow.push({
9722
- table: copiedTable,
9723
- style: this.getTableStyleToCopy(position),
9724
- isWholeTableCopied: copiedTablesIds.has(table.id),
9725
- });
9732
+ if (mode !== "shiftCells") {
9733
+ tableCellsInRow.push({
9734
+ table: copiedTable,
9735
+ style: this.getTableStyleToCopy(position),
9736
+ isWholeTableCopied: copiedTablesIds.has(table.id),
9737
+ });
9738
+ }
9726
9739
  }
9727
9740
  }
9728
9741
  return {
@@ -14806,8 +14819,9 @@ function interactiveSort(env, sheetId, anchor, zone, sortDirection, sortOptions)
14806
14819
  }
14807
14820
 
14808
14821
  function sortMatrix(matrix, locale, ...criteria) {
14809
- for (const [i, value] of criteria.entries()) {
14810
- assert(() => value !== undefined, _t("Value for parameter %d is missing, while the function [[FUNCTION_NAME]] expect a number or a range.", i + 1));
14822
+ for (let i = 0; i < criteria.length; i++) {
14823
+ const param = i % 2 === 0 ? "sort_column" : "is_ascending";
14824
+ assert(() => criteria[i] !== undefined, _t("Value for parameter %s is missing in [[FUNCTION_NAME]].", param));
14811
14825
  }
14812
14826
  const sortingOrders = [];
14813
14827
  const sortColumns = [];
@@ -30884,7 +30898,7 @@ const SUPPORTED_HORIZONTAL_ALIGNMENTS = [
30884
30898
  ];
30885
30899
  const SUPPORTED_VERTICAL_ALIGNMENTS = ["top", "center", "bottom"];
30886
30900
  const SUPPORTED_FONTS = ["Arial"];
30887
- const SUPPORTED_FILL_PATTERNS = ["solid"];
30901
+ const SUPPORTED_FILL_PATTERNS = ["solid", "none"];
30888
30902
  const SUPPORTED_CF_TYPES = [
30889
30903
  "expression",
30890
30904
  "cellIs",
@@ -31069,7 +31083,7 @@ const SUBTOTAL_FUNCTION_CONVERSION_MAP = {
31069
31083
  };
31070
31084
  /** Mapping between Excel format indexes (see XLSX_FORMAT_MAP) and some supported formats */
31071
31085
  const XLSX_FORMATS_CONVERSION_MAP = {
31072
- 0: "",
31086
+ 0: "General",
31073
31087
  1: "0",
31074
31088
  2: "0.00",
31075
31089
  3: "#,#00",
@@ -31395,11 +31409,11 @@ const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/
31395
31409
  * Excel format are defined in openXML §18.8.31
31396
31410
  */
31397
31411
  function convertXlsxFormat(numFmtId, formats, warningManager) {
31398
- if (numFmtId === 0) {
31399
- return undefined;
31400
- }
31401
31412
  // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
31402
31413
  let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || formats.find((f) => f.id === numFmtId)?.format;
31414
+ if (format === "General") {
31415
+ return undefined;
31416
+ }
31403
31417
  if (format) {
31404
31418
  try {
31405
31419
  let convertedFormat = format.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
@@ -34244,10 +34258,11 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
34244
34258
  });
34245
34259
  }
34246
34260
  extractRows(worksheet) {
34261
+ const spilledCells = new Set();
34247
34262
  return this.mapOnElements({ parent: worksheet, query: "sheetData row" }, (rowElement) => {
34248
34263
  return {
34249
34264
  index: this.extractAttr(rowElement, "r", { required: true })?.asNum(),
34250
- cells: this.extractCells(rowElement),
34265
+ cells: this.extractCells(rowElement, spilledCells),
34251
34266
  height: this.extractAttr(rowElement, "ht")?.asNum(),
34252
34267
  customHeight: this.extractAttr(rowElement, "customHeight")?.asBool(),
34253
34268
  hidden: this.extractAttr(rowElement, "hidden")?.asBool(),
@@ -34257,14 +34272,26 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
34257
34272
  };
34258
34273
  });
34259
34274
  }
34260
- extractCells(row) {
34275
+ extractCells(row, spilledCells) {
34261
34276
  return this.mapOnElements({ parent: row, query: "c" }, (cellElement) => {
34277
+ const xc = this.extractAttr(cellElement, "r", { required: true })?.asString();
34278
+ const formula = this.extractCellFormula(cellElement);
34279
+ if (formula?.ref && formula.sharedIndex === undefined) {
34280
+ const zone = toZone(formula.ref);
34281
+ for (const { col, row } of positions(zone)) {
34282
+ const followerXc = toXC(col, row);
34283
+ if (followerXc !== xc) {
34284
+ spilledCells.add(followerXc);
34285
+ }
34286
+ }
34287
+ }
34288
+ const isSpilled = spilledCells.has(xc);
34262
34289
  return {
34263
- xc: this.extractAttr(cellElement, "r", { required: true })?.asString(),
34290
+ xc,
34264
34291
  styleIndex: this.extractAttr(cellElement, "s")?.asNum(),
34265
34292
  type: CELL_TYPE_CONVERSION_MAP[this.extractAttr(cellElement, "t", { default: "n" })?.asString()],
34266
- value: this.extractChildTextContent(cellElement, "v"),
34267
- formula: this.extractCellFormula(cellElement),
34293
+ value: isSpilled ? undefined : this.extractChildTextContent(cellElement, "v") ?? undefined,
34294
+ formula: isSpilled ? undefined : formula,
34268
34295
  };
34269
34296
  });
34270
34297
  }
@@ -34272,11 +34299,14 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
34272
34299
  const formulaElement = this.querySelector(cellElement, "f");
34273
34300
  if (!formulaElement)
34274
34301
  return undefined;
34275
- return {
34276
- content: this.extractTextContent(formulaElement),
34277
- sharedIndex: this.extractAttr(formulaElement, "si")?.asNum(),
34278
- ref: this.extractAttr(formulaElement, "ref")?.asString(),
34279
- };
34302
+ const content = this.extractTextContent(formulaElement);
34303
+ const sharedIndex = this.extractAttr(formulaElement, "si")?.asNum();
34304
+ const ref = this.extractAttr(formulaElement, "ref")?.asString();
34305
+ // This is the case of spilled cells of array formulas where <f> is empty
34306
+ if ((content === undefined || content.trim() === "") && sharedIndex === undefined) {
34307
+ return undefined;
34308
+ }
34309
+ return { content, sharedIndex, ref };
34280
34310
  }
34281
34311
  extractHyperLinks(worksheet) {
34282
34312
  return this.mapOnElements({ parent: worksheet, query: "hyperlink" }, (linkElement) => {
@@ -48859,12 +48889,13 @@ class PivotLayoutConfigurator extends Component {
48859
48889
  addCalculatedMeasure() {
48860
48890
  const { measures } = this.props.definition;
48861
48891
  const measureName = this.env.model.getters.generateNewCalculatedMeasureName(measures);
48892
+ const aggregator = "sum";
48862
48893
  this.props.onDimensionsUpdated({
48863
48894
  measures: measures.concat([
48864
48895
  {
48865
- id: this.getMeasureId(measureName),
48896
+ id: this.getMeasureId(measureName, aggregator),
48866
48897
  fieldName: measureName,
48867
- aggregator: "sum",
48898
+ aggregator,
48868
48899
  computedBy: {
48869
48900
  sheetId: this.env.model.getters.getActiveSheetId(),
48870
48901
  formula: "=0",
@@ -66215,7 +66246,7 @@ function withPivotPresentationLayer (PivotClass) {
66215
66246
  return { value: 0 };
66216
66247
  }
66217
66248
  const { columns, rows } = super.definition;
66218
- if (columns.length + rows.length !== domain.length) {
66249
+ if (measure.aggregator && columns.length + rows.length !== domain.length) {
66219
66250
  const values = this.getValuesToAggregate(measure, domain);
66220
66251
  const aggregator = AGGREGATORS_FN[measure.aggregator];
66221
66252
  if (!aggregator) {
@@ -66234,11 +66265,17 @@ function withPivotPresentationLayer (PivotClass) {
66234
66265
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
66235
66266
  const { colDomain } = domainToColRowDomain(this, domain);
66236
66267
  const symbolIndex = colDomain.findIndex((node) => node.field === symbolName);
66268
+ if (symbolIndex === -1) {
66269
+ return new NotAvailableError();
66270
+ }
66237
66271
  return this.getPivotHeaderValueAndFormat(colDomain.slice(0, symbolIndex + 1));
66238
66272
  }
66239
66273
  if (rows.find((row) => row.nameWithGranularity === symbolName)) {
66240
66274
  const { rowDomain } = domainToColRowDomain(this, domain);
66241
66275
  const symbolIndex = rowDomain.findIndex((row) => row.field === symbolName);
66276
+ if (symbolIndex === -1) {
66277
+ return new NotAvailableError();
66278
+ }
66242
66279
  return this.getPivotHeaderValueAndFormat(rowDomain.slice(0, symbolIndex + 1));
66243
66280
  }
66244
66281
  return this.getPivotCellValueAndFormat(symbolName, domain);
@@ -68829,7 +68866,7 @@ class DataCleanupPlugin extends UIPlugin {
68829
68866
  bottom: rowIndex,
68830
68867
  }));
68831
68868
  const handler = new CellClipboardHandler(this.getters, this.dispatch);
68832
- const data = handler.copy(getClipboardDataPositions(sheetId, rowsToKeep));
68869
+ const data = handler.copy(getClipboardDataPositions(sheetId, rowsToKeep), false);
68833
68870
  if (!data) {
68834
68871
  return;
68835
68872
  }
@@ -70869,12 +70906,12 @@ class ClipboardPlugin extends UIPlugin {
70869
70906
  }
70870
70907
  case "INSERT_CELL": {
70871
70908
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
70872
- const copiedData = this.copy(cut);
70909
+ const copiedData = this.copy(cut, "shiftCells");
70873
70910
  return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
70874
70911
  }
70875
70912
  case "DELETE_CELL": {
70876
70913
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
70877
- const copiedData = this.copy(cut);
70914
+ const copiedData = this.copy(cut, "shiftCells");
70878
70915
  return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
70879
70916
  }
70880
70917
  }
@@ -70985,13 +71022,13 @@ class ClipboardPlugin extends UIPlugin {
70985
71022
  });
70986
71023
  break;
70987
71024
  }
70988
- const copiedData = this.copy(cut);
71025
+ const copiedData = this.copy(cut, "shiftCells");
70989
71026
  this.paste(paste, copiedData, { isCutOperation: true });
70990
71027
  break;
70991
71028
  }
70992
71029
  case "INSERT_CELL": {
70993
71030
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
70994
- const copiedData = this.copy(cut);
71031
+ const copiedData = this.copy(cut, "shiftCells");
70995
71032
  this.paste(paste, copiedData, { isCutOperation: true });
70996
71033
  break;
70997
71034
  }
@@ -71106,11 +71143,11 @@ class ClipboardPlugin extends UIPlugin {
71106
71143
  }
71107
71144
  return false;
71108
71145
  }
71109
- copy(zones) {
71146
+ copy(zones, mode = "copyPaste") {
71110
71147
  let copiedData = {};
71111
71148
  const clipboardData = this.getClipboardData(zones);
71112
71149
  for (const { handlerName, handler } of this.selectClipboardHandlers(clipboardData)) {
71113
- const data = handler.copy(clipboardData, this._isCutOperation);
71150
+ const data = handler.copy(clipboardData, this._isCutOperation, mode);
71114
71151
  copiedData[handlerName] = data;
71115
71152
  const minimalKeys = ["sheetId", "cells", "zones", "figureId"];
71116
71153
  for (const key of minimalKeys) {
@@ -72034,13 +72071,10 @@ class GridSelectionPlugin extends UIPlugin {
72034
72071
  const deltaCol = isBasedBefore && isCol ? thickness : 0;
72035
72072
  const deltaRow = isBasedBefore && !isCol ? thickness : 0;
72036
72073
  const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
72037
- const originalSize = Object.fromEntries(toRemove.map((element) => {
72038
- const size = isCol
72039
- ? this.getters.getColSize(cmd.sheetId, element)
72040
- : this.getters.getUserRowSize(cmd.sheetId, element);
72041
- const isDefaultCol = isCol && size === DEFAULT_CELL_WIDTH;
72042
- return [element, isDefaultCol ? undefined : size];
72043
- }));
72074
+ const originalSize = {};
72075
+ for (const element of toRemove) {
72076
+ originalSize[element] = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, element);
72077
+ }
72044
72078
  const target = [
72045
72079
  {
72046
72080
  left: isCol ? start + deltaCol : 0,
@@ -72061,7 +72095,7 @@ class GridSelectionPlugin extends UIPlugin {
72061
72095
  ];
72062
72096
  for (const Handler of clipboardHandlersRegistries.cellHandlers.getAll()) {
72063
72097
  const handler = new Handler(this.getters, this.dispatch);
72064
- const data = handler.copy(getClipboardDataPositions(sheetId, target));
72098
+ const data = handler.copy(getClipboardDataPositions(sheetId, target), false, "shiftCells");
72065
72099
  if (!data) {
72066
72100
  continue;
72067
72101
  }
@@ -72076,11 +72110,11 @@ class GridSelectionPlugin extends UIPlugin {
72076
72110
  for (const element of toRemove) {
72077
72111
  const size = originalSize[element];
72078
72112
  const currentSize = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, currentIndex);
72079
- if (size && size != currentSize) {
72113
+ if (size != currentSize) {
72080
72114
  resizingGroups[size] ??= [];
72081
72115
  resizingGroups[size].push(currentIndex);
72082
- currentIndex += 1;
72083
72116
  }
72117
+ currentIndex += 1;
72084
72118
  }
72085
72119
  for (const size in resizingGroups) {
72086
72120
  this.dispatch("RESIZE_COLUMNS_ROWS", {
@@ -80252,7 +80286,7 @@ class Model extends EventBus {
80252
80286
  handlers = [];
80253
80287
  uiHandlers = [];
80254
80288
  coreHandlers = [];
80255
- constructor(data = {}, config = {}, stateUpdateMessages = [], uuidGenerator = new UuidGenerator(), verboseImport = true) {
80289
+ constructor(data = {}, config = {}, stateUpdateMessages = [], uuidGenerator = new UuidGenerator(), verboseImport = false) {
80256
80290
  const start = performance.now();
80257
80291
  console.debug("##### Model creation #####");
80258
80292
  super();
@@ -80949,6 +80983,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
80949
80983
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, 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 };
80950
80984
 
80951
80985
 
80952
- __info__.version = "18.3.19";
80953
- __info__.date = "2025-09-05T07:38:30.661Z";
80954
- __info__.hash = "77fd307";
80986
+ __info__.version = "18.3.21";
80987
+ __info__.date = "2025-09-19T07:25:12.089Z";
80988
+ __info__.hash = "b64ee85";