@odoo/o-spreadsheet 17.0.47 → 17.0.49

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.47
6
- * @date 2025-01-31T07:56:50.980Z
7
- * @hash a22bce2
5
+ * @version 17.0.49
6
+ * @date 2025-02-10T08:55:47.771Z
7
+ * @hash 1049319
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';
@@ -686,9 +686,16 @@ function deepEquals(o1, o2) {
686
686
  }
687
687
  return true;
688
688
  }
689
- /** Check if the given array contains all the values of the other array. */
689
+ /**
690
+ * Check if the given array contains all the values of the other array.
691
+ * It makes the assumption that both array do not contain duplicates.
692
+ */
690
693
  function includesAll(arr, values) {
691
- return values.every((value) => arr.includes(value));
694
+ if (arr.length < values.length) {
695
+ return false;
696
+ }
697
+ const set = new Set(arr);
698
+ return values.every((value) => set.has(value));
692
699
  }
693
700
  /**
694
701
  * Return an object with all the keys in the object that have a falsy value removed.
@@ -18557,20 +18564,21 @@ const HLOOKUP = {
18557
18564
  description: _t("Horizontal lookup"),
18558
18565
  args: [
18559
18566
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18560
- arg("range (range)", _t("The range to consider for the search. The first row in the range is searched for the key specified in search_key.")),
18567
+ arg("range (any, range)", _t("The range to consider for the search. The first row in the range is searched for the key specified in search_key.")),
18561
18568
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18562
18569
  arg(`is_sorted (boolean, default=${DEFAULT_IS_SORTED})`, _t("Indicates whether the row to be searched (the first row of the specified range) is sorted, in which case the closest match for search_key will be returned.")),
18563
18570
  ],
18564
18571
  returns: ["ANY"],
18565
18572
  computeValueAndFormat: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18566
18573
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18567
- assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18574
+ const _range = toMatrix(range);
18575
+ assert(() => 1 <= _index && _index <= _range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18568
18576
  const getValueFromRange = (range, index) => range[index][0].value;
18569
18577
  const _isSorted = toBoolean(isSorted.value);
18570
18578
  const colIndex = _isSorted
18571
- ? dichotomicSearch(range, searchKey?.value, "nextSmaller", "asc", range.length, getValueFromRange)
18572
- : linearSearch(range, searchKey?.value, "strict", range.length, getValueFromRange);
18573
- const col = range[colIndex];
18579
+ ? dichotomicSearch(_range, searchKey?.value, "nextSmaller", "asc", _range.length, getValueFromRange)
18580
+ : linearSearch(_range, searchKey?.value, "strict", _range.length, getValueFromRange);
18581
+ const col = _range[colIndex];
18574
18582
  assertAvailable(col, searchKey?.value);
18575
18583
  return col[_index - 1];
18576
18584
  },
@@ -18615,36 +18623,38 @@ const LOOKUP = {
18615
18623
  description: _t("Look up a value."),
18616
18624
  args: [
18617
18625
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18618
- arg("search_array (range)", _t("One method of using this function is to provide a single sorted row or column search_array to look through for the search_key with a second argument result_range. The other way is to combine these two arguments into one search_array where the first row or column is searched and a value is returned from the last row or column in the array. If search_key is not found, a non-exact match may be returned.")),
18619
- arg("result_range (range, optional)", _t("The range from which to return a result. The value returned corresponds to the location where search_key is found in search_range. This range must be only a single row or column and should not be used if using the search_result_array method.")),
18626
+ arg("search_array (any, range)", _t("One method of using this function is to provide a single sorted row or column search_array to look through for the search_key with a second argument result_range. The other way is to combine these two arguments into one search_array where the first row or column is searched and a value is returned from the last row or column in the array. If search_key is not found, a non-exact match may be returned.")),
18627
+ arg("result_range (any, range, optional)", _t("The range from which to return a result. The value returned corresponds to the location where search_key is found in search_range. This range must be only a single row or column and should not be used if using the search_result_array method.")),
18620
18628
  ],
18621
18629
  returns: ["ANY"],
18622
18630
  computeValueAndFormat: function (searchKey, searchArray, resultRange) {
18623
- let nbCol = searchArray.length;
18624
- let nbRow = searchArray[0].length;
18631
+ const _searchArray = toMatrix(searchArray);
18632
+ const _resultRange = toMatrix(resultRange);
18633
+ let nbCol = _searchArray.length;
18634
+ let nbRow = _searchArray[0].length;
18625
18635
  const verticalSearch = nbRow >= nbCol;
18626
18636
  const getElement = verticalSearch
18627
18637
  ? (range, index) => range[0][index].value
18628
18638
  : (range, index) => range[index][0].value;
18629
18639
  const rangeLength = verticalSearch ? nbRow : nbCol;
18630
- const index = dichotomicSearch(searchArray, searchKey?.value, "nextSmaller", "asc", rangeLength, getElement);
18640
+ const index = dichotomicSearch(_searchArray, searchKey?.value, "nextSmaller", "asc", rangeLength, getElement);
18631
18641
  if (index === -1)
18632
18642
  assertAvailable(undefined, searchKey?.value);
18633
18643
  verticalSearch
18634
- ? assertAvailable(searchArray[0][index], searchKey?.value)
18635
- : assertAvailable(searchArray[index][nbRow - 1], searchKey?.value);
18636
- if (resultRange === undefined) {
18637
- return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
18644
+ ? assertAvailable(_searchArray[0][index], searchKey?.value)
18645
+ : assertAvailable(_searchArray[index][nbRow - 1], searchKey?.value);
18646
+ if (_resultRange[0].length === 0) {
18647
+ return verticalSearch ? _searchArray[nbCol - 1][index] : _searchArray[index][nbRow - 1];
18638
18648
  }
18639
- nbCol = resultRange.length;
18640
- nbRow = resultRange[0].length;
18649
+ nbCol = _resultRange.length;
18650
+ nbRow = _resultRange[0].length;
18641
18651
  assert(() => nbCol === 1 || nbRow === 1, _t("The result_range must be a single row or a single column."));
18642
18652
  if (nbCol > 1) {
18643
18653
  assert(() => index <= nbCol - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range row value %s.", (index + 1).toString()));
18644
- return resultRange[index][0];
18654
+ return _resultRange[index][0];
18645
18655
  }
18646
18656
  assert(() => index <= nbRow - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range column value %s.", (index + 1).toString()));
18647
- return resultRange[0][index];
18657
+ return _resultRange[0][index];
18648
18658
  },
18649
18659
  isExported: true,
18650
18660
  };
@@ -18662,27 +18672,28 @@ const MATCH = {
18662
18672
  returns: ["NUMBER"],
18663
18673
  compute: function (searchKey, range, searchType = DEFAULT_SEARCH_TYPE) {
18664
18674
  let _searchType = toNumber(searchType, this.locale);
18665
- const nbCol = range.length;
18666
- const nbRow = range[0].length;
18675
+ const _range = toMatrix(range);
18676
+ const nbCol = _range.length;
18677
+ const nbRow = _range[0].length;
18667
18678
  assert(() => nbCol === 1 || nbRow === 1, _t("The range must be a single row or a single column."));
18668
18679
  let index = -1;
18669
18680
  const getElement = nbCol === 1
18670
- ? (range, index) => range[0][index]
18671
- : (range, index) => range[index][0];
18672
- const rangeLen = nbCol === 1 ? range[0].length : range.length;
18681
+ ? (_range, index) => _range[0][index]
18682
+ : (_range, index) => _range[index][0];
18683
+ const rangeLen = nbCol === 1 ? _range[0].length : _range.length;
18673
18684
  _searchType = Math.sign(_searchType);
18674
18685
  switch (_searchType) {
18675
18686
  case 1:
18676
- index = dichotomicSearch(range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18687
+ index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18677
18688
  break;
18678
18689
  case 0:
18679
- index = linearSearch(range, searchKey, "strict", rangeLen, getElement);
18690
+ index = linearSearch(_range, searchKey, "strict", rangeLen, getElement);
18680
18691
  break;
18681
18692
  case -1:
18682
- index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18693
+ index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18683
18694
  break;
18684
18695
  }
18685
- assertAvailable(nbCol === 1 ? range[0][index] : range[index], searchKey);
18696
+ assertAvailable(nbCol === 1 ? _range[0][index] : _range[index], searchKey);
18686
18697
  return index + 1;
18687
18698
  },
18688
18699
  isExported: true,
@@ -18731,13 +18742,14 @@ const VLOOKUP = {
18731
18742
  returns: ["ANY"],
18732
18743
  computeValueAndFormat: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18733
18744
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18734
- assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18745
+ const _range = toMatrix(range);
18746
+ assert(() => 1 <= _index && _index <= _range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18735
18747
  const getValueFromRange = (range, index) => range[0][index].value;
18736
18748
  const _isSorted = toBoolean(isSorted.value);
18737
18749
  const rowIndex = _isSorted
18738
- ? dichotomicSearch(range, searchKey?.value, "nextSmaller", "asc", range[0].length, getValueFromRange)
18739
- : linearSearch(range, searchKey?.value, "strict", range[0].length, getValueFromRange);
18740
- const value = range[_index - 1][rowIndex];
18750
+ ? dichotomicSearch(_range, searchKey?.value, "nextSmaller", "asc", _range[0].length, getValueFromRange)
18751
+ : linearSearch(_range, searchKey?.value, "strict", _range[0].length, getValueFromRange);
18752
+ const value = _range[_index - 1][rowIndex];
18741
18753
  assertAvailable(value, searchKey?.value);
18742
18754
  return value;
18743
18755
  },
@@ -18764,26 +18776,28 @@ const XLOOKUP = {
18764
18776
  computeValueAndFormat: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18765
18777
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18766
18778
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
18767
- assert(() => lookupRange.length === 1 || lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18779
+ const _lookupRange = toMatrix(lookupRange);
18780
+ const _returnRange = toMatrix(returnRange);
18781
+ assert(() => _lookupRange.length === 1 || _lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18768
18782
  assert(() => [-1, 1, -2, 2].includes(_searchMode), _t("searchMode should be a value in [-1, 1, -2, 2]."));
18769
18783
  assert(() => [-1, 0, 1].includes(_matchMode), _t("matchMode should be a value in [-1, 0, 1]."));
18770
- const lookupDirection = lookupRange.length === 1 ? "col" : "row";
18784
+ const lookupDirection = _lookupRange.length === 1 ? "col" : "row";
18771
18785
  assert(() => lookupDirection === "col"
18772
- ? returnRange[0].length === lookupRange[0].length
18773
- : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18786
+ ? _returnRange[0].length === _lookupRange[0].length
18787
+ : _returnRange.length === _lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18774
18788
  const getElement = lookupDirection === "col"
18775
18789
  ? (range, index) => range[0][index].value
18776
18790
  : (range, index) => range[index][0].value;
18777
- const rangeLen = lookupDirection === "col" ? lookupRange[0].length : lookupRange.length;
18791
+ const rangeLen = lookupDirection === "col" ? _lookupRange[0].length : _lookupRange.length;
18778
18792
  const mode = _matchMode === 0 ? "strict" : _matchMode === 1 ? "nextGreater" : "nextSmaller";
18779
18793
  const reverseSearch = _searchMode === -1;
18780
18794
  const index = _searchMode === 2 || _searchMode === -2
18781
- ? dichotomicSearch(lookupRange, searchKey?.value, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18782
- : linearSearch(lookupRange, searchKey?.value, mode, rangeLen, getElement, reverseSearch);
18795
+ ? dichotomicSearch(_lookupRange, searchKey?.value, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18796
+ : linearSearch(_lookupRange, searchKey?.value, mode, rangeLen, getElement, reverseSearch);
18783
18797
  if (index !== -1) {
18784
18798
  return lookupDirection === "col"
18785
- ? returnRange.map((col) => [col[index]])
18786
- : [returnRange[index]];
18799
+ ? _returnRange.map((col) => [col[index]])
18800
+ : [_returnRange[index]];
18787
18801
  }
18788
18802
  const _defaultValue = defaultValue?.();
18789
18803
  assertAvailable(_defaultValue, searchKey?.value);
@@ -29241,6 +29255,9 @@ function useGridDrawing(refName, model, canvasSize) {
29241
29255
  canvas.width = width * dpr;
29242
29256
  canvas.height = height * dpr;
29243
29257
  canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
29258
+ if (width === 0 || height === 0) {
29259
+ return;
29260
+ }
29244
29261
  // Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
29245
29262
  // are the edges of the squares. If you draw a one-unit-wide line between whole-number
29246
29263
  // coordinates, it will overlap opposite sides of the pixel square, and the resulting
@@ -34721,7 +34738,7 @@ class BordersPlugin extends CorePlugin {
34721
34738
  getCommonSides(border1, border2) {
34722
34739
  const commonBorder = {};
34723
34740
  for (let side of ["top", "bottom", "left", "right"]) {
34724
- if (border1[side] && border1[side] === border2[side]) {
34741
+ if (border1[side] && deepEquals(border1[side], border2[side])) {
34725
34742
  commonBorder[side] = border1[side];
34726
34743
  }
34727
34744
  }
@@ -46267,11 +46284,10 @@ class RendererPlugin extends UIPlugin {
46267
46284
  switch (layer) {
46268
46285
  case 0 /* LAYERS.Background */:
