@odoo/o-spreadsheet 18.0.18 → 18.0.20

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.0.18
6
- * @date 2025-03-07T10:38:36.883Z
7
- * @hash 06c9bc5
5
+ * @version 18.0.20
6
+ * @date 2025-03-19T08:21:32.426Z
7
+ * @hash 3f48d8b
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -420,7 +420,6 @@
420
420
  * Sparse arrays remain sparse.
421
421
  */
422
422
  function deepCopy(obj) {
423
- const result = Array.isArray(obj) ? [] : {};
424
423
  switch (typeof obj) {
425
424
  case "object": {
426
425
  if (obj === null) {
@@ -432,8 +431,18 @@
432
431
  else if (!(isPlainObject(obj) || obj instanceof Array)) {
433
432
  throw new Error("Unsupported type: only objects and arrays are supported");
434
433
  }
435
- for (const key in obj) {
436
- result[key] = deepCopy(obj[key]);
434
+ const result = Array.isArray(obj) ? new Array(obj.length) : {};
435
+ if (Array.isArray(obj)) {
436
+ for (let i = 0, len = obj.length; i < len; i++) {
437
+ if (i in obj) {
438
+ result[i] = deepCopy(obj[i]);
439
+ }
440
+ }
441
+ }
442
+ else {
443
+ for (const key in obj) {
444
+ result[key] = deepCopy(obj[key]);
445
+ }
437
446
  }
438
447
  return result;
439
448
  }
@@ -2535,21 +2544,30 @@
2535
2544
  return mergedZones;
2536
2545
  }
2537
2546
 
2547
+ const globalReverseLookup$1 = new WeakMap();
2548
+ const globalIdCounter = new WeakMap();
2538
2549
  /**
2539
2550
  * Get the id of the given item (its key in the given dictionary).
2540
2551
  * If the given item does not exist in the dictionary, it creates one with a new id.
2541
2552
  */
2542
2553
  function getItemId(item, itemsDic) {
2543
- for (const key in itemsDic) {
2544
- if (deepEquals(itemsDic[key], item)) {
2545
- return parseInt(key, 10);
2546
- }
2554
+ if (!globalReverseLookup$1.has(itemsDic)) {
2555
+ globalReverseLookup$1.set(itemsDic, new Map());
2556
+ globalIdCounter.set(itemsDic, 0);
2557
+ }
2558
+ const reverseLookup = globalReverseLookup$1.get(itemsDic);
2559
+ const canonical = getCanonicalRepresentation(item);
2560
+ if (reverseLookup.has(canonical)) {
2561
+ const id = reverseLookup.get(canonical);
2562
+ itemsDic[id] = item;
2563
+ return id;
2547
2564
  }
2548
2565
  // Generate new Id if the item didn't exist in the dictionary
2549
- const ids = Object.keys(itemsDic);
2550
- const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
2551
- itemsDic[maxId + 1] = item;
2552
- return maxId + 1;
2566
+ const newId = globalIdCounter.get(itemsDic) + 1;
2567
+ reverseLookup.set(canonical, newId);
2568
+ globalIdCounter.set(itemsDic, newId);
2569
+ itemsDic[newId] = item;
2570
+ return newId;
2553
2571
  }
2554
2572
  function groupItemIdsByZones(positionsByItemId) {
2555
2573
  const result = {};
@@ -2561,6 +2579,33 @@
2561
2579
  }
2562
2580
  return result;
2563
2581
  }
2582
+ function getCanonicalRepresentation(item) {
2583
+ if (item === null)
2584
+ return "null";
2585
+ if (item === undefined)
2586
+ return "undefined";
2587
+ if (typeof item !== "object")
2588
+ return String(item);
2589
+ if (Array.isArray(item)) {
2590
+ const len = item.length;
2591
+ let result = "[";
2592
+ for (let i = 0; i < len; i++) {
2593
+ if (i > 0)
2594
+ result += ",";
2595
+ result += getCanonicalRepresentation(item[i]);
2596
+ }
2597
+ return result + "]";
2598
+ }
2599
+ const keys = Object.keys(item).sort();
2600
+ let repr = "{";
2601
+ for (const key of keys) {
2602
+ if (item[key] !== undefined) {
2603
+ repr += `"${key}":${getCanonicalRepresentation(item[key])},`;
2604
+ }
2605
+ }
2606
+ repr += "}";
2607
+ return repr;
2608
+ }
2564
2609
 
2565
2610
  // -----------------------------------------------------------------------------
2566
2611
  // Date Type
@@ -6063,11 +6108,13 @@
6063
6108
  if (!cell || (!cell.isFormula && !cell.content)) {
6064
6109
  return DEFAULT_CELL_HEIGHT;
6065
6110
  }
6066
- const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
6067
- const numberOfLines = cell.isFormula
6068
- ? 1
6069
- : splitTextToWidth(ctx, cell.content, cell.style, maxWidth).length;
6070
- const fontSize = computeTextFontSizeInPixels(cell.style);
6111
+ const content = cell.isFormula ? "" : cell.content;
6112
+ return getCellContentHeight(ctx, content, cell.style, colSize);
6113
+ }
6114
+ function getCellContentHeight(ctx, content, style, colSize) {
6115
+ const maxWidth = style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
6116
+ const numberOfLines = splitTextToWidth(ctx, content, style, maxWidth).length;
6117
+ const fontSize = computeTextFontSizeInPixels(style);
6071
6118
  return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
6072
6119
  }
6073
6120
  function getDefaultContextFont(fontSize, bold = false, italic = false) {
@@ -8230,13 +8277,6 @@
8230
8277
  this.clearClippedZones(content);
8231
8278
  const selection = target[0];
8232
8279
  this.pasteZone(sheetId, selection.left, selection.top, content.cells, options);
8233
- this.dispatch("MOVE_RANGES", {
8234
- target: content.zones,
8235
- sheetId: content.sheetId,
8236
- targetSheetId: sheetId,
8237
- col: selection.left,
8238
- row: selection.top,
8239
- });
8240
8280
  }
8241
8281
  /**
8242
8282
  * Clear the clipped zones: remove the cells and clear the formatting
@@ -8745,14 +8785,15 @@
8745
8785
  }
8746
8786
  merges.push(mergesInRow);
8747
8787
  }
8748
- return { merges };
8788
+ return { merges, sheetId };
8749
8789
  }
8750
8790
  /**
8751
8791
  * Paste the clipboard content in the given target
8752
8792
  */
8753
8793
  paste(target, content, options) {
8754
8794
  if (options.isCutOperation) {
8755
- return;
8795
+ const copiedMerges = content.merges.flat().filter(isDefined);
8796
+ this.dispatch("REMOVE_MERGE", { sheetId: content.sheetId, target: copiedMerges });
8756
8797
  }
8757
8798
  this.pasteFromCopy(target.sheetId, target.zones, content.merges, options);
8758
8799
  }
@@ -8787,6 +8828,27 @@
8787
8828
  }
8788
8829
  }
