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