46269
46286
  this.drawGlobalBackground(renderingContext);
46270
- for (const zone of this.getters.getAllActiveViewportsZones()) {
46287
+ for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
46271
46288
  const { ctx } = renderingContext;
46272
46289
  ctx.save();
46273
46290
  ctx.beginPath();
46274
- const rect = this.getters.getVisibleRect(zone);
46275
46291
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
46276
46292
  ctx.clip();
46277
46293
  this.boxes = this.getGridBoxes(zone);
@@ -46541,10 +46557,8 @@ class RendererPlugin extends UIPlugin {
46541
46557
  const { ctx, thinLineWidth } = renderingContext;
46542
46558
  const visibleCols = this.getters.getSheetViewVisibleCols();
46543
46559
  const left = visibleCols[0];
46544
- const right = visibleCols[visibleCols.length - 1];
46545
46560
  const visibleRows = this.getters.getSheetViewVisibleRows();
46546
46561
  const top = visibleRows[0];
46547
- const bottom = visibleRows[visibleRows.length - 1];
46548
46562
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
46549
46563
  const selection = this.getters.getSelectedZones();
46550
46564
  const selectedCols = getZonesCols(selection);
@@ -46560,7 +46574,7 @@ class RendererPlugin extends UIPlugin {
46560
46574
  ctx.lineWidth = thinLineWidth;
46561
46575
  ctx.strokeStyle = "#333";
46562
46576
  // Columns headers background
46563
- for (let col = left; col <= right; col++) {
46577
+ for (const col of visibleCols) {
46564
46578
  const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
46565
46579
  const { x, width } = this.getters.getVisibleRect(colZone);
46566
46580
  const colHasFilter = this.getters.doesZonesContainFilter(sheetId, [colZone]);
@@ -46580,7 +46594,7 @@ class RendererPlugin extends UIPlugin {
46580
46594
  ctx.fillRect(x, 0, width, HEADER_HEIGHT);
46581
46595
  }
46582
46596
  // Rows headers background
46583
- for (let row = top; row <= bottom; row++) {
46597
+ for (const row of visibleRows) {
46584
46598
  const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
46585
46599
  const { y, height } = this.getters.getVisibleRect(rowZone);
46586
46600
  const rowHasFilter = this.getters.doesZonesContainFilter(sheetId, [rowZone]);
@@ -46609,21 +46623,21 @@ class RendererPlugin extends UIPlugin {
46609
46623
  ctx.stroke();
46610
46624
  ctx.beginPath();
46611
46625
  // column text + separator
46612
- for (const i of visibleCols) {
46613
- const colSize = this.getters.getColSize(sheetId, i);
46614
- const colName = numberToLetters(i);
46615
- ctx.fillStyle = activeCols.has(i) ? "#fff" : TEXT_HEADER_COLOR;
46616
- let colStart = this.getHeaderOffset("COL", left, i);
46626
+ for (const col of visibleCols) {
46627
+ const colSize = this.getters.getColSize(sheetId, col);
46628
+ const colName = numberToLetters(col);
46629
+ ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
46630
+ let colStart = this.getHeaderOffset("COL", left, col);
46617
46631
  ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
46618
46632
  ctx.moveTo(colStart + colSize, 0);
46619
46633
  ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
46620
46634
  }
46621
46635
  // row text + separator
46622
- for (const i of visibleRows) {
46623
- const rowSize = this.getters.getRowSize(sheetId, i);
46624
- ctx.fillStyle = activeRows.has(i) ? "#fff" : TEXT_HEADER_COLOR;
46625
- let rowStart = this.getHeaderOffset("ROW", top, i);
46626
- ctx.fillText(String(i + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
46636
+ for (const row of visibleRows) {
46637
+ const rowSize = this.getters.getRowSize(sheetId, row);
46638
+ ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
46639
+ let rowStart = this.getHeaderOffset("ROW", top, row);
46640
+ ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
46627
46641
  ctx.moveTo(0, rowStart + rowSize);
46628
46642
  ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
46629
46643
  }
@@ -50514,8 +50528,17 @@ class InternalViewport {
50514
50528
  this.getters = getters;
50515
50529
  this.sheetId = sheetId;
50516
50530
  this.boundaries = boundaries;
50517
- this.viewportWidth = sizeInGrid.width;
50518
- this.viewportHeight = sizeInGrid.height;
50531
+ if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
50532
+ throw new Error("Viewport size cannot be negative");
50533
+ }
50534
+ this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
50535
+ this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
50536
+ this.top = boundaries.top;
50537
+ this.bottom = boundaries.bottom;
50538
+ this.left = boundaries.left;
50539
+ this.right = boundaries.right;
50540
+ this.offsetX = offsets.x;
50541
+ this.offsetY = offsets.y;
50519
50542
  this.offsetScrollbarX = offsets.x;
50520
50543
  this.offsetScrollbarY = offsets.y;
50521
50544
  this.canScrollVertically = options.canScrollVertically;
@@ -50558,9 +50581,9 @@ class InternalViewport {
50558
50581
  Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
50559
50582
  );
50560
50583
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
50561
- }
50562
- if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
50563
- height += FOOTER_HEIGHT;
50584
+ if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
50585
+ height += FOOTER_HEIGHT;
50586
+ }
50564
50587
  }
50565
50588
  return { width, height };
50566
50589
  }
@@ -50707,6 +50730,9 @@ class InternalViewport {
50707
50730
  }
50708
50731
  // PRIVATE
50709
50732
  searchHeaderIndex(dimension, position, startIndex = 0) {
50733
+ if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
50734
+ return -1;
50735
+ }
50710
50736
  const sheetId = this.sheetId;
50711
50737
  const headers = this.getters.getNumberHeaders(sheetId, dimension);
50712
50738
  // using a binary search:
@@ -50746,7 +50772,7 @@ class InternalViewport {
50746
50772
  this.adjustViewportZoneY();
50747
50773
  }
50748
50774
  /** Corrects the viewport's horizontal offset based on the current structure
50749
- * To make sure that at least on column is visible inside the viewport.
50775
+ * To make sure that at least one column is visible inside the viewport.
50750
50776
  */
50751
50777
  adjustViewportOffsetX() {
50752
50778
  if (this.canScrollHorizontally) {
@@ -50763,7 +50789,7 @@ class InternalViewport {
50763
50789
  this.adjustViewportZoneX();
50764
50790
  }
50765
50791
  /** Corrects the viewport's vertical offset based on the current structure
50766
- * To make sure that at least on row is visible inside the viewport.
50792
+ * To make sure that at least one row is visible inside the viewport.
50767
50793
  */
50768
50794
  adjustViewportOffsetY() {
50769
50795
  if (this.canScrollVertically) {
@@ -50785,11 +50811,14 @@ class InternalViewport {
50785
50811
  const sheetId = this.sheetId;
50786
50812
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
50787
50813
  this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
50814
+ if (!this.viewportWidth) {
50815
+ return;
50816
+ }
50788
50817
  if (this.left === -1) {
50789
50818
  this.left = this.boundaries.left;
50790
50819
  }
50791
50820
  if (this.right === -1) {
50792
- this.right = this.getters.getNumberCols(sheetId) - 1;
50821
+ this.right = this.boundaries.right;
50793
50822
  }
50794
50823
  this.offsetX =
50795
50824
  this.getters.getColDimensions(sheetId, this.left).start -
@@ -50801,11 +50830,14 @@ class InternalViewport {
50801
50830
  const sheetId = this.sheetId;
50802
50831
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
50803
50832
  this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
50833
+ if (!this.viewportHeight) {
50834
+ return;
50835
+ }
50804
50836
  if (this.top === -1) {
50805
50837
  this.top = this.boundaries.top;
50806
50838
  }
50807
50839
  if (this.bottom === -1) {
50808
- this.bottom = this.getters.getNumberRows(sheetId) - 1;
50840
+ this.bottom = this.boundaries.bottom;
50809
50841
  }
50810
50842
  this.offsetY =
50811
50843
  this.getters.getRowDimensions(sheetId, this.top).start -
@@ -50877,7 +50909,7 @@ class SheetViewPlugin extends UIPlugin {
50877
50909
  "getSheetViewVisibleRows",
50878
50910
  "getFrozenSheetViewRatio",
50879
50911
  "isPositionVisible",
50880
- "getAllActiveViewportsZones",
50912
+ "getAllActiveViewportsZonesAndRect",
50881
50913
  "getRect",
50882
50914
  ];
50883
50915
  viewports = {};
@@ -51111,12 +51143,12 @@ class SheetViewPlugin extends UIPlugin {
51111
51143
  const sheetId = this.getters.getActiveSheetId();
51112
51144
  const viewports = this.getSubViewports(sheetId);
51113
51145
  //TODO ake another commit to eimprove this
51114
- return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
51146
+ return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
51115
51147
  }
51116
51148
  getSheetViewVisibleRows() {
51117
51149
  const sheetId = this.getters.getActiveSheetId();
51118
51150
  const viewports = this.getSubViewports(sheetId);
51119
- return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
51151
+ return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
51120
51152
  }
51121
51153
  /**
51122
51154
  * Get the positions of all the cells that are visible in the viewport, taking merges into account.
@@ -51159,19 +51191,19 @@ class SheetViewPlugin extends UIPlugin {
51159
51191
  maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
51160
51192
  };
51161
51193
  }
51162
- getColRowOffsetInViewport(dimension, referenceIndex, index) {
51163
- const sheetId = this.getters.getActiveSheetId();
51164
- const visibleCols = this.getters.getSheetViewVisibleCols();
51165
- const visibleRows = this.getters.getSheetViewVisibleRows();
51166
- if (index < referenceIndex) {
51167
- return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
51194
+ getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
51195
+ if (targetHeaderIndex < referenceHeaderIndex) {
51196
+ return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
51168
51197
  }
51198
+ const sheetId = this.getters.getActiveSheetId();
51199
+ const visibleHeaders = dimension === "COL"
51200
+ ? this.getters.getSheetViewVisibleCols()
51201
+ : this.getters.getSheetViewVisibleRows();
51202
+ const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
51203
+ const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
51204
+ const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
51169
51205
  let offset = 0;
51170
- const visibleIndexes = dimension === "COL" ? visibleCols : visibleRows;
51171
- for (let i = referenceIndex; i < index; i++) {
51172
- if (!visibleIndexes.includes(i)) {
51173
- continue;
51174
- }
51206
+ for (const i of relevantIndexes) {
51175
51207
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
51176
51208
  }
51177
51209
  return offset;
@@ -51218,7 +51250,7 @@ class SheetViewPlugin extends UIPlugin {
51218
51250
  }
51219
51251
  return { canEdgeScroll, direction, delay };
51220
51252
  }
51221
- getEdgeScrollRow(y, previousY, tartingY) {
51253
+ getEdgeScrollRow(y, previousY, startingY) {
51222
51254
  let canEdgeScroll = false;
51223
51255
  let direction = 0;
51224
51256
  let delay = 0;
@@ -51239,7 +51271,7 @@ class SheetViewPlugin extends UIPlugin {
51239
51271
  delay = scrollDelay(y - height);
51240
51272
  direction = 1;
51241
51273
  }
51242
- else if (y < offsetCorrectionY && tartingY >= offsetCorrectionY && currentOffsetY > 0) {
51274
+ else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
51243
51275
  // 2
51244
51276
  canEdgeScroll = true;
51245
51277
  delay = scrollDelay(offsetCorrectionY - y);
@@ -51265,13 +51297,7 @@ class SheetViewPlugin extends UIPlugin {
51265
51297
  */
51266
51298
  getVisibleRectWithoutHeaders(zone) {
51267
51299
  const sheetId = this.getters.getActiveSheetId();
51268
- const viewportRects = this.getSubViewports(sheetId)
51269
- .map((viewport) => viewport.getVisibleRect(zone))
51270
- .filter(isDefined$1);
51271
- if (viewportRects.length === 0) {
51272
- return { x: 0, y: 0, width: 0, height: 0 };
51273
- }
51274
- return this.recomposeRect(viewportRects);
51300
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
51275
51301
  }
51276
51302
  /**
51277
51303
  * Computes the actual size and position (:Rect) of the zone on the canvas
@@ -51279,13 +51305,7 @@ class SheetViewPlugin extends UIPlugin {
51279
51305
  */
51280
51306
  getRect(zone) {
51281
51307
  const sheetId = this.getters.getActiveSheetId();
51282
- const viewportRects = this.getSubViewports(sheetId)
51283
- .map((viewport) => viewport.getFullRect(zone))
51284
- .filter(isDefined$1);
51285
- if (viewportRects.length === 0) {
51286
- return { x: 0, y: 0, width: 0, height: 0 };
51287
- }
51288
- const rect = this.recomposeRect(viewportRects);
51308
+ const rect = this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
51289
51309
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
51290
51310
  }
51291
51311
  /**
@@ -51300,9 +51320,18 @@ class SheetViewPlugin extends UIPlugin {
51300
51320
  const y = this.getters.getRowDimensions(sheetId, ySplit).start;
51301
51321
  return { x, y };
51302
51322
  }
51303
- getAllActiveViewportsZones() {
51323
+ getAllActiveViewportsZonesAndRect() {
51304
51324
  const sheetId = this.getters.getActiveSheetId();
51305
- return this.getSubViewports(sheetId);
51325
+ return this.getSubViewports(sheetId).map((viewport) => {
51326
+ return {
51327
+ zone: viewport,
51328
+ rect: {
51329
+ x: viewport.offsetCorrectionX + this.gridOffsetX,
51330
+ y: viewport.offsetCorrectionY + this.gridOffsetY,
51331
+ ...viewport.getMaxSize(),
51332
+ },
51333
+ };
51334
+ });
51306
51335
  }
51307
51336
  // ---------------------------------------------------------------------------
51308
51337
  // Private
@@ -51355,12 +51384,11 @@ class SheetViewPlugin extends UIPlugin {
51355
51384
  }
51356
51385
  /** gets rid of deprecated sheetIds */
51357
51386
  cleanViewports() {
51358
- const sheetIds = this.getters.getSheetIds();
51359
- for (let sheetId of Object.keys(this.viewports)) {
51360
- if (!sheetIds.includes(sheetId)) {
51361
- delete this.viewports[sheetId];
51362
- }
51387
+ const newViewport = {};
51388
+ for (const sheetId of this.getters.getSheetIds()) {
51389
+ newViewport[sheetId] = this.viewports[sheetId];
51363
51390
  }
51391
+ this.viewports = newViewport;
51364
51392
  }
51365
51393
  resizeSheetView(height, width, gridOffsetX = 0, gridOffsetY = 0) {
51366
51394
  this.sheetViewHeight = height;
@@ -51370,14 +51398,14 @@ class SheetViewPlugin extends UIPlugin {
51370
51398
  this.recomputeViewports();
51371
51399
  }
51372
51400
  recomputeViewports() {
51373
- for (let sheetId of Object.keys(this.viewports)) {
51401
+ for (const sheetId of this.getters.getSheetIds()) {
51374
51402
  this.resetViewports(sheetId);
51375
51403
  }
51376
51404
  }
51377
51405
  setSheetViewOffset(offsetX, offsetY) {
51378
51406
  const sheetId = this.getters.getActiveSheetId();
51379
51407
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
51380
- Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
51408
+ this.getSubViewports(sheetId).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
51381
51409
  }
51382
51410
  getViewportOffset(sheetId) {
51383
51411
  return {
@@ -51392,8 +51420,10 @@ class SheetViewPlugin extends UIPlugin {
51392
51420
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
51393
51421
  const nCols = this.getters.getNumberCols(sheetId);
51394
51422
  const nRows = this.getters.getNumberRows(sheetId);
51395
- const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
51396
- const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
51423
+ const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
51424
+ const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
51425
+ const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
51426
+ const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
51397
51427
  const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
51398
51428
  const canScrollHorizontally = xRatio < 1.0;
51399
51429
  const canScrollVertically = yRatio < 1.0;
@@ -51404,14 +51434,14 @@ class SheetViewPlugin extends UIPlugin {
51404
51434
  new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: 0, bottom: ySplit - 1 }, { width: colOffset, height: rowOffset }, { canScrollHorizontally: false, canScrollVertically: false }, { x: 0, y: 0 })) ||
51405
51435
  undefined,
51406
51436
  topRight: (ySplit &&
51407
- new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: 0, bottom: ySplit - 1 }, { width: this.sheetViewWidth - colOffset, height: rowOffset }, { canScrollHorizontally, canScrollVertically: false }, { x: canScrollHorizontally ? previousOffset.x : 0, y: 0 })) ||
51437
+ new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: 0, bottom: ySplit - 1 }, { width: unfrozenWidth, height: rowOffset }, { canScrollHorizontally, canScrollVertically: false }, { x: canScrollHorizontally ? previousOffset.x : 0, y: 0 })) ||
51408
51438
  undefined,
51409
51439
  bottomLeft: (xSplit &&
51410
- new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: ySplit, bottom: nRows - 1 }, { width: colOffset, height: this.sheetViewHeight - rowOffset }, { canScrollHorizontally: false, canScrollVertically }, { x: 0, y: canScrollVertically ? previousOffset.y : 0 })) ||
51440
+ new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: ySplit, bottom: nRows - 1 }, { width: colOffset, height: unfrozenHeight }, { canScrollHorizontally: false, canScrollVertically }, { x: 0, y: canScrollVertically ? previousOffset.y : 0 })) ||
51411
51441
  undefined,
51412
51442
  bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
51413
- width: this.sheetViewWidth - colOffset,
51414
- height: this.sheetViewHeight - rowOffset,
51443
+ width: unfrozenWidth,
51444
+ height: unfrozenHeight,
51415
51445
  }, { canScrollHorizontally, canScrollVertically }, {
51416
51446
  x: canScrollHorizontally ? previousOffset.x : 0,
51417
51447
  y: canScrollVertically ? previousOffset.y : 0,
@@ -51423,7 +51453,7 @@ class SheetViewPlugin extends UIPlugin {
51423
51453
  * Adjust the viewport such that the anchor position is visible
51424
51454
  */
51425
51455
  refreshViewport(sheetId, anchorPosition) {
51426
- Object.values(this.getSubViewports(sheetId)).forEach((viewport) => {
51456
+ this.getSubViewports(sheetId).forEach((viewport) => {
51427
51457
  viewport.adjustViewportZone();
51428
51458
  viewport.adjustPosition(anchorPosition);
51429
51459
  });
@@ -51488,12 +51518,26 @@ class SheetViewPlugin extends UIPlugin {
51488
51518
  const height = this.sheetViewHeight + this.gridOffsetY;
51489
51519
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
51490
51520
  }
51491
- recomposeRect(viewportRects) {
51492
- const x = Math.min(...viewportRects.map((rect) => rect.x));
51493
- const y = Math.min(...viewportRects.map((rect) => rect.y));
51494
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
51495
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
51496
- return { x, y, width, height };
51521
+ mapViewportsToRect(sheetId, rectCallBack) {
51522
+ let x = Infinity;
51523
+ let y = Infinity;
51524
+ let width = 0;
51525
+ let height = 0;
51526
+ let hasViewports = false;
51527
+ for (const viewport of this.getSubViewports(sheetId)) {
51528
+ const rect = rectCallBack(viewport);
51529
+ if (rect) {
51530
+ hasViewports = true;
51531
+ x = Math.min(x, rect.x);
51532
+ y = Math.min(y, rect.y);
51533
+ width = Math.max(width, rect.x + rect.width);
51534
+ height = Math.max(height, rect.y + rect.height);
51535
+ }
51536
+ }
51537
+ if (!hasViewports) {
51538
+ return { x: 0, y: 0, width: 0, height: 0 };
51539
+ }
51540
+ return { x, y, width: width - x, height: height - y };
51497
51541
  }
51498
51542
  }
51499
51543
 
@@ -57767,6 +57811,6 @@ const constants = {
57767
57811
  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 };
57768
57812
 
57769
57813
 
57770
- __info__.version = "17.0.47";
57771
- __info__.date = "2025-01-31T07:56:50.980Z";
57772
- __info__.hash = "a22bce2";
57814
+ __info__.version = "17.0.49";
57815
+ __info__.date = "2025-02-10T08:55:47.771Z";
57816
+ __info__.hash = "1049319";