8789
8830
 
8831
+ class ReferenceClipboardHandler extends AbstractCellClipboardHandler {
8832
+ copy(data) {
8833
+ return {
8834
+ zones: data.clippedZones,
8835
+ sheetId: data.sheetId,
8836
+ };
8837
+ }
8838
+ paste(target, content, options) {
8839
+ if (options.isCutOperation) {
8840
+ const selection = target.zones[0];
8841
+ this.dispatch("MOVE_RANGES", {
8842
+ target: content.zones,
8843
+ sheetId: content.sheetId,
8844
+ targetSheetId: target.sheetId,
8845
+ col: selection.left,
8846
+ row: selection.top,
8847
+ });
8848
+ }
8849
+ }
8850
+ }
8851
+
8790
8852
  class SheetClipboardHandler extends AbstractCellClipboardHandler {
8791
8853
  isPasteAllowed(sheetId, target, content, options) {
8792
8854
  if (!("cells" in content)) {
@@ -8954,7 +9016,8 @@
8954
9016
  .add("merge", MergeClipboardHandler)
8955
9017
  .add("border", BorderClipboardHandler)
8956
9018
  .add("table", TableClipboardHandler)
8957
- .add("conditionalFormat", ConditionalFormatClipboardHandler);
9019
+ .add("conditionalFormat", ConditionalFormatClipboardHandler)
9020
+ .add("references", ReferenceClipboardHandler);
8958
9021
 
8959
9022
  function transformZone(zone, executed) {
8960
9023
  if (executed.type === "REMOVE_COLUMNS_ROWS") {
@@ -11563,16 +11626,25 @@ stores.inject(MyMetaStore, storeInstance);
11563
11626
  }
11564
11627
  return id;
11565
11628
  }
11629
+ const globalReverseLookup = new WeakMap();
11566
11630
  function pushElement(property, propertyList) {
11567
- let len = propertyList.length;
11568
- const operator = typeof property === "object" ? deepEquals : (a, b) => a === b;
11569
- for (let i = 0; i < len; i++) {
11570
- if (operator(property, propertyList[i])) {
11571
- return i;
11631
+ let reverseLookup = globalReverseLookup.get(propertyList);
11632
+ if (!reverseLookup) {
11633
+ reverseLookup = new Map();
11634
+ for (let i = 0; i < propertyList.length; i++) {
11635
+ const canonical = getCanonicalRepresentation(propertyList[i]);
11636
+ reverseLookup.set(canonical, i);
11572
11637
  }
11638
+ globalReverseLookup.set(propertyList, reverseLookup);
11639
+ }
11640
+ const canonical = getCanonicalRepresentation(property);
11641
+ if (reverseLookup.has(canonical)) {
11642
+ return reverseLookup.get(canonical);
11573
11643
  }
11574
- propertyList[propertyList.length] = property;
11575
- return propertyList.length - 1;
11644
+ const maxId = propertyList.length;
11645
+ propertyList.push(property);
11646
+ reverseLookup.set(canonical, maxId);
11647
+ return maxId;
11576
11648
  }
11577
11649
  const chartIds = [];
11578
11650
  /**
@@ -13425,7 +13497,7 @@ stores.inject(MyMetaStore, storeInstance);
13425
13497
  title: { text: chartTitle },
13426
13498
  type: CHART_TYPE_CONVERSION_MAP[chartType],
13427
13499
  dataSets: this.extractChartDatasets(this.querySelectorAll(rootChartElement, `c:${chartType}`), chartType),
13428
- labelRange: this.extractChildTextContent(rootChartElement, `c:ser ${chartType === "scatterChart" ? "c:numRef" : "c:cat"} c:f`),
13500
+ labelRange: this.extractLabelRange(chartType, rootChartElement),
13429
13501
  backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
13430
13502
  default: "ffffff",
13431
13503
  }).asString(),
@@ -13437,6 +13509,13 @@ stores.inject(MyMetaStore, storeInstance);
13437
13509
  };
13438
13510
  })[0];
13439
13511
  }
13512
+ extractLabelRange(chartType, rootChartElement) {
13513
+ if (chartType === "scatterChart") {
13514
+ return (this.extractChildTextContent(rootChartElement, `c:ser c:strRef c:f`) ||
13515
+ this.extractChildTextContent(rootChartElement, `c:ser c:numRef c:f`));
13516
+ }
13517
+ return this.extractChildTextContent(rootChartElement, `c:ser c:cat c:f`);
13518
+ }
13440
13519
  extractComboChart(chartElement) {
13441
13520
  // Title can be separated into multiple xml elements (for styling and such), we only import the text
13442
13521
  const chartTitle = this.mapOnElements({ parent: chartElement, query: "c:title a:t" }, (textElement) => {
@@ -16898,6 +16977,7 @@ stores.inject(MyMetaStore, storeInstance);
16898
16977
  const autoCompleteProviders = new Registry();
16899
16978
 
16900
16979
  autoCompleteProviders.add("dataValidation", {
16980
+ displayAllOnInitialContent: true,
16901
16981
  getProposals(tokenAtCursor, content) {
16902
16982
  if (content.startsWith("=")) {
16903
16983
  return [];
@@ -28374,7 +28454,7 @@ stores.inject(MyMetaStore, storeInstance);
28374
28454
  text,
28375
28455
  description: usedLabel,
28376
28456
  htmlContent: [{ value: text, color }],
28377
- fuzzySearchKey: value + usedLabel,
28457
+ fuzzySearchKey: text + usedLabel,
28378
28458
  };
28379
28459
  });
28380
28460
  },
@@ -38777,8 +38857,8 @@ stores.inject(MyMetaStore, storeInstance);
38777
38857
  this.updateRangeColor();
38778
38858
  }
38779
38859
  cancelEdition() {
38780
- this.cancelEditionAndActivateSheet();
38781
38860
  this.resetContent();
38861
+ this.cancelEditionAndActivateSheet();
38782
38862
  }
38783
38863
  setCurrentContent(content, selection) {
38784
38864
  if (selection && !this.isSelectionValid(content.length, selection.start, selection.end)) {
@@ -38794,8 +38874,8 @@ stores.inject(MyMetaStore, storeInstance);
38794
38874
  switch (cmd.type) {
38795
38875
  case "SELECT_FIGURE":
38796
38876
  if (cmd.id) {
38797
- this.cancelEditionAndActivateSheet();
38798
38877
  this.resetContent();
38878
+ this.cancelEditionAndActivateSheet();
38799
38879
  }
38800
38880
  break;
38801
38881
  case "START_CHANGE_HIGHLIGHT":
@@ -39146,6 +39226,15 @@ stores.inject(MyMetaStore, storeInstance);
39146
39226
  const exactMatch = proposals?.find((p) => p.text === tokenAtCursor.value);
39147
39227
  // remove tokens that are likely to be other parts of the formula that slipped in the token if it's a string
39148
39228
  const searchTerm = tokenAtCursor.value.replace(/[ ,\(\)]/g, "");
39229
+ if (this._currentContent === this.initialContent &&
39230
+ provider.displayAllOnInitialContent &&
39231
+ proposals?.length) {
39232
+ return {
39233
+ proposals,
39234
+ selectProposal: provider.selectProposal,
39235
+ autoSelectFirstProposal: provider.autoSelectFirstProposal ?? false,
39236
+ };
39237
+ }
39149
39238
  if (exactMatch && this._currentContent !== this.initialContent) {
39150
39239
  // this means the user has chosen a proposal
39151
39240
  return;
@@ -44681,6 +44770,7 @@ stores.inject(MyMetaStore, storeInstance);
44681
44770
  columns: {},
44682
44771
  });
44683
44772
  setup() {
44773
+ this.updateColumns();
44684
44774
  owl.onWillUpdateProps(() => this.updateColumns());
44685
44775
  }
44686
44776
  toggleHasHeader() {
@@ -46469,8 +46559,8 @@ stores.inject(MyMetaStore, storeInstance);
46469
46559
  const sheetIdExists = !!this.getters.tryGetSheet(this.sheetId);
46470
46560
  if (!sheetIdExists && this.editionMode !== "inactive") {
46471
46561
  this.sheetId = this.getters.getActiveSheetId();
46472
- this.cancelEditionAndActivateSheet();
46473
46562
  this.resetContent();
46563
+ this.cancelEditionAndActivateSheet();
46474
46564
  this.notificationStore.raiseError(CELL_DELETED_MESSAGE);
46475
46565
  }
46476
46566
  break;
@@ -62826,12 +62916,7 @@ stores.inject(MyMetaStore, storeInstance);
62826
62916
  }
62827
62917
  break;
62828
62918
  case "AUTORESIZE_ROWS":
62829
- this.dispatch("RESIZE_COLUMNS_ROWS", {
62830
- elements: cmd.rows,
62831
- dimension: "ROW",
62832
- size: null,
62833
- sheetId: cmd.sheetId,
62834
- });
62919
+ this.autoResizeRows(cmd.sheetId, cmd.rows);
62835
62920
  break;
62836
62921
  }
62837
62922
  }
@@ -62996,6 +63081,48 @@ stores.inject(MyMetaStore, storeInstance);
62996
63081
  }
62997
63082
  return "Success" /* CommandResult.Success */;
62998
63083
  }
63084
+ autoResizeRows(sheetId, rows) {
63085
+ const rowSizes = [];
63086
+ for (const row of rows) {
63087
+ let evaluatedRowSize = 0;
63088
+ for (const cellId of this.getters.getRowCells(sheetId, row)) {
63089
+ const cell = this.getters.getCellById(cellId);
63090
+ if (!cell) {
63091
+ continue;
63092
+ }
63093
+ const position = this.getters.getCellPosition(cell.id);
63094
+ const colSize = this.getters.getColSize(sheetId, position.col);
63095
+ if (cell.isFormula) {
63096
+ const content = this.getters.getEvaluatedCell(position).formattedValue;
63097
+ const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
63098
+ if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
63099
+ evaluatedRowSize = evaluatedSize;
63100
+ }
63101
+ }
63102
+ else {
63103
+ const content = cell.content;
63104
+ const dynamicRowSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
63105
+ // Only keep the size of evaluated cells if it's bigger than the dynamic row size
63106
+ if (dynamicRowSize >= evaluatedRowSize && dynamicRowSize > DEFAULT_CELL_HEIGHT) {
63107
+ evaluatedRowSize = 0;
63108
+ }
63109
+ }
63110
+ }
63111
+ rowSizes.push(evaluatedRowSize || null);
63112
+ }
63113
+ const groupedSizes = new Map(rowSizes.map((size) => [size, []]));
63114
+ for (let i = 0; i < rowSizes.length; i++) {
63115
+ groupedSizes.get(rowSizes[i])?.push(rows[i]);
63116
+ }
63117
+ for (const [size, rows] of groupedSizes) {
63118
+ this.dispatch("RESIZE_COLUMNS_ROWS", {
63119
+ elements: rows,
63120
+ dimension: "ROW",
63121
+ size,
63122
+ sheetId,
63123
+ });
63124
+ }
63125
+ }
62999
63126
  }
63000
63127
 
63001
63128
  class TableComputedStylePlugin extends UIPlugin {
@@ -72015,7 +72142,7 @@ stores.inject(MyMetaStore, storeInstance);
72015
72142
  }
72016
72143
  if (alignAttrs.length > 0) {
72017
72144
  attributes.push(["applyAlignment", "1"]); // for Libre Office
72018
- styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}>${escapeXml /*xml*/ `<alignment ${formatAttributes(alignAttrs)} />`}</xf> `);
72145
+ styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}><alignment ${formatAttributes(alignAttrs)} /></xf> `);
72019
72146
  }
72020
72147
  else {
72021
72148
  styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)} />`);
@@ -73479,9 +73606,9 @@ stores.inject(MyMetaStore, storeInstance);
73479
73606
  exports.tokenize = tokenize;
73480
73607
 
73481
73608
 
73482
- __info__.version = "18.0.18";
73483
- __info__.date = "2025-03-07T10:38:36.883Z";
73484
- __info__.hash = "06c9bc5";
73609
+ __info__.version = "18.0.20";
73610
+ __info__.date = "2025-03-19T08:21:32.426Z";
73611
+ __info__.hash = "3f48d8b";
73485
73612
 
73486
73613
 
73487
73614
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);