@odoo/o-spreadsheet 17.2.34 → 17.2.36

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.36
7
+ * @date 2025-02-10T08:59:25.719Z
8
+ * @hash 5a942bd
9
9
  */
10
10
 
11
11
  'use strict';
@@ -606,9 +606,16 @@ function deepEquals(o1, o2) {
606
606
  }
607
607
  return true;
608
608
  }
609
- /** Check if the given array contains all the values of the other array. */
609
+ /**
610
+ * Check if the given array contains all the values of the other array.
611
+ * It makes the assumption that both array do not contain duplicates.
612
+ */
610
613
  function includesAll(arr, values) {
611
- return values.every((value) => arr.includes(value));
614
+ if (arr.length < values.length) {
615
+ return false;
616
+ }
617
+ const set = new Set(arr);
618
+ return values.every((value) => set.has(value));
612
619
  }
613
620
  /**
614
621
  * Return an object with all the keys in the object that have a falsy value removed.
@@ -17753,23 +17760,24 @@ const HLOOKUP = {
17753
17760
  description: _t("Horizontal lookup"),
17754
17761
  args: [
17755
17762
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
17756
- 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.")),
17763
+ 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.")),
17757
17764
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
17758
17765
  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.")),
17759
17766
  ],
17760
17767
  returns: ["ANY"],
17761
17768
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
17762
17769
  const _index = Math.trunc(toNumber(index?.value, this.locale));
17763
- assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
17770
+ const _range = toMatrix(range);
17771
+ assert(() => 1 <= _index && _index <= _range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
17764
17772
  if (searchKey && isEvaluationError(searchKey.value)) {
17765
17773
  return searchKey;
17766
17774
  }
17767
17775
  const getValueFromRange = (range, index) => range[index][0].value;
17768
17776
  const _isSorted = toBoolean(isSorted.value);
17769
17777
  const colIndex = _isSorted
17770
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
17771
- : linearSearch(range, searchKey, "wildcard", range.length, getValueFromRange);
17772
- const col = range[colIndex];
17778
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
17779
+ : linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange);
17780
+ const col = _range[colIndex];
17773
17781
  if (col === undefined) {
17774
17782
  return valueNotAvailable(searchKey);
17775
17783
  }
@@ -17878,36 +17886,38 @@ const LOOKUP = {
17878
17886
  description: _t("Look up a value."),
17879
17887
  args: [
17880
17888
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
17881
- 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.")),
17882
- 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.")),
17889
+ 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.")),
17890
+ 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.")),
17883
17891
  ],
17884
17892
  returns: ["ANY"],
17885
17893
  compute: function (searchKey, searchArray, resultRange) {
17886
- let nbCol = searchArray.length;
17887
- let nbRow = searchArray[0].length;
17894
+ const _searchArray = toMatrix(searchArray);
17895
+ const _resultRange = toMatrix(resultRange);
17896
+ let nbCol = _searchArray.length;
17897
+ let nbRow = _searchArray[0].length;
17888
17898
  const verticalSearch = nbRow >= nbCol;
17889
17899
  const getElement = verticalSearch
17890
17900
  ? (range, index) => range[0][index].value
17891
17901
  : (range, index) => range[index][0].value;
17892
17902
  const rangeLength = verticalSearch ? nbRow : nbCol;
17893
- const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
17903
+ const index = dichotomicSearch(_searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
17894
17904
  if (index === -1 ||
17895
- (verticalSearch && searchArray[0][index] === undefined) ||
17896
- (!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
17905
+ (verticalSearch && _searchArray[0][index] === undefined) ||
17906
+ (!verticalSearch && _searchArray[index][nbRow - 1] === undefined)) {
17897
17907
  return valueNotAvailable(searchKey);
17898
17908
  }
17899
- if (resultRange === undefined) {
17900
- return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
17909
+ if (_resultRange[0].length === 0) {
17910
+ return verticalSearch ? _searchArray[nbCol - 1][index] : _searchArray[index][nbRow - 1];
17901
17911
  }
17902
- nbCol = resultRange.length;
17903
- nbRow = resultRange[0].length;
17912
+ nbCol = _resultRange.length;
17913
+ nbRow = _resultRange[0].length;
17904
17914
  assert(() => nbCol === 1 || nbRow === 1, _t("The result_range must be a single row or a single column."));
17905
17915
  if (nbCol > 1) {
17906
17916
  assert(() => index <= nbCol - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range row value %s.", (index + 1).toString()));
17907
- return resultRange[index][0];
17917
+ return _resultRange[index][0];
17908
17918
  }
17909
17919
  assert(() => index <= nbRow - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range column value %s.", (index + 1).toString()));
17910
- return resultRange[0][index];
17920
+ return _resultRange[0][index];
17911
17921
  },
17912
17922
  isExported: true,
17913
17923
  };
@@ -17925,28 +17935,29 @@ const MATCH = {
17925
17935
  returns: ["NUMBER"],
17926
17936
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
17927
17937
  let _searchType = toNumber(searchType, this.locale);
17928
- const nbCol = range.length;
17929
- const nbRow = range[0].length;
17938
+ const _range = toMatrix(range);
17939
+ const nbCol = _range.length;
17940
+ const nbRow = _range[0].length;
17930
17941
  assert(() => nbCol === 1 || nbRow === 1, _t("The range must be a single row or a single column."));
17931
17942
  let index = -1;
17932
17943
  const getElement = nbCol === 1
17933
- ? (range, index) => range[0][index].value
17934
- : (range, index) => range[index][0].value;
17935
- const rangeLen = nbCol === 1 ? range[0].length : range.length;
17944
+ ? (_range, index) => _range[0][index].value
17945
+ : (_range, index) => _range[index][0].value;
17946
+ const rangeLen = nbCol === 1 ? _range[0].length : _range.length;
17936
17947
  _searchType = Math.sign(_searchType);
17937
17948
  switch (_searchType) {
17938
17949
  case 1:
17939
- index = dichotomicSearch(range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
17950
+ index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
17940
17951
  break;
17941
17952
  case 0:
17942
- index = linearSearch(range, searchKey, "wildcard", rangeLen, getElement);
17953
+ index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement);
17943
17954
  break;
17944
17955
  case -1:
17945
- index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
17956
+ index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
17946
17957
  break;
17947
17958
  }
17948
- if ((nbCol === 1 && range[0][index] === undefined) ||
17949
- (nbCol !== 1 && range[index] === undefined)) {
17959
+ if ((nbCol === 1 && _range[0][index] === undefined) ||
17960
+ (nbCol !== 1 && _range[index] === undefined)) {
17950
17961
  return valueNotAvailable(searchKey);
17951
17962
  }
17952
17963
  return index + 1;
@@ -17997,16 +18008,17 @@ const VLOOKUP = {
17997
18008
  returns: ["ANY"],
17998
18009
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
17999
18010
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18000
- assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18011
+ const _range = toMatrix(range);
18012
+ assert(() => 1 <= _index && _index <= _range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18001
18013
  if (searchKey && isEvaluationError(searchKey.value)) {
18002
18014
  return searchKey;
18003
18015
  }
18004
18016
  const getValueFromRange = (range, index) => range[0][index].value;
18005
18017
  const _isSorted = toBoolean(isSorted.value);
18006
18018
  const rowIndex = _isSorted
18007
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
18008
- : linearSearch(range, searchKey, "wildcard", range[0].length, getValueFromRange);
18009
- const value = range[_index - 1][rowIndex];
18019
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
18020
+ : linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange);
18021
+ const value = _range[_index - 1][rowIndex];
18010
18022
  if (value === undefined) {
18011
18023
  return valueNotAvailable(searchKey);
18012
18024
  }
@@ -18044,30 +18056,32 @@ const XLOOKUP = {
18044
18056
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18045
18057
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18046
18058
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
18047
- assert(() => lookupRange.length === 1 || lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18059
+ const _lookupRange = toMatrix(lookupRange);
18060
+ const _returnRange = toMatrix(returnRange);
18061
+ assert(() => _lookupRange.length === 1 || _lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18048
18062
  assert(() => [-1, 1, -2, 2].includes(_searchMode), _t("search_mode should be a value in [-1, 1, -2, 2]."));
18049
18063
  assert(() => [-1, 0, 1, 2].includes(_matchMode), _t("match_mode should be a value in [-1, 0, 1, 2]."));
18050
- const lookupDirection = lookupRange.length === 1 ? "col" : "row";
18064
+ const lookupDirection = _lookupRange.length === 1 ? "col" : "row";
18051
18065
  assert(() => !(_matchMode === 2 && [-2, 2].includes(_searchMode)), _t("the search and match mode combination is not supported for XLOOKUP evaluation."));
18052
18066
  assert(() => lookupDirection === "col"
18053
- ? returnRange[0].length === lookupRange[0].length
18054
- : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18067
+ ? _returnRange[0].length === _lookupRange[0].length
18068
+ : _returnRange.length === _lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18055
18069
  if (searchKey && isEvaluationError(searchKey.value)) {
18056
18070
  return [[searchKey]];
18057
18071
  }
18058
18072
  const getElement = lookupDirection === "col"
18059
18073
  ? (range, index) => range[0][index].value
18060
18074
  : (range, index) => range[index][0].value;
18061
- const rangeLen = lookupDirection === "col" ? lookupRange[0].length : lookupRange.length;
18075
+ const rangeLen = lookupDirection === "col" ? _lookupRange[0].length : _lookupRange.length;
18062
18076
  const mode = MATCH_MODE[_matchMode];
18063
18077
  const reverseSearch = _searchMode === -1;
18064
18078
  const index = _searchMode === 2 || _searchMode === -2
18065
- ? dichotomicSearch(lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18066
- : linearSearch(lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
18079
+ ? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18080
+ : linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
18067
18081
  if (index !== -1) {
18068
18082
  return lookupDirection === "col"
18069
- ? returnRange.map((col) => [col[index]])
18070
- : [returnRange[index]];
18083
+ ? _returnRange.map((col) => [col[index]])
18084
+ : [_returnRange[index]];
18071
18085
  }
18072
18086
  if (defaultValue === undefined) {
18073
18087
  return valueNotAvailable(searchKey);
@@ -34697,11 +34711,10 @@ class GridRenderer {
34697
34711
  switch (layer) {
34698
34712
  case "Background":
34699
34713
  this.drawGlobalBackground(renderingContext);
34700
- for (const zone of this.getters.getAllActiveViewportsZones()) {
34714
+ for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
34701
34715
  const { ctx } = renderingContext;
34702
34716
  ctx.save();
34703
34717
  ctx.beginPath();
34704
- const rect = this.getters.getVisibleRect(zone);
34705
34718
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
34706
34719
  ctx.clip();
34707
34720
  const boxes = this.getGridBoxes(zone);
@@ -34971,10 +34984,8 @@ class GridRenderer {
34971
34984
  const { ctx, thinLineWidth } = renderingContext;
34972
34985
  const visibleCols = this.getters.getSheetViewVisibleCols();
34973
34986
  const left = visibleCols[0];
34974
- const right = visibleCols[visibleCols.length - 1];
34975
34987
  const visibleRows = this.getters.getSheetViewVisibleRows();
34976
34988
  const top = visibleRows[0];
34977
- const bottom = visibleRows[visibleRows.length - 1];
34978
34989
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
34979
34990
  const selection = this.getters.getSelectedZones();
34980
34991
  const selectedCols = getZonesCols(selection);
@@ -34990,7 +35001,7 @@ class GridRenderer {
34990
35001
  ctx.lineWidth = thinLineWidth;
34991
35002
  ctx.strokeStyle = "#333";
34992
35003
  // Columns headers background
34993
- for (let col = left; col <= right; col++) {
35004
+ for (const col of visibleCols) {
34994
35005
  const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
34995
35006
  const { x, width } = this.getters.getVisibleRect(colZone);
34996
35007
  const isColActive = activeCols.has(col);
@@ -35007,7 +35018,7 @@ class GridRenderer {
35007
35018
  ctx.fillRect(x, 0, width, HEADER_HEIGHT);
35008
35019
  }
35009
35020
  // Rows headers background
35010
- for (let row = top; row <= bottom; row++) {
35021
+ for (const row of visibleRows) {
35011
35022
  const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
35012
35023
  const { y, height } = this.getters.getVisibleRect(rowZone);
35013
35024
  const isRowActive = activeRows.has(row);
@@ -35033,21 +35044,21 @@ class GridRenderer {
35033
35044
  ctx.stroke();
35034
35045
  ctx.beginPath();
35035
35046
  // column text + separator
35036
- for (const i of visibleCols) {
35037
- const colSize = this.getters.getColSize(sheetId, i);
35038
- const colName = numberToLetters(i);
35039
- ctx.fillStyle = activeCols.has(i) ? "#fff" : TEXT_HEADER_COLOR;
35040
- let colStart = this.getHeaderOffset("COL", left, i);
35047
+ for (const col of visibleCols) {
35048
+ const colSize = this.getters.getColSize(sheetId, col);
35049
+ const colName = numberToLetters(col);
35050
+ ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
35051
+ let colStart = this.getHeaderOffset("COL", left, col);
35041
35052
  ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
35042
35053
  ctx.moveTo(colStart + colSize, 0);
35043
35054
  ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
35044
35055
  }
35045
35056
  // row text + separator
35046
- for (const i of visibleRows) {
35047
- const rowSize = this.getters.getRowSize(sheetId, i);
35048
- ctx.fillStyle = activeRows.has(i) ? "#fff" : TEXT_HEADER_COLOR;
35049
- let rowStart = this.getHeaderOffset("ROW", top, i);
35050
- ctx.fillText(String(i + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
35057
+ for (const row of visibleRows) {
35058
+ const rowSize = this.getters.getRowSize(sheetId, row);
35059
+ ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
35060
+ let rowStart = this.getHeaderOffset("ROW", top, row);
35061
+ ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
35051
35062
  ctx.moveTo(0, rowStart + rowSize);
35052
35063
  ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
35053
35064
  }
@@ -35339,6 +35350,9 @@ function useGridDrawing(refName, model, canvasSize) {
35339
35350
  canvas.width = width * dpr;
35340
35351
  canvas.height = height * dpr;
35341
35352
  canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
35353
+ if (width === 0 || height === 0) {
35354
+ return;
35355
+ }
35342
35356
  // Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
35343
35357
  // are the edges of the squares. If you draw a one-unit-wide line between whole-number
35344
35358
  // coordinates, it will overlap opposite sides of the pixel square, and the resulting
@@ -40896,7 +40910,7 @@ class BordersPlugin extends CorePlugin {
40896
40910
  getCommonSides(border1, border2) {
40897
40911
  const commonBorder = {};
40898
40912
  for (let side of ["top", "bottom", "left", "right"]) {
40899
- if (border1[side] && border1[side] === border2[side]) {
40913
+ if (border1[side] && deepEquals(border1[side], border2[side])) {
40900
40914
  commonBorder[side] = border1[side];
40901
40915
  }
40902
40916
  }
@@ -53807,8 +53821,17 @@ class InternalViewport {
53807
53821
  this.getters = getters;
53808
53822
  this.sheetId = sheetId;
53809
53823
  this.boundaries = boundaries;
53810
- this.viewportWidth = sizeInGrid.width;
53811
- this.viewportHeight = sizeInGrid.height;
53824
+ if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
53825
+ throw new Error("Viewport size cannot be negative");
53826
+ }
53827
+ this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
53828
+ this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
53829
+ this.top = boundaries.top;
53830
+ this.bottom = boundaries.bottom;
53831
+ this.left = boundaries.left;
53832
+ this.right = boundaries.right;
53833
+ this.offsetX = offsets.x;
53834
+ this.offsetY = offsets.y;
53812
53835
  this.offsetScrollbarX = offsets.x;
53813
53836
  this.offsetScrollbarY = offsets.y;
53814
53837
  this.canScrollVertically = options.canScrollVertically;
@@ -53851,9 +53874,9 @@ class InternalViewport {
53851
53874
  Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
53852
53875
  );
53853
53876
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
53854
- }
53855
- if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
53856
- height += FOOTER_HEIGHT;
53877
+ if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
53878
+ height += FOOTER_HEIGHT;
53879
+ }
53857
53880
  }
53858
53881
  return { width, height };
53859
53882
  }
@@ -53990,6 +54013,9 @@ class InternalViewport {
53990
54013
  !this.getters.isRowHidden(this.sheetId, row));
53991
54014
  }
53992
54015
  searchHeaderIndex(dimension, position, startIndex = 0) {
54016
+ if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
54017
+ return -1;
54018
+ }
53993
54019
  const sheetId = this.sheetId;
53994
54020
  const headers = this.getters.getNumberHeaders(sheetId, dimension);
53995
54021
  // using a binary search:
@@ -54026,7 +54052,7 @@ class InternalViewport {
54026
54052
  this.adjustViewportZoneY();
54027
54053
  }
54028
54054
  /** Corrects the viewport's horizontal offset based on the current structure
54029
- * To make sure that at least on column is visible inside the viewport.
54055
+ * To make sure that at least one column is visible inside the viewport.
54030
54056
  */
