@odoo/o-spreadsheet 17.0.47 → 17.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 17.0.47
6
- * @date 2025-01-31T07:56:50.980Z
7
- * @hash a22bce2
5
+ * @version 17.0.48
6
+ * @date 2025-02-05T07:18:39.331Z
7
+ * @hash aea9101
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -18557,20 +18557,21 @@ const HLOOKUP = {
18557
18557
  description: _t("Horizontal lookup"),
18558
18558
  args: [
18559
18559
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18560
- arg("range (range)", _t("The range to consider for the search. The first row in the range is searched for the key specified in search_key.")),
18560
+ arg("range (any, range)", _t("The range to consider for the search. The first row in the range is searched for the key specified in search_key.")),
18561
18561
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18562
18562
  arg(`is_sorted (boolean, default=${DEFAULT_IS_SORTED})`, _t("Indicates whether the row to be searched (the first row of the specified range) is sorted, in which case the closest match for search_key will be returned.")),
18563
18563
  ],
18564
18564
  returns: ["ANY"],
18565
18565
  computeValueAndFormat: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18566
18566
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18567
- assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18567
+ const _range = toMatrix(range);
18568
+ assert(() => 1 <= _index && _index <= _range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18568
18569
  const getValueFromRange = (range, index) => range[index][0].value;
18569
18570
  const _isSorted = toBoolean(isSorted.value);
18570
18571
  const colIndex = _isSorted
18571
- ? dichotomicSearch(range, searchKey?.value, "nextSmaller", "asc", range.length, getValueFromRange)
18572
- : linearSearch(range, searchKey?.value, "strict", range.length, getValueFromRange);
18573
- const col = range[colIndex];
18572
+ ? dichotomicSearch(_range, searchKey?.value, "nextSmaller", "asc", _range.length, getValueFromRange)
18573
+ : linearSearch(_range, searchKey?.value, "strict", _range.length, getValueFromRange);
18574
+ const col = _range[colIndex];
18574
18575
  assertAvailable(col, searchKey?.value);
18575
18576
  return col[_index - 1];
18576
18577
  },
@@ -18615,36 +18616,38 @@ const LOOKUP = {
18615
18616
  description: _t("Look up a value."),
18616
18617
  args: [
18617
18618
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18618
- arg("search_array (range)", _t("One method of using this function is to provide a single sorted row or column search_array to look through for the search_key with a second argument result_range. The other way is to combine these two arguments into one search_array where the first row or column is searched and a value is returned from the last row or column in the array. If search_key is not found, a non-exact match may be returned.")),
18619
- arg("result_range (range, optional)", _t("The range from which to return a result. The value returned corresponds to the location where search_key is found in search_range. This range must be only a single row or column and should not be used if using the search_result_array method.")),
18619
+ 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.")),
18620
+ arg("result_range (any, range, optional)", _t("The range from which to return a result. The value returned corresponds to the location where search_key is found in search_range. This range must be only a single row or column and should not be used if using the search_result_array method.")),
18620
18621
  ],
18621
18622
  returns: ["ANY"],
18622
18623
  computeValueAndFormat: function (searchKey, searchArray, resultRange) {
18623
- let nbCol = searchArray.length;
18624
- let nbRow = searchArray[0].length;
18624
+ const _searchArray = toMatrix(searchArray);
18625
+ const _resultRange = toMatrix(resultRange);
18626
+ let nbCol = _searchArray.length;
18627
+ let nbRow = _searchArray[0].length;
18625
18628
  const verticalSearch = nbRow >= nbCol;
18626
18629
  const getElement = verticalSearch
18627
18630
  ? (range, index) => range[0][index].value
18628
18631
  : (range, index) => range[index][0].value;
18629
18632
  const rangeLength = verticalSearch ? nbRow : nbCol;
18630
- const index = dichotomicSearch(searchArray, searchKey?.value, "nextSmaller", "asc", rangeLength, getElement);
18633
+ const index = dichotomicSearch(_searchArray, searchKey?.value, "nextSmaller", "asc", rangeLength, getElement);
18631
18634
  if (index === -1)
18632
18635
  assertAvailable(undefined, searchKey?.value);
18633
18636
  verticalSearch
18634
- ? assertAvailable(searchArray[0][index], searchKey?.value)
18635
- : assertAvailable(searchArray[index][nbRow - 1], searchKey?.value);
18636
- if (resultRange === undefined) {
18637
- return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
18637
+ ? assertAvailable(_searchArray[0][index], searchKey?.value)
18638
+ : assertAvailable(_searchArray[index][nbRow - 1], searchKey?.value);
18639
+ if (_resultRange[0].length === 0) {
18640
+ return verticalSearch ? _searchArray[nbCol - 1][index] : _searchArray[index][nbRow - 1];
18638
18641
  }
18639
- nbCol = resultRange.length;
18640
- nbRow = resultRange[0].length;
18642
+ nbCol = _resultRange.length;
18643
+ nbRow = _resultRange[0].length;
18641
18644
  assert(() => nbCol === 1 || nbRow === 1, _t("The result_range must be a single row or a single column."));
18642
18645
  if (nbCol > 1) {
18643
18646
  assert(() => index <= nbCol - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range row value %s.", (index + 1).toString()));
18644
- return resultRange[index][0];
18647
+ return _resultRange[index][0];
18645
18648
  }
18646
18649
  assert(() => index <= nbRow - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range column value %s.", (index + 1).toString()));
18647
- return resultRange[0][index];
18650
+ return _resultRange[0][index];
18648
18651
  },
18649
18652
  isExported: true,
18650
18653
  };
@@ -18662,27 +18665,28 @@ const MATCH = {
18662
18665
  returns: ["NUMBER"],
18663
18666
  compute: function (searchKey, range, searchType = DEFAULT_SEARCH_TYPE) {
18664
18667
  let _searchType = toNumber(searchType, this.locale);
18665
- const nbCol = range.length;
18666
- const nbRow = range[0].length;
18668
+ const _range = toMatrix(range);
18669
+ const nbCol = _range.length;
18670
+ const nbRow = _range[0].length;
18667
18671
  assert(() => nbCol === 1 || nbRow === 1, _t("The range must be a single row or a single column."));
18668
18672
  let index = -1;
18669
18673
  const getElement = nbCol === 1
18670
- ? (range, index) => range[0][index]
18671
- : (range, index) => range[index][0];
18672
- const rangeLen = nbCol === 1 ? range[0].length : range.length;
18674
+ ? (_range, index) => _range[0][index]
18675
+ : (_range, index) => _range[index][0];
18676
+ const rangeLen = nbCol === 1 ? _range[0].length : _range.length;
18673
18677
  _searchType = Math.sign(_searchType);
18674
18678
  switch (_searchType) {
18675
18679
  case 1:
18676
- index = dichotomicSearch(range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18680
+ index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18677
18681
  break;
18678
18682
  case 0:
18679
- index = linearSearch(range, searchKey, "strict", rangeLen, getElement);
18683
+ index = linearSearch(_range, searchKey, "strict", rangeLen, getElement);
18680
18684
  break;
18681
18685
  case -1:
18682
- index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18686
+ index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18683
18687
  break;
18684
18688
  }
18685
- assertAvailable(nbCol === 1 ? range[0][index] : range[index], searchKey);
18689
+ assertAvailable(nbCol === 1 ? _range[0][index] : _range[index], searchKey);
18686
18690
  return index + 1;
18687
18691
  },
18688
18692
  isExported: true,
@@ -18731,13 +18735,14 @@ const VLOOKUP = {
18731
18735
  returns: ["ANY"],
18732
18736
  computeValueAndFormat: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18733
18737
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18734
- assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18738
+ const _range = toMatrix(range);
18739
+ assert(() => 1 <= _index && _index <= _range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18735
18740
  const getValueFromRange = (range, index) => range[0][index].value;
18736
18741
  const _isSorted = toBoolean(isSorted.value);
18737
18742
  const rowIndex = _isSorted
18738
- ? dichotomicSearch(range, searchKey?.value, "nextSmaller", "asc", range[0].length, getValueFromRange)
18739
- : linearSearch(range, searchKey?.value, "strict", range[0].length, getValueFromRange);
18740
- const value = range[_index - 1][rowIndex];
18743
+ ? dichotomicSearch(_range, searchKey?.value, "nextSmaller", "asc", _range[0].length, getValueFromRange)
18744
+ : linearSearch(_range, searchKey?.value, "strict", _range[0].length, getValueFromRange);
18745
+ const value = _range[_index - 1][rowIndex];
18741
18746
  assertAvailable(value, searchKey?.value);
18742
18747
  return value;
18743
18748
  },
@@ -18764,26 +18769,28 @@ const XLOOKUP = {
18764
18769
  computeValueAndFormat: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18765
18770
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18766
18771
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
18767
- assert(() => lookupRange.length === 1 || lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18772
+ const _lookupRange = toMatrix(lookupRange);
18773
+ const _returnRange = toMatrix(returnRange);
18774
+ assert(() => _lookupRange.length === 1 || _lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18768
18775
  assert(() => [-1, 1, -2, 2].includes(_searchMode), _t("searchMode should be a value in [-1, 1, -2, 2]."));
18769
18776
  assert(() => [-1, 0, 1].includes(_matchMode), _t("matchMode should be a value in [-1, 0, 1]."));
18770
- const lookupDirection = lookupRange.length === 1 ? "col" : "row";
18777
+ const lookupDirection = _lookupRange.length === 1 ? "col" : "row";
18771
18778
  assert(() => lookupDirection === "col"
18772
- ? returnRange[0].length === lookupRange[0].length
18773
- : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18779
+ ? _returnRange[0].length === _lookupRange[0].length
18780
+ : _returnRange.length === _lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18774
18781
  const getElement = lookupDirection === "col"
18775
18782
  ? (range, index) => range[0][index].value
18776
18783
  : (range, index) => range[index][0].value;
18777
- const rangeLen = lookupDirection === "col" ? lookupRange[0].length : lookupRange.length;
18784
+ const rangeLen = lookupDirection === "col" ? _lookupRange[0].length : _lookupRange.length;
18778
18785
  const mode = _matchMode === 0 ? "strict" : _matchMode === 1 ? "nextGreater" : "nextSmaller";
18779
18786
  const reverseSearch = _searchMode === -1;
18780
18787
  const index = _searchMode === 2 || _searchMode === -2
18781
- ? dichotomicSearch(lookupRange, searchKey?.value, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18782
- : linearSearch(lookupRange, searchKey?.value, mode, rangeLen, getElement, reverseSearch);
18788
+ ? dichotomicSearch(_lookupRange, searchKey?.value, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18789
+ : linearSearch(_lookupRange, searchKey?.value, mode, rangeLen, getElement, reverseSearch);
18783
18790
  if (index !== -1) {
18784
18791
  return lookupDirection === "col"
18785
- ? returnRange.map((col) => [col[index]])
18786
- : [returnRange[index]];
18792
+ ? _returnRange.map((col) => [col[index]])
18793
+ : [_returnRange[index]];
18787
18794
  }
18788
18795
  const _defaultValue = defaultValue?.();
18789
18796
  assertAvailable(_defaultValue, searchKey?.value);
@@ -29241,6 +29248,9 @@ function useGridDrawing(refName, model, canvasSize) {
29241
29248
  canvas.width = width * dpr;
29242
29249
  canvas.height = height * dpr;
29243
29250
  canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
29251
+ if (width === 0 || height === 0) {
29252
+ return;
29253
+ }
29244
29254
  // Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
29245
29255
  // are the edges of the squares. If you draw a one-unit-wide line between whole-number
29246
29256
  // coordinates, it will overlap opposite sides of the pixel square, and the resulting
@@ -34721,7 +34731,7 @@ class BordersPlugin extends CorePlugin {
34721
34731
  getCommonSides(border1, border2) {
34722
34732
  const commonBorder = {};
34723
34733
  for (let side of ["top", "bottom", "left", "right"]) {
34724
- if (border1[side] && border1[side] === border2[side]) {
34734
+ if (border1[side] && deepEquals(border1[side], border2[side])) {
34725
34735
  commonBorder[side] = border1[side];
34726
34736
  }
34727
34737
  }
@@ -46267,11 +46277,10 @@ class RendererPlugin extends UIPlugin {
46267
46277
  switch (layer) {
46268
46278
  case 0 /* LAYERS.Background */:
46269
46279
  this.drawGlobalBackground(renderingContext);
46270
- for (const zone of this.getters.getAllActiveViewportsZones()) {
46280
+ for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
46271
46281
  const { ctx } = renderingContext;
46272
46282
  ctx.save();
46273
46283
  ctx.beginPath();
46274
- const rect = this.getters.getVisibleRect(zone);
46275
46284
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
46276
46285
  ctx.clip();
46277
46286
  this.boxes = this.getGridBoxes(zone);
@@ -46541,10 +46550,8 @@ class RendererPlugin extends UIPlugin {
46541
46550
  const { ctx, thinLineWidth } = renderingContext;
46542
46551
  const visibleCols = this.getters.getSheetViewVisibleCols();
46543
46552
  const left = visibleCols[0];
46544
- const right = visibleCols[visibleCols.length - 1];
46545
46553
  const visibleRows = this.getters.getSheetViewVisibleRows();
46546
46554
  const top = visibleRows[0];
46547
- const bottom = visibleRows[visibleRows.length - 1];
46548
46555
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
46549
46556
  const selection = this.getters.getSelectedZones();
46550
46557
  const selectedCols = getZonesCols(selection);
@@ -46560,7 +46567,7 @@ class RendererPlugin extends UIPlugin {
46560
46567
  ctx.lineWidth = thinLineWidth;
46561
46568
  ctx.strokeStyle = "#333";
46562
46569
  // Columns headers background
46563
- for (let col = left; col <= right; col++) {
46570
+ for (const col of visibleCols) {
46564
46571
  const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
46565
46572
  const { x, width } = this.getters.getVisibleRect(colZone);
46566
46573
  const colHasFilter = this.getters.doesZonesContainFilter(sheetId, [colZone]);
@@ -46580,7 +46587,7 @@ class RendererPlugin extends UIPlugin {
46580
46587
  ctx.fillRect(x, 0, width, HEADER_HEIGHT);
46581
46588
  }
46582
46589
  // Rows headers background
46583
- for (let row = top; row <= bottom; row++) {
46590
+ for (const row of visibleRows) {
46584
46591
  const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
46585
46592
  const { y, height } = this.getters.getVisibleRect(rowZone);
46586
46593
  const rowHasFilter = this.getters.doesZonesContainFilter(sheetId, [rowZone]);
@@ -46609,21 +46616,21 @@ class RendererPlugin extends UIPlugin {
46609
46616
  ctx.stroke();
46610
46617
  ctx.beginPath();
46611
46618
  // column text + separator
46612
- for (const i of visibleCols) {
46613
- const colSize = this.getters.getColSize(sheetId, i);
46614
- const colName = numberToLetters(i);
46615
- ctx.fillStyle = activeCols.has(i) ? "#fff" : TEXT_HEADER_COLOR;
46616
- let colStart = this.getHeaderOffset("COL", left, i);
46619
+ for (const col of visibleCols) {
46620
+ const colSize = this.getters.getColSize(sheetId, col);
46621
+ const colName = numberToLetters(col);
46622
+ ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
46623
+ let colStart = this.getHeaderOffset("COL", left, col);
46617
46624
  ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
46618
46625
  ctx.moveTo(colStart + colSize, 0);
46619
46626
  ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
46620
46627
  }
46621
46628
  // row text + separator
46622
- for (const i of visibleRows) {
46623
- const rowSize = this.getters.getRowSize(sheetId, i);
46624
- ctx.fillStyle = activeRows.has(i) ? "#fff" : TEXT_HEADER_COLOR;
46625
- let rowStart = this.getHeaderOffset("ROW", top, i);
46626
- ctx.fillText(String(i + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
46629
+ for (const row of visibleRows) {
46630
+ const rowSize = this.getters.getRowSize(sheetId, row);
46631
+ ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
46632
+ let rowStart = this.getHeaderOffset("ROW", top, row);
46633
+ ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
46627
46634
  ctx.moveTo(0, rowStart + rowSize);
46628
46635
  ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
46629
46636
  }
@@ -50514,8 +50521,17 @@ class InternalViewport {
50514
50521
  this.getters = getters;
50515
50522
  this.sheetId = sheetId;
50516
50523
  this.boundaries = boundaries;
50517
- this.viewportWidth = sizeInGrid.width;
50518
- this.viewportHeight = sizeInGrid.height;
50524
+ if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
50525
+ throw new Error("Viewport size cannot be negative");
50526
+ }
50527
+ this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
50528
+ this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
50529
+ this.top = boundaries.top;
50530
+ this.bottom = boundaries.bottom;
50531
+ this.left = boundaries.left;
50532
+ this.right = boundaries.right;
50533
+ this.offsetX = offsets.x;
50534
+ this.offsetY = offsets.y;
50519
50535
  this.offsetScrollbarX = offsets.x;
50520
50536
  this.offsetScrollbarY = offsets.y;
50521
50537
  this.canScrollVertically = options.canScrollVertically;
@@ -50558,9 +50574,9 @@ class InternalViewport {
50558
50574
  Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
50559
50575
  );
50560
50576
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
50561
- }
50562
- if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
50563
- height += FOOTER_HEIGHT;
50577
+ if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
50578
+ height += FOOTER_HEIGHT;
50579
+ }
50564
50580
  }
50565
50581
  return { width, height };
50566
50582
  }
@@ -50707,6 +50723,9 @@ class InternalViewport {
50707
50723
  }
50708
50724
  // PRIVATE
50709
50725
  searchHeaderIndex(dimension, position, startIndex = 0) {
50726
+ if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
50727
+ return -1;
50728
+ }
50710
50729
  const sheetId = this.sheetId;
50711
50730
  const headers = this.getters.getNumberHeaders(sheetId, dimension);
50712
50731
  // using a binary search:
@@ -50746,7 +50765,7 @@ class InternalViewport {
50746
50765
  this.adjustViewportZoneY();
50747
50766
  }
50748
50767
  /** Corrects the viewport's horizontal offset based on the current structure
50749
- * To make sure that at least on column is visible inside the viewport.
50768
+ * To make sure that at least one column is visible inside the viewport.
50750
50769
  */
50751
50770
  adjustViewportOffsetX() {
50752
50771
  if (this.canScrollHorizontally) {
@@ -50763,7 +50782,7 @@ class InternalViewport {
50763
50782
  this.adjustViewportZoneX();
50764
50783
  }
50765
50784
  /** Corrects the viewport's vertical offset based on the current structure
50766
- * To make sure that at least on row is visible inside the viewport.
50785
+ * To make sure that at least one row is visible inside the viewport.
50767
50786
  */
50768
50787
  adjustViewportOffsetY() {
50769
50788
  if (this.canScrollVertically) {
@@ -50785,11 +50804,14 @@ class InternalViewport {
50785
50804
  const sheetId = this.sheetId;
50786
50805
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
50787
50806
  this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
50807
+ if (!this.viewportWidth) {
50808
+ return;
50809
+ }
50788
50810
  if (this.left === -1) {
50789
50811
  this.left = this.boundaries.left;
50790
50812
  }
50791
50813
  if (this.right === -1) {
50792
- this.right = this.getters.getNumberCols(sheetId) - 1;
50814
+ this.right = this.boundaries.right;
50793
50815
  }
50794
50816
  this.offsetX =
50795
50817
  this.getters.getColDimensions(sheetId, this.left).start -
@@ -50801,11 +50823,14 @@ class InternalViewport {
50801
50823
  const sheetId = this.sheetId;
50802
50824
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
50803
50825
  this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
50826
+ if (!this.viewportHeight) {
50827
+ return;
50828
+ }
50804
50829
  if (this.top === -1) {
50805
50830
  this.top = this.boundaries.top;
50806
50831
  }
50807
50832
  if (this.bottom === -1) {
50808
- this.bottom = this.getters.getNumberRows(sheetId) - 1;
50833
+ this.bottom = this.boundaries.bottom;
50809
50834
  }
50810
50835
  this.offsetY =
50811
50836
  this.getters.getRowDimensions(sheetId, this.top).start -
@@ -50877,7 +50902,7 @@ class SheetViewPlugin extends UIPlugin {
50877
50902
  "getSheetViewVisibleRows",
50878
50903
  "getFrozenSheetViewRatio",
50879
50904
  "isPositionVisible",
50880
- "getAllActiveViewportsZones",
50905
+ "getAllActiveViewportsZonesAndRect",
50881
50906
  "getRect",
50882
50907
  ];
50883
50908
  viewports = {};
@@ -51111,12 +51136,12 @@ class SheetViewPlugin extends UIPlugin {
51111
51136
  const sheetId = this.getters.getActiveSheetId();
51112
51137
  const viewports = this.getSubViewports(sheetId);
51113
51138
  //TODO ake another commit to eimprove this
51114
- return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
51139
+ return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
51115
51140
  }
51116
51141
  getSheetViewVisibleRows() {
51117
51142
  const sheetId = this.getters.getActiveSheetId();
51118
51143
  const viewports = this.getSubViewports(sheetId);
51119
- return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
51144
+ return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
51120
51145
  }
51121
51146
  /**
51122
51147
  * Get the positions of all the cells that are visible in the viewport, taking merges into account.
@@ -51159,19 +51184,19 @@ class SheetViewPlugin extends UIPlugin {
51159
51184
  maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
51160
51185
  };
51161
51186
  }
51162
- getColRowOffsetInViewport(dimension, referenceIndex, index) {
51163
- const sheetId = this.getters.getActiveSheetId();
51164
- const visibleCols = this.getters.getSheetViewVisibleCols();
51165
- const visibleRows = this.getters.getSheetViewVisibleRows();
51166
- if (index < referenceIndex) {
51167
- return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
51187
+ getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
51188
+ if (targetHeaderIndex < referenceHeaderIndex) {
51189
+ return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
51168
51190
  }
51191
+ const sheetId = this.getters.getActiveSheetId();
51192
+ const visibleHeaders = dimension === "COL"
51193
+ ? this.getters.getSheetViewVisibleCols()
51194
+ : this.getters.getSheetViewVisibleRows();
51195
+ const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
51196
+ const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
51197
+ const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
51169
51198
  let offset = 0;
51170
- const visibleIndexes = dimension === "COL" ? visibleCols : visibleRows;
51171
- for (let i = referenceIndex; i < index; i++) {
51172
- if (!visibleIndexes.includes(i)) {
51173
- continue;
51174
- }
51199
+ for (const i of relevantIndexes) {
51175
51200
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
51176
51201
  }
51177
51202
  return offset;
@@ -51218,7 +51243,7 @@ class SheetViewPlugin extends UIPlugin {
51218
51243
  }
51219
51244
  return { canEdgeScroll, direction, delay };
51220
51245
  }
51221
- getEdgeScrollRow(y, previousY, tartingY) {
51246
+ getEdgeScrollRow(y, previousY, startingY) {
51222
51247
  let canEdgeScroll = false;
51223
51248
  let direction = 0;
51224
51249
  let delay = 0;
@@ -51239,7 +51264,7 @@ class SheetViewPlugin extends UIPlugin {
51239
51264
  delay = scrollDelay(y - height);
51240
51265
  direction = 1;
51241
51266
  }
51242
- else if (y < offsetCorrectionY && tartingY >= offsetCorrectionY && currentOffsetY > 0) {
51267
+ else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
51243
51268
  // 2
51244
51269
  canEdgeScroll = true;
51245
51270
  delay = scrollDelay(offsetCorrectionY - y);
@@ -51265,13 +51290,7 @@ class SheetViewPlugin extends UIPlugin {
51265
51290
  */
51266
51291
  getVisibleRectWithoutHeaders(zone) {
51267
51292
  const sheetId = this.getters.getActiveSheetId();
51268
- const viewportRects = this.getSubViewports(sheetId)
51269
- .map((viewport) => viewport.getVisibleRect(zone))
51270
- .filter(isDefined$1);
51271
- if (viewportRects.length === 0) {
51272
- return { x: 0, y: 0, width: 0, height: 0 };
51273
- }
51274
- return this.recomposeRect(viewportRects);
51293
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
51275
51294
  }
51276
51295
  /**
51277
51296
  * Computes the actual size and position (:Rect) of the zone on the canvas
@@ -51279,13 +51298,7 @@ class SheetViewPlugin extends UIPlugin {
51279
51298
  */
51280
51299
  getRect(zone) {
51281
51300
  const sheetId = this.getters.getActiveSheetId();
51282
- const viewportRects = this.getSubViewports(sheetId)
51283
- .map((viewport) => viewport.getFullRect(zone))
51284
- .filter(isDefined$1);
51285
- if (viewportRects.length === 0) {
51286
- return { x: 0, y: 0, width: 0, height: 0 };
51287
- }
51288
- const rect = this.recomposeRect(viewportRects);
51301
+ const rect = this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
51289
51302
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
51290
51303
  }
51291
51304
  /**
@@ -51300,9 +51313,18 @@ class SheetViewPlugin extends UIPlugin {
51300
51313
  const y = this.getters.getRowDimensions(sheetId, ySplit).start;
51301
51314
  return { x, y };
51302
51315
  }
51303
- getAllActiveViewportsZones() {
51316
+ getAllActiveViewportsZonesAndRect() {
51304
51317
  const sheetId = this.getters.getActiveSheetId();
51305
- return this.getSubViewports(sheetId);
51318
+ return this.getSubViewports(sheetId).map((viewport) => {
51319
+ return {
51320
+ zone: viewport,
51321
+ rect: {
51322
+ x: viewport.offsetCorrectionX + this.gridOffsetX,
51323
+ y: viewport.offsetCorrectionY + this.gridOffsetY,
51324
+ ...viewport.getMaxSize(),
51325
+ },
51326
+ };
51327
+ });
51306
51328
  }
51307
51329
  // ---------------------------------------------------------------------------
51308
51330
  // Private
@@ -51355,12 +51377,11 @@ class SheetViewPlugin extends UIPlugin {
51355
51377
  }
51356
51378
  /** gets rid of deprecated sheetIds */
51357
51379
  cleanViewports() {
51358
- const sheetIds = this.getters.getSheetIds();
51359
- for (let sheetId of Object.keys(this.viewports)) {
51360
- if (!sheetIds.includes(sheetId)) {
51361
- delete this.viewports[sheetId];
51362
- }
51380
+ const newViewport = {};
51381
+ for (const sheetId of this.getters.getSheetIds()) {
51382
+ newViewport[sheetId] = this.viewports[sheetId];
51363
51383
  }
51384
+ this.viewports = newViewport;
51364
51385
  }
51365
51386
  resizeSheetView(height, width, gridOffsetX = 0, gridOffsetY = 0) {
51366
51387
  this.sheetViewHeight = height;
@@ -51370,14 +51391,14 @@ class SheetViewPlugin extends UIPlugin {
51370
51391
  this.recomputeViewports();
51371
51392
  }
51372
51393
  recomputeViewports() {
51373
- for (let sheetId of Object.keys(this.viewports)) {
51394
+ for (const sheetId of this.getters.getSheetIds()) {
51374
51395
  this.resetViewports(sheetId);
51375
51396
  }
51376
51397
  }
51377
51398
  setSheetViewOffset(offsetX, offsetY) {
51378
51399
  const sheetId = this.getters.getActiveSheetId();
51379
51400
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
51380
- Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
51401
+ this.getSubViewports(sheetId).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
51381
51402
  }
51382
51403
  getViewportOffset(sheetId) {
51383
51404
  return {
@@ -51392,8 +51413,10 @@ class SheetViewPlugin extends UIPlugin {
51392
51413
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
51393
51414
  const nCols = this.getters.getNumberCols(sheetId);
51394
51415
  const nRows = this.getters.getNumberRows(sheetId);
51395
- const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
51396
- const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
51416
+ const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
51417
+ const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
51418
+ const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
51419
+ const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
51397
51420
  const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
51398
51421
  const canScrollHorizontally = xRatio < 1.0;
51399
51422
  const canScrollVertically = yRatio < 1.0;
@@ -51404,14 +51427,14 @@ class SheetViewPlugin extends UIPlugin {
51404
51427
  new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: 0, bottom: ySplit - 1 }, { width: colOffset, height: rowOffset }, { canScrollHorizontally: false, canScrollVertically: false }, { x: 0, y: 0 })) ||
51405
51428
  undefined,
51406
51429
  topRight: (ySplit &&
51407
- new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: 0, bottom: ySplit - 1 }, { width: this.sheetViewWidth - colOffset, height: rowOffset }, { canScrollHorizontally, canScrollVertically: false }, { x: canScrollHorizontally ? previousOffset.x : 0, y: 0 })) ||
51430
+ new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: 0, bottom: ySplit - 1 }, { width: unfrozenWidth, height: rowOffset }, { canScrollHorizontally, canScrollVertically: false }, { x: canScrollHorizontally ? previousOffset.x : 0, y: 0 })) ||
51408
51431
  undefined,
51409
51432
  bottomLeft: (xSplit &&
51410
- new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: ySplit, bottom: nRows - 1 }, { width: colOffset, height: this.sheetViewHeight - rowOffset }, { canScrollHorizontally: false, canScrollVertically }, { x: 0, y: canScrollVertically ? previousOffset.y : 0 })) ||
51433
+ new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: ySplit, bottom: nRows - 1 }, { width: colOffset, height: unfrozenHeight }, { canScrollHorizontally: false, canScrollVertically }, { x: 0, y: canScrollVertically ? previousOffset.y : 0 })) ||
51411
51434
  undefined,
51412
51435
  bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
51413
- width: this.sheetViewWidth - colOffset,
51414
- height: this.sheetViewHeight - rowOffset,
51436
+ width: unfrozenWidth,
51437
+ height: unfrozenHeight,
51415
51438
  }, { canScrollHorizontally, canScrollVertically }, {
51416
51439
  x: canScrollHorizontally ? previousOffset.x : 0,
51417
51440
  y: canScrollVertically ? previousOffset.y : 0,
@@ -51423,7 +51446,7 @@ class SheetViewPlugin extends UIPlugin {
51423
51446
  * Adjust the viewport such that the anchor position is visible
51424
51447
  */
51425
51448
  refreshViewport(sheetId, anchorPosition) {
51426
- Object.values(this.getSubViewports(sheetId)).forEach((viewport) => {
51449
+ this.getSubViewports(sheetId).forEach((viewport) => {
51427
51450
  viewport.adjustViewportZone();
51428
51451
  viewport.adjustPosition(anchorPosition);
51429
51452
  });
@@ -51488,12 +51511,26 @@ class SheetViewPlugin extends UIPlugin {
51488
51511
  const height = this.sheetViewHeight + this.gridOffsetY;
51489
51512
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
51490
51513
  }
51491
- recomposeRect(viewportRects) {
51492
- const x = Math.min(...viewportRects.map((rect) => rect.x));
51493
- const y = Math.min(...viewportRects.map((rect) => rect.y));
51494
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
51495
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
51496
- return { x, y, width, height };
51514
+ mapViewportsToRect(sheetId, rectCallBack) {
51515
+ let x = Infinity;
51516
+ let y = Infinity;
51517
+ let width = 0;
51518
+ let height = 0;
51519
+ let hasViewports = false;
51520
+ for (const viewport of this.getSubViewports(sheetId)) {
51521
+ const rect = rectCallBack(viewport);
51522
+ if (rect) {
51523
+ hasViewports = true;
51524
+ x = Math.min(x, rect.x);
51525
+ y = Math.min(y, rect.y);
51526
+ width = Math.max(width, rect.x + rect.width);
51527
+ height = Math.max(height, rect.y + rect.height);
51528
+ }
51529
+ }
51530
+ if (!hasViewports) {
51531
+ return { x: 0, y: 0, width: 0, height: 0 };
51532
+ }
51533
+ return { x, y, width: width - x, height: height - y };
51497
51534
  }
51498
51535
  }
51499
51536
 
@@ -57767,6 +57804,6 @@ const constants = {
57767
57804
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
57768
57805
 
57769
57806
 
57770
- __info__.version = "17.0.47";
57771
- __info__.date = "2025-01-31T07:56:50.980Z";
57772
- __info__.hash = "a22bce2";
57807
+ __info__.version = "17.0.48";
57808
+ __info__.date = "2025-02-05T07:18:39.331Z";
57809
+ __info__.hash = "aea9101";