@odoo/o-spreadsheet 18.2.2 → 18.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 18.2.2
6
- * @date 2025-03-07T10:41:04.411Z
7
- * @hash f567932
5
+ * @version 18.2.4
6
+ * @date 2025-03-19T08:20:57.717Z
7
+ * @hash 958936a
8
8
  */
9
9
 
10
10
  'use strict';
@@ -425,7 +425,6 @@ function escapeRegExp(str) {
425
425
  * Sparse arrays remain sparse.
426
426
  */
427
427
  function deepCopy(obj) {
428
- const result = Array.isArray(obj) ? [] : {};
429
428
  switch (typeof obj) {
430
429
  case "object": {
431
430
  if (obj === null) {
@@ -437,8 +436,18 @@ function deepCopy(obj) {
437
436
  else if (!(isPlainObject(obj) || obj instanceof Array)) {
438
437
  throw new Error("Unsupported type: only objects and arrays are supported");
439
438
  }
440
- for (const key in obj) {
441
- result[key] = deepCopy(obj[key]);
439
+ const result = Array.isArray(obj) ? new Array(obj.length) : {};
440
+ if (Array.isArray(obj)) {
441
+ for (let i = 0, len = obj.length; i < len; i++) {
442
+ if (i in obj) {
443
+ result[i] = deepCopy(obj[i]);
444
+ }
445
+ }
446
+ }
447
+ else {
448
+ for (const key in obj) {
449
+ result[key] = deepCopy(obj[key]);
450
+ }
442
451
  }
443
452
  return result;
444
453
  }
@@ -2701,21 +2710,30 @@ function mergeContiguousZones(zones) {
2701
2710
  return mergedZones;
2702
2711
  }
2703
2712
 
2713
+ const globalReverseLookup$1 = new WeakMap();
2714
+ const globalIdCounter = new WeakMap();
2704
2715
  /**
2705
2716
  * Get the id of the given item (its key in the given dictionary).
2706
2717
  * If the given item does not exist in the dictionary, it creates one with a new id.
2707
2718
  */
2708
2719
  function getItemId(item, itemsDic) {
2709
- for (const key in itemsDic) {
2710
- if (deepEquals(itemsDic[key], item)) {
2711
- return parseInt(key, 10);
2712
- }
2720
+ if (!globalReverseLookup$1.has(itemsDic)) {
2721
+ globalReverseLookup$1.set(itemsDic, new Map());
2722
+ globalIdCounter.set(itemsDic, 0);
2723
+ }
2724
+ const reverseLookup = globalReverseLookup$1.get(itemsDic);
2725
+ const canonical = getCanonicalRepresentation(item);
2726
+ if (reverseLookup.has(canonical)) {
2727
+ const id = reverseLookup.get(canonical);
2728
+ itemsDic[id] = item;
2729
+ return id;
2713
2730
  }
2714
2731
  // Generate new Id if the item didn't exist in the dictionary
2715
- const ids = Object.keys(itemsDic);
2716
- const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
2717
- itemsDic[maxId + 1] = item;
2718
- return maxId + 1;
2732
+ const newId = globalIdCounter.get(itemsDic) + 1;
2733
+ reverseLookup.set(canonical, newId);
2734
+ globalIdCounter.set(itemsDic, newId);
2735
+ itemsDic[newId] = item;
2736
+ return newId;
2719
2737
  }
2720
2738
  function groupItemIdsByZones(positionsByItemId) {
2721
2739
  const result = {};
@@ -2739,6 +2757,33 @@ function* iterateItemIdsPositions(sheetId, itemIdsByZones) {
2739
2757
  }
2740
2758
  }
2741
2759
  }
2760
+ function getCanonicalRepresentation(item) {
2761
+ if (item === null)
2762
+ return "null";
2763
+ if (item === undefined)
2764
+ return "undefined";
2765
+ if (typeof item !== "object")
2766
+ return String(item);
2767
+ if (Array.isArray(item)) {
2768
+ const len = item.length;
2769
+ let result = "[";
2770
+ for (let i = 0; i < len; i++) {
2771
+ if (i > 0)
2772
+ result += ",";
2773
+ result += getCanonicalRepresentation(item[i]);
2774
+ }
2775
+ return result + "]";
2776
+ }
2777
+ const keys = Object.keys(item).sort();
2778
+ let repr = "{";
2779
+ for (const key of keys) {
2780
+ if (item[key] !== undefined) {
2781
+ repr += `"${key}":${getCanonicalRepresentation(item[key])},`;
2782
+ }
2783
+ }
2784
+ repr += "}";
2785
+ return repr;
2786
+ }
2742
2787
 
2743
2788
  // -----------------------------------------------------------------------------
2744
2789
  // Date Type
@@ -6242,11 +6287,13 @@ function getDefaultCellHeight(ctx, cell, colSize) {
6242
6287
  if (!cell || (!cell.isFormula && !cell.content)) {
6243
6288
  return DEFAULT_CELL_HEIGHT;
6244
6289
  }
6245
- const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
6246
- const numberOfLines = cell.isFormula
6247
- ? 1
6248
- : splitTextToWidth(ctx, cell.content, cell.style, maxWidth).length;
6249
- const fontSize = computeTextFontSizeInPixels(cell.style);
6290
+ const content = cell.isFormula ? "" : cell.content;
6291
+ return getCellContentHeight(ctx, content, cell.style, colSize);
6292
+ }
6293
+ function getCellContentHeight(ctx, content, style, colSize) {
6294
+ const maxWidth = style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
6295
+ const numberOfLines = splitTextToWidth(ctx, content, style, maxWidth).length;
6296
+ const fontSize = computeTextFontSizeInPixels(style);
6250
6297
  return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
6251
6298
  }
6252
6299
  function getDefaultContextFont(fontSize, bold = false, italic = false) {
@@ -8291,7 +8338,8 @@ function isSortedColumnValid(sortedColumn, pivot) {
8291
8338
  const possibleValues = pivot
8292
8339
  .getPossibleFieldValues(columns[i])
8293
8340
  .map((v) => v.value);
8294
- if (!possibleValues.includes(sortedColumn.domain[i].value)) {
8341
+ if (!possibleValues.includes(sortedColumn.domain[i].value) &&
8342
+ !(sortedColumn.domain[i].value === null && possibleValues.includes(""))) {
8295
8343
  return false;
8296
8344
  }
8297
8345
  }
@@ -8442,13 +8490,6 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
8442
8490
  this.clearClippedZones(content);
8443
8491
  const selection = target[0];
8444
8492
  this.pasteZone(sheetId, selection.left, selection.top, content.cells, options);
8445
- this.dispatch("MOVE_RANGES", {
8446
- target: content.zones,
8447
- sheetId: content.sheetId,
8448
- targetSheetId: sheetId,
8449
- col: selection.left,
8450
- row: selection.top,
8451
- });
8452
8493
  }
8453
8494
  /**
8454
8495
  * Clear the clipped zones: remove the cells and clear the formatting
@@ -8957,14 +8998,15 @@ class MergeClipboardHandler extends AbstractCellClipboardHandler {
8957
8998
  }
8958
8999
  merges.push(mergesInRow);
8959
9000
  }
8960
- return { merges };
9001
+ return { merges, sheetId };
8961
9002
  }
8962
9003
  /**
8963
9004
  * Paste the clipboard content in the given target
8964
9005
  */
8965
9006
  paste(target, content, options) {
8966
9007
  if (options.isCutOperation) {
8967
- return;
9008
+ const copiedMerges = content.merges.flat().filter(isDefined);
9009
+ this.dispatch("REMOVE_MERGE", { sheetId: content.sheetId, target: copiedMerges });
8968
9010
  }
8969
9011
  this.pasteFromCopy(target.sheetId, target.zones, content.merges, options);
8970
9012
  }
@@ -8999,6 +9041,27 @@ class MergeClipboardHandler extends AbstractCellClipboardHandler {
8999
9041
  }
9000
9042
  }
9001
9043
 
9044
+ class ReferenceClipboardHandler extends AbstractCellClipboardHandler {
9045
+ copy(data) {
9046
+ return {
9047
+ zones: data.clippedZones,
9048
+ sheetId: data.sheetId,
9049
+ };
9050
+ }
9051
+ paste(target, content, options) {
9052
+ if (options.isCutOperation) {
9053
+ const selection = target.zones[0];
9054
+ this.dispatch("MOVE_RANGES", {
9055
+ target: content.zones,
9056
+ sheetId: content.sheetId,
9057
+ targetSheetId: target.sheetId,
9058
+ col: selection.left,
9059
+ row: selection.top,
9060
+ });
9061
+ }
9062
+ }
9063
+ }
9064
+
9002
9065
  class SheetClipboardHandler extends AbstractCellClipboardHandler {
9003
9066
  isPasteAllowed(sheetId, target, content, options) {
9004
9067
  if (!("cells" in content)) {
@@ -9162,7 +9225,8 @@ clipboardHandlersRegistries.cellHandlers
9162
9225
  .add("merge", MergeClipboardHandler)
9163
9226
  .add("border", BorderClipboardHandler)
9164
9227
  .add("table", TableClipboardHandler)
9165
- .add("conditionalFormat", ConditionalFormatClipboardHandler);
9228
+ .add("conditionalFormat", ConditionalFormatClipboardHandler)
9229
+ .add("references", ReferenceClipboardHandler);
9166
9230
 
9167
9231
  function transformZone(zone, executed) {
9168
9232
  if (executed.type === "REMOVE_COLUMNS_ROWS") {
@@ -11320,6 +11384,7 @@ class ScorecardChart extends owl.Component {
11320
11384
  const autoCompleteProviders = new Registry();
11321
11385
 
11322
11386
  autoCompleteProviders.add("dataValidation", {
11387
+ displayAllOnInitialContent: true,
11323
11388
  getProposals(tokenAtCursor, content) {
11324
11389
  if (content.startsWith("=")) {
11325
11390
  return [];
@@ -21112,8 +21177,8 @@ class AbstractComposerStore extends SpreadsheetStore {
21112
21177
  this.computeParenthesisRelatedToCursor();
21113
21178
  }
21114
21179
  cancelEdition() {
21115
- this.cancelEditionAndActivateSheet();
21116
21180
  this.resetContent();
21181
+ this.cancelEditionAndActivateSheet();
21117
21182
  }
21118
21183
  setCurrentContent(content, selection) {
21119
21184
  if (selection && !this.isSelectionValid(content.length, selection.start, selection.end)) {
@@ -21131,8 +21196,8 @@ class AbstractComposerStore extends SpreadsheetStore {
21131
21196
  switch (cmd.type) {
21132
21197
  case "SELECT_FIGURE":
21133
21198
  if (cmd.id) {
21134
- this.cancelEditionAndActivateSheet();
21135
21199
  this.resetContent();
21200
+ this.cancelEditionAndActivateSheet();
21136
21201
  }
21137
21202
  break;
21138
21203
  case "START_CHANGE_HIGHLIGHT":
@@ -21616,6 +21681,15 @@ class AbstractComposerStore extends SpreadsheetStore {
21616
21681
  const exactMatch = proposals?.find((p) => p.text === tokenAtCursor.value);
21617
21682
  // remove tokens that are likely to be other parts of the formula that slipped in the token if it's a string
21618
21683
  const searchTerm = tokenAtCursor.value.replace(/[ ,\(\)]/g, "");
21684
+ if (this._currentContent === this.initialContent &&
21685
+ provider.displayAllOnInitialContent &&
21686
+ proposals?.length) {
21687
+ return {
21688
+ proposals,
21689
+ selectProposal: provider.selectProposal,
21690
+ autoSelectFirstProposal: provider.autoSelectFirstProposal ?? false,
21691
+ };
21692
+ }
21619
21693
  if (exactMatch && this._currentContent !== this.initialContent) {
21620
21694
  // this means the user has chosen a proposal
21621
21695
  return;
@@ -22439,7 +22513,7 @@ autoCompleteProviders.add("pivot_group_values", {
22439
22513
  text,
22440
22514
  description: usedLabel,
22441
22515
  htmlContent: [{ value: text, color }],
22442
- fuzzySearchKey: value + usedLabel,
22516
+ fuzzySearchKey: text + usedLabel,
22443
22517
  };
22444
22518
  });
22445
22519
  },
@@ -24361,16 +24435,25 @@ function addRelsToFile(relsFiles, path, rel) {
24361
24435
  }
24362
24436
  return id;
24363
24437
  }
24438
+ const globalReverseLookup = new WeakMap();
24364
24439
  function pushElement(property, propertyList) {
24365
- let len = propertyList.length;
24366
- const operator = typeof property === "object" ? deepEquals : (a, b) => a === b;
24367
- for (let i = 0; i < len; i++) {
24368
- if (operator(property, propertyList[i])) {
24369
- return i;
24440
+ let reverseLookup = globalReverseLookup.get(propertyList);
24441
+ if (!reverseLookup) {
24442
+ reverseLookup = new Map();
24443
+ for (let i = 0; i < propertyList.length; i++) {
24444
+ const canonical = getCanonicalRepresentation(propertyList[i]);
24445
+ reverseLookup.set(canonical, i);
24370
24446
  }
24447
+ globalReverseLookup.set(propertyList, reverseLookup);
24371
24448
  }
24372
- propertyList[propertyList.length] = property;
24373
- return propertyList.length - 1;
24449
+ const canonical = getCanonicalRepresentation(property);
24450
+ if (reverseLookup.has(canonical)) {
24451
+ return reverseLookup.get(canonical);
24452
+ }
24453
+ const maxId = propertyList.length;
24454
+ propertyList.push(property);
24455
+ reverseLookup.set(canonical, maxId);
24456
+ return maxId;
24374
24457
  }
24375
24458
  const chartIds = [];
24376
24459
  /**
@@ -26217,7 +26300,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
26217
26300
  title: { text: chartTitle },
26218
26301
  type: CHART_TYPE_CONVERSION_MAP[chartType],
26219
26302
  dataSets: this.extractChartDatasets(this.querySelectorAll(rootChartElement, `c:${chartType}`), chartType),
26220
- labelRange: this.extractChildTextContent(rootChartElement, `c:ser ${chartType === "scatterChart" ? "c:numRef" : "c:cat"} c:f`),
26303
+ labelRange: this.extractLabelRange(chartType, rootChartElement),
26221
26304
  backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
26222
26305
  default: "ffffff",
26223
26306
  }).asString(),
@@ -26229,6 +26312,13 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
26229
26312
  };
26230
26313
  })[0];
26231
26314
  }
26315
+ extractLabelRange(chartType, rootChartElement) {
26316
+ if (chartType === "scatterChart") {
26317
+ return (this.extractChildTextContent(rootChartElement, `c:ser c:strRef c:f`) ||
26318
+ this.extractChildTextContent(rootChartElement, `c:ser c:numRef c:f`));
26319
+ }
26320
+ return this.extractChildTextContent(rootChartElement, `c:ser c:cat c:f`);
26321
+ }
26232
26322
  extractComboChart(chartElement) {
26233
26323
  // Title can be separated into multiple xml elements (for styling and such), we only import the text
26234
26324
  const chartTitle = this.mapOnElements({ parent: chartElement, query: "c:title a:t" }, (textElement) => {
@@ -36401,6 +36491,7 @@ const irregularityMap = {
36401
36491
  fingerprintStore.enable();
36402
36492
  }
36403
36493
  },
36494
+ isReadonlyAllowed: true,
36404
36495
  icon: "o-spreadsheet-Icon.IRREGULARITY_MAP",
36405
36496
  };
36406
36497
  const viewFormulas = {
@@ -47099,6 +47190,7 @@ class RemoveDuplicatesPanel extends owl.Component {
47099
47190
  columns: {},
47100
47191
  });
47101
47192
  setup() {
47193
+ this.updateColumns();
47102
47194
  owl.onWillUpdateProps(() => this.updateColumns());
47103
47195
  }
47104
47196
  toggleHasHeader() {
@@ -48882,8 +48974,8 @@ class CellComposerStore extends AbstractComposerStore {
48882
48974
  const sheetIdExists = !!this.getters.tryGetSheet(this.sheetId);
48883
48975
  if (!sheetIdExists && this.editionMode !== "inactive") {
48884
48976
  this.sheetId = this.getters.getActiveSheetId();
48885
- this.cancelEditionAndActivateSheet();
48886
48977
  this.resetContent();
48978
+ this.cancelEditionAndActivateSheet();
48887
48979
  this.notificationStore.raiseError(CELL_DELETED_MESSAGE);
48888
48980
  }
48889
48981
  break;
@@ -50462,6 +50554,71 @@ class GridPopover extends owl.Component {
50462
50554
  }
50463
50555
  }
50464
50556
 
50557
+ class UnhideRowHeaders extends owl.Component {
50558
+ static template = "o-spreadsheet-UnhideRowHeaders";
50559
+ static props = {
50560
+ headersGroups: Array,
50561
+ headerRange: Object,
50562
+ offset: { type: Number, optional: true },
50563
+ };
50564
+ static defaultProps = { offset: 0 };
50565
+ get sheetId() {
50566
+ return this.env.model.getters.getActiveSheetId();
50567
+ }
50568
+ getUnhidePreviousButtonStyle(hiddenIndex) {
50569
+ const rect = this.env.model.getters.getRect(positionToZone({ col: 0, row: hiddenIndex }));
50570
+ const y = rect.y + rect.height - HEADER_HEIGHT;
50571
+ return cssPropertiesToCss({ top: y - this.props.offset + "px", "margin-right": "1px" });
50572
+ }
50573
+ getUnhideNextButtonStyle(hiddenIndex) {
50574
+ const rect = this.env.model.getters.getRect(positionToZone({ col: 0, row: hiddenIndex }));
50575
+ const y = rect.y - HEADER_HEIGHT;
50576
+ return cssPropertiesToCss({ top: y - this.props.offset + "px", "margin-right": "1px" });
50577
+ }
50578
+ unhide(hiddenElements) {
50579
+ this.env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
50580
+ sheetId: this.sheetId,
50581
+ dimension: "ROW",
50582
+ elements: hiddenElements,
50583
+ });
50584
+ }
50585
+ isVisible(header) {
50586
+ return header >= this.props.headerRange.start && header <= this.props.headerRange.end;
50587
+ }
50588
+ }
50589
+ class UnhideColumnHeaders extends owl.Component {
50590
+ static template = "o-spreadsheet-UnhideColumnHeaders";
50591
+ static props = {
50592
+ headersGroups: Array,
50593
+ headerRange: Object,
50594
+ offset: { type: Number, optional: true },
50595
+ };
50596
+ static defaultProps = { offset: 0 };
50597
+ get sheetId() {
50598
+ return this.env.model.getters.getActiveSheetId();
50599
+ }
50600
+ getUnhidePreviousButtonStyle(hiddenIndex) {
50601
+ const rect = this.env.model.getters.getRect(positionToZone({ col: hiddenIndex, row: 0 }));
50602
+ const x = rect.x + rect.width - HEADER_WIDTH;
50603
+ return cssPropertiesToCss({ left: x - this.props.offset + "px" });
50604
+ }
50605
+ getUnhideNextButtonStyle(hiddenIndex) {
50606
+ const rect = this.env.model.getters.getRect(positionToZone({ col: hiddenIndex, row: 0 }));
50607
+ const x = rect.x - HEADER_WIDTH;
50608
+ return cssPropertiesToCss({ left: x - this.props.offset + "px" });
50609
+ }
50610
+ unhide(hiddenElements) {
50611
+ this.env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
50612
+ sheetId: this.sheetId,
50613
+ dimension: "COL",
50614
+ elements: hiddenElements,
50615
+ });
50616
+ }
50617
+ isVisible(header) {
50618
+ return header >= this.props.headerRange.start && header <= this.props.headerRange.end;
50619
+ }
50620
+ }
50621
+
50465
50622
  class AbstractResizer extends owl.Component {
50466
50623
  static props = {
50467
50624
  onOpenContextMenu: Function,
@@ -50680,6 +50837,7 @@ css /* scss */ `
50680
50837
  left: ${HEADER_WIDTH}px;
50681
50838
  right: 0;
50682
50839
  height: ${HEADER_HEIGHT}px;
50840
+ width: calc(100% - ${HEADER_WIDTH + SCROLLBAR_WIDTH}px);
50683
50841
  &.o-dragging {
50684
50842
  cursor: grabbing;
50685
50843
  }
@@ -50729,6 +50887,7 @@ class ColResizer extends AbstractResizer {
50729
50887
  onOpenContextMenu: Function,
50730
50888
  };
50731
50889
  static template = "o-spreadsheet-ColResizer";
50890
+ static components = { UnhideColumnHeaders };
50732
50891
  colResizerRef;
50733
50892
  setup() {
50734
50893
  super.setup();
@@ -50737,6 +50896,9 @@ class ColResizer extends AbstractResizer {
50737
50896
  this.MAX_SIZE_MARGIN = 90;
50738
50897
  this.MIN_ELEMENT_SIZE = MIN_COL_WIDTH;
50739
50898
  }
50899
+ get sheetId() {
50900
+ return this.env.model.getters.getActiveSheetId();
50901
+ }
50740
50902
  _getEvOffset(ev) {
50741
50903
  return ev.offsetX;
50742
50904
  }
@@ -50759,10 +50921,10 @@ class ColResizer extends AbstractResizer {
50759
50921
  return this.env.model.getters.getEdgeScrollCol(position, position, position);
50760
50922
  }
50761
50923
  _getDimensionsInViewport(index) {
50762
- return this.env.model.getters.getColDimensionsInViewport(this.env.model.getters.getActiveSheetId(), index);
50924
+ return this.env.model.getters.getColDimensionsInViewport(this.sheetId, index);
50763
50925
  }
50764
50926
  _getElementSize(index) {
50765
- return this.env.model.getters.getColSize(this.env.model.getters.getActiveSheetId(), index);
50927
+ return this.env.model.getters.getColSize(this.sheetId, index);
50766
50928
  }
50767
50929
  _getMaxSize() {
50768
50930
  return this.colResizerRef.el.clientWidth;
@@ -50773,7 +50935,7 @@ class ColResizer extends AbstractResizer {
50773
50935
  const cols = this.env.model.getters.getActiveCols();
50774
50936
  this.env.model.dispatch("RESIZE_COLUMNS_ROWS", {
50775
50937
  dimension: "COL",
50776
- sheetId: this.env.model.getters.getActiveSheetId(),
50938
+ sheetId: this.sheetId,
50777
50939
  elements: cols.has(index) ? [...cols] : [index],
50778
50940
  size,
50779
50941
  });
@@ -50786,7 +50948,7 @@ class ColResizer extends AbstractResizer {
50786
50948
  elements.push(colIndex);
50787
50949
  }
50788
50950
  const result = this.env.model.dispatch("MOVE_COLUMNS_ROWS", {
50789
- sheetId: this.env.model.getters.getActiveSheetId(),
50951
+ sheetId: this.sheetId,
50790
50952
  dimension: "COL",
50791
50953
  base: this.state.base,
50792
50954
  elements,
@@ -50805,7 +50967,7 @@ class ColResizer extends AbstractResizer {
50805
50967
  _fitElementSize(index) {
50806
50968
  const cols = this.env.model.getters.getActiveCols();
50807
50969
  this.env.model.dispatch("AUTORESIZE_COLUMNS", {
50808
- sheetId: this.env.model.getters.getActiveSheetId(),
50970
+ sheetId: this.sheetId,
50809
50971
  cols: cols.has(index) ? [...cols] : [index],
50810
50972
  });
50811
50973
  }
@@ -50816,7 +50978,7 @@ class ColResizer extends AbstractResizer {
50816
50978
  return this.env.model.getters.getActiveCols();
50817
50979
  }
50818
50980
  _getPreviousVisibleElement(index) {
50819
- const sheetId = this.env.model.getters.getActiveSheetId();
50981
+ const sheetId = this.sheetId;
50820
50982
  let row;
50821
50983
  for (row = index - 1; row >= 0; row--) {
50822
50984
  if (!this.env.model.getters.isColHidden(sheetId, row)) {
@@ -50827,13 +50989,38 @@ class ColResizer extends AbstractResizer {
50827
50989
  }
50828
50990
  unhide(hiddenElements) {
50829
50991
  this.env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
50830
- sheetId: this.env.model.getters.getActiveSheetId(),
50992
+ sheetId: this.sheetId,
50831
50993
  elements: hiddenElements,
50832
50994
  dimension: "COL",
50833
50995
  });
50834
50996
  }
50835
- getUnhideButtonStyle(hiddenIndex) {
50836
- return cssPropertiesToCss({ left: this._getDimensionsInViewport(hiddenIndex).start + "px" });
50997
+ get mainUnhideHeadersProps() {
50998
+ const { left, right } = this.env.model.getters.getActiveMainViewport();
50999
+ const { xSplit } = this.env.model.getters.getPaneDivisions(this.sheetId);
51000
+ const hiddenGroups = this.env.model.getters.getHiddenColsGroups(this.sheetId);
51001
+ const index = hiddenGroups.findIndex((group) => group[0] >= xSplit - 1);
51002
+ return {
51003
+ headersGroups: hiddenGroups.slice(index),
51004
+ offset: this.env.model.getters.getMainViewportCoordinates().x,
51005
+ headerRange: { start: left, end: right },
51006
+ };
51007
+ }
51008
+ get frozenUnhideHeadersProps() {
51009
+ const { xSplit } = this.env.model.getters.getPaneDivisions(this.sheetId);
51010
+ const hiddenGroups = this.env.model.getters.getHiddenColsGroups(this.sheetId);
51011
+ const index = hiddenGroups.findIndex((group) => group[0] >= xSplit - 1);
51012
+ return {
51013
+ headersGroups: hiddenGroups.slice(0, index + 1),
51014
+ headerRange: { start: 0, end: xSplit - 1 },
51015
+ };
51016
+ }
51017
+ get frozenContainerStyle() {
51018
+ return cssPropertiesToCss({
51019
+ width: this.env.model.getters.getMainViewportCoordinates().x + "px",
51020
+ });
51021
+ }
51022
+ get hasFrozenPane() {
51023
+ return this.env.model.getters.getPaneDivisions(this.sheetId).xSplit > 0;
50837
51024
  }
50838
51025
  }
50839
51026
  css /* scss */ `
@@ -50843,7 +51030,7 @@ css /* scss */ `
50843
51030
  left: 0;
50844
51031
  right: 0;
50845
51032
  width: ${HEADER_WIDTH}px;
50846
- height: 100%;
51033
+ height: calc(100% - ${HEADER_HEIGHT + SCROLLBAR_WIDTH}px);
50847
51034
  &.o-dragging {
50848
51035
  cursor: grabbing;
50849
51036
  }
@@ -50893,6 +51080,7 @@ class RowResizer extends AbstractResizer {
50893
51080
  onOpenContextMenu: Function,
50894
51081
  };
50895
51082
  static template = "o-spreadsheet-RowResizer";
51083
+ static components = { UnhideRowHeaders };
50896
51084
  setup() {
50897
51085
  super.setup();
50898
51086
  this.rowResizerRef = owl.useRef("rowResizer");
@@ -50901,6 +51089,9 @@ class RowResizer extends AbstractResizer {
50901
51089
  this.MIN_ELEMENT_SIZE = MIN_ROW_HEIGHT;
50902
51090
  }
50903
51091
  rowResizerRef;
51092
+ get sheetId() {
51093
+ return this.env.model.getters.getActiveSheetId();
51094
+ }
50904
51095
  _getEvOffset(ev) {
50905
51096
  return ev.offsetY;
50906
51097
  }
@@ -50923,10 +51114,10 @@ class RowResizer extends AbstractResizer {
50923
51114
  return this.env.model.getters.getEdgeScrollRow(position, position, position);
50924
51115
  }
50925
51116
  _getDimensionsInViewport(index) {
50926
- return this.env.model.getters.getRowDimensionsInViewport(this.env.model.getters.getActiveSheetId(), index);
51117
+ return this.env.model.getters.getRowDimensionsInViewport(this.sheetId, index);
50927
51118
  }
50928
51119
  _getElementSize(index) {
50929
- return this.env.model.getters.getRowSize(this.env.model.getters.getActiveSheetId(), index);
51120
+ return this.env.model.getters.getRowSize(this.sheetId, index);
50930
51121
  }
50931
51122
  _getMaxSize() {
50932
51123
  return this.rowResizerRef.el.clientHeight;
@@ -50937,7 +51128,7 @@ class RowResizer extends AbstractResizer {
50937
51128
  const rows = this.env.model.getters.getActiveRows();
50938
51129
  this.env.model.dispatch("RESIZE_COLUMNS_ROWS", {
50939
51130
  dimension: "ROW",
50940
- sheetId: this.env.model.getters.getActiveSheetId(),
51131
+ sheetId: this.sheetId,
50941
51132
  elements: rows.has(index) ? [...rows] : [index],
50942
51133
  size,
50943
51134
  });
@@ -50950,7 +51141,7 @@ class RowResizer extends AbstractResizer {
50950
51141
  elements.push(rowIndex);
50951
51142
  }
50952
51143
  const result = this.env.model.dispatch("MOVE_COLUMNS_ROWS", {
50953
- sheetId: this.env.model.getters.getActiveSheetId(),
51144
+ sheetId: this.sheetId,
50954
51145
  dimension: "ROW",
50955
51146
  base: this.state.base,
50956
51147
  elements,
@@ -50969,7 +51160,7 @@ class RowResizer extends AbstractResizer {
50969
51160
  _fitElementSize(index) {
50970
51161
  const rows = this.env.model.getters.getActiveRows();
50971
51162
  this.env.model.dispatch("AUTORESIZE_ROWS", {
50972
- sheetId: this.env.model.getters.getActiveSheetId(),
51163
+ sheetId: this.sheetId,
50973
51164
  rows: rows.has(index) ? [...rows] : [index],
50974
51165
  });
50975
51166
  }
@@ -50980,7 +51171,7 @@ class RowResizer extends AbstractResizer {
50980
51171
  return this.env.model.getters.getActiveRows();
50981
51172
  }
50982
51173
  _getPreviousVisibleElement(index) {
50983
- const sheetId = this.env.model.getters.getActiveSheetId();
51174
+ const sheetId = this.sheetId;
50984
51175
  let row;
50985
51176
  for (row = index - 1; row >= 0; row--) {
50986
51177
  if (!this.env.model.getters.isRowHidden(sheetId, row)) {
@@ -50989,15 +51180,33 @@ class RowResizer extends AbstractResizer {
50989
51180
  }
50990
51181
  return row;
50991
51182
  }
50992
- unhide(hiddenElements) {
50993
- this.env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
50994
- sheetId: this.env.model.getters.getActiveSheetId(),
50995
- dimension: "ROW",
50996
- elements: hiddenElements,
51183
+ get mainUnhideHeadersProps() {
51184
+ const { top, bottom } = this.env.model.getters.getActiveMainViewport();
51185
+ const { ySplit } = this.env.model.getters.getPaneDivisions(this.sheetId);
51186
+ const hiddenGroups = this.env.model.getters.getHiddenRowsGroups(this.sheetId);
51187
+ const index = hiddenGroups.findIndex((group) => group[0] >= ySplit - 1);
51188
+ return {
51189
+ headersGroups: hiddenGroups.slice(index),
51190
+ offset: this.env.model.getters.getMainViewportCoordinates().y,
51191
+ headerRange: { start: top, end: bottom },
51192
+ };
51193
+ }
51194
+ get frozenUnhideHeadersProps() {
51195
+ const { ySplit } = this.env.model.getters.getPaneDivisions(this.sheetId);
51196
+ const hiddenGroups = this.env.model.getters.getHiddenRowsGroups(this.sheetId);
51197
+ const index = hiddenGroups.findIndex((group) => group[0] >= ySplit - 1);
51198
+ return {
51199
+ headersGroups: hiddenGroups.slice(0, index + 1),
51200
+ headerRange: { start: 0, end: ySplit - 1 },
51201
+ };
51202
+ }
51203
+ get frozenContainerStyle() {
51204
+ return cssPropertiesToCss({
51205
+ height: this.env.model.getters.getMainViewportCoordinates().y + "px",
50997
51206
  });
50998
51207
  }
50999
- getUnhideButtonStyle(hiddenIndex) {
51000
- return cssPropertiesToCss({ top: this._getDimensionsInViewport(hiddenIndex).start + "px" });
51208
+ get hasFrozenPane() {
51209
+ return this.env.model.getters.getPaneDivisions(this.sheetId).ySplit > 0;
51001
51210
  }
51002
51211
  }
51003
51212
  css /* scss */ `
@@ -65194,12 +65403,7 @@ class SheetUIPlugin extends UIPlugin {
65194
65403
  }
65195
65404
  break;
65196
65405
  case "AUTORESIZE_ROWS":
65197
- this.dispatch("RESIZE_COLUMNS_ROWS", {
65198
- elements: cmd.rows,
65199
- dimension: "ROW",
65200
- size: null,
65201
- sheetId: cmd.sheetId,
65202
- });
65406
+ this.autoResizeRows(cmd.sheetId, cmd.rows);
65203
65407
  break;
65204
65408
  }
65205
65409
  }
@@ -65363,6 +65567,48 @@ class SheetUIPlugin extends UIPlugin {
65363
65567
  }
65364
65568
  return "Success" /* CommandResult.Success */;
65365
65569
  }
65570
+ autoResizeRows(sheetId, rows) {
65571
+ const rowSizes = [];
65572
+ for (const row of rows) {
65573
+ let evaluatedRowSize = 0;
65574
+ for (const cellId of this.getters.getRowCells(sheetId, row)) {
65575
+ const cell = this.getters.getCellById(cellId);
65576
+ if (!cell) {
65577
+ continue;
65578
+ }
65579
+ const position = this.getters.getCellPosition(cell.id);
65580
+ const colSize = this.getters.getColSize(sheetId, position.col);
65581
+ if (cell.isFormula) {
65582
+ const content = this.getters.getEvaluatedCell(position).formattedValue;
65583
+ const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
65584
+ if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
65585
+ evaluatedRowSize = evaluatedSize;
65586
+ }
65587
+ }
65588
+ else {
65589
+ const content = cell.content;
65590
+ const dynamicRowSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
65591
+ // Only keep the size of evaluated cells if it's bigger than the dynamic row size
65592
+ if (dynamicRowSize >= evaluatedRowSize && dynamicRowSize > DEFAULT_CELL_HEIGHT) {
65593
+ evaluatedRowSize = 0;
65594
+ }
65595
+ }
65596
+ }
65597
+ rowSizes.push(evaluatedRowSize || null);
65598
+ }
65599
+ const groupedSizes = new Map(rowSizes.map((size) => [size, []]));
65600
+ for (let i = 0; i < rowSizes.length; i++) {
65601
+ groupedSizes.get(rowSizes[i])?.push(rows[i]);
65602
+ }
65603
+ for (const [size, rows] of groupedSizes) {
65604
+ this.dispatch("RESIZE_COLUMNS_ROWS", {
65605
+ elements: rows,
65606
+ dimension: "ROW",
65607
+ size,
65608
+ sheetId,
65609
+ });
65610
+ }
65611
+ }
65366
65612
  }
65367
65613
 
65368
65614
  class TableComputedStylePlugin extends UIPlugin {
@@ -67767,7 +68013,7 @@ class InternalViewport {
67767
68013
  *
67768
68014
  */
67769
68015
  getFullRect(zone) {
67770
- const targetZone = intersection(zone, this);
68016
+ const targetZone = intersection(zone, this.boundaries);
67771
68017
  const scrollDeltaX = this.snapCorrection.x;
67772
68018
  const scrollDeltaY = this.snapCorrection.y;
67773
68019
  if (targetZone) {
@@ -68235,7 +68481,8 @@ class SheetViewPlugin extends UIPlugin {
68235
68481
  ? this.getters.getSheetViewVisibleCols()
68236
68482
  : this.getters.getSheetViewVisibleRows();
68237
68483
  const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
68238
- const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
68484
+ let endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
68485
+ endIndex = endIndex === -1 ? visibleHeaders.length : endIndex;
68239
68486
  const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
68240
68487
  let offset = 0;
68241
68488
  for (const i of relevantIndexes) {
@@ -68360,11 +68607,12 @@ class SheetViewPlugin extends UIPlugin {
68360
68607
  * column of the current viewport
68361
68608
  */
68362
68609
  getColDimensionsInViewport(sheetId, col) {
68610
+ const { top } = this.getMainInternalViewport(sheetId);
68363
68611
  const zone = {
68364
68612
  left: col,
68365
68613
  right: col,
68366
- top: 0,
68367
- bottom: this.getters.getNumberRows(sheetId) - 1,
68614
+ top: top,
68615
+ bottom: top,
68368
68616
  };
68369
68617
  const { x, width } = this.getVisibleRect(zone);
68370
68618
  const start = x - this.gridOffsetX;
@@ -68375,9 +68623,10 @@ class SheetViewPlugin extends UIPlugin {
68375
68623
  * of the current viewport
68376
68624
  */
68377
68625
  getRowDimensionsInViewport(sheetId, row) {
68626
+ const { left } = this.getMainInternalViewport(sheetId);
68378
68627
  const zone = {
68379
68628
  left: 0,
68380
- right: this.getters.getNumberCols(sheetId) - 1,
68629
+ right: left,
68381
68630
  top: row,
68382
68631
  bottom: row,
68383
68632
  };
@@ -74329,7 +74578,7 @@ function addStyles(styles) {
74329
74578
  }
74330
74579
  if (alignAttrs.length > 0) {
74331
74580
  attributes.push(["applyAlignment", "1"]); // for Libre Office
74332
- styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}>${escapeXml /*xml*/ `<alignment ${formatAttributes(alignAttrs)} />`}</xf> `);
74581
+ styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}><alignment ${formatAttributes(alignAttrs)} /></xf> `);
74333
74582
  }
74334
74583
  else {
74335
74584
  styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)} />`);
@@ -74497,6 +74746,9 @@ function addColumns(cols) {
74497
74746
  }
74498
74747
  function addRows(construct, data, sheet) {
74499
74748
  const rowNodes = [];
74749
+ const styles = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.styles));
74750
+ const borders = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.borders));
74751
+ const formats = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.formats));
74500
74752
  for (let r = 0; r < sheet.rowNumber; r++) {
74501
74753
  const rowAttrs = [["r", r + 1]];
74502
74754
  const row = sheet.rows[r] || {};
@@ -74512,9 +74764,6 @@ function addRows(construct, data, sheet) {
74512
74764
  if (row.collapsed) {
74513
74765
  rowAttrs.push(["collapsed", 1]);
74514
74766
  }
74515
- const styles = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.styles));
74516
- const borders = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.borders));
74517
- const formats = new PositionMap(iterateItemIdsPositions(sheet.id, sheet.formats));
74518
74767
  const cellNodes = [];
74519
74768
  for (let c = 0; c < sheet.colNumber; c++) {
74520
74769
  const xc = toXC(c, r);
@@ -75819,6 +76068,6 @@ exports.tokenColors = tokenColors;
75819
76068
  exports.tokenize = tokenize;
75820
76069
 
75821
76070
 
75822
- __info__.version = "18.2.2";
75823
- __info__.date = "2025-03-07T10:41:04.411Z";
75824
- __info__.hash = "f567932";
76071
+ __info__.version = "18.2.4";
76072
+ __info__.date = "2025-03-19T08:20:57.717Z";
76073
+ __info__.hash = "958936a";