54031
54057
  adjustViewportOffsetX() {
54032
54058
  if (this.canScrollHorizontally) {
@@ -54038,7 +54064,7 @@ class InternalViewport {
54038
54064
  this.adjustViewportZoneX();
54039
54065
  }
54040
54066
  /** Corrects the viewport's vertical offset based on the current structure
54041
- * To make sure that at least on row is visible inside the viewport.
54067
+ * To make sure that at least one row is visible inside the viewport.
54042
54068
  */
54043
54069
  adjustViewportOffsetY() {
54044
54070
  if (this.canScrollVertically) {
@@ -54055,11 +54081,14 @@ class InternalViewport {
54055
54081
  const sheetId = this.sheetId;
54056
54082
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
54057
54083
  this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
54084
+ if (!this.viewportWidth) {
54085
+ return;
54086
+ }
54058
54087
  if (this.left === -1) {
54059
54088
  this.left = this.boundaries.left;
54060
54089
  }
54061
54090
  if (this.right === -1) {
54062
- this.right = this.getters.getNumberCols(sheetId) - 1;
54091
+ this.right = this.boundaries.right;
54063
54092
  }
54064
54093
  this.offsetX =
54065
54094
  this.getters.getColDimensions(sheetId, this.left).start -
@@ -54071,11 +54100,14 @@ class InternalViewport {
54071
54100
  const sheetId = this.sheetId;
54072
54101
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
54073
54102
  this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
54103
+ if (!this.viewportHeight) {
54104
+ return;
54105
+ }
54074
54106
  if (this.top === -1) {
54075
54107
  this.top = this.boundaries.top;
54076
54108
  }
54077
54109
  if (this.bottom === -1) {
54078
- this.bottom = this.getters.getNumberRows(sheetId) - 1;
54110
+ this.bottom = this.boundaries.bottom;
54079
54111
  }
54080
54112
  this.offsetY =
54081
54113
  this.getters.getRowDimensions(sheetId, this.top).start -
@@ -54149,7 +54181,7 @@ class SheetViewPlugin extends UIPlugin {
54149
54181
  "isPositionVisible",
54150
54182
  "getColDimensionsInViewport",
54151
54183
  "getRowDimensionsInViewport",
54152
- "getAllActiveViewportsZones",
54184
+ "getAllActiveViewportsZonesAndRect",
54153
54185
  "getRect",
54154
54186
  ];
54155
54187
  viewports = {};
@@ -54383,12 +54415,12 @@ class SheetViewPlugin extends UIPlugin {
54383
54415
  const sheetId = this.getters.getActiveSheetId();
54384
54416
  const viewports = this.getSubViewports(sheetId);
54385
54417
  //TODO ake another commit to eimprove this
54386
- return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
54418
+ return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
54387
54419
  }
54388
54420
  getSheetViewVisibleRows() {
54389
54421
  const sheetId = this.getters.getActiveSheetId();
54390
54422
  const viewports = this.getSubViewports(sheetId);
54391
- return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
54423
+ return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
54392
54424
  }
54393
54425
  /**
54394
54426
  * Get the positions of all the cells that are visible in the viewport, taking merges into account.
@@ -54431,19 +54463,19 @@ class SheetViewPlugin extends UIPlugin {
54431
54463
  maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
54432
54464
  };
54433
54465
  }
54434
- getColRowOffsetInViewport(dimension, referenceIndex, index) {
54435
- const sheetId = this.getters.getActiveSheetId();
54436
- const visibleCols = this.getters.getSheetViewVisibleCols();
54437
- const visibleRows = this.getters.getSheetViewVisibleRows();
54438
- if (index < referenceIndex) {
54439
- return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
54466
+ getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
54467
+ if (targetHeaderIndex < referenceHeaderIndex) {
54468
+ return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
54440
54469
  }
54470
+ const sheetId = this.getters.getActiveSheetId();
54471
+ const visibleHeaders = dimension === "COL"
54472
+ ? this.getters.getSheetViewVisibleCols()
54473
+ : this.getters.getSheetViewVisibleRows();
54474
+ const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
54475
+ const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
54476
+ const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
54441
54477
  let offset = 0;
54442
- const visibleIndexes = dimension === "COL" ? visibleCols : visibleRows;
54443
- for (let i = referenceIndex; i < index; i++) {
54444
- if (!visibleIndexes.includes(i)) {
54445
- continue;
54446
- }
54478
+ for (const i of relevantIndexes) {
54447
54479
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
54448
54480
  }
54449
54481
  return offset;
@@ -54490,7 +54522,7 @@ class SheetViewPlugin extends UIPlugin {
54490
54522
  }
54491
54523
  return { canEdgeScroll, direction, delay };
54492
54524
  }
54493
- getEdgeScrollRow(y, previousY, tartingY) {
54525
+ getEdgeScrollRow(y, previousY, startingY) {
54494
54526
  let canEdgeScroll = false;
54495
54527
  let direction = 0;
54496
54528
  let delay = 0;
@@ -54511,7 +54543,7 @@ class SheetViewPlugin extends UIPlugin {
54511
54543
  delay = scrollDelay(y - height);
54512
54544
  direction = 1;
54513
54545
  }
54514
- else if (y < offsetCorrectionY && tartingY >= offsetCorrectionY && currentOffsetY > 0) {
54546
+ else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
54515
54547
  // 2
54516
54548
  canEdgeScroll = true;
54517
54549
  delay = scrollDelay(offsetCorrectionY - y);
@@ -54537,13 +54569,7 @@ class SheetViewPlugin extends UIPlugin {
54537
54569
  */
54538
54570
  getVisibleRectWithoutHeaders(zone) {
54539
54571
  const sheetId = this.getters.getActiveSheetId();
54540
- const viewportRects = this.getSubViewports(sheetId)
54541
- .map((viewport) => viewport.getVisibleRect(zone))
54542
- .filter(isDefined$1);
54543
- if (viewportRects.length === 0) {
54544
- return { x: 0, y: 0, width: 0, height: 0 };
54545
- }
54546
- return this.recomposeRect(viewportRects);
54572
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
54547
54573
  }
54548
54574
  /**
54549
54575
  * Computes the actual size and position (:Rect) of the zone on the canvas
@@ -54551,13 +54577,7 @@ class SheetViewPlugin extends UIPlugin {
54551
54577
  */
54552
54578
  getRect(zone) {
54553
54579
  const sheetId = this.getters.getActiveSheetId();
54554
- const viewportRects = this.getSubViewports(sheetId)
54555
- .map((viewport) => viewport.getFullRect(zone))
54556
- .filter(isDefined$1);
54557
- if (viewportRects.length === 0) {
54558
- return { x: 0, y: 0, width: 0, height: 0 };
54559
- }
54560
- const rect = this.recomposeRect(viewportRects);
54580
+ const rect = this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
54561
54581
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
54562
54582
  }
54563
54583
  /**
@@ -54602,9 +54622,18 @@ class SheetViewPlugin extends UIPlugin {
54602
54622
  end: start + (isRowHidden ? 0 : size),
54603
54623
  };
54604
54624
  }
54605
- getAllActiveViewportsZones() {
54625
+ getAllActiveViewportsZonesAndRect() {
54606
54626
  const sheetId = this.getters.getActiveSheetId();
54607
- return this.getSubViewports(sheetId);
54627
+ return this.getSubViewports(sheetId).map((viewport) => {
54628
+ return {
54629
+ zone: viewport,
54630
+ rect: {
54631
+ x: viewport.offsetCorrectionX + this.gridOffsetX,
54632
+ y: viewport.offsetCorrectionY + this.gridOffsetY,
54633
+ ...viewport.getMaxSize(),
54634
+ },
54635
+ };
54636
+ });
54608
54637
  }
54609
54638
  // ---------------------------------------------------------------------------
54610
54639
  // Private
@@ -54657,12 +54686,11 @@ class SheetViewPlugin extends UIPlugin {
54657
54686
  }
54658
54687
  /** gets rid of deprecated sheetIds */
54659
54688
  cleanViewports() {
54660
- const sheetIds = this.getters.getSheetIds();
54661
- for (let sheetId of Object.keys(this.viewports)) {
54662
- if (!sheetIds.includes(sheetId)) {
54663
- delete this.viewports[sheetId];
54664
- }
54689
+ const newViewport = {};
54690
+ for (const sheetId of this.getters.getSheetIds()) {
54691
+ newViewport[sheetId] = this.viewports[sheetId];
54665
54692
  }
54693
+ this.viewports = newViewport;
54666
54694
  }
54667
54695
  resizeSheetView(height, width, gridOffsetX = 0, gridOffsetY = 0) {
54668
54696
  this.sheetViewHeight = height;
@@ -54672,14 +54700,14 @@ class SheetViewPlugin extends UIPlugin {
54672
54700
  this.recomputeViewports();
54673
54701
  }
54674
54702
  recomputeViewports() {
54675
- for (let sheetId of Object.keys(this.viewports)) {
54703
+ for (const sheetId of this.getters.getSheetIds()) {
54676
54704
  this.resetViewports(sheetId);
54677
54705
  }
54678
54706
  }
54679
54707
  setSheetViewOffset(offsetX, offsetY) {
54680
54708
  const sheetId = this.getters.getActiveSheetId();
54681
54709
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
54682
- Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
54710
+ this.getSubViewports(sheetId).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
54683
54711
  }
54684
54712
  getViewportOffset(sheetId) {
54685
54713
  return {
@@ -54694,8 +54722,10 @@ class SheetViewPlugin extends UIPlugin {
54694
54722
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
54695
54723
  const nCols = this.getters.getNumberCols(sheetId);
54696
54724
  const nRows = this.getters.getNumberRows(sheetId);
54697
- const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
54698
- const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
54725
+ const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
54726
+ const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
54727
+ const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
54728
+ const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
54699
54729
  const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
54700
54730
  const canScrollHorizontally = xRatio < 1.0;
54701
54731
  const canScrollVertically = yRatio < 1.0;
@@ -54706,14 +54736,14 @@ class SheetViewPlugin extends UIPlugin {
54706
54736
  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 })) ||
54707
54737
  undefined,
54708
54738
  topRight: (ySplit &&
54709
- 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 })) ||
54739
+ 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 })) ||
54710
54740
  undefined,
54711
54741
  bottomLeft: (xSplit &&
54712
- 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 })) ||
54742
+ 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 })) ||
54713
54743
  undefined,
