@odoo/o-spreadsheet 17.2.34 → 17.2.35

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.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.2.34
7
- * @date 2025-01-31T07:58:03.953Z
8
- * @hash 0bffee9
6
+ * @version 17.2.35
7
+ * @date 2025-02-05T07:12:34.721Z
8
+ * @hash 76b12a1
9
9
  */
10
10
 
11
11
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw } from '@odoo/owl';
@@ -17751,23 +17751,24 @@ const HLOOKUP = {
17751
17751
  description: _t("Horizontal lookup"),
17752
17752
  args: [
17753
17753
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
17754
- 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.")),
17754
+ 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.")),
17755
17755
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
17756
17756
  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.")),
17757
17757
  ],
17758
17758
  returns: ["ANY"],
17759
17759
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
17760
17760
  const _index = Math.trunc(toNumber(index?.value, this.locale));
17761
- assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
17761
+ const _range = toMatrix(range);
17762
+ assert(() => 1 <= _index && _index <= _range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
17762
17763
  if (searchKey && isEvaluationError(searchKey.value)) {
17763
17764
  return searchKey;
17764
17765
  }
17765
17766
  const getValueFromRange = (range, index) => range[index][0].value;
17766
17767
  const _isSorted = toBoolean(isSorted.value);
17767
17768
  const colIndex = _isSorted
17768
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
17769
- : linearSearch(range, searchKey, "wildcard", range.length, getValueFromRange);
17770
- const col = range[colIndex];
17769
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
17770
+ : linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange);
17771
+ const col = _range[colIndex];
17771
17772
  if (col === undefined) {
17772
17773
  return valueNotAvailable(searchKey);
17773
17774
  }
@@ -17876,36 +17877,38 @@ const LOOKUP = {
17876
17877
  description: _t("Look up a value."),
17877
17878
  args: [
17878
17879
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
17879
- 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.")),
17880
- 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.")),
17880
+ 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.")),
17881
+ 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.")),
17881
17882
  ],
17882
17883
  returns: ["ANY"],
17883
17884
  compute: function (searchKey, searchArray, resultRange) {
17884
- let nbCol = searchArray.length;
17885
- let nbRow = searchArray[0].length;
17885
+ const _searchArray = toMatrix(searchArray);
17886
+ const _resultRange = toMatrix(resultRange);
17887
+ let nbCol = _searchArray.length;
17888
+ let nbRow = _searchArray[0].length;
17886
17889
  const verticalSearch = nbRow >= nbCol;
17887
17890
  const getElement = verticalSearch
17888
17891
  ? (range, index) => range[0][index].value
17889
17892
  : (range, index) => range[index][0].value;
17890
17893
  const rangeLength = verticalSearch ? nbRow : nbCol;
17891
- const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
17894
+ const index = dichotomicSearch(_searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
17892
17895
  if (index === -1 ||
17893
- (verticalSearch && searchArray[0][index] === undefined) ||
17894
- (!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
17896
+ (verticalSearch && _searchArray[0][index] === undefined) ||
17897
+ (!verticalSearch && _searchArray[index][nbRow - 1] === undefined)) {
17895
17898
  return valueNotAvailable(searchKey);
17896
17899
  }
17897
- if (resultRange === undefined) {
17898
- return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
17900
+ if (_resultRange[0].length === 0) {
17901
+ return verticalSearch ? _searchArray[nbCol - 1][index] : _searchArray[index][nbRow - 1];
17899
17902
  }
17900
- nbCol = resultRange.length;
17901
- nbRow = resultRange[0].length;
17903
+ nbCol = _resultRange.length;
17904
+ nbRow = _resultRange[0].length;
17902
17905
  assert(() => nbCol === 1 || nbRow === 1, _t("The result_range must be a single row or a single column."));
17903
17906
  if (nbCol > 1) {
17904
17907
  assert(() => index <= nbCol - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range row value %s.", (index + 1).toString()));
17905
- return resultRange[index][0];
17908
+ return _resultRange[index][0];
17906
17909
  }
17907
17910
  assert(() => index <= nbRow - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range column value %s.", (index + 1).toString()));
17908
- return resultRange[0][index];
17911
+ return _resultRange[0][index];
17909
17912
  },
17910
17913
  isExported: true,
17911
17914
  };
@@ -17923,28 +17926,29 @@ const MATCH = {
17923
17926
  returns: ["NUMBER"],
17924
17927
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
17925
17928
  let _searchType = toNumber(searchType, this.locale);
17926
- const nbCol = range.length;
17927
- const nbRow = range[0].length;
17929
+ const _range = toMatrix(range);
17930
+ const nbCol = _range.length;
17931
+ const nbRow = _range[0].length;
17928
17932
  assert(() => nbCol === 1 || nbRow === 1, _t("The range must be a single row or a single column."));
17929
17933
  let index = -1;
17930
17934
  const getElement = nbCol === 1
17931
- ? (range, index) => range[0][index].value
17932
- : (range, index) => range[index][0].value;
17933
- const rangeLen = nbCol === 1 ? range[0].length : range.length;
17935
+ ? (_range, index) => _range[0][index].value
17936
+ : (_range, index) => _range[index][0].value;
17937
+ const rangeLen = nbCol === 1 ? _range[0].length : _range.length;
17934
17938
  _searchType = Math.sign(_searchType);
17935
17939
  switch (_searchType) {
17936
17940
  case 1:
17937
- index = dichotomicSearch(range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
17941
+ index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
17938
17942
  break;
17939
17943
  case 0:
17940
- index = linearSearch(range, searchKey, "wildcard", rangeLen, getElement);
17944
+ index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement);
17941
17945
  break;
17942
17946
  case -1:
17943
- index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
17947
+ index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
17944
17948
  break;
17945
17949
  }
17946
- if ((nbCol === 1 && range[0][index] === undefined) ||
17947
- (nbCol !== 1 && range[index] === undefined)) {
17950
+ if ((nbCol === 1 && _range[0][index] === undefined) ||
17951
+ (nbCol !== 1 && _range[index] === undefined)) {
17948
17952
  return valueNotAvailable(searchKey);
17949
17953
  }
17950
17954
  return index + 1;
@@ -17995,16 +17999,17 @@ const VLOOKUP = {
17995
17999
  returns: ["ANY"],
17996
18000
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
17997
18001
  const _index = Math.trunc(toNumber(index?.value, this.locale));
17998
- assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18002
+ const _range = toMatrix(range);
18003
+ assert(() => 1 <= _index && _index <= _range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
17999
18004
  if (searchKey && isEvaluationError(searchKey.value)) {
18000
18005
  return searchKey;
18001
18006
  }
18002
18007
  const getValueFromRange = (range, index) => range[0][index].value;
18003
18008
  const _isSorted = toBoolean(isSorted.value);
18004
18009
  const rowIndex = _isSorted
18005
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
18006
- : linearSearch(range, searchKey, "wildcard", range[0].length, getValueFromRange);
18007
- const value = range[_index - 1][rowIndex];
18010
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
18011
+ : linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange);
18012
+ const value = _range[_index - 1][rowIndex];
18008
18013
  if (value === undefined) {
18009
18014
  return valueNotAvailable(searchKey);
18010
18015
  }
@@ -18042,30 +18047,32 @@ const XLOOKUP = {
18042
18047
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18043
18048
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18044
18049
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
18045
- assert(() => lookupRange.length === 1 || lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18050
+ const _lookupRange = toMatrix(lookupRange);
18051
+ const _returnRange = toMatrix(returnRange);
18052
+ assert(() => _lookupRange.length === 1 || _lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18046
18053
  assert(() => [-1, 1, -2, 2].includes(_searchMode), _t("search_mode should be a value in [-1, 1, -2, 2]."));
18047
18054
  assert(() => [-1, 0, 1, 2].includes(_matchMode), _t("match_mode should be a value in [-1, 0, 1, 2]."));
18048
- const lookupDirection = lookupRange.length === 1 ? "col" : "row";
18055
+ const lookupDirection = _lookupRange.length === 1 ? "col" : "row";
18049
18056
  assert(() => !(_matchMode === 2 && [-2, 2].includes(_searchMode)), _t("the search and match mode combination is not supported for XLOOKUP evaluation."));
18050
18057
  assert(() => lookupDirection === "col"
18051
- ? returnRange[0].length === lookupRange[0].length
18052
- : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18058
+ ? _returnRange[0].length === _lookupRange[0].length
18059
+ : _returnRange.length === _lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18053
18060
  if (searchKey && isEvaluationError(searchKey.value)) {
18054
18061
  return [[searchKey]];
18055
18062
  }
18056
18063
  const getElement = lookupDirection === "col"
18057
18064
  ? (range, index) => range[0][index].value
18058
18065
  : (range, index) => range[index][0].value;
18059
- const rangeLen = lookupDirection === "col" ? lookupRange[0].length : lookupRange.length;
18066
+ const rangeLen = lookupDirection === "col" ? _lookupRange[0].length : _lookupRange.length;
18060
18067
  const mode = MATCH_MODE[_matchMode];
18061
18068
  const reverseSearch = _searchMode === -1;
18062
18069
  const index = _searchMode === 2 || _searchMode === -2
18063
- ? dichotomicSearch(lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18064
- : linearSearch(lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
18070
+ ? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18071
+ : linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
18065
18072
  if (index !== -1) {
18066
18073
  return lookupDirection === "col"
18067
- ? returnRange.map((col) => [col[index]])
18068
- : [returnRange[index]];
18074
+ ? _returnRange.map((col) => [col[index]])
18075
+ : [_returnRange[index]];
18069
18076
  }
18070
18077
  if (defaultValue === undefined) {
18071
18078
  return valueNotAvailable(searchKey);
@@ -34695,11 +34702,10 @@ class GridRenderer {
34695
34702
  switch (layer) {
34696
34703
  case "Background":
34697
34704
  this.drawGlobalBackground(renderingContext);
34698
- for (const zone of this.getters.getAllActiveViewportsZones()) {
34705
+ for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
34699
34706
  const { ctx } = renderingContext;
34700
34707
  ctx.save();
34701
34708
  ctx.beginPath();
34702
- const rect = this.getters.getVisibleRect(zone);
34703
34709
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
34704
34710
  ctx.clip();
34705
34711
  const boxes = this.getGridBoxes(zone);
@@ -34969,10 +34975,8 @@ class GridRenderer {
34969
34975
  const { ctx, thinLineWidth } = renderingContext;
34970
34976
  const visibleCols = this.getters.getSheetViewVisibleCols();
34971
34977
  const left = visibleCols[0];
34972
- const right = visibleCols[visibleCols.length - 1];
34973
34978
  const visibleRows = this.getters.getSheetViewVisibleRows();
34974
34979
  const top = visibleRows[0];
34975
- const bottom = visibleRows[visibleRows.length - 1];
34976
34980
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
34977
34981
  const selection = this.getters.getSelectedZones();
34978
34982
  const selectedCols = getZonesCols(selection);
@@ -34988,7 +34992,7 @@ class GridRenderer {
34988
34992
  ctx.lineWidth = thinLineWidth;
34989
34993
  ctx.strokeStyle = "#333";
34990
34994
  // Columns headers background
34991
- for (let col = left; col <= right; col++) {
34995
+ for (const col of visibleCols) {
34992
34996
  const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
34993
34997
  const { x, width } = this.getters.getVisibleRect(colZone);
34994
34998
  const isColActive = activeCols.has(col);
@@ -35005,7 +35009,7 @@ class GridRenderer {
35005
35009
  ctx.fillRect(x, 0, width, HEADER_HEIGHT);
35006
35010
  }
35007
35011
  // Rows headers background
35008
- for (let row = top; row <= bottom; row++) {
35012
+ for (const row of visibleRows) {
35009
35013
  const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
35010
35014
  const { y, height } = this.getters.getVisibleRect(rowZone);
35011
35015
  const isRowActive = activeRows.has(row);
@@ -35031,21 +35035,21 @@ class GridRenderer {
35031
35035
  ctx.stroke();
35032
35036
  ctx.beginPath();
35033
35037
  // column text + separator
35034
- for (const i of visibleCols) {
35035
- const colSize = this.getters.getColSize(sheetId, i);
35036
- const colName = numberToLetters(i);
35037
- ctx.fillStyle = activeCols.has(i) ? "#fff" : TEXT_HEADER_COLOR;
35038
- let colStart = this.getHeaderOffset("COL", left, i);
35038
+ for (const col of visibleCols) {
35039
+ const colSize = this.getters.getColSize(sheetId, col);
35040
+ const colName = numberToLetters(col);
35041
+ ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
35042
+ let colStart = this.getHeaderOffset("COL", left, col);
35039
35043
  ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
35040
35044
  ctx.moveTo(colStart + colSize, 0);
35041
35045
  ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
35042
35046
  }
35043
35047
  // row text + separator
35044
- for (const i of visibleRows) {
35045
- const rowSize = this.getters.getRowSize(sheetId, i);
35046
- ctx.fillStyle = activeRows.has(i) ? "#fff" : TEXT_HEADER_COLOR;
35047
- let rowStart = this.getHeaderOffset("ROW", top, i);
35048
- ctx.fillText(String(i + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
35048
+ for (const row of visibleRows) {
35049
+ const rowSize = this.getters.getRowSize(sheetId, row);
35050
+ ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
35051
+ let rowStart = this.getHeaderOffset("ROW", top, row);
35052
+ ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
35049
35053
  ctx.moveTo(0, rowStart + rowSize);
35050
35054
  ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
35051
35055
  }
@@ -35337,6 +35341,9 @@ function useGridDrawing(refName, model, canvasSize) {
35337
35341
  canvas.width = width * dpr;
35338
35342
  canvas.height = height * dpr;
35339
35343
  canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
35344
+ if (width === 0 || height === 0) {
35345
+ return;
35346
+ }
35340
35347
  // Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
35341
35348
  // are the edges of the squares. If you draw a one-unit-wide line between whole-number
35342
35349
  // coordinates, it will overlap opposite sides of the pixel square, and the resulting
@@ -40894,7 +40901,7 @@ class BordersPlugin extends CorePlugin {
40894
40901
  getCommonSides(border1, border2) {
40895
40902
  const commonBorder = {};
40896
40903
  for (let side of ["top", "bottom", "left", "right"]) {
40897
- if (border1[side] && border1[side] === border2[side]) {
40904
+ if (border1[side] && deepEquals(border1[side], border2[side])) {
40898
40905
  commonBorder[side] = border1[side];
40899
40906
  }
40900
40907
  }
@@ -53805,8 +53812,17 @@ class InternalViewport {
53805
53812
  this.getters = getters;
53806
53813
  this.sheetId = sheetId;
53807
53814
  this.boundaries = boundaries;
53808
- this.viewportWidth = sizeInGrid.width;
53809
- this.viewportHeight = sizeInGrid.height;
53815
+ if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
53816
+ throw new Error("Viewport size cannot be negative");
53817
+ }
53818
+ this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
53819
+ this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
53820
+ this.top = boundaries.top;
53821
+ this.bottom = boundaries.bottom;
53822
+ this.left = boundaries.left;
53823
+ this.right = boundaries.right;
53824
+ this.offsetX = offsets.x;
53825
+ this.offsetY = offsets.y;
53810
53826
  this.offsetScrollbarX = offsets.x;
53811
53827
  this.offsetScrollbarY = offsets.y;
53812
53828
  this.canScrollVertically = options.canScrollVertically;
@@ -53849,9 +53865,9 @@ class InternalViewport {
53849
53865
  Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
53850
53866
  );
53851
53867
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
53852
- }
53853
- if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
53854
- height += FOOTER_HEIGHT;
53868
+ if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
53869
+ height += FOOTER_HEIGHT;
53870
+ }
53855
53871
  }
53856
53872
  return { width, height };
53857
53873
  }
@@ -53988,6 +54004,9 @@ class InternalViewport {
53988
54004
  !this.getters.isRowHidden(this.sheetId, row));
53989
54005
  }
53990
54006
  searchHeaderIndex(dimension, position, startIndex = 0) {
54007
+ if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
54008
+ return -1;
54009
+ }
53991
54010
  const sheetId = this.sheetId;
53992
54011
  const headers = this.getters.getNumberHeaders(sheetId, dimension);
53993
54012
  // using a binary search:
@@ -54024,7 +54043,7 @@ class InternalViewport {
54024
54043
  this.adjustViewportZoneY();
54025
54044
  }
54026
54045
  /** Corrects the viewport's horizontal offset based on the current structure
54027
- * To make sure that at least on column is visible inside the viewport.
54046
+ * To make sure that at least one column is visible inside the viewport.
54028
54047
  */
54029
54048
  adjustViewportOffsetX() {
54030
54049
  if (this.canScrollHorizontally) {
@@ -54036,7 +54055,7 @@ class InternalViewport {
54036
54055
  this.adjustViewportZoneX();
54037
54056
  }
54038
54057
  /** Corrects the viewport's vertical offset based on the current structure
54039
- * To make sure that at least on row is visible inside the viewport.
54058
+ * To make sure that at least one row is visible inside the viewport.
54040
54059
  */
54041
54060
  adjustViewportOffsetY() {
54042
54061
  if (this.canScrollVertically) {
@@ -54053,11 +54072,14 @@ class InternalViewport {
54053
54072
  const sheetId = this.sheetId;
54054
54073
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
54055
54074
  this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
54075
+ if (!this.viewportWidth) {
54076
+ return;
54077
+ }
54056
54078
  if (this.left === -1) {
54057
54079
  this.left = this.boundaries.left;
54058
54080
  }
54059
54081
  if (this.right === -1) {
54060
- this.right = this.getters.getNumberCols(sheetId) - 1;
54082
+ this.right = this.boundaries.right;
54061
54083
  }
54062
54084
  this.offsetX =
54063
54085
  this.getters.getColDimensions(sheetId, this.left).start -
@@ -54069,11 +54091,14 @@ class InternalViewport {
54069
54091
  const sheetId = this.sheetId;
54070
54092
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
54071
54093
  this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
54094
+ if (!this.viewportHeight) {
54095
+ return;
54096
+ }
54072
54097
  if (this.top === -1) {
54073
54098
  this.top = this.boundaries.top;
54074
54099
  }
54075
54100
  if (this.bottom === -1) {
54076
- this.bottom = this.getters.getNumberRows(sheetId) - 1;
54101
+ this.bottom = this.boundaries.bottom;
54077
54102
  }
54078
54103
  this.offsetY =
54079
54104
  this.getters.getRowDimensions(sheetId, this.top).start -
@@ -54147,7 +54172,7 @@ class SheetViewPlugin extends UIPlugin {
54147
54172
  "isPositionVisible",
54148
54173
  "getColDimensionsInViewport",
54149
54174
  "getRowDimensionsInViewport",
54150
- "getAllActiveViewportsZones",
54175
+ "getAllActiveViewportsZonesAndRect",
54151
54176
  "getRect",
54152
54177
  ];
54153
54178
  viewports = {};
@@ -54381,12 +54406,12 @@ class SheetViewPlugin extends UIPlugin {
54381
54406
  const sheetId = this.getters.getActiveSheetId();
54382
54407
  const viewports = this.getSubViewports(sheetId);
54383
54408
  //TODO ake another commit to eimprove this
54384
- return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
54409
+ return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
54385
54410
  }
54386
54411
  getSheetViewVisibleRows() {
54387
54412
  const sheetId = this.getters.getActiveSheetId();
54388
54413
  const viewports = this.getSubViewports(sheetId);
54389
- return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
54414
+ return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
54390
54415
  }
54391
54416
  /**
54392
54417
  * Get the positions of all the cells that are visible in the viewport, taking merges into account.
@@ -54429,19 +54454,19 @@ class SheetViewPlugin extends UIPlugin {
54429
54454
  maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
54430
54455
  };
54431
54456
  }
54432
- getColRowOffsetInViewport(dimension, referenceIndex, index) {
54433
- const sheetId = this.getters.getActiveSheetId();
54434
- const visibleCols = this.getters.getSheetViewVisibleCols();
54435
- const visibleRows = this.getters.getSheetViewVisibleRows();
54436
- if (index < referenceIndex) {
54437
- return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
54457
+ getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
54458
+ if (targetHeaderIndex < referenceHeaderIndex) {
54459
+ return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
54438
54460
  }
54461
+ const sheetId = this.getters.getActiveSheetId();
54462
+ const visibleHeaders = dimension === "COL"
54463
+ ? this.getters.getSheetViewVisibleCols()
54464
+ : this.getters.getSheetViewVisibleRows();
54465
+ const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
54466
+ const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
54467
+ const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
54439
54468
  let offset = 0;
54440
- const visibleIndexes = dimension === "COL" ? visibleCols : visibleRows;
54441
- for (let i = referenceIndex; i < index; i++) {
54442
- if (!visibleIndexes.includes(i)) {
54443
- continue;
54444
- }
54469
+ for (const i of relevantIndexes) {
54445
54470
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
54446
54471
  }
54447
54472
  return offset;
@@ -54488,7 +54513,7 @@ class SheetViewPlugin extends UIPlugin {
54488
54513
  }
54489
54514
  return { canEdgeScroll, direction, delay };
54490
54515
  }
54491
- getEdgeScrollRow(y, previousY, tartingY) {
54516
+ getEdgeScrollRow(y, previousY, startingY) {
54492
54517
  let canEdgeScroll = false;
54493
54518
  let direction = 0;
54494
54519
  let delay = 0;
@@ -54509,7 +54534,7 @@ class SheetViewPlugin extends UIPlugin {
54509
54534
  delay = scrollDelay(y - height);
54510
54535
  direction = 1;
54511
54536
  }
54512
- else if (y < offsetCorrectionY && tartingY >= offsetCorrectionY && currentOffsetY > 0) {
54537
+ else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
54513
54538
  // 2
54514
54539
  canEdgeScroll = true;
54515
54540
  delay = scrollDelay(offsetCorrectionY - y);
@@ -54535,13 +54560,7 @@ class SheetViewPlugin extends UIPlugin {
54535
54560
  */
54536
54561
  getVisibleRectWithoutHeaders(zone) {
54537
54562
  const sheetId = this.getters.getActiveSheetId();
54538
- const viewportRects = this.getSubViewports(sheetId)
54539
- .map((viewport) => viewport.getVisibleRect(zone))
54540
- .filter(isDefined$1);
54541
- if (viewportRects.length === 0) {
54542
- return { x: 0, y: 0, width: 0, height: 0 };
54543
- }
54544
- return this.recomposeRect(viewportRects);
54563
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
54545
54564
  }
54546
54565
  /**
54547
54566
  * Computes the actual size and position (:Rect) of the zone on the canvas
@@ -54549,13 +54568,7 @@ class SheetViewPlugin extends UIPlugin {
54549
54568
  */
54550
54569
  getRect(zone) {
54551
54570
  const sheetId = this.getters.getActiveSheetId();
54552
- const viewportRects = this.getSubViewports(sheetId)
54553
- .map((viewport) => viewport.getFullRect(zone))
54554
- .filter(isDefined$1);
54555
- if (viewportRects.length === 0) {
54556
- return { x: 0, y: 0, width: 0, height: 0 };
54557
- }
54558
- const rect = this.recomposeRect(viewportRects);
54571
+ const rect = this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
54559
54572
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
54560
54573
  }
54561
54574
  /**
@@ -54600,9 +54613,18 @@ class SheetViewPlugin extends UIPlugin {
54600
54613
  end: start + (isRowHidden ? 0 : size),
54601
54614
  };
54602
54615
  }
54603
- getAllActiveViewportsZones() {
54616
+ getAllActiveViewportsZonesAndRect() {
54604
54617
  const sheetId = this.getters.getActiveSheetId();
54605
- return this.getSubViewports(sheetId);
54618
+ return this.getSubViewports(sheetId).map((viewport) => {
54619
+ return {
54620
+ zone: viewport,
54621
+ rect: {
54622
+ x: viewport.offsetCorrectionX + this.gridOffsetX,
54623
+ y: viewport.offsetCorrectionY + this.gridOffsetY,
54624
+ ...viewport.getMaxSize(),
54625
+ },
54626
+ };
54627
+ });
54606
54628
  }
54607
54629
  // ---------------------------------------------------------------------------
54608
54630
  // Private
@@ -54655,12 +54677,11 @@ class SheetViewPlugin extends UIPlugin {
54655
54677
  }
54656
54678
  /** gets rid of deprecated sheetIds */
54657
54679
  cleanViewports() {
54658
- const sheetIds = this.getters.getSheetIds();
54659
- for (let sheetId of Object.keys(this.viewports)) {
54660
- if (!sheetIds.includes(sheetId)) {
54661
- delete this.viewports[sheetId];
54662
- }
54680
+ const newViewport = {};
54681
+ for (const sheetId of this.getters.getSheetIds()) {
54682
+ newViewport[sheetId] = this.viewports[sheetId];
54663
54683
  }
54684
+ this.viewports = newViewport;
54664
54685
  }
54665
54686
  resizeSheetView(height, width, gridOffsetX = 0, gridOffsetY = 0) {
54666
54687
  this.sheetViewHeight = height;
@@ -54670,14 +54691,14 @@ class SheetViewPlugin extends UIPlugin {
54670
54691
  this.recomputeViewports();
54671
54692
  }
54672
54693
  recomputeViewports() {
54673
- for (let sheetId of Object.keys(this.viewports)) {
54694
+ for (const sheetId of this.getters.getSheetIds()) {
54674
54695
  this.resetViewports(sheetId);
54675
54696
  }
54676
54697
  }
54677
54698
  setSheetViewOffset(offsetX, offsetY) {
54678
54699
  const sheetId = this.getters.getActiveSheetId();
54679
54700
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
54680
- Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
54701
+ this.getSubViewports(sheetId).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
54681
54702
  }
54682
54703
  getViewportOffset(sheetId) {
54683
54704
  return {
@@ -54692,8 +54713,10 @@ class SheetViewPlugin extends UIPlugin {
54692
54713
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
54693
54714
  const nCols = this.getters.getNumberCols(sheetId);
54694
54715
  const nRows = this.getters.getNumberRows(sheetId);
54695
- const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
54696
- const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
54716
+ const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
54717
+ const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
54718
+ const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
54719
+ const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
54697
54720
  const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
54698
54721
  const canScrollHorizontally = xRatio < 1.0;
54699
54722
  const canScrollVertically = yRatio < 1.0;
@@ -54704,14 +54727,14 @@ class SheetViewPlugin extends UIPlugin {
54704
54727
  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 })) ||
54705
54728
  undefined,
54706
54729
  topRight: (ySplit &&
54707
- 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 })) ||
54730
+ 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 })) ||
54708
54731
  undefined,
54709
54732
  bottomLeft: (xSplit &&
54710
- 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 })) ||
54733
+ 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 })) ||
54711
54734
  undefined,
54712
54735
  bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
54713
- width: this.sheetViewWidth - colOffset,
54714
- height: this.sheetViewHeight - rowOffset,
54736
+ width: unfrozenWidth,
54737
+ height: unfrozenHeight,
54715
54738
  }, { canScrollHorizontally, canScrollVertically }, {
54716
54739
  x: canScrollHorizontally ? previousOffset.x : 0,
54717
54740
  y: canScrollVertically ? previousOffset.y : 0,
@@ -54723,7 +54746,7 @@ class SheetViewPlugin extends UIPlugin {
54723
54746
  * Adjust the viewport such that the anchor position is visible
54724
54747
  */
54725
54748
  refreshViewport(sheetId, anchorPosition) {
54726
- Object.values(this.getSubViewports(sheetId)).forEach((viewport) => {
54749
+ this.getSubViewports(sheetId).forEach((viewport) => {
54727
54750
  viewport.adjustViewportZone();
54728
54751
  viewport.adjustPosition(anchorPosition);
54729
54752
  });
@@ -54788,12 +54811,26 @@ class SheetViewPlugin extends UIPlugin {
54788
54811
  const height = this.sheetViewHeight + this.gridOffsetY;
54789
54812
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
54790
54813
  }
54791
- recomposeRect(viewportRects) {
54792
- const x = Math.min(...viewportRects.map((rect) => rect.x));
54793
- const y = Math.min(...viewportRects.map((rect) => rect.y));
54794
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
54795
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
54796
- return { x, y, width, height };
54814
+ mapViewportsToRect(sheetId, rectCallBack) {
54815
+ let x = Infinity;
54816
+ let y = Infinity;
54817
+ let width = 0;
54818
+ let height = 0;
54819
+ let hasViewports = false;
54820
+ for (const viewport of this.getSubViewports(sheetId)) {
54821
+ const rect = rectCallBack(viewport);
54822
+ if (rect) {
54823
+ hasViewports = true;
54824
+ x = Math.min(x, rect.x);
54825
+ y = Math.min(y, rect.y);
54826
+ width = Math.max(width, rect.x + rect.width);
54827
+ height = Math.max(height, rect.y + rect.height);
54828
+ }
54829
+ }
54830
+ if (!hasViewports) {
54831
+ return { x: 0, y: 0, width: 0, height: 0 };
54832
+ }
54833
+ return { x, y, width: width - x, height: height - y };
54797
54834
  }
54798
54835
  }
54799
54836
 
@@ -61091,6 +61128,6 @@ const constants = {
61091
61128
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
61092
61129
 
61093
61130
 
61094
- __info__.version = "17.2.34";
61095
- __info__.date = "2025-01-31T07:58:03.953Z";
61096
- __info__.hash = "0bffee9";
61131
+ __info__.version = "17.2.35";
61132
+ __info__.date = "2025-02-05T07:12:34.721Z";
61133
+ __info__.hash = "76b12a1";