@odoo/o-spreadsheet 17.0.72 → 17.0.74

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 17.0.72
6
- * @date 2025-09-05T07:33:34.433Z
7
- * @hash 8c68f3d
5
+ * @version 17.0.74
6
+ * @date 2025-09-19T07:22:25.998Z
7
+ * @hash bf7d9c8
8
8
  */
9
9
 
10
10
  'use strict';
@@ -778,8 +778,19 @@ function memoize(func) {
778
778
  },
779
779
  }[funcName];
780
780
  }
781
+ /**
782
+ * Removes the specified indexes from the array.
783
+ * Sparse (empty) elements are transformed to undefined (unless their index is explicitly removed).
784
+ */
781
785
  function removeIndexesFromArray(array, indexes) {
782
- return array.filter((_, index) => !indexes.includes(index));
786
+ const toRemove = new Set(indexes);
787
+ const newArray = [];
788
+ for (let i = 0; i < array.length; i++) {
789
+ if (!toRemove.has(i)) {
790
+ newArray.push(array[i]);
791
+ }
792
+ }
793
+ return newArray;
783
794
  }
784
795
  function insertItemsAtIndex(array, items, index) {
785
796
  const newArray = [...array];
@@ -15922,8 +15933,9 @@ function interactiveSortSelection(env, sheetId, anchor, zone, sortDirection) {
15922
15933
  }
15923
15934
 
15924
15935
  function sortMatrix(matrix, locale, ...criteria) {
15925
- for (const [i, value] of criteria.entries()) {
15926
- assert(() => value !== undefined, _t("Value for parameter %d is missing, while the function [[FUNCTION_NAME]] expect a number or a range.", i + 1));
15936
+ for (let i = 0; i < criteria.length; i++) {
15937
+ const param = i % 2 === 0 ? "sort_column" : "is_ascending";
15938
+ assert(() => criteria[i] !== undefined, _t("Value for parameter %s is missing in [[FUNCTION_NAME]].", param));
15927
15939
  }
15928
15940
  const sortingOrders = [];
15929
15941
  const sortColumns = [];
@@ -31666,7 +31678,7 @@ const SUPPORTED_HORIZONTAL_ALIGNMENTS = [
31666
31678
  ];
31667
31679
  const SUPPORTED_VERTICAL_ALIGNMENTS = ["top", "center", "bottom"];
31668
31680
  const SUPPORTED_FONTS = ["Arial"];
31669
- const SUPPORTED_FILL_PATTERNS = ["solid"];
31681
+ const SUPPORTED_FILL_PATTERNS = ["solid", "none"];
31670
31682
  const SUPPORTED_CF_TYPES = [
31671
31683
  "expression",
31672
31684
  "cellIs",
@@ -31850,7 +31862,7 @@ const SUBTOTAL_FUNCTION_CONVERSION_MAP = {
31850
31862
  };
31851
31863
  /** Mapping between Excel format indexes (see XLSX_FORMAT_MAP) and some supported formats */
31852
31864
  const XLSX_FORMATS_CONVERSION_MAP = {
31853
- 0: "",
31865
+ 0: "General",
31854
31866
  1: "0",
31855
31867
  2: "0.00",
31856
31868
  3: "#,#00",
@@ -32149,11 +32161,11 @@ const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/
32149
32161
  * Excel format are defined in openXML §18.8.31
32150
32162
  */
32151
32163
  function convertXlsxFormat(numFmtId, formats, warningManager) {
32152
- if (numFmtId === 0) {
32153
- return undefined;
32154
- }
32155
32164
  // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
32156
32165
  let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || formats.find((f) => f.id === numFmtId)?.format;
32166
+ if (format === "General") {
32167
+ return undefined;
32168
+ }
32157
32169
  if (format) {
32158
32170
  try {
32159
32171
  let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
@@ -34455,10 +34467,11 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
34455
34467
  });
34456
34468
  }
34457
34469
  extractRows(worksheet) {
34470
+ const spilledCells = new Set();
34458
34471
  return this.mapOnElements({ parent: worksheet, query: "sheetData row" }, (rowElement) => {
34459
34472
  return {
34460
34473
  index: this.extractAttr(rowElement, "r", { required: true })?.asNum(),
34461
- cells: this.extractCells(rowElement),
34474
+ cells: this.extractCells(rowElement, spilledCells),
34462
34475
  height: this.extractAttr(rowElement, "ht")?.asNum(),
34463
34476
  customHeight: this.extractAttr(rowElement, "customHeight")?.asBool(),
34464
34477
  hidden: this.extractAttr(rowElement, "hidden")?.asBool(),
@@ -34466,14 +34479,26 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
34466
34479
  };
34467
34480
  });
34468
34481
  }
34469
- extractCells(row) {
34482
+ extractCells(row, spilledCells) {
34470
34483
  return this.mapOnElements({ parent: row, query: "c" }, (cellElement) => {
34484
+ const xc = this.extractAttr(cellElement, "r", { required: true })?.asString();
34485
+ const formula = this.extractCellFormula(cellElement);
34486
+ if (formula?.ref && formula.sharedIndex === undefined) {
34487
+ const zone = toZone(formula.ref);
34488
+ for (const { col, row } of positions(zone)) {
34489
+ const followerXc = toXC(col, row);
34490
+ if (followerXc !== xc) {
34491
+ spilledCells.add(followerXc);
34492
+ }
34493
+ }
34494
+ }
34495
+ const isSpilled = spilledCells.has(xc);
34471
34496
  return {
34472
- xc: this.extractAttr(cellElement, "r", { required: true })?.asString(),
34497
+ xc,
34473
34498
  styleIndex: this.extractAttr(cellElement, "s")?.asNum(),
34474
34499
  type: CELL_TYPE_CONVERSION_MAP[this.extractAttr(cellElement, "t", { default: "n" })?.asString()],
34475
- value: this.extractChildTextContent(cellElement, "v"),
34476
- formula: this.extractCellFormula(cellElement),
34500
+ value: isSpilled ? undefined : this.extractChildTextContent(cellElement, "v") ?? undefined,
34501
+ formula: isSpilled ? undefined : formula,
34477
34502
  };
34478
34503
  });
34479
34504
  }
@@ -34481,11 +34506,14 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
34481
34506
  const formulaElement = this.querySelector(cellElement, "f");
34482
34507
  if (!formulaElement)
34483
34508
  return undefined;
34484
- return {
34485
- content: this.extractTextContent(formulaElement),
34486
- sharedIndex: this.extractAttr(formulaElement, "si")?.asNum(),
34487
- ref: this.extractAttr(formulaElement, "ref")?.asString(),
34488
- };
34509
+ const content = this.extractTextContent(formulaElement);
34510
+ const sharedIndex = this.extractAttr(formulaElement, "si")?.asNum();
34511
+ const ref = this.extractAttr(formulaElement, "ref")?.asString();
34512
+ // This is the case of spilled cells of array formulas where <f> is empty
34513
+ if ((content === undefined || content.trim() === "") && sharedIndex === undefined) {
34514
+ return undefined;
34515
+ }
34516
+ return { content, sharedIndex, ref };
34489
34517
  }
34490
34518
  extractHyperLinks(worksheet) {
34491
34519
  return this.mapOnElements({ parent: worksheet, query: "hyperlink" }, (linkElement) => {
@@ -45519,7 +45547,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
45519
45547
  queuedBordersToAdd = {};
45520
45548
  queuedCFChanges = {};
45521
45549
  queuedDVChanges = {};
45522
- constructor(zones, operation, getters, dispatch, selection) {
45550
+ constructor(zones, operation, getters, dispatch, selection, mode = "copyPaste") {
45523
45551
  super(operation, getters, dispatch, selection);
45524
45552
  if (!zones.length) {
45525
45553
  this.cells = [[]];
@@ -45549,7 +45577,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
45549
45577
  const spreader = getters.getArrayFormulaSpreadingOn(position);
45550
45578
  let cell = getters.getCell(position);
45551
45579
  const evaluatedCell = getters.getEvaluatedCell(position);
45552
- if (spreader) {
45580
+ if (mode !== "shiftCells" && spreader) {
45553
45581
  const isSpreaderCopied = rowsIndex.includes(spreader.row) && columnsIndex.includes(spreader.col);
45554
45582
  const content = isSpreaderCopied
45555
45583
  ? ""
@@ -49110,12 +49138,12 @@ class ClipboardPlugin extends UIPlugin {
49110
49138
  }
49111
49139
  case "INSERT_CELL": {
49112
49140
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
49113
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49141
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49114
49142
  return state.isPasteAllowed(paste);
49115
49143
  }
49116
49144
  case "DELETE_CELL": {
49117
49145
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
49118
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49146
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49119
49147
  return state.isPasteAllowed(paste);
49120
49148
  }
49121
49149
  case "ACTIVATE_PAINT_FORMAT": {
@@ -49196,13 +49224,13 @@ class ClipboardPlugin extends UIPlugin {
49196
49224
  });
49197
49225
  break;
49198
49226
  }
49199
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49227
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49200
49228
  state.paste(paste);
49201
49229
  break;
49202
49230
  }
49203
49231
  case "INSERT_CELL": {
49204
49232
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
49205
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49233
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49206
49234
  state.paste(paste);
49207
49235
  break;
49208
49236
  }
@@ -49352,8 +49380,8 @@ class ClipboardPlugin extends UIPlugin {
49352
49380
  }
49353
49381
  return { cut: [cut], paste: [paste] };
49354
49382
  }
49355
- getClipboardStateForCopyCells(zones, operation) {
49356
- return new ClipboardCellsState(zones, operation, this.getters, this.dispatch, this.selection);
49383
+ getClipboardStateForCopyCells(zones, operation, mode = "copyPaste") {
49384
+ return new ClipboardCellsState(zones, operation, this.getters, this.dispatch, this.selection, mode);
49357
49385
  }
49358
49386
  /**
49359
49387
  * Get the clipboard state from the given zones.
@@ -50923,7 +50951,7 @@ class GridSelectionPlugin extends UIPlugin {
50923
50951
  bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
50924
50952
  },
50925
50953
  ];
50926
- const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
50954
+ const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection, "shiftCells");
50927
50955
  const base = isBasedBefore ? cmd.base : cmd.base + 1;
50928
50956
  const pasteTarget = [
50929
50957
  {
@@ -58475,6 +58503,6 @@ exports.setTranslationMethod = setTranslationMethod;
58475
58503
  exports.tokenize = tokenize;
58476
58504
 
58477
58505
 
58478
- __info__.version = "17.0.72";
58479
- __info__.date = "2025-09-05T07:33:34.433Z";
58480
- __info__.hash = "8c68f3d";
58506
+ __info__.version = "17.0.74";
58507
+ __info__.date = "2025-09-19T07:22:25.998Z";
58508
+ __info__.hash = "bf7d9c8";
@@ -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 17.0.72
6
- * @date 2025-09-05T07:33:34.433Z
7
- * @hash 8c68f3d
5
+ * @version 17.0.74
6
+ * @date 2025-09-19T07:22:25.998Z
7
+ * @hash bf7d9c8
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -776,8 +776,19 @@ function memoize(func) {
776
776
  },
777
777
  }[funcName];
778
778
  }
779
+ /**
780
+ * Removes the specified indexes from the array.
781
+ * Sparse (empty) elements are transformed to undefined (unless their index is explicitly removed).
782
+ */
779
783
  function removeIndexesFromArray(array, indexes) {
780
- return array.filter((_, index) => !indexes.includes(index));
784
+ const toRemove = new Set(indexes);
785
+ const newArray = [];
786
+ for (let i = 0; i < array.length; i++) {
787
+ if (!toRemove.has(i)) {
788
+ newArray.push(array[i]);
789
+ }
790
+ }
791
+ return newArray;
781
792
  }
782
793
  function insertItemsAtIndex(array, items, index) {
783
794
  const newArray = [...array];
@@ -15920,8 +15931,9 @@ function interactiveSortSelection(env, sheetId, anchor, zone, sortDirection) {
15920
15931
  }
15921
15932
 
15922
15933
  function sortMatrix(matrix, locale, ...criteria) {
15923
- for (const [i, value] of criteria.entries()) {
15924
- assert(() => value !== undefined, _t("Value for parameter %d is missing, while the function [[FUNCTION_NAME]] expect a number or a range.", i + 1));
15934
+ for (let i = 0; i < criteria.length; i++) {
15935
+ const param = i % 2 === 0 ? "sort_column" : "is_ascending";
15936
+ assert(() => criteria[i] !== undefined, _t("Value for parameter %s is missing in [[FUNCTION_NAME]].", param));
15925
15937
  }
15926
15938
  const sortingOrders = [];
15927
15939
  const sortColumns = [];
@@ -31664,7 +31676,7 @@ const SUPPORTED_HORIZONTAL_ALIGNMENTS = [
31664
31676
  ];
31665
31677
  const SUPPORTED_VERTICAL_ALIGNMENTS = ["top", "center", "bottom"];
31666
31678
  const SUPPORTED_FONTS = ["Arial"];
31667
- const SUPPORTED_FILL_PATTERNS = ["solid"];
31679
+ const SUPPORTED_FILL_PATTERNS = ["solid", "none"];
31668
31680
  const SUPPORTED_CF_TYPES = [
31669
31681
  "expression",
31670
31682
  "cellIs",
@@ -31848,7 +31860,7 @@ const SUBTOTAL_FUNCTION_CONVERSION_MAP = {
31848
31860
  };
31849
31861
  /** Mapping between Excel format indexes (see XLSX_FORMAT_MAP) and some supported formats */
31850
31862
  const XLSX_FORMATS_CONVERSION_MAP = {
31851
- 0: "",
31863
+ 0: "General",
31852
31864
  1: "0",
31853
31865
  2: "0.00",
31854
31866
  3: "#,#00",
@@ -32147,11 +32159,11 @@ const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/
32147
32159
  * Excel format are defined in openXML §18.8.31
32148
32160
  */
32149
32161
  function convertXlsxFormat(numFmtId, formats, warningManager) {
32150
- if (numFmtId === 0) {
32151
- return undefined;
32152
- }
32153
32162
  // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
32154
32163
  let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || formats.find((f) => f.id === numFmtId)?.format;
32164
+ if (format === "General") {
32165
+ return undefined;
32166
+ }
32155
32167
  if (format) {
32156
32168
  try {
32157
32169
  let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
@@ -34453,10 +34465,11 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
34453
34465
  });
34454
34466
  }
34455
34467
  extractRows(worksheet) {
34468
+ const spilledCells = new Set();
34456
34469
  return this.mapOnElements({ parent: worksheet, query: "sheetData row" }, (rowElement) => {
34457
34470
  return {
34458
34471
  index: this.extractAttr(rowElement, "r", { required: true })?.asNum(),
34459
- cells: this.extractCells(rowElement),
34472
+ cells: this.extractCells(rowElement, spilledCells),
34460
34473
  height: this.extractAttr(rowElement, "ht")?.asNum(),
34461
34474
  customHeight: this.extractAttr(rowElement, "customHeight")?.asBool(),
34462
34475
  hidden: this.extractAttr(rowElement, "hidden")?.asBool(),
@@ -34464,14 +34477,26 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
34464
34477
  };
34465
34478
  });
34466
34479
  }
34467
- extractCells(row) {
34480
+ extractCells(row, spilledCells) {
34468
34481
  return this.mapOnElements({ parent: row, query: "c" }, (cellElement) => {
34482
+ const xc = this.extractAttr(cellElement, "r", { required: true })?.asString();
34483
+ const formula = this.extractCellFormula(cellElement);
34484
+ if (formula?.ref && formula.sharedIndex === undefined) {
34485
+ const zone = toZone(formula.ref);
34486
+ for (const { col, row } of positions(zone)) {
34487
+ const followerXc = toXC(col, row);
34488
+ if (followerXc !== xc) {
34489
+ spilledCells.add(followerXc);
34490
+ }
34491
+ }
34492
+ }
34493
+ const isSpilled = spilledCells.has(xc);
34469
34494
  return {
34470
- xc: this.extractAttr(cellElement, "r", { required: true })?.asString(),
34495
+ xc,
34471
34496
  styleIndex: this.extractAttr(cellElement, "s")?.asNum(),
34472
34497
  type: CELL_TYPE_CONVERSION_MAP[this.extractAttr(cellElement, "t", { default: "n" })?.asString()],
34473
- value: this.extractChildTextContent(cellElement, "v"),
34474
- formula: this.extractCellFormula(cellElement),
34498
+ value: isSpilled ? undefined : this.extractChildTextContent(cellElement, "v") ?? undefined,
34499
+ formula: isSpilled ? undefined : formula,
34475
34500
  };
34476
34501
  });
34477
34502
  }
@@ -34479,11 +34504,14 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
34479
34504
  const formulaElement = this.querySelector(cellElement, "f");
34480
34505
  if (!formulaElement)
34481
34506
  return undefined;
34482
- return {
34483
- content: this.extractTextContent(formulaElement),
34484
- sharedIndex: this.extractAttr(formulaElement, "si")?.asNum(),
34485
- ref: this.extractAttr(formulaElement, "ref")?.asString(),
34486
- };
34507
+ const content = this.extractTextContent(formulaElement);
34508
+ const sharedIndex = this.extractAttr(formulaElement, "si")?.asNum();
34509
+ const ref = this.extractAttr(formulaElement, "ref")?.asString();
34510
+ // This is the case of spilled cells of array formulas where <f> is empty
34511
+ if ((content === undefined || content.trim() === "") && sharedIndex === undefined) {
34512
+ return undefined;
34513
+ }
34514
+ return { content, sharedIndex, ref };
34487
34515
  }
34488
34516
  extractHyperLinks(worksheet) {
34489
34517
  return this.mapOnElements({ parent: worksheet, query: "hyperlink" }, (linkElement) => {
@@ -45517,7 +45545,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
45517
45545
  queuedBordersToAdd = {};
45518
45546
  queuedCFChanges = {};
45519
45547
  queuedDVChanges = {};
45520
- constructor(zones, operation, getters, dispatch, selection) {
45548
+ constructor(zones, operation, getters, dispatch, selection, mode = "copyPaste") {
45521
45549
  super(operation, getters, dispatch, selection);
45522
45550
  if (!zones.length) {
45523
45551
  this.cells = [[]];
@@ -45547,7 +45575,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
45547
45575
  const spreader = getters.getArrayFormulaSpreadingOn(position);
45548
45576
  let cell = getters.getCell(position);
45549
45577
  const evaluatedCell = getters.getEvaluatedCell(position);
45550
- if (spreader) {
45578
+ if (mode !== "shiftCells" && spreader) {
45551
45579
  const isSpreaderCopied = rowsIndex.includes(spreader.row) && columnsIndex.includes(spreader.col);
45552
45580
  const content = isSpreaderCopied
45553
45581
  ? ""
@@ -49108,12 +49136,12 @@ class ClipboardPlugin extends UIPlugin {
49108
49136
  }
49109
49137
  case "INSERT_CELL": {
49110
49138
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
49111
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49139
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49112
49140
  return state.isPasteAllowed(paste);
49113
49141
  }
49114
49142
  case "DELETE_CELL": {
49115
49143
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
49116
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49144
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49117
49145
  return state.isPasteAllowed(paste);
49118
49146
  }
49119
49147
  case "ACTIVATE_PAINT_FORMAT": {
@@ -49194,13 +49222,13 @@ class ClipboardPlugin extends UIPlugin {
49194
49222
  });
49195
49223
  break;
49196
49224
  }
49197
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49225
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49198
49226
  state.paste(paste);
49199
49227
  break;
49200
49228
  }
49201
49229
  case "INSERT_CELL": {
49202
49230
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
49203
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49231
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49204
49232
  state.paste(paste);
49205
49233
  break;
49206
49234
  }
@@ -49350,8 +49378,8 @@ class ClipboardPlugin extends UIPlugin {
49350
49378
  }
49351
49379
  return { cut: [cut], paste: [paste] };
49352
49380
  }
49353
- getClipboardStateForCopyCells(zones, operation) {
49354
- return new ClipboardCellsState(zones, operation, this.getters, this.dispatch, this.selection);
49381
+ getClipboardStateForCopyCells(zones, operation, mode = "copyPaste") {
49382
+ return new ClipboardCellsState(zones, operation, this.getters, this.dispatch, this.selection, mode);
49355
49383
  }
49356
49384
  /**
49357
49385
  * Get the clipboard state from the given zones.
@@ -50921,7 +50949,7 @@ class GridSelectionPlugin extends UIPlugin {
50921
50949
  bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
50922
50950
  },
50923
50951
  ];
50924
- const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
50952
+ const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection, "shiftCells");
50925
50953
  const base = isBasedBefore ? cmd.base : cmd.base + 1;
50926
50954
  const pasteTarget = [
50927
50955
  {
@@ -58438,6 +58466,6 @@ const constants = {
58438
58466
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
58439
58467
 
58440
58468
 
58441
- __info__.version = "17.0.72";
58442
- __info__.date = "2025-09-05T07:33:34.433Z";
58443
- __info__.hash = "8c68f3d";
58469
+ __info__.version = "17.0.74";
58470
+ __info__.date = "2025-09-19T07:22:25.998Z";
58471
+ __info__.hash = "bf7d9c8";
@@ -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 17.0.72
6
- * @date 2025-09-05T07:33:34.433Z
7
- * @hash 8c68f3d
5
+ * @version 17.0.74
6
+ * @date 2025-09-19T07:22:25.998Z
7
+ * @hash bf7d9c8
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -777,8 +777,19 @@
777
777
  },
778
778
  }[funcName];
779
779
  }
780
+ /**
781
+ * Removes the specified indexes from the array.
782
+ * Sparse (empty) elements are transformed to undefined (unless their index is explicitly removed).
783
+ */
780
784
  function removeIndexesFromArray(array, indexes) {
781
- return array.filter((_, index) => !indexes.includes(index));
785
+ const toRemove = new Set(indexes);
786
+ const newArray = [];
787
+ for (let i = 0; i < array.length; i++) {
788
+ if (!toRemove.has(i)) {
789
+ newArray.push(array[i]);
790
+ }
791
+ }
792
+ return newArray;
782
793
  }
783
794
  function insertItemsAtIndex(array, items, index) {
784
795
  const newArray = [...array];
@@ -15921,8 +15932,9 @@
15921
15932
  }
15922
15933
 
15923
15934
  function sortMatrix(matrix, locale, ...criteria) {
15924
- for (const [i, value] of criteria.entries()) {
15925
- assert(() => value !== undefined, _t("Value for parameter %d is missing, while the function [[FUNCTION_NAME]] expect a number or a range.", i + 1));
15935
+ for (let i = 0; i < criteria.length; i++) {
15936
+ const param = i % 2 === 0 ? "sort_column" : "is_ascending";
15937
+ assert(() => criteria[i] !== undefined, _t("Value for parameter %s is missing in [[FUNCTION_NAME]].", param));
15926
15938
  }
15927
15939
  const sortingOrders = [];
15928
15940
  const sortColumns = [];
@@ -31665,7 +31677,7 @@
31665
31677
  ];
31666
31678
  const SUPPORTED_VERTICAL_ALIGNMENTS = ["top", "center", "bottom"];
31667
31679
  const SUPPORTED_FONTS = ["Arial"];
31668
- const SUPPORTED_FILL_PATTERNS = ["solid"];
31680
+ const SUPPORTED_FILL_PATTERNS = ["solid", "none"];
31669
31681
  const SUPPORTED_CF_TYPES = [
31670
31682
  "expression",
31671
31683
  "cellIs",
@@ -31849,7 +31861,7 @@
31849
31861
  };
31850
31862
  /** Mapping between Excel format indexes (see XLSX_FORMAT_MAP) and some supported formats */
31851
31863
  const XLSX_FORMATS_CONVERSION_MAP = {
31852
- 0: "",
31864
+ 0: "General",
31853
31865
  1: "0",
31854
31866
  2: "0.00",
31855
31867
  3: "#,#00",
@@ -32148,11 +32160,11 @@
32148
32160
  * Excel format are defined in openXML §18.8.31
32149
32161
  */
32150
32162
  function convertXlsxFormat(numFmtId, formats, warningManager) {
32151
- if (numFmtId === 0) {
32152
- return undefined;
32153
- }
32154
32163
  // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
32155
32164
  let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || formats.find((f) => f.id === numFmtId)?.format;
32165
+ if (format === "General") {
32166
+ return undefined;
32167
+ }
32156
32168
  if (format) {
32157
32169
  try {
32158
32170
  let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
@@ -34454,10 +34466,11 @@
34454
34466
  });
34455
34467
  }
34456
34468
  extractRows(worksheet) {
34469
+ const spilledCells = new Set();
34457
34470
  return this.mapOnElements({ parent: worksheet, query: "sheetData row" }, (rowElement) => {
34458
34471
  return {
34459
34472
  index: this.extractAttr(rowElement, "r", { required: true })?.asNum(),
34460
- cells: this.extractCells(rowElement),
34473
+ cells: this.extractCells(rowElement, spilledCells),
34461
34474
  height: this.extractAttr(rowElement, "ht")?.asNum(),
34462
34475
  customHeight: this.extractAttr(rowElement, "customHeight")?.asBool(),
34463
34476
  hidden: this.extractAttr(rowElement, "hidden")?.asBool(),
@@ -34465,14 +34478,26 @@
34465
34478
  };
34466
34479
  });
34467
34480
  }
34468
- extractCells(row) {
34481
+ extractCells(row, spilledCells) {
34469
34482
  return this.mapOnElements({ parent: row, query: "c" }, (cellElement) => {
34483
+ const xc = this.extractAttr(cellElement, "r", { required: true })?.asString();
34484
+ const formula = this.extractCellFormula(cellElement);
34485
+ if (formula?.ref && formula.sharedIndex === undefined) {
34486
+ const zone = toZone(formula.ref);
34487
+ for (const { col, row } of positions(zone)) {
34488
+ const followerXc = toXC(col, row);
34489
+ if (followerXc !== xc) {
34490
+ spilledCells.add(followerXc);
34491
+ }
34492
+ }
34493
+ }
34494
+ const isSpilled = spilledCells.has(xc);
34470
34495
  return {
34471
- xc: this.extractAttr(cellElement, "r", { required: true })?.asString(),
34496
+ xc,
34472
34497
  styleIndex: this.extractAttr(cellElement, "s")?.asNum(),
34473
34498
  type: CELL_TYPE_CONVERSION_MAP[this.extractAttr(cellElement, "t", { default: "n" })?.asString()],
34474
- value: this.extractChildTextContent(cellElement, "v"),
34475
- formula: this.extractCellFormula(cellElement),
34499
+ value: isSpilled ? undefined : this.extractChildTextContent(cellElement, "v") ?? undefined,
34500
+ formula: isSpilled ? undefined : formula,
34476
34501
  };
34477
34502
  });
34478
34503
  }
@@ -34480,11 +34505,14 @@
34480
34505
  const formulaElement = this.querySelector(cellElement, "f");
34481
34506
  if (!formulaElement)
34482
34507
  return undefined;
34483
- return {
34484
- content: this.extractTextContent(formulaElement),
34485
- sharedIndex: this.extractAttr(formulaElement, "si")?.asNum(),
34486
- ref: this.extractAttr(formulaElement, "ref")?.asString(),
34487
- };
34508
+ const content = this.extractTextContent(formulaElement);
34509
+ const sharedIndex = this.extractAttr(formulaElement, "si")?.asNum();
34510
+ const ref = this.extractAttr(formulaElement, "ref")?.asString();
34511
+ // This is the case of spilled cells of array formulas where <f> is empty
34512
+ if ((content === undefined || content.trim() === "") && sharedIndex === undefined) {
34513
+ return undefined;
34514
+ }
34515
+ return { content, sharedIndex, ref };
34488
34516
  }
34489
34517
  extractHyperLinks(worksheet) {
34490
34518
  return this.mapOnElements({ parent: worksheet, query: "hyperlink" }, (linkElement) => {
@@ -45518,7 +45546,7 @@
45518
45546
  queuedBordersToAdd = {};
45519
45547
  queuedCFChanges = {};
45520
45548
  queuedDVChanges = {};
45521
- constructor(zones, operation, getters, dispatch, selection) {
45549
+ constructor(zones, operation, getters, dispatch, selection, mode = "copyPaste") {
45522
45550
  super(operation, getters, dispatch, selection);
45523
45551
  if (!zones.length) {
45524
45552
  this.cells = [[]];
@@ -45548,7 +45576,7 @@
45548
45576
  const spreader = getters.getArrayFormulaSpreadingOn(position);
45549
45577
  let cell = getters.getCell(position);
45550
45578
  const evaluatedCell = getters.getEvaluatedCell(position);
45551
- if (spreader) {
45579
+ if (mode !== "shiftCells" && spreader) {
45552
45580
  const isSpreaderCopied = rowsIndex.includes(spreader.row) && columnsIndex.includes(spreader.col);
45553
45581
  const content = isSpreaderCopied
45554
45582
  ? ""
@@ -49109,12 +49137,12 @@
49109
49137
  }
49110
49138
  case "INSERT_CELL": {
49111
49139
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
49112
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49140
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49113
49141
  return state.isPasteAllowed(paste);
49114
49142
  }
49115
49143
  case "DELETE_CELL": {
49116
49144
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
49117
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49145
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49118
49146
  return state.isPasteAllowed(paste);
49119
49147
  }
49120
49148
  case "ACTIVATE_PAINT_FORMAT": {
@@ -49195,13 +49223,13 @@
49195
49223
  });
49196
49224
  break;
49197
49225
  }
49198
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49226
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49199
49227
  state.paste(paste);
49200
49228
  break;
49201
49229
  }
49202
49230
  case "INSERT_CELL": {
49203
49231
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
49204
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49232
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49205
49233
  state.paste(paste);
49206
49234
  break;
49207
49235
  }
@@ -49351,8 +49379,8 @@
49351
49379
  }
49352
49380
  return { cut: [cut], paste: [paste] };
49353
49381
  }
49354
- getClipboardStateForCopyCells(zones, operation) {
49355
- return new ClipboardCellsState(zones, operation, this.getters, this.dispatch, this.selection);
49382
+ getClipboardStateForCopyCells(zones, operation, mode = "copyPaste") {
49383
+ return new ClipboardCellsState(zones, operation, this.getters, this.dispatch, this.selection, mode);
49356
49384
  }
49357
49385
  /**
49358
49386
  * Get the clipboard state from the given zones.
@@ -50922,7 +50950,7 @@
50922
50950
  bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
50923
50951
  },
50924
50952
  ];
50925
- const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
50953
+ const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection, "shiftCells");
50926
50954
  const base = isBasedBefore ? cmd.base : cmd.base + 1;
50927
50955
  const pasteTarget = [
50928
50956
  {
@@ -58474,9 +58502,9 @@
58474
58502
  exports.tokenize = tokenize;
58475
58503
 
58476
58504
 
58477
- __info__.version = "17.0.72";
58478
- __info__.date = "2025-09-05T07:33:34.433Z";
58479
- __info__.hash = "8c68f3d";
58505
+ __info__.version = "17.0.74";
58506
+ __info__.date = "2025-09-19T07:22:25.998Z";
58507
+ __info__.hash = "bf7d9c8";
58480
58508
 
58481
58509
 
58482
58510
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);