54714
54744
  bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
54715
- width: this.sheetViewWidth - colOffset,
54716
- height: this.sheetViewHeight - rowOffset,
54745
+ width: unfrozenWidth,
54746
+ height: unfrozenHeight,
54717
54747
  }, { canScrollHorizontally, canScrollVertically }, {
54718
54748
  x: canScrollHorizontally ? previousOffset.x : 0,
54719
54749
  y: canScrollVertically ? previousOffset.y : 0,
@@ -54725,7 +54755,7 @@ class SheetViewPlugin extends UIPlugin {
54725
54755
  * Adjust the viewport such that the anchor position is visible
54726
54756
  */
54727
54757
  refreshViewport(sheetId, anchorPosition) {
54728
- Object.values(this.getSubViewports(sheetId)).forEach((viewport) => {
54758
+ this.getSubViewports(sheetId).forEach((viewport) => {
54729
54759
  viewport.adjustViewportZone();
54730
54760
  viewport.adjustPosition(anchorPosition);
54731
54761
  });
@@ -54790,12 +54820,26 @@ class SheetViewPlugin extends UIPlugin {
54790
54820
  const height = this.sheetViewHeight + this.gridOffsetY;
54791
54821
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
54792
54822
  }
54793
- recomposeRect(viewportRects) {
54794
- const x = Math.min(...viewportRects.map((rect) => rect.x));
54795
- const y = Math.min(...viewportRects.map((rect) => rect.y));
54796
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
54797
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
54798
- return { x, y, width, height };
54823
+ mapViewportsToRect(sheetId, rectCallBack) {
54824
+ let x = Infinity;
54825
+ let y = Infinity;
54826
+ let width = 0;
54827
+ let height = 0;
54828
+ let hasViewports = false;
54829
+ for (const viewport of this.getSubViewports(sheetId)) {
54830
+ const rect = rectCallBack(viewport);
54831
+ if (rect) {
54832
+ hasViewports = true;
54833
+ x = Math.min(x, rect.x);
54834
+ y = Math.min(y, rect.y);
54835
+ width = Math.max(width, rect.x + rect.width);
54836
+ height = Math.max(height, rect.y + rect.height);
54837
+ }
54838
+ }
54839
+ if (!hasViewports) {
54840
+ return { x: 0, y: 0, width: 0, height: 0 };
54841
+ }
54842
+ return { x, y, width: width - x, height: height - y };
54799
54843
  }
54800
54844
  }
54801
54845
 
@@ -61134,6 +61178,6 @@ exports.tokenColors = tokenColors;
61134
61178
  exports.tokenize = tokenize;
61135
61179
 
61136
61180
 
61137
- __info__.version = "17.2.34";
61138
- __info__.date = "2025-01-31T07:58:03.953Z";
61139
- __info__.hash = "0bffee9";
61181
+ __info__.version = "17.2.36";
61182
+ __info__.date = "2025-02-10T08:59:25.719Z";
61183
+ __info__.hash = "5a942bd";