@odoo/o-spreadsheet 17.4.20 → 17.4.21

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.4.20
6
- * @date 2025-01-31T08:00:07.103Z
7
- * @hash 54a344a
5
+ * @version 17.4.21
6
+ * @date 2025-02-05T06:46:54.366Z
7
+ * @hash 0c55e18
8
8
  */
9
9
 
10
10
  'use strict';
@@ -18883,22 +18883,23 @@ const HLOOKUP = {
18883
18883
  description: _t("Horizontal lookup"),
18884
18884
  args: [
18885
18885
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18886
- 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.")),
18886
+ 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.")),
18887
18887
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18888
18888
  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.")),
18889
18889
  ],
18890
18890
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18891
18891
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18892
- assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18892
+ const _range = toMatrix(range);
18893
+ assert(() => 1 <= _index && _index <= _range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18893
18894
  if (searchKey && isEvaluationError(searchKey.value)) {
18894
18895
  return searchKey;
18895
18896
  }
18896
18897
  const getValueFromRange = (range, index) => range[index][0].value;
18897
18898
  const _isSorted = toBoolean(isSorted.value);
18898
18899
  const colIndex = _isSorted
18899
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
18900
- : linearSearch(range, searchKey, "wildcard", range.length, getValueFromRange);
18901
- const col = range[colIndex];
18900
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
18901
+ : linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange);
18902
+ const col = _range[colIndex];
18902
18903
  if (col === undefined) {
18903
18904
  return valueNotAvailable(searchKey);
18904
18905
  }
@@ -18997,35 +18998,37 @@ const LOOKUP = {
18997
18998
  description: _t("Look up a value."),
18998
18999
  args: [
18999
19000
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
19000
- 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.")),
19001
- 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.")),
19001
+ 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.")),
19002
+ 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.")),
19002
19003
  ],
19003
19004
  compute: function (searchKey, searchArray, resultRange) {
19004
- let nbCol = searchArray.length;
19005
- let nbRow = searchArray[0].length;
19005
+ const _searchArray = toMatrix(searchArray);
19006
+ const _resultRange = toMatrix(resultRange);
19007
+ let nbCol = _searchArray.length;
19008
+ let nbRow = _searchArray[0].length;
19006
19009
  const verticalSearch = nbRow >= nbCol;
19007
19010
  const getElement = verticalSearch
19008
19011
  ? (range, index) => range[0][index].value
19009
19012
  : (range, index) => range[index][0].value;
19010
19013
  const rangeLength = verticalSearch ? nbRow : nbCol;
19011
- const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
19014
+ const index = dichotomicSearch(_searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
19012
19015
  if (index === -1 ||
19013
- (verticalSearch && searchArray[0][index] === undefined) ||
19014
- (!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
19016
+ (verticalSearch && _searchArray[0][index] === undefined) ||
19017
+ (!verticalSearch && _searchArray[index][nbRow - 1] === undefined)) {
19015
19018
  return valueNotAvailable(searchKey);
19016
19019
  }
19017
- if (resultRange === undefined) {
19018
- return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
19020
+ if (_resultRange[0].length === 0) {
19021
+ return verticalSearch ? _searchArray[nbCol - 1][index] : _searchArray[index][nbRow - 1];
19019
19022
  }
19020
- nbCol = resultRange.length;
19021
- nbRow = resultRange[0].length;
19023
+ nbCol = _resultRange.length;
19024
+ nbRow = _resultRange[0].length;
19022
19025
  assert(() => nbCol === 1 || nbRow === 1, _t("The result_range must be a single row or a single column."));
19023
19026
  if (nbCol > 1) {
19024
19027
  assert(() => index <= nbCol - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range row value %s.", (index + 1).toString()));
19025
- return resultRange[index][0];
19028
+ return _resultRange[index][0];
19026
19029
  }
19027
19030
  assert(() => index <= nbRow - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range column value %s.", (index + 1).toString()));
19028
- return resultRange[0][index];
19031
+ return _resultRange[0][index];
19029
19032
  },
19030
19033
  isExported: true,
19031
19034
  };
@@ -19042,28 +19045,29 @@ const MATCH = {
19042
19045
  ],
19043
19046
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
19044
19047
  let _searchType = toNumber(searchType, this.locale);
19045
- const nbCol = range.length;
19046
- const nbRow = range[0].length;
19048
+ const _range = toMatrix(range);
19049
+ const nbCol = _range.length;
19050
+ const nbRow = _range[0].length;
19047
19051
  assert(() => nbCol === 1 || nbRow === 1, _t("The range must be a single row or a single column."));
19048
19052
  let index = -1;
19049
19053
  const getElement = nbCol === 1
19050
- ? (range, index) => range[0][index].value
19051
- : (range, index) => range[index][0].value;
19052
- const rangeLen = nbCol === 1 ? range[0].length : range.length;
19054
+ ? (_range, index) => _range[0][index].value
19055
+ : (_range, index) => _range[index][0].value;
19056
+ const rangeLen = nbCol === 1 ? _range[0].length : _range.length;
19053
19057
  _searchType = Math.sign(_searchType);
19054
19058
  switch (_searchType) {
19055
19059
  case 1:
19056
- index = dichotomicSearch(range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
19060
+ index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
19057
19061
  break;
19058
19062
  case 0:
19059
- index = linearSearch(range, searchKey, "wildcard", rangeLen, getElement);
19063
+ index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement);
19060
19064
  break;
19061
19065
  case -1:
19062
- index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
19066
+ index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
19063
19067
  break;
19064
19068
  }
19065
- if ((nbCol === 1 && range[0][index] === undefined) ||
19066
- (nbCol !== 1 && range[index] === undefined)) {
19069
+ if ((nbCol === 1 && _range[0][index] === undefined) ||
19070
+ (nbCol !== 1 && _range[index] === undefined)) {
19067
19071
  return valueNotAvailable(searchKey);
19068
19072
  }
19069
19073
  return index + 1;
@@ -19117,16 +19121,17 @@ const VLOOKUP = {
19117
19121
  ],
19118
19122
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
19119
19123
  const _index = Math.trunc(toNumber(index?.value, this.locale));
19120
- assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
19124
+ const _range = toMatrix(range);
19125
+ assert(() => 1 <= _index && _index <= _range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
19121
19126
  if (searchKey && isEvaluationError(searchKey.value)) {
19122
19127
  return searchKey;
19123
19128
  }
19124
19129
  const getValueFromRange = (range, index) => range[0][index].value;
19125
19130
  const _isSorted = toBoolean(isSorted.value);
19126
19131
  const rowIndex = _isSorted
19127
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
19128
- : linearSearch(range, searchKey, "wildcard", range[0].length, getValueFromRange);
19129
- const value = range[_index - 1][rowIndex];
19132
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
19133
+ : linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange);
19134
+ const value = _range[_index - 1][rowIndex];
19130
19135
  if (value === undefined) {
19131
19136
  return valueNotAvailable(searchKey);
19132
19137
  }
@@ -19163,30 +19168,32 @@ const XLOOKUP = {
19163
19168
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
19164
19169
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
19165
19170
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
19166
- assert(() => lookupRange.length === 1 || lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
19171
+ const _lookupRange = toMatrix(lookupRange);
19172
+ const _returnRange = toMatrix(returnRange);
19173
+ assert(() => _lookupRange.length === 1 || _lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
19167
19174
  assert(() => [-1, 1, -2, 2].includes(_searchMode), _t("search_mode should be a value in [-1, 1, -2, 2]."));
19168
19175
  assert(() => [-1, 0, 1, 2].includes(_matchMode), _t("match_mode should be a value in [-1, 0, 1, 2]."));
19169
- const lookupDirection = lookupRange.length === 1 ? "col" : "row";
19176
+ const lookupDirection = _lookupRange.length === 1 ? "col" : "row";
19170
19177
  assert(() => !(_matchMode === 2 && [-2, 2].includes(_searchMode)), _t("the search and match mode combination is not supported for XLOOKUP evaluation."));
19171
19178
  assert(() => lookupDirection === "col"
19172
- ? returnRange[0].length === lookupRange[0].length
19173
- : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
19179
+ ? _returnRange[0].length === _lookupRange[0].length
19180
+ : _returnRange.length === _lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
19174
19181
  if (searchKey && isEvaluationError(searchKey.value)) {
19175
19182
  return [[searchKey]];
19176
19183
  }
19177
19184
  const getElement = lookupDirection === "col"
19178
19185
  ? (range, index) => range[0][index].value
19179
19186
  : (range, index) => range[index][0].value;
19180
- const rangeLen = lookupDirection === "col" ? lookupRange[0].length : lookupRange.length;
19187
+ const rangeLen = lookupDirection === "col" ? _lookupRange[0].length : _lookupRange.length;
19181
19188
  const mode = MATCH_MODE[_matchMode];
19182
19189
  const reverseSearch = _searchMode === -1;
19183
19190
  const index = _searchMode === 2 || _searchMode === -2
19184
- ? dichotomicSearch(lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
19185
- : linearSearch(lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
19191
+ ? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
19192
+ : linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
19186
19193
  if (index !== -1) {
19187
19194
  return lookupDirection === "col"
19188
- ? returnRange.map((col) => [col[index]])
19189
- : [returnRange[index]];
19195
+ ? _returnRange.map((col) => [col[index]])
19196
+ : [_returnRange[index]];
19190
19197
  }
19191
19198
  if (defaultValue === undefined) {
19192
19199
  return valueNotAvailable(searchKey);
@@ -41220,11 +41227,10 @@ class GridRenderer {
41220
41227
  switch (layer) {
41221
41228
  case "Background":
41222
41229
  this.drawGlobalBackground(renderingContext);
41223
- for (const zone of this.getters.getAllActiveViewportsZones()) {
41230
+ for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
41224
41231
  const { ctx } = renderingContext;
41225
41232
  ctx.save();
41226
41233
  ctx.beginPath();
41227
- const rect = this.getters.getVisibleRect(zone);
41228
41234
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
41229
41235
  ctx.clip();
41230
41236
  const boxes = this.getGridBoxes(zone);
@@ -41494,10 +41500,8 @@ class GridRenderer {
41494
41500
  const { ctx, thinLineWidth } = renderingContext;
41495
41501
  const visibleCols = this.getters.getSheetViewVisibleCols();
41496
41502
  const left = visibleCols[0];
41497
- const right = visibleCols[visibleCols.length - 1];
41498
41503
  const visibleRows = this.getters.getSheetViewVisibleRows();
41499
41504
  const top = visibleRows[0];
41500
- const bottom = visibleRows[visibleRows.length - 1];
41501
41505
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
41502
41506
  const selection = this.getters.getSelectedZones();
41503
41507
  const selectedCols = getZonesCols(selection);
@@ -41513,7 +41517,7 @@ class GridRenderer {
41513
41517
  ctx.lineWidth = thinLineWidth;
41514
41518
  ctx.strokeStyle = "#333";
41515
41519
  // Columns headers background
41516
- for (let col = left; col <= right; col++) {
41520
+ for (const col of visibleCols) {
41517
41521
  const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
41518
41522
  const { x, width } = this.getters.getVisibleRect(colZone);
41519
41523
  const isColActive = activeCols.has(col);
@@ -41530,7 +41534,7 @@ class GridRenderer {
41530
41534
  ctx.fillRect(x, 0, width, HEADER_HEIGHT);
41531
41535
  }
41532
41536
  // Rows headers background
41533
- for (let row = top; row <= bottom; row++) {
41537
+ for (const row of visibleRows) {
41534
41538
  const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
41535
41539
  const { y, height } = this.getters.getVisibleRect(rowZone);
41536
41540
  const isRowActive = activeRows.has(row);
@@ -41556,21 +41560,21 @@ class GridRenderer {
41556
41560
  ctx.stroke();
41557
41561
  ctx.beginPath();
41558
41562
  // column text + separator
41559
- for (const i of visibleCols) {
41560
- const colSize = this.getters.getColSize(sheetId, i);
41561
- const colName = numberToLetters(i);
41562
- ctx.fillStyle = activeCols.has(i) ? "#fff" : TEXT_HEADER_COLOR;
41563
- let colStart = this.getHeaderOffset("COL", left, i);
41563
+ for (const col of visibleCols) {
41564
+ const colSize = this.getters.getColSize(sheetId, col);
41565
+ const colName = numberToLetters(col);
41566
+ ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
41567
+ let colStart = this.getHeaderOffset("COL", left, col);
41564
41568
  ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
41565
41569
  ctx.moveTo(colStart + colSize, 0);
41566
41570
  ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
41567
41571
  }
41568
41572
  // row text + separator
41569
- for (const i of visibleRows) {
41570
- const rowSize = this.getters.getRowSize(sheetId, i);
41571
- ctx.fillStyle = activeRows.has(i) ? "#fff" : TEXT_HEADER_COLOR;
41572
- let rowStart = this.getHeaderOffset("ROW", top, i);
41573
- ctx.fillText(String(i + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
41573
+ for (const row of visibleRows) {
41574
+ const rowSize = this.getters.getRowSize(sheetId, row);
41575
+ ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
41576
+ let rowStart = this.getHeaderOffset("ROW", top, row);
41577
+ ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
41574
41578
  ctx.moveTo(0, rowStart + rowSize);
41575
41579
  ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
41576
41580
  }
@@ -41868,6 +41872,9 @@ function useGridDrawing(refName, model, canvasSize) {
41868
41872
  canvas.width = width * dpr;
41869
41873
  canvas.height = height * dpr;
41870
41874
  canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
41875
+ if (width === 0 || height === 0) {
41876
+ return;
41877
+ }
41871
41878
  // Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
41872
41879
  // are the edges of the squares. If you draw a one-unit-wide line between whole-number
41873
41880
  // coordinates, it will overlap opposite sides of the pixel square, and the resulting
@@ -47600,7 +47607,7 @@ class BordersPlugin extends CorePlugin {
47600
47607
  getCommonSides(border1, border2) {
47601
47608
  const commonBorder = {};
47602
47609
  for (let side of ["top", "bottom", "left", "right"]) {
47603
- if (border1[side] && border1[side] === border2[side]) {
47610
+ if (border1[side] && deepEquals(border1[side], border2[side])) {
47604
47611
  commonBorder[side] = border1[side];
47605
47612
  }
47606
47613
  }
@@ -60943,8 +60950,17 @@ class InternalViewport {
60943
60950
  this.getters = getters;
60944
60951
  this.sheetId = sheetId;
60945
60952
  this.boundaries = boundaries;
60946
- this.viewportWidth = sizeInGrid.width;
60947
- this.viewportHeight = sizeInGrid.height;
60953
+ if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
60954
+ throw new Error("Viewport size cannot be negative");
60955
+ }
60956
+ this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
60957
+ this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
60958
+ this.top = boundaries.top;
60959
+ this.bottom = boundaries.bottom;
60960
+ this.left = boundaries.left;
60961
+ this.right = boundaries.right;
60962
+ this.offsetX = offsets.x;
60963
+ this.offsetY = offsets.y;
60948
60964
  this.offsetScrollbarX = offsets.x;
60949
60965
  this.offsetScrollbarY = offsets.y;
60950
60966
  this.canScrollVertically = options.canScrollVertically;
@@ -60987,9 +61003,9 @@ class InternalViewport {
60987
61003
  Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
60988
61004
  );
60989
61005
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
60990
- }
60991
- if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
60992
- height += FOOTER_HEIGHT;
61006
+ if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
61007
+ height += FOOTER_HEIGHT;
61008
+ }
60993
61009
  }
60994
61010
  return { width, height };
60995
61011
  }
@@ -61130,6 +61146,9 @@ class InternalViewport {
61130
61146
  !this.getters.isRowHidden(this.sheetId, row));
61131
61147
  }
61132
61148
  searchHeaderIndex(dimension, position, startIndex = 0) {
61149
+ if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
61150
+ return -1;
61151
+ }
61133
61152
  const sheetId = this.sheetId;
61134
61153
  const headers = this.getters.getNumberHeaders(sheetId, dimension);
61135
61154
  // using a binary search:
@@ -61166,7 +61185,7 @@ class InternalViewport {
61166
61185
  this.adjustViewportZoneY();
61167
61186
  }
61168
61187
  /** Corrects the viewport's horizontal offset based on the current structure
61169
- * To make sure that at least on column is visible inside the viewport.
61188
+ * To make sure that at least one column is visible inside the viewport.
61170
61189
  */
61171
61190
  adjustViewportOffsetX() {
61172
61191
  if (this.canScrollHorizontally) {
@@ -61178,7 +61197,7 @@ class InternalViewport {
61178
61197
  this.adjustViewportZoneX();
61179
61198
  }
61180
61199
  /** Corrects the viewport's vertical offset based on the current structure
61181
- * To make sure that at least on row is visible inside the viewport.
61200
+ * To make sure that at least one row is visible inside the viewport.
61182
61201
  */
61183
61202
  adjustViewportOffsetY() {
61184
61203
  if (this.canScrollVertically) {
@@ -61195,11 +61214,14 @@ class InternalViewport {
61195
61214
  const sheetId = this.sheetId;
61196
61215
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
61197
61216
  this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
61217
+ if (!this.viewportWidth) {
61218
+ return;
61219
+ }
61198
61220
  if (this.left === -1) {
61199
61221
  this.left = this.boundaries.left;
61200
61222
  }
61201
61223
  if (this.right === -1) {
61202
- this.right = this.getters.getNumberCols(sheetId) - 1;
61224
+ this.right = this.boundaries.right;
61203
61225
  }
61204
61226
  this.offsetX =
61205
61227
  this.getters.getColDimensions(sheetId, this.left).start -
@@ -61211,11 +61233,14 @@ class InternalViewport {
61211
61233
  const sheetId = this.sheetId;
61212
61234
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
61213
61235
  this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
61236
+ if (!this.viewportHeight) {
61237
+ return;
61238
+ }
61214
61239
  if (this.top === -1) {
61215
61240
  this.top = this.boundaries.top;
61216
61241
  }
61217
61242
  if (this.bottom === -1) {
61218
- this.bottom = this.getters.getNumberRows(sheetId) - 1;
61243
+ this.bottom = this.boundaries.bottom;
61219
61244
  }
61220
61245
  this.offsetY =
61221
61246
  this.getters.getRowDimensions(sheetId, this.top).start -
@@ -61289,7 +61314,7 @@ class SheetViewPlugin extends UIPlugin {
61289
61314
  "isPositionVisible",
61290
61315
  "getColDimensionsInViewport",
61291
61316
  "getRowDimensionsInViewport",
61292
- "getAllActiveViewportsZones",
61317
+ "getAllActiveViewportsZonesAndRect",
61293
61318
  "getRect",
61294
61319
  ];
61295
61320
  viewports = {};
@@ -61522,12 +61547,12 @@ class SheetViewPlugin extends UIPlugin {
61522
61547
  const sheetId = this.getters.getActiveSheetId();
61523
61548
  const viewports = this.getSubViewports(sheetId);
61524
61549
  //TODO ake another commit to eimprove this
61525
- return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
61550
+ return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
61526
61551
  }
61527
61552
  getSheetViewVisibleRows() {
61528
61553
  const sheetId = this.getters.getActiveSheetId();
61529
61554
  const viewports = this.getSubViewports(sheetId);
61530
- return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
61555
+ return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
61531
61556
  }
61532
61557
  /**
61533
61558
  * Get the positions of all the cells that are visible in the viewport, taking merges into account.
@@ -61570,19 +61595,19 @@ class SheetViewPlugin extends UIPlugin {
61570
61595
  maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
61571
61596
  };
61572
61597
  }
61573
- getColRowOffsetInViewport(dimension, referenceIndex, index) {
61574
- const sheetId = this.getters.getActiveSheetId();
61575
- const visibleCols = this.getters.getSheetViewVisibleCols();
61576
- const visibleRows = this.getters.getSheetViewVisibleRows();
61577
- if (index < referenceIndex) {
61578
- return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
61598
+ getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
61599
+ if (targetHeaderIndex < referenceHeaderIndex) {
61600
+ return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
61579
61601
  }
61602
+ const sheetId = this.getters.getActiveSheetId();
61603
+ const visibleHeaders = dimension === "COL"
61604
+ ? this.getters.getSheetViewVisibleCols()
61605
+ : this.getters.getSheetViewVisibleRows();
61606
+ const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
61607
+ const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
61608
+ const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
61580
61609
  let offset = 0;
61581
- const visibleIndexes = dimension === "COL" ? visibleCols : visibleRows;
61582
- for (let i = referenceIndex; i < index; i++) {
61583
- if (!visibleIndexes.includes(i)) {
61584
- continue;
61585
- }
61610
+ for (const i of relevantIndexes) {
61586
61611
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
61587
61612
  }
61588
61613
  return offset;
@@ -61629,7 +61654,7 @@ class SheetViewPlugin extends UIPlugin {
61629
61654
  }
61630
61655
  return { canEdgeScroll, direction, delay };
61631
61656
  }
61632
- getEdgeScrollRow(y, previousY, tartingY) {
61657
+ getEdgeScrollRow(y, previousY, startingY) {
61633
61658
  let canEdgeScroll = false;
61634
61659
  let direction = 0;
61635
61660
  let delay = 0;
@@ -61650,7 +61675,7 @@ class SheetViewPlugin extends UIPlugin {
61650
61675
  delay = scrollDelay(y - height);
61651
61676
  direction = 1;
61652
61677
  }
61653
- else if (y < offsetCorrectionY && tartingY >= offsetCorrectionY && currentOffsetY > 0) {
61678
+ else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
61654
61679
  // 2
61655
61680
  canEdgeScroll = true;
61656
61681
  delay = scrollDelay(offsetCorrectionY - y);
@@ -61676,13 +61701,7 @@ class SheetViewPlugin extends UIPlugin {
61676
61701
  */
61677
61702
  getVisibleRectWithoutHeaders(zone) {
61678
61703
  const sheetId = this.getters.getActiveSheetId();
61679
- const viewportRects = this.getSubViewports(sheetId)
61680
- .map((viewport) => viewport.getVisibleRect(zone))
61681
- .filter(isDefined);
61682
- if (viewportRects.length === 0) {
61683
- return { x: 0, y: 0, width: 0, height: 0 };
61684
- }
61685
- return this.recomposeRect(viewportRects);
61704
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
61686
61705
  }
61687
61706
  /**
61688
61707
  * Computes the actual size and position (:Rect) of the zone on the canvas
@@ -61690,13 +61709,7 @@ class SheetViewPlugin extends UIPlugin {
61690
61709
  */
61691
61710
  getRect(zone) {
61692
61711
  const sheetId = this.getters.getActiveSheetId();
61693
- const viewportRects = this.getSubViewports(sheetId)
61694
- .map((viewport) => viewport.getFullRect(zone))
61695
- .filter(isDefined);
61696
- if (viewportRects.length === 0) {
61697
- return { x: 0, y: 0, width: 0, height: 0 };
61698
- }
61699
- const rect = this.recomposeRect(viewportRects);
61712
+ const rect = this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
61700
61713
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
61701
61714
  }
61702
61715
  /**
@@ -61741,9 +61754,18 @@ class SheetViewPlugin extends UIPlugin {
61741
61754
  end: start + (isRowHidden ? 0 : size),
61742
61755
  };
61743
61756
  }
61744
- getAllActiveViewportsZones() {
61757
+ getAllActiveViewportsZonesAndRect() {
61745
61758
  const sheetId = this.getters.getActiveSheetId();
61746
- return this.getSubViewports(sheetId);
61759
+ return this.getSubViewports(sheetId).map((viewport) => {
61760
+ return {
61761
+ zone: viewport,
61762
+ rect: {
61763
+ x: viewport.offsetCorrectionX + this.gridOffsetX,
61764
+ y: viewport.offsetCorrectionY + this.gridOffsetY,
61765
+ ...viewport.getMaxSize(),
61766
+ },
61767
+ };
61768
+ });
61747
61769
  }
61748
61770
  // ---------------------------------------------------------------------------
61749
61771
  // Private
@@ -61802,12 +61824,11 @@ class SheetViewPlugin extends UIPlugin {
61802
61824
  }
61803
61825
  /** gets rid of deprecated sheetIds */
61804
61826
  cleanViewports() {
61805
- const sheetIds = this.getters.getSheetIds();
61806
- for (let sheetId of Object.keys(this.viewports)) {
61807
- if (!sheetIds.includes(sheetId)) {
61808
- delete this.viewports[sheetId];
61809
- }
61827
+ const newViewport = {};
61828
+ for (const sheetId of this.getters.getSheetIds()) {
61829
+ newViewport[sheetId] = this.viewports[sheetId];
61810
61830
  }
61831
+ this.viewports = newViewport;
61811
61832
  }
61812
61833
  resizeSheetView(height, width, gridOffsetX = 0, gridOffsetY = 0) {
61813
61834
  this.sheetViewHeight = height;
@@ -61817,7 +61838,7 @@ class SheetViewPlugin extends UIPlugin {
61817
61838
  this.recomputeViewports();
61818
61839
  }
61819
61840
  recomputeViewports() {
61820
- for (let sheetId of Object.keys(this.viewports)) {
61841
+ for (const sheetId of this.getters.getSheetIds()) {
61821
61842
  this.resetViewports(sheetId);
61822
61843
  }
61823
61844
  }
@@ -61839,8 +61860,10 @@ class SheetViewPlugin extends UIPlugin {
61839
61860
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
61840
61861
  const nCols = this.getters.getNumberCols(sheetId);
61841
61862
  const nRows = this.getters.getNumberRows(sheetId);
61842
- const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
61843
- const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
61863
+ const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
61864
+ const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
61865
+ const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
61866
+ const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
61844
61867
  const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
61845
61868
  const canScrollHorizontally = xRatio < 1.0;
61846
61869
  const canScrollVertically = yRatio < 1.0;
@@ -61851,14 +61874,14 @@ class SheetViewPlugin extends UIPlugin {
61851
61874
  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 })) ||
61852
61875
  undefined,
61853
61876
  topRight: (ySplit &&
61854
- 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 })) ||
61877
+ 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 })) ||
61855
61878
  undefined,
61856
61879
  bottomLeft: (xSplit &&
61857
- 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 })) ||
61880
+ 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 })) ||
61858
61881
  undefined,
61859
61882
  bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
61860
- width: this.sheetViewWidth - colOffset,
61861
- height: this.sheetViewHeight - rowOffset,
61883
+ width: unfrozenWidth,
61884
+ height: unfrozenHeight,
61862
61885
  }, { canScrollHorizontally, canScrollVertically }, {
61863
61886
  x: canScrollHorizontally ? previousOffset.x : 0,
61864
61887
  y: canScrollVertically ? previousOffset.y : 0,
@@ -61935,12 +61958,26 @@ class SheetViewPlugin extends UIPlugin {
61935
61958
  const height = this.sheetViewHeight + this.gridOffsetY;
61936
61959
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
61937
61960
  }
61938
- recomposeRect(viewportRects) {
61939
- const x = Math.min(...viewportRects.map((rect) => rect.x));
61940
- const y = Math.min(...viewportRects.map((rect) => rect.y));
61941
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
61942
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
61943
- return { x, y, width, height };
61961
+ mapViewportsToRect(sheetId, rectCallBack) {
61962
+ let x = Infinity;
61963
+ let y = Infinity;
61964
+ let width = 0;
61965
+ let height = 0;
61966
+ let hasViewports = false;
61967
+ for (const viewport of this.getSubViewports(sheetId)) {
61968
+ const rect = rectCallBack(viewport);
61969
+ if (rect) {
61970
+ hasViewports = true;
61971
+ x = Math.min(x, rect.x);
61972
+ y = Math.min(y, rect.y);
61973
+ width = Math.max(width, rect.x + rect.width);
61974
+ height = Math.max(height, rect.y + rect.height);
61975
+ }
61976
+ }
61977
+ if (!hasViewports) {
61978
+ return { x: 0, y: 0, width: 0, height: 0 };
61979
+ }
61980
+ return { x, y, width: width - x, height: height - y };
61944
61981
  }
61945
61982
  }
61946
61983
 
@@ -68873,6 +68910,6 @@ exports.tokenColors = tokenColors;
68873
68910
  exports.tokenize = tokenize;
68874
68911
 
68875
68912
 
68876
- __info__.version = "17.4.20";
68877
- __info__.date = "2025-01-31T08:00:07.103Z";
68878
- __info__.hash = "54a344a";
68913
+ __info__.version = "17.4.21";
68914
+ __info__.date = "2025-02-05T06:46:54.366Z";
68915
+ __info__.hash = "0c55e18";