@odoo/o-spreadsheet 18.1.5 → 18.1.6

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 18.1.5
6
- * @date 2025-01-31T08:00:10.263Z
7
- * @hash 97acb8b
5
+ * @version 18.1.6
6
+ * @date 2025-02-05T07:18:57.089Z
7
+ * @hash f5b97e0
8
8
  */
9
9
 
10
10
  'use strict';
@@ -18456,19 +18456,20 @@ const HLOOKUP = {
18456
18456
  description: _t("Horizontal lookup"),
18457
18457
  args: [
18458
18458
  arg("search_key (string, number, boolean)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18459
- 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.")),
18459
+ 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.")),
18460
18460
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18461
18461
  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.")),
18462
18462
  ],
18463
18463
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18464
18464
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18465
- assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18465
+ const _range = toMatrix(range);
18466
+ assert(() => 1 <= _index && _index <= _range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18466
18467
  const getValueFromRange = (range, index) => range[index][0].value;
18467
18468
  const _isSorted = toBoolean(isSorted.value);
18468
18469
  const colIndex = _isSorted
18469
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
18470
- : linearSearch(range, searchKey, "wildcard", range.length, getValueFromRange);
18471
- const col = range[colIndex];
18470
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
18471
+ : linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange);
18472
+ const col = _range[colIndex];
18472
18473
  if (col === undefined) {
18473
18474
  return valueNotAvailable(searchKey);
18474
18475
  }
@@ -18560,35 +18561,37 @@ const LOOKUP = {
18560
18561
  description: _t("Look up a value."),
18561
18562
  args: [
18562
18563
  arg("search_key (string, number, boolean)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18563
- 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.")),
18564
- 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.")),
18564
+ 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.")),
18565
+ 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.")),
18565
18566
  ],
18566
18567
  compute: function (searchKey, searchArray, resultRange) {
18567
- let nbCol = searchArray.length;
18568
- let nbRow = searchArray[0].length;
18568
+ const _searchArray = toMatrix(searchArray);
18569
+ const _resultRange = toMatrix(resultRange);
18570
+ let nbCol = _searchArray.length;
18571
+ let nbRow = _searchArray[0].length;
18569
18572
  const verticalSearch = nbRow >= nbCol;
18570
18573
  const getElement = verticalSearch
18571
18574
  ? (range, index) => range[0][index].value
18572
18575
  : (range, index) => range[index][0].value;
18573
18576
  const rangeLength = verticalSearch ? nbRow : nbCol;
18574
- const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
18577
+ const index = dichotomicSearch(_searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
18575
18578
  if (index === -1 ||
18576
- (verticalSearch && searchArray[0][index] === undefined) ||
18577
- (!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
18579
+ (verticalSearch && _searchArray[0][index] === undefined) ||
18580
+ (!verticalSearch && _searchArray[index][nbRow - 1] === undefined)) {
18578
18581
  return valueNotAvailable(searchKey);
18579
18582
  }
18580
- if (resultRange === undefined) {
18581
- return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
18583
+ if (_resultRange[0].length === 0) {
18584
+ return verticalSearch ? _searchArray[nbCol - 1][index] : _searchArray[index][nbRow - 1];
18582
18585
  }
18583
- nbCol = resultRange.length;
18584
- nbRow = resultRange[0].length;
18586
+ nbCol = _resultRange.length;
18587
+ nbRow = _resultRange[0].length;
18585
18588
  assert(() => nbCol === 1 || nbRow === 1, _t("The result_range must be a single row or a single column."));
18586
18589
  if (nbCol > 1) {
18587
18590
  assert(() => index <= nbCol - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range row value %s.", (index + 1).toString()));
18588
- return resultRange[index][0];
18591
+ return _resultRange[index][0];
18589
18592
  }
18590
18593
  assert(() => index <= nbRow - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range column value %s.", (index + 1).toString()));
18591
- return resultRange[0][index];
18594
+ return _resultRange[0][index];
18592
18595
  },
18593
18596
  isExported: true,
18594
18597
  };
@@ -18605,28 +18608,29 @@ const MATCH = {
18605
18608
  ],
18606
18609
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
18607
18610
  let _searchType = toNumber(searchType, this.locale);
18608
- const nbCol = range.length;
18609
- const nbRow = range[0].length;
18611
+ const _range = toMatrix(range);
18612
+ const nbCol = _range.length;
18613
+ const nbRow = _range[0].length;
18610
18614
  assert(() => nbCol === 1 || nbRow === 1, _t("The range must be a single row or a single column."));
18611
18615
  let index = -1;
18612
18616
  const getElement = nbCol === 1
18613
- ? (range, index) => range[0][index].value
18614
- : (range, index) => range[index][0].value;
18615
- const rangeLen = nbCol === 1 ? range[0].length : range.length;
18617
+ ? (_range, index) => _range[0][index].value
18618
+ : (_range, index) => _range[index][0].value;
18619
+ const rangeLen = nbCol === 1 ? _range[0].length : _range.length;
18616
18620
  _searchType = Math.sign(_searchType);
18617
18621
  switch (_searchType) {
18618
18622
  case 1:
18619
- index = dichotomicSearch(range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18623
+ index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18620
18624
  break;
18621
18625
  case 0:
18622
- index = linearSearch(range, searchKey, "wildcard", rangeLen, getElement);
18626
+ index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement);
18623
18627
  break;
18624
18628
  case -1:
18625
- index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18629
+ index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18626
18630
  break;
18627
18631
  }
18628
- if ((nbCol === 1 && range[0][index] === undefined) ||
18629
- (nbCol !== 1 && range[index] === undefined)) {
18632
+ if ((nbCol === 1 && _range[0][index] === undefined) ||
18633
+ (nbCol !== 1 && _range[index] === undefined)) {
18630
18634
  return valueNotAvailable(searchKey);
18631
18635
  }
18632
18636
  return index + 1;
@@ -18681,13 +18685,14 @@ const VLOOKUP = {
18681
18685
  ],
18682
18686
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18683
18687
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18684
- assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18688
+ const _range = toMatrix(range);
18689
+ assert(() => 1 <= _index && _index <= _range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18685
18690
  const getValueFromRange = (range, index) => range[0][index].value;
18686
18691
  const _isSorted = toBoolean(isSorted.value);
18687
18692
  const rowIndex = _isSorted
18688
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
18689
- : linearSearch(range, searchKey, "wildcard", range[0].length, getValueFromRange);
18690
- const value = range[_index - 1][rowIndex];
18693
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
18694
+ : linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange);
18695
+ const value = _range[_index - 1][rowIndex];
18691
18696
  if (value === undefined) {
18692
18697
  return valueNotAvailable(searchKey);
18693
18698
  }
@@ -18724,27 +18729,29 @@ const XLOOKUP = {
18724
18729
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18725
18730
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18726
18731
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
18727
- assert(() => lookupRange.length === 1 || lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18732
+ const _lookupRange = toMatrix(lookupRange);
18733
+ const _returnRange = toMatrix(returnRange);
18734
+ assert(() => _lookupRange.length === 1 || _lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18728
18735
  assert(() => [-1, 1, -2, 2].includes(_searchMode), _t("search_mode should be a value in [-1, 1, -2, 2]."));
18729
18736
  assert(() => [-1, 0, 1, 2].includes(_matchMode), _t("match_mode should be a value in [-1, 0, 1, 2]."));
18730
- const lookupDirection = lookupRange.length === 1 ? "col" : "row";
18737
+ const lookupDirection = _lookupRange.length === 1 ? "col" : "row";
18731
18738
  assert(() => !(_matchMode === 2 && [-2, 2].includes(_searchMode)), _t("the search and match mode combination is not supported for XLOOKUP evaluation."));
18732
18739
  assert(() => lookupDirection === "col"
18733
- ? returnRange[0].length === lookupRange[0].length
18734
- : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18740
+ ? _returnRange[0].length === _lookupRange[0].length
18741
+ : _returnRange.length === _lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18735
18742
  const getElement = lookupDirection === "col"
18736
18743
  ? (range, index) => range[0][index].value
18737
18744
  : (range, index) => range[index][0].value;
18738
- const rangeLen = lookupDirection === "col" ? lookupRange[0].length : lookupRange.length;
18745
+ const rangeLen = lookupDirection === "col" ? _lookupRange[0].length : _lookupRange.length;
18739
18746
  const mode = MATCH_MODE[_matchMode];
18740
18747
  const reverseSearch = _searchMode === -1;
18741
18748
  const index = _searchMode === 2 || _searchMode === -2
18742
- ? dichotomicSearch(lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18743
- : linearSearch(lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
18749
+ ? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18750
+ : linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
18744
18751
  if (index !== -1) {
18745
18752
  return lookupDirection === "col"
18746
- ? returnRange.map((col) => [col[index]])
18747
- : [returnRange[index]];
18753
+ ? _returnRange.map((col) => [col[index]])
18754
+ : [_returnRange[index]];
18748
18755
  }
18749
18756
  if (defaultValue === undefined) {
18750
18757
  return valueNotAvailable(searchKey);
@@ -28436,11 +28443,7 @@ function interpolateData(config, values, labels, newLabels) {
28436
28443
  if (values.length < 2 || labels.length < 2 || newLabels.length === 0) {
28437
28444
  return [];
28438
28445
  }
28439
- const labelMin = Math.min(...labels);
28440
- const labelMax = Math.max(...labels);
28441
- const labelRange = labelMax - labelMin;
28442
- const normalizedLabels = labels.map((v) => (v - labelMin) / labelRange);
28443
- const normalizedNewLabels = newLabels.map((v) => (v - labelMin) / labelRange);
28446
+ const { normalizedLabels, normalizedNewLabels } = normalizeLabels(labels, newLabels, config);
28444
28447
  try {
28445
28448
  switch (config.type) {
28446
28449
  case "polynomial": {
@@ -28485,6 +28488,30 @@ function interpolateData(config, values, labels, newLabels) {
28485
28488
  return newLabels.map((x) => ({ x, y: NaN }));
28486
28489
  }
28487
28490
  }
28491
+ function normalizeLabels(labels, newLabels, config) {
28492
+ let normalizedLabels = [];
28493
+ let normalizedNewLabels = [];
28494
+ if (config.type === "logarithmic") {
28495
+ // Logarithmic trends in charts are used to visualize proportional growth or
28496
+ // relative changes. Therefore, we change the normalization technique for
28497
+ // logarithmic trend lines for a better fit. The method used here is Max Absolute
28498
+ // Scaling. This Technique is ideal for data spanning several orders of magnitude,
28499
+ // as it balances differences between small and large values by compressing larger
28500
+ // values while preserving proportionality and ensuring all values are scaled relative
28501
+ // to the largest magnitude.
28502
+ const labelMax = Math.max(...labels.map(Math.abs));
28503
+ normalizedLabels = labels.map((l) => l / labelMax);
28504
+ normalizedNewLabels = newLabels.map((l) => l / labelMax);
28505
+ }
28506
+ else {
28507
+ const labelMax = Math.max(...labels);
28508
+ const labelMin = Math.min(...labels);
28509
+ const labelRange = labelMax - labelMin;
28510
+ normalizedLabels = labels.map((l) => (l - labelMax) / labelRange);
28511
+ normalizedNewLabels = newLabels.map((l) => (l - labelMax) / labelRange);
28512
+ }
28513
+ return { normalizedLabels, normalizedNewLabels };
28514
+ }
28488
28515
  function getChartAxisType(chart, labelRange, getters) {
28489
28516
  if (isDateChart(chart, labelRange, getters) && isLuxonTimeAdapterInstalled()) {
28490
28517
  return "time";
@@ -50488,11 +50515,10 @@ class GridRenderer {
50488
50515
  switch (layer) {
50489
50516
  case "Background":
50490
50517
  this.drawGlobalBackground(renderingContext);
50491
- for (const zone of this.getters.getAllActiveViewportsZones()) {
50518
+ for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
50492
50519
  const { ctx } = renderingContext;
50493
50520
  ctx.save();
50494
50521
  ctx.beginPath();
50495
- const rect = this.getters.getVisibleRect(zone);
50496
50522
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
50497
50523
  ctx.clip();
50498
50524
  const boxes = this.getGridBoxes(zone);
@@ -50768,10 +50794,8 @@ class GridRenderer {
50768
50794
  const { ctx, thinLineWidth } = renderingContext;
50769
50795
  const visibleCols = this.getters.getSheetViewVisibleCols();
50770
50796
  const left = visibleCols[0];
50771
- const right = visibleCols[visibleCols.length - 1];
50772
50797
  const visibleRows = this.getters.getSheetViewVisibleRows();
50773
50798
  const top = visibleRows[0];
50774
- const bottom = visibleRows[visibleRows.length - 1];
50775
50799
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
50776
50800
  const selection = this.getters.getSelectedZones();
50777
50801
  const selectedCols = getZonesCols(selection);
@@ -50787,7 +50811,7 @@ class GridRenderer {
50787
50811
  ctx.lineWidth = thinLineWidth;
50788
50812
  ctx.strokeStyle = "#333";
50789
50813
  // Columns headers background
50790
- for (let col = left; col <= right; col++) {
50814
+ for (const col of visibleCols) {
50791
50815
  const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
50792
50816
  const { x, width } = this.getters.getVisibleRect(colZone);
50793
50817
  const isColActive = activeCols.has(col);
@@ -50804,7 +50828,7 @@ class GridRenderer {
50804
50828
  ctx.fillRect(x, 0, width, HEADER_HEIGHT);
50805
50829
  }
50806
50830
  // Rows headers background
50807
- for (let row = top; row <= bottom; row++) {
50831
+ for (const row of visibleRows) {
50808
50832
  const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
50809
50833
  const { y, height } = this.getters.getVisibleRect(rowZone);
50810
50834
  const isRowActive = activeRows.has(row);
@@ -50830,21 +50854,21 @@ class GridRenderer {
50830
50854
  ctx.stroke();
50831
50855
  ctx.beginPath();
50832
50856
  // column text + separator
50833
- for (const i of visibleCols) {
50834
- const colSize = this.getters.getColSize(sheetId, i);
50835
- const colName = numberToLetters(i);
50836
- ctx.fillStyle = activeCols.has(i) ? "#fff" : TEXT_HEADER_COLOR;
50837
- let colStart = this.getHeaderOffset("COL", left, i);
50857
+ for (const col of visibleCols) {
50858
+ const colSize = this.getters.getColSize(sheetId, col);
50859
+ const colName = numberToLetters(col);
50860
+ ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
50861
+ let colStart = this.getHeaderOffset("COL", left, col);
50838
50862
  ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
50839
50863
  ctx.moveTo(colStart + colSize, 0);
50840
50864
  ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
50841
50865
  }
50842
50866
  // row text + separator
50843
- for (const i of visibleRows) {
50844
- const rowSize = this.getters.getRowSize(sheetId, i);
50845
- ctx.fillStyle = activeRows.has(i) ? "#fff" : TEXT_HEADER_COLOR;
50846
- let rowStart = this.getHeaderOffset("ROW", top, i);
50847
- ctx.fillText(String(i + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
50867
+ for (const row of visibleRows) {
50868
+ const rowSize = this.getters.getRowSize(sheetId, row);
50869
+ ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
50870
+ let rowStart = this.getHeaderOffset("ROW", top, row);
50871
+ ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
50848
50872
  ctx.moveTo(0, rowStart + rowSize);
50849
50873
  ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
50850
50874
  }
@@ -51151,6 +51175,9 @@ function useGridDrawing(refName, model, canvasSize) {
51151
51175
  canvas.width = width * dpr;
51152
51176
  canvas.height = height * dpr;
51153
51177
  canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
51178
+ if (width === 0 || height === 0) {
51179
+ return;
51180
+ }
51154
51181
  // Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
51155
51182
  // are the edges of the squares. If you draw a one-unit-wide line between whole-number
51156
51183
  // coordinates, it will overlap opposite sides of the pixel square, and the resulting
@@ -52697,7 +52724,7 @@ class BordersPlugin extends CorePlugin {
52697
52724
  getCommonSides(border1, border2) {
52698
52725
  const commonBorder = {};
52699
52726
  for (let side of ["top", "bottom", "left", "right"]) {
52700
- if (border1[side] && border1[side] === border2[side]) {
52727
+ if (border1[side] && deepEquals(border1[side], border2[side])) {
52701
52728
  commonBorder[side] = border1[side];
52702
52729
  }
52703
52730
  }
@@ -66913,8 +66940,17 @@ class InternalViewport {
66913
66940
  this.getters = getters;
66914
66941
  this.sheetId = sheetId;
66915
66942
  this.boundaries = boundaries;
66916
- this.viewportWidth = sizeInGrid.width;
66917
- this.viewportHeight = sizeInGrid.height;
66943
+ if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
66944
+ throw new Error("Viewport size cannot be negative");
66945
+ }
66946
+ this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
66947
+ this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
66948
+ this.top = boundaries.top;
66949
+ this.bottom = boundaries.bottom;
66950
+ this.left = boundaries.left;
66951
+ this.right = boundaries.right;
66952
+ this.offsetX = offsets.x;
66953
+ this.offsetY = offsets.y;
66918
66954
  this.offsetScrollbarX = offsets.x;
66919
66955
  this.offsetScrollbarY = offsets.y;
66920
66956
  this.canScrollVertically = options.canScrollVertically;
@@ -66957,9 +66993,9 @@ class InternalViewport {
66957
66993
  Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
66958
66994
  );
66959
66995
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
66960
- }
66961
- if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
66962
- height += FOOTER_HEIGHT;
66996
+ if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
66997
+ height += FOOTER_HEIGHT;
66998
+ }
66963
66999
  }
66964
67000
  return { width, height };
66965
67001
  }
@@ -67100,6 +67136,9 @@ class InternalViewport {
67100
67136
  !this.getters.isRowHidden(this.sheetId, row));
67101
67137
  }
67102
67138
  searchHeaderIndex(dimension, position, startIndex = 0) {
67139
+ if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
67140
+ return -1;
67141
+ }
67103
67142
  const sheetId = this.sheetId;
67104
67143
  const headers = this.getters.getNumberHeaders(sheetId, dimension);
67105
67144
  // using a binary search:
@@ -67136,7 +67175,7 @@ class InternalViewport {
67136
67175
  this.adjustViewportZoneY();
67137
67176
  }
67138
67177
  /** Corrects the viewport's horizontal offset based on the current structure
67139
- * To make sure that at least on column is visible inside the viewport.
67178
+ * To make sure that at least one column is visible inside the viewport.
67140
67179
  */
67141
67180
  adjustViewportOffsetX() {
67142
67181
  if (this.canScrollHorizontally) {
@@ -67148,7 +67187,7 @@ class InternalViewport {
67148
67187
  this.adjustViewportZoneX();
67149
67188
  }
67150
67189
  /** Corrects the viewport's vertical offset based on the current structure
67151
- * To make sure that at least on row is visible inside the viewport.
67190
+ * To make sure that at least one row is visible inside the viewport.
67152
67191
  */
67153
67192
  adjustViewportOffsetY() {
67154
67193
  if (this.canScrollVertically) {
@@ -67165,11 +67204,14 @@ class InternalViewport {
67165
67204
  const sheetId = this.sheetId;
67166
67205
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
67167
67206
  this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
67207
+ if (!this.viewportWidth) {
67208
+ return;
67209
+ }
67168
67210
  if (this.left === -1) {
67169
67211
  this.left = this.boundaries.left;
67170
67212
  }
67171
67213
  if (this.right === -1) {
67172
- this.right = this.getters.getNumberCols(sheetId) - 1;
67214
+ this.right = this.boundaries.right;
67173
67215
  }
67174
67216
  this.offsetX =
67175
67217
  this.getters.getColDimensions(sheetId, this.left).start -
@@ -67181,11 +67223,14 @@ class InternalViewport {
67181
67223
  const sheetId = this.sheetId;
67182
67224
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
67183
67225
  this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
67226
+ if (!this.viewportHeight) {
67227
+ return;
67228
+ }
67184
67229
  if (this.top === -1) {
67185
67230
  this.top = this.boundaries.top;
67186
67231
  }
67187
67232
  if (this.bottom === -1) {
67188
- this.bottom = this.getters.getNumberRows(sheetId) - 1;
67233
+ this.bottom = this.boundaries.bottom;
67189
67234
  }
67190
67235
  this.offsetY =
67191
67236
  this.getters.getRowDimensions(sheetId, this.top).start -
@@ -67259,7 +67304,7 @@ class SheetViewPlugin extends UIPlugin {
67259
67304
  "isPositionVisible",
67260
67305
  "getColDimensionsInViewport",
67261
67306
  "getRowDimensionsInViewport",
67262
- "getAllActiveViewportsZones",
67307
+ "getAllActiveViewportsZonesAndRect",
67263
67308
  "getRect",
67264
67309
  ];
67265
67310
  viewports = {};
@@ -67489,12 +67534,12 @@ class SheetViewPlugin extends UIPlugin {
67489
67534
  const sheetId = this.getters.getActiveSheetId();
67490
67535
  const viewports = this.getSubViewports(sheetId);
67491
67536
  //TODO ake another commit to eimprove this
67492
- return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
67537
+ return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
67493
67538
  }
67494
67539
  getSheetViewVisibleRows() {
67495
67540
  const sheetId = this.getters.getActiveSheetId();
67496
67541
  const viewports = this.getSubViewports(sheetId);
67497
- return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
67542
+ return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
67498
67543
  }
67499
67544
  /**
67500
67545
  * Get the positions of all the cells that are visible in the viewport, taking merges into account.
@@ -67537,19 +67582,19 @@ class SheetViewPlugin extends UIPlugin {
67537
67582
  maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
67538
67583
  };
67539
67584
  }
67540
- getColRowOffsetInViewport(dimension, referenceIndex, index) {
67541
- const sheetId = this.getters.getActiveSheetId();
67542
- const visibleCols = this.getters.getSheetViewVisibleCols();
67543
- const visibleRows = this.getters.getSheetViewVisibleRows();
67544
- if (index < referenceIndex) {
67545
- return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
67585
+ getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
67586
+ if (targetHeaderIndex < referenceHeaderIndex) {
67587
+ return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
67546
67588
  }
67589
+ const sheetId = this.getters.getActiveSheetId();
67590
+ const visibleHeaders = dimension === "COL"
67591
+ ? this.getters.getSheetViewVisibleCols()
67592
+ : this.getters.getSheetViewVisibleRows();
67593
+ const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
67594
+ const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
67595
+ const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
67547
67596
  let offset = 0;
67548
- const visibleIndexes = dimension === "COL" ? visibleCols : visibleRows;
67549
- for (let i = referenceIndex; i < index; i++) {
67550
- if (!visibleIndexes.includes(i)) {
67551
- continue;
67552
- }
67597
+ for (const i of relevantIndexes) {
67553
67598
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
67554
67599
  }
67555
67600
  return offset;
@@ -67596,7 +67641,7 @@ class SheetViewPlugin extends UIPlugin {
67596
67641
  }
67597
67642
  return { canEdgeScroll, direction, delay };
67598
67643
  }
67599
- getEdgeScrollRow(y, previousY, tartingY) {
67644
+ getEdgeScrollRow(y, previousY, startingY) {
67600
67645
  let canEdgeScroll = false;
67601
67646
  let direction = 0;
67602
67647
  let delay = 0;
@@ -67617,7 +67662,7 @@ class SheetViewPlugin extends UIPlugin {
67617
67662
  delay = scrollDelay(y - height);
67618
67663
  direction = 1;
67619
67664
  }
67620
- else if (y < offsetCorrectionY && tartingY >= offsetCorrectionY && currentOffsetY > 0) {
67665
+ else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
67621
67666
  // 2
67622
67667
  canEdgeScroll = true;
67623
67668
  delay = scrollDelay(offsetCorrectionY - y);
@@ -67643,13 +67688,7 @@ class SheetViewPlugin extends UIPlugin {
67643
67688
  */
67644
67689
  getVisibleRectWithoutHeaders(zone) {
67645
67690
  const sheetId = this.getters.getActiveSheetId();
67646
- const viewportRects = this.getSubViewports(sheetId)
67647
- .map((viewport) => viewport.getVisibleRect(zone))
67648
- .filter(isDefined);
67649
- if (viewportRects.length === 0) {
67650
- return { x: 0, y: 0, width: 0, height: 0 };
67651
- }
67652
- return this.recomposeRect(viewportRects);
67691
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
67653
67692
  }
67654
67693
  /**
67655
67694
  * Computes the actual size and position (:Rect) of the zone on the canvas
@@ -67657,13 +67696,7 @@ class SheetViewPlugin extends UIPlugin {
67657
67696
  */
67658
67697
  getRect(zone) {
67659
67698
  const sheetId = this.getters.getActiveSheetId();
67660
- const viewportRects = this.getSubViewports(sheetId)
67661
- .map((viewport) => viewport.getFullRect(zone))
67662
- .filter(isDefined);
67663
- if (viewportRects.length === 0) {
67664
- return { x: 0, y: 0, width: 0, height: 0 };
67665
- }
67666
- const rect = this.recomposeRect(viewportRects);
67699
+ const rect = this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
67667
67700
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
67668
67701
  }
67669
67702
  /**
@@ -67708,9 +67741,18 @@ class SheetViewPlugin extends UIPlugin {
67708
67741
  end: start + (isRowHidden ? 0 : size),
67709
67742
  };
67710
67743
  }
67711
- getAllActiveViewportsZones() {
67744
+ getAllActiveViewportsZonesAndRect() {
67712
67745
  const sheetId = this.getters.getActiveSheetId();
67713
- return this.getSubViewports(sheetId);
67746
+ return this.getSubViewports(sheetId).map((viewport) => {
67747
+ return {
67748
+ zone: viewport,
67749
+ rect: {
67750
+ x: viewport.offsetCorrectionX + this.gridOffsetX,
67751
+ y: viewport.offsetCorrectionY + this.gridOffsetY,
67752
+ ...viewport.getMaxSize(),
67753
+ },
67754
+ };
67755
+ });
67714
67756
  }
67715
67757
  // ---------------------------------------------------------------------------
67716
67758
  // Private
@@ -67769,12 +67811,11 @@ class SheetViewPlugin extends UIPlugin {
67769
67811
  }
67770
67812
  /** gets rid of deprecated sheetIds */
67771
67813
  cleanViewports() {
67772
- const sheetIds = this.getters.getSheetIds();
67773
- for (let sheetId of Object.keys(this.viewports)) {
67774
- if (!sheetIds.includes(sheetId)) {
67775
- delete this.viewports[sheetId];
67776
- }
67814
+ const newViewport = {};
67815
+ for (const sheetId of this.getters.getSheetIds()) {
67816
+ newViewport[sheetId] = this.viewports[sheetId];
67777
67817
  }
67818
+ this.viewports = newViewport;
67778
67819
  }
67779
67820
  resizeSheetView(height, width, gridOffsetX = 0, gridOffsetY = 0) {
67780
67821
  this.sheetViewHeight = height;
@@ -67784,7 +67825,7 @@ class SheetViewPlugin extends UIPlugin {
67784
67825
  this.recomputeViewports();
67785
67826
  }
67786
67827
  recomputeViewports() {
67787
- for (let sheetId of Object.keys(this.viewports)) {
67828
+ for (const sheetId of this.getters.getSheetIds()) {
67788
67829
  this.resetViewports(sheetId);
67789
67830
  }
67790
67831
  }
@@ -67806,8 +67847,10 @@ class SheetViewPlugin extends UIPlugin {
67806
67847
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
67807
67848
  const nCols = this.getters.getNumberCols(sheetId);
67808
67849
  const nRows = this.getters.getNumberRows(sheetId);
67809
- const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
67810
- const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
67850
+ const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
67851
+ const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
67852
+ const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
67853
+ const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
67811
67854
  const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
67812
67855
  const canScrollHorizontally = xRatio < 1.0;
67813
67856
  const canScrollVertically = yRatio < 1.0;
@@ -67818,14 +67861,14 @@ class SheetViewPlugin extends UIPlugin {
67818
67861
  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 })) ||
67819
67862
  undefined,
67820
67863
  topRight: (ySplit &&
67821
- 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 })) ||
67864
+ 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 })) ||
67822
67865
  undefined,
67823
67866
  bottomLeft: (xSplit &&
67824
- 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 })) ||
67867
+ 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 })) ||
67825
67868
  undefined,
67826
67869
  bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
67827
- width: this.sheetViewWidth - colOffset,
67828
- height: this.sheetViewHeight - rowOffset,
67870
+ width: unfrozenWidth,
67871
+ height: unfrozenHeight,
67829
67872
  }, { canScrollHorizontally, canScrollVertically }, {
67830
67873
  x: canScrollHorizontally ? previousOffset.x : 0,
67831
67874
  y: canScrollVertically ? previousOffset.y : 0,
@@ -67902,12 +67945,26 @@ class SheetViewPlugin extends UIPlugin {
67902
67945
  const height = this.sheetViewHeight + this.gridOffsetY;
67903
67946
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
67904
67947
  }
67905
- recomposeRect(viewportRects) {
67906
- const x = Math.min(...viewportRects.map((rect) => rect.x));
67907
- const y = Math.min(...viewportRects.map((rect) => rect.y));
67908
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
67909
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
67910
- return { x, y, width, height };
67948
+ mapViewportsToRect(sheetId, rectCallBack) {
67949
+ let x = Infinity;
67950
+ let y = Infinity;
67951
+ let width = 0;
67952
+ let height = 0;
67953
+ let hasViewports = false;
67954
+ for (const viewport of this.getSubViewports(sheetId)) {
67955
+ const rect = rectCallBack(viewport);
67956
+ if (rect) {
67957
+ hasViewports = true;
67958
+ x = Math.min(x, rect.x);
67959
+ y = Math.min(y, rect.y);
67960
+ width = Math.max(width, rect.x + rect.width);
67961
+ height = Math.max(height, rect.y + rect.height);
67962
+ }
67963
+ }
67964
+ if (!hasViewports) {
67965
+ return { x: 0, y: 0, width: 0, height: 0 };
67966
+ }
67967
+ return { x, y, width: width - x, height: height - y };
67911
67968
  }
67912
67969
  }
67913
67970
 
@@ -75043,6 +75100,6 @@ exports.tokenColors = tokenColors;
75043
75100
  exports.tokenize = tokenize;
75044
75101
 
75045
75102
 
75046
- __info__.version = "18.1.5";
75047
- __info__.date = "2025-01-31T08:00:10.263Z";
75048
- __info__.hash = "97acb8b";
75103
+ __info__.version = "18.1.6";
75104
+ __info__.date = "2025-02-05T07:18:57.089Z";
75105
+ __info__.hash = "f5b97e0";