@odoo/o-spreadsheet 17.4.19 → 17.4.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 17.4.19
6
- * @date 2025-01-27T10:04:10.249Z
7
- * @hash f2a7840
5
+ * @version 17.4.21
6
+ * @date 2025-02-05T06:46:54.366Z
7
+ * @hash 0c55e18
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -1953,11 +1953,11 @@
1953
1953
  * number from the point of view of the isNumber function.
1954
1954
  */
1955
1955
  function parseNumber(str, locale) {
1956
+ // remove invaluable characters
1957
+ str = str.replace(getInvaluableSymbolsRegexp(locale), "");
1956
1958
  if (locale.decimalSeparator !== ".") {
1957
1959
  str = str.replace(locale.decimalSeparator, ".");
1958
1960
  }
1959
- // remove invaluable characters
1960
- str = str.replace(getInvaluableSymbolsRegexp(locale), "");
1961
1961
  let n = Number(str);
1962
1962
  if (isNaN(n) && str.includes("%")) {
1963
1963
  n = Number(str.split("%")[0]);
@@ -18882,22 +18882,23 @@ stores.inject(MyMetaStore, storeInstance);
18882
18882
  description: _t("Horizontal lookup"),
18883
18883
  args: [
18884
18884
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18885
- 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.")),
18885
+ 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.")),
18886
18886
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18887
18887
  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.")),
18888
18888
  ],
18889
18889
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18890
18890
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18891
- assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18891
+ const _range = toMatrix(range);
18892
+ assert(() => 1 <= _index && _index <= _range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18892
18893
  if (searchKey && isEvaluationError(searchKey.value)) {
18893
18894
  return searchKey;
18894
18895
  }
18895
18896
  const getValueFromRange = (range, index) => range[index][0].value;
18896
18897
  const _isSorted = toBoolean(isSorted.value);
18897
18898
  const colIndex = _isSorted
18898
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
18899
- : linearSearch(range, searchKey, "wildcard", range.length, getValueFromRange);
18900
- const col = range[colIndex];
18899
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
18900
+ : linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange);
18901
+ const col = _range[colIndex];
18901
18902
  if (col === undefined) {
18902
18903
  return valueNotAvailable(searchKey);
18903
18904
  }
@@ -18996,35 +18997,37 @@ stores.inject(MyMetaStore, storeInstance);
18996
18997
  description: _t("Look up a value."),
18997
18998
  args: [
18998
18999
  arg("search_key (any)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18999
- 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.")),
19000
- 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.")),
19000
+ 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.")),
19001
+ 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.")),
19001
19002
  ],
19002
19003
  compute: function (searchKey, searchArray, resultRange) {
19003
- let nbCol = searchArray.length;
19004
- let nbRow = searchArray[0].length;
19004
+ const _searchArray = toMatrix(searchArray);
19005
+ const _resultRange = toMatrix(resultRange);
19006
+ let nbCol = _searchArray.length;
19007
+ let nbRow = _searchArray[0].length;
19005
19008
  const verticalSearch = nbRow >= nbCol;
19006
19009
  const getElement = verticalSearch
19007
19010
  ? (range, index) => range[0][index].value
19008
19011
  : (range, index) => range[index][0].value;
19009
19012
  const rangeLength = verticalSearch ? nbRow : nbCol;
19010
- const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
19013
+ const index = dichotomicSearch(_searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
19011
19014
  if (index === -1 ||
19012
- (verticalSearch && searchArray[0][index] === undefined) ||
19013
- (!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
19015
+ (verticalSearch && _searchArray[0][index] === undefined) ||
19016
+ (!verticalSearch && _searchArray[index][nbRow - 1] === undefined)) {
19014
19017
  return valueNotAvailable(searchKey);
19015
19018
  }
19016
- if (resultRange === undefined) {
19017
- return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
19019
+ if (_resultRange[0].length === 0) {
19020
+ return verticalSearch ? _searchArray[nbCol - 1][index] : _searchArray[index][nbRow - 1];
19018
19021
  }
19019
- nbCol = resultRange.length;
19020
- nbRow = resultRange[0].length;
19022
+ nbCol = _resultRange.length;
19023
+ nbRow = _resultRange[0].length;
19021
19024
  assert(() => nbCol === 1 || nbRow === 1, _t("The result_range must be a single row or a single column."));
19022
19025
  if (nbCol > 1) {
19023
19026
  assert(() => index <= nbCol - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range row value %s.", (index + 1).toString()));
19024
- return resultRange[index][0];
19027
+ return _resultRange[index][0];
19025
19028
  }
19026
19029
  assert(() => index <= nbRow - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range column value %s.", (index + 1).toString()));
19027
- return resultRange[0][index];
19030
+ return _resultRange[0][index];
19028
19031
  },
19029
19032
  isExported: true,
19030
19033
  };
@@ -19041,28 +19044,29 @@ stores.inject(MyMetaStore, storeInstance);
19041
19044
  ],
19042
19045
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
19043
19046
  let _searchType = toNumber(searchType, this.locale);
19044
- const nbCol = range.length;
19045
- const nbRow = range[0].length;
19047
+ const _range = toMatrix(range);
19048
+ const nbCol = _range.length;
19049
+ const nbRow = _range[0].length;
19046
19050
  assert(() => nbCol === 1 || nbRow === 1, _t("The range must be a single row or a single column."));
19047
19051
  let index = -1;
19048
19052
  const getElement = nbCol === 1
19049
- ? (range, index) => range[0][index].value
19050
- : (range, index) => range[index][0].value;
19051
- const rangeLen = nbCol === 1 ? range[0].length : range.length;
19053
+ ? (_range, index) => _range[0][index].value
19054
+ : (_range, index) => _range[index][0].value;
19055
+ const rangeLen = nbCol === 1 ? _range[0].length : _range.length;
19052
19056
  _searchType = Math.sign(_searchType);
19053
19057
  switch (_searchType) {
19054
19058
  case 1:
19055
- index = dichotomicSearch(range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
19059
+ index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
19056
19060
  break;
19057
19061
  case 0:
19058
- index = linearSearch(range, searchKey, "wildcard", rangeLen, getElement);
19062
+ index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement);
19059
19063
  break;
19060
19064
  case -1:
19061
- index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
19065
+ index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
19062
19066
  break;
19063
19067
  }
19064
- if ((nbCol === 1 && range[0][index] === undefined) ||
19065
- (nbCol !== 1 && range[index] === undefined)) {
19068
+ if ((nbCol === 1 && _range[0][index] === undefined) ||
19069
+ (nbCol !== 1 && _range[index] === undefined)) {
19066
19070
  return valueNotAvailable(searchKey);
19067
19071
  }
19068
19072
  return index + 1;
@@ -19116,16 +19120,17 @@ stores.inject(MyMetaStore, storeInstance);
19116
19120
  ],
19117
19121
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
19118
19122
  const _index = Math.trunc(toNumber(index?.value, this.locale));
19119
- assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
19123
+ const _range = toMatrix(range);
19124
+ assert(() => 1 <= _index && _index <= _range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
19120
19125
  if (searchKey && isEvaluationError(searchKey.value)) {
19121
19126
  return searchKey;
19122
19127
  }
19123
19128
  const getValueFromRange = (range, index) => range[0][index].value;
19124
19129
  const _isSorted = toBoolean(isSorted.value);
19125
19130
  const rowIndex = _isSorted
19126
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
19127
- : linearSearch(range, searchKey, "wildcard", range[0].length, getValueFromRange);
19128
- const value = range[_index - 1][rowIndex];
19131
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
19132
+ : linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange);
19133
+ const value = _range[_index - 1][rowIndex];
19129
19134
  if (value === undefined) {
19130
19135
  return valueNotAvailable(searchKey);
19131
19136
  }
@@ -19162,30 +19167,32 @@ stores.inject(MyMetaStore, storeInstance);
19162
19167
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
19163
19168
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
19164
19169
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
19165
- assert(() => lookupRange.length === 1 || lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
19170
+ const _lookupRange = toMatrix(lookupRange);
19171
+ const _returnRange = toMatrix(returnRange);
19172
+ assert(() => _lookupRange.length === 1 || _lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
19166
19173
  assert(() => [-1, 1, -2, 2].includes(_searchMode), _t("search_mode should be a value in [-1, 1, -2, 2]."));
19167
19174
  assert(() => [-1, 0, 1, 2].includes(_matchMode), _t("match_mode should be a value in [-1, 0, 1, 2]."));
19168
- const lookupDirection = lookupRange.length === 1 ? "col" : "row";
19175
+ const lookupDirection = _lookupRange.length === 1 ? "col" : "row";
19169
19176
  assert(() => !(_matchMode === 2 && [-2, 2].includes(_searchMode)), _t("the search and match mode combination is not supported for XLOOKUP evaluation."));
19170
19177
  assert(() => lookupDirection === "col"
19171
- ? returnRange[0].length === lookupRange[0].length
19172
- : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
19178
+ ? _returnRange[0].length === _lookupRange[0].length
19179
+ : _returnRange.length === _lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
19173
19180
  if (searchKey && isEvaluationError(searchKey.value)) {
19174
19181
  return [[searchKey]];
19175
19182
  }
19176
19183
  const getElement = lookupDirection === "col"
19177
19184
  ? (range, index) => range[0][index].value
19178
19185
  : (range, index) => range[index][0].value;
19179
- const rangeLen = lookupDirection === "col" ? lookupRange[0].length : lookupRange.length;
19186
+ const rangeLen = lookupDirection === "col" ? _lookupRange[0].length : _lookupRange.length;
19180
19187
  const mode = MATCH_MODE[_matchMode];
19181
19188
  const reverseSearch = _searchMode === -1;
19182
19189
  const index = _searchMode === 2 || _searchMode === -2
19183
- ? dichotomicSearch(lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
19184
- : linearSearch(lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
19190
+ ? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
19191
+ : linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
19185
19192
  if (index !== -1) {
19186
19193
  return lookupDirection === "col"
19187
- ? returnRange.map((col) => [col[index]])
19188
- : [returnRange[index]];
19194
+ ? _returnRange.map((col) => [col[index]])
19195
+ : [_returnRange[index]];
19189
19196
  }
19190
19197
  if (defaultValue === undefined) {
19191
19198
  return valueNotAvailable(searchKey);
@@ -21615,6 +21622,12 @@ stores.inject(MyMetaStore, storeInstance);
21615
21622
  }
21616
21623
  this.contentHelper.updateEl(el);
21617
21624
  });
21625
+ this.env.model.selection.observe(this, {
21626
+ handleEvent: () => this.autoCompleteState.hide(),
21627
+ });
21628
+ owl.onWillUnmount(() => {
21629
+ this.env.model.selection.detachObserver(this);
21630
+ });
21618
21631
  owl.useEffect(() => {
21619
21632
  this.processContent();
21620
21633
  });
@@ -41213,11 +41226,10 @@ stores.inject(MyMetaStore, storeInstance);
41213
41226
  switch (layer) {
41214
41227
  case "Background":
41215
41228
  this.drawGlobalBackground(renderingContext);
41216
- for (const zone of this.getters.getAllActiveViewportsZones()) {
41229
+ for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
41217
41230
  const { ctx } = renderingContext;
41218
41231
  ctx.save();
41219
41232
  ctx.beginPath();
41220
- const rect = this.getters.getVisibleRect(zone);
41221
41233
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
41222
41234
  ctx.clip();
41223
41235
  const boxes = this.getGridBoxes(zone);
@@ -41487,10 +41499,8 @@ stores.inject(MyMetaStore, storeInstance);
41487
41499
  const { ctx, thinLineWidth } = renderingContext;
41488
41500
  const visibleCols = this.getters.getSheetViewVisibleCols();
41489
41501
  const left = visibleCols[0];
41490
- const right = visibleCols[visibleCols.length - 1];
41491
41502
  const visibleRows = this.getters.getSheetViewVisibleRows();
41492
41503
  const top = visibleRows[0];
41493
- const bottom = visibleRows[visibleRows.length - 1];
41494
41504
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
41495
41505
  const selection = this.getters.getSelectedZones();
41496
41506
  const selectedCols = getZonesCols(selection);
@@ -41506,7 +41516,7 @@ stores.inject(MyMetaStore, storeInstance);
41506
41516
  ctx.lineWidth = thinLineWidth;
41507
41517
  ctx.strokeStyle = "#333";
41508
41518
  // Columns headers background
41509
- for (let col = left; col <= right; col++) {
41519
+ for (const col of visibleCols) {
41510
41520
  const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
41511
41521
  const { x, width } = this.getters.getVisibleRect(colZone);
41512
41522
  const isColActive = activeCols.has(col);
@@ -41523,7 +41533,7 @@ stores.inject(MyMetaStore, storeInstance);
41523
41533
  ctx.fillRect(x, 0, width, HEADER_HEIGHT);
41524
41534
  }
41525
41535
  // Rows headers background
41526
- for (let row = top; row <= bottom; row++) {
41536
+ for (const row of visibleRows) {
41527
41537
  const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
41528
41538
  const { y, height } = this.getters.getVisibleRect(rowZone);
41529
41539
  const isRowActive = activeRows.has(row);
@@ -41549,21 +41559,21 @@ stores.inject(MyMetaStore, storeInstance);
41549
41559
  ctx.stroke();
41550
41560
  ctx.beginPath();
41551
41561
  // column text + separator
41552
- for (const i of visibleCols) {
41553
- const colSize = this.getters.getColSize(sheetId, i);
41554
- const colName = numberToLetters(i);
41555
- ctx.fillStyle = activeCols.has(i) ? "#fff" : TEXT_HEADER_COLOR;
41556
- let colStart = this.getHeaderOffset("COL", left, i);
41562
+ for (const col of visibleCols) {
41563
+ const colSize = this.getters.getColSize(sheetId, col);
41564
+ const colName = numberToLetters(col);
41565
+ ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
41566
+ let colStart = this.getHeaderOffset("COL", left, col);
41557
41567
  ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
41558
41568
  ctx.moveTo(colStart + colSize, 0);
41559
41569
  ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
41560
41570
  }
41561
41571
  // row text + separator
41562
- for (const i of visibleRows) {
41563
- const rowSize = this.getters.getRowSize(sheetId, i);
41564
- ctx.fillStyle = activeRows.has(i) ? "#fff" : TEXT_HEADER_COLOR;
41565
- let rowStart = this.getHeaderOffset("ROW", top, i);
41566
- ctx.fillText(String(i + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
41572
+ for (const row of visibleRows) {
41573
+ const rowSize = this.getters.getRowSize(sheetId, row);
41574
+ ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
41575
+ let rowStart = this.getHeaderOffset("ROW", top, row);
41576
+ ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
41567
41577
  ctx.moveTo(0, rowStart + rowSize);
41568
41578
  ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
41569
41579
  }
@@ -41861,6 +41871,9 @@ stores.inject(MyMetaStore, storeInstance);
41861
41871
  canvas.width = width * dpr;
41862
41872
  canvas.height = height * dpr;
41863
41873
  canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
41874
+ if (width === 0 || height === 0) {
41875
+ return;
41876
+ }
41864
41877
  // Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
41865
41878
  // are the edges of the squares. If you draw a one-unit-wide line between whole-number
41866
41879
  // coordinates, it will overlap opposite sides of the pixel square, and the resulting
@@ -47593,7 +47606,7 @@ stores.inject(MyMetaStore, storeInstance);
47593
47606
  getCommonSides(border1, border2) {
47594
47607
  const commonBorder = {};
47595
47608
  for (let side of ["top", "bottom", "left", "right"]) {
47596
- if (border1[side] && border1[side] === border2[side]) {
47609
+ if (border1[side] && deepEquals(border1[side], border2[side])) {
47597
47610
  commonBorder[side] = border1[side];
47598
47611
  }
47599
47612
  }
@@ -58534,14 +58547,12 @@ stores.inject(MyMetaStore, storeInstance);
58534
58547
  }
58535
58548
  break;
58536
58549
  case "AUTORESIZE_ROWS":
58537
- for (let row of cmd.rows) {
58538
- this.dispatch("RESIZE_COLUMNS_ROWS", {
58539
- elements: [row],
58540
- dimension: "ROW",
58541
- size: null,
58542
- sheetId: cmd.sheetId,
58543
- });
58544
- }
58550
+ this.dispatch("RESIZE_COLUMNS_ROWS", {
58551
+ elements: cmd.rows,
58552
+ dimension: "ROW",
58553
+ size: null,
58554
+ sheetId: cmd.sheetId,
58555
+ });
58545
58556
  break;
58546
58557
  }
58547
58558
  }
@@ -60938,8 +60949,17 @@ stores.inject(MyMetaStore, storeInstance);
60938
60949
  this.getters = getters;
60939
60950
  this.sheetId = sheetId;
60940
60951
  this.boundaries = boundaries;
60941
- this.viewportWidth = sizeInGrid.width;
60942
- this.viewportHeight = sizeInGrid.height;
60952
+ if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
60953
+ throw new Error("Viewport size cannot be negative");
60954
+ }
60955
+ this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
60956
+ this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
60957
+ this.top = boundaries.top;
60958
+ this.bottom = boundaries.bottom;
60959
+ this.left = boundaries.left;
60960
+ this.right = boundaries.right;
60961
+ this.offsetX = offsets.x;
60962
+ this.offsetY = offsets.y;
60943
60963
  this.offsetScrollbarX = offsets.x;
60944
60964
  this.offsetScrollbarY = offsets.y;
60945
60965
  this.canScrollVertically = options.canScrollVertically;
@@ -60982,9 +61002,9 @@ stores.inject(MyMetaStore, storeInstance);
60982
61002
  Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
60983
61003
  );
60984
61004
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
60985
- }
60986
- if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
60987
- height += FOOTER_HEIGHT;
61005
+ if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
61006
+ height += FOOTER_HEIGHT;
61007
+ }
60988
61008
  }
60989
61009
  return { width, height };
60990
61010
  }
@@ -61125,6 +61145,9 @@ stores.inject(MyMetaStore, storeInstance);
61125
61145
  !this.getters.isRowHidden(this.sheetId, row));
61126
61146
  }
61127
61147
  searchHeaderIndex(dimension, position, startIndex = 0) {
61148
+ if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
61149
+ return -1;
61150
+ }
61128
61151
  const sheetId = this.sheetId;
61129
61152
  const headers = this.getters.getNumberHeaders(sheetId, dimension);
61130
61153
  // using a binary search:
@@ -61161,7 +61184,7 @@ stores.inject(MyMetaStore, storeInstance);
61161
61184
  this.adjustViewportZoneY();
61162
61185
  }
61163
61186
  /** Corrects the viewport's horizontal offset based on the current structure
61164
- * To make sure that at least on column is visible inside the viewport.
61187
+ * To make sure that at least one column is visible inside the viewport.
61165
61188
  */
61166
61189
  adjustViewportOffsetX() {
61167
61190
  if (this.canScrollHorizontally) {
@@ -61173,7 +61196,7 @@ stores.inject(MyMetaStore, storeInstance);
61173
61196
  this.adjustViewportZoneX();
61174
61197
  }
61175
61198
  /** Corrects the viewport's vertical offset based on the current structure
61176
- * To make sure that at least on row is visible inside the viewport.
61199
+ * To make sure that at least one row is visible inside the viewport.
61177
61200
  */
61178
61201
  adjustViewportOffsetY() {
61179
61202
  if (this.canScrollVertically) {
@@ -61190,11 +61213,14 @@ stores.inject(MyMetaStore, storeInstance);
61190
61213
  const sheetId = this.sheetId;
61191
61214
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
61192
61215
  this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
61216
+ if (!this.viewportWidth) {
61217
+ return;
61218
+ }
61193
61219
  if (this.left === -1) {
61194
61220
  this.left = this.boundaries.left;
61195
61221
  }
61196
61222
  if (this.right === -1) {
61197
- this.right = this.getters.getNumberCols(sheetId) - 1;
61223
+ this.right = this.boundaries.right;
61198
61224
  }
61199
61225
  this.offsetX =
61200
61226
  this.getters.getColDimensions(sheetId, this.left).start -
@@ -61206,11 +61232,14 @@ stores.inject(MyMetaStore, storeInstance);
61206
61232
  const sheetId = this.sheetId;
61207
61233
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
61208
61234
  this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
61235
+ if (!this.viewportHeight) {
61236
+ return;
61237
+ }
61209
61238
  if (this.top === -1) {
61210
61239
  this.top = this.boundaries.top;
61211
61240
  }
61212
61241
  if (this.bottom === -1) {
61213
- this.bottom = this.getters.getNumberRows(sheetId) - 1;
61242
+ this.bottom = this.boundaries.bottom;
61214
61243
  }
61215
61244
  this.offsetY =
61216
61245
  this.getters.getRowDimensions(sheetId, this.top).start -
@@ -61284,7 +61313,7 @@ stores.inject(MyMetaStore, storeInstance);
61284
61313
  "isPositionVisible",
61285
61314
  "getColDimensionsInViewport",
61286
61315
  "getRowDimensionsInViewport",
61287
- "getAllActiveViewportsZones",
61316
+ "getAllActiveViewportsZonesAndRect",
61288
61317
  "getRect",
61289
61318
  ];
61290
61319
  viewports = {};
@@ -61517,12 +61546,12 @@ stores.inject(MyMetaStore, storeInstance);
61517
61546
  const sheetId = this.getters.getActiveSheetId();
61518
61547
  const viewports = this.getSubViewports(sheetId);
61519
61548
  //TODO ake another commit to eimprove this
61520
- return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
61549
+ return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
61521
61550
  }
61522
61551
  getSheetViewVisibleRows() {
61523
61552
  const sheetId = this.getters.getActiveSheetId();
61524
61553
  const viewports = this.getSubViewports(sheetId);
61525
- return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
61554
+ return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
61526
61555
  }
61527
61556
  /**
61528
61557
  * Get the positions of all the cells that are visible in the viewport, taking merges into account.
@@ -61565,19 +61594,19 @@ stores.inject(MyMetaStore, storeInstance);
61565
61594
  maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
61566
61595
  };
61567
61596
  }
61568
- getColRowOffsetInViewport(dimension, referenceIndex, index) {
61569
- const sheetId = this.getters.getActiveSheetId();
61570
- const visibleCols = this.getters.getSheetViewVisibleCols();
61571
- const visibleRows = this.getters.getSheetViewVisibleRows();
61572
- if (index < referenceIndex) {
61573
- return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
61597
+ getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
61598
+ if (targetHeaderIndex < referenceHeaderIndex) {
61599
+ return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
61574
61600
  }
61601
+ const sheetId = this.getters.getActiveSheetId();
61602
+ const visibleHeaders = dimension === "COL"
61603
+ ? this.getters.getSheetViewVisibleCols()
61604
+ : this.getters.getSheetViewVisibleRows();
61605
+ const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
61606
+ const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
61607
+ const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
61575
61608
  let offset = 0;
61576
- const visibleIndexes = dimension === "COL" ? visibleCols : visibleRows;
61577
- for (let i = referenceIndex; i < index; i++) {
61578
- if (!visibleIndexes.includes(i)) {
61579
- continue;
61580
- }
61609
+ for (const i of relevantIndexes) {
61581
61610
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
61582
61611
  }
61583
61612
  return offset;
@@ -61624,7 +61653,7 @@ stores.inject(MyMetaStore, storeInstance);
61624
61653
  }
61625
61654
  return { canEdgeScroll, direction, delay };
61626
61655
  }
61627
- getEdgeScrollRow(y, previousY, tartingY) {
61656
+ getEdgeScrollRow(y, previousY, startingY) {
61628
61657
  let canEdgeScroll = false;
61629
61658
  let direction = 0;
61630
61659
  let delay = 0;
@@ -61645,7 +61674,7 @@ stores.inject(MyMetaStore, storeInstance);
61645
61674
  delay = scrollDelay(y - height);
61646
61675
  direction = 1;
61647
61676
  }
61648
- else if (y < offsetCorrectionY && tartingY >= offsetCorrectionY && currentOffsetY > 0) {
61677
+ else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
61649
61678
  // 2
61650
61679
  canEdgeScroll = true;
61651
61680
  delay = scrollDelay(offsetCorrectionY - y);
@@ -61671,13 +61700,7 @@ stores.inject(MyMetaStore, storeInstance);
61671
61700
  */
61672
61701
  getVisibleRectWithoutHeaders(zone) {
61673
61702
  const sheetId = this.getters.getActiveSheetId();
61674
- const viewportRects = this.getSubViewports(sheetId)
61675
- .map((viewport) => viewport.getVisibleRect(zone))
61676
- .filter(isDefined);
61677
- if (viewportRects.length === 0) {
61678
- return { x: 0, y: 0, width: 0, height: 0 };
61679
- }
61680
- return this.recomposeRect(viewportRects);
61703
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
61681
61704
  }
61682
61705
  /**
61683
61706
  * Computes the actual size and position (:Rect) of the zone on the canvas
@@ -61685,13 +61708,7 @@ stores.inject(MyMetaStore, storeInstance);
61685
61708
  */
61686
61709
  getRect(zone) {
61687
61710
  const sheetId = this.getters.getActiveSheetId();
61688
- const viewportRects = this.getSubViewports(sheetId)
61689
- .map((viewport) => viewport.getFullRect(zone))
61690
- .filter(isDefined);
61691
- if (viewportRects.length === 0) {
61692
- return { x: 0, y: 0, width: 0, height: 0 };
61693
- }
61694
- const rect = this.recomposeRect(viewportRects);
61711
+ const rect = this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
61695
61712
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
61696
61713
  }
61697
61714
  /**
@@ -61736,9 +61753,18 @@ stores.inject(MyMetaStore, storeInstance);
61736
61753
  end: start + (isRowHidden ? 0 : size),
61737
61754
  };
61738
61755
  }
61739
- getAllActiveViewportsZones() {
61756
+ getAllActiveViewportsZonesAndRect() {
61740
61757
  const sheetId = this.getters.getActiveSheetId();
61741
- return this.getSubViewports(sheetId);
61758
+ return this.getSubViewports(sheetId).map((viewport) => {
61759
+ return {
61760
+ zone: viewport,
61761
+ rect: {
61762
+ x: viewport.offsetCorrectionX + this.gridOffsetX,
61763
+ y: viewport.offsetCorrectionY + this.gridOffsetY,
61764
+ ...viewport.getMaxSize(),
61765
+ },
61766
+ };
61767
+ });
61742
61768
  }
61743
61769
  // ---------------------------------------------------------------------------
61744
61770
  // Private
@@ -61797,12 +61823,11 @@ stores.inject(MyMetaStore, storeInstance);
61797
61823
  }
61798
61824
  /** gets rid of deprecated sheetIds */
61799
61825
  cleanViewports() {
61800
- const sheetIds = this.getters.getSheetIds();
61801
- for (let sheetId of Object.keys(this.viewports)) {
61802
- if (!sheetIds.includes(sheetId)) {
61803
- delete this.viewports[sheetId];
61804
- }
61826
+ const newViewport = {};
61827
+ for (const sheetId of this.getters.getSheetIds()) {
61828
+ newViewport[sheetId] = this.viewports[sheetId];
61805
61829
  }
61830
+ this.viewports = newViewport;
61806
61831
  }
61807
61832
  resizeSheetView(height, width, gridOffsetX = 0, gridOffsetY = 0) {
61808
61833
  this.sheetViewHeight = height;
@@ -61812,7 +61837,7 @@ stores.inject(MyMetaStore, storeInstance);
61812
61837
  this.recomputeViewports();
61813
61838
  }
61814
61839
  recomputeViewports() {
61815
- for (let sheetId of Object.keys(this.viewports)) {
61840
+ for (const sheetId of this.getters.getSheetIds()) {
61816
61841
  this.resetViewports(sheetId);
61817
61842
  }
61818
61843
  }
@@ -61834,8 +61859,10 @@ stores.inject(MyMetaStore, storeInstance);
61834
61859
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
61835
61860
  const nCols = this.getters.getNumberCols(sheetId);
61836
61861
  const nRows = this.getters.getNumberRows(sheetId);
61837
- const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
61838
- const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
61862
+ const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
61863
+ const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
61864
+ const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
61865
+ const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
61839
61866
  const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
61840
61867
  const canScrollHorizontally = xRatio < 1.0;
61841
61868
  const canScrollVertically = yRatio < 1.0;
@@ -61846,14 +61873,14 @@ stores.inject(MyMetaStore, storeInstance);
61846
61873
  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 })) ||
61847
61874
  undefined,
61848
61875
  topRight: (ySplit &&
61849
- 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 })) ||
61876
+ 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 })) ||
61850
61877
  undefined,
61851
61878
  bottomLeft: (xSplit &&
61852
- 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 })) ||
61879
+ 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 })) ||
61853
61880
  undefined,
61854
61881
  bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
61855
- width: this.sheetViewWidth - colOffset,
61856
- height: this.sheetViewHeight - rowOffset,
61882
+ width: unfrozenWidth,
61883
+ height: unfrozenHeight,
61857
61884
  }, { canScrollHorizontally, canScrollVertically }, {
61858
61885
  x: canScrollHorizontally ? previousOffset.x : 0,
61859
61886
  y: canScrollVertically ? previousOffset.y : 0,
@@ -61930,12 +61957,26 @@ stores.inject(MyMetaStore, storeInstance);
61930
61957
  const height = this.sheetViewHeight + this.gridOffsetY;
61931
61958
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
61932
61959
  }
61933
- recomposeRect(viewportRects) {
61934
- const x = Math.min(...viewportRects.map((rect) => rect.x));
61935
- const y = Math.min(...viewportRects.map((rect) => rect.y));
61936
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
61937
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
61938
- return { x, y, width, height };
61960
+ mapViewportsToRect(sheetId, rectCallBack) {
61961
+ let x = Infinity;
61962
+ let y = Infinity;
61963
+ let width = 0;
61964
+ let height = 0;
61965
+ let hasViewports = false;
61966
+ for (const viewport of this.getSubViewports(sheetId)) {
61967
+ const rect = rectCallBack(viewport);
61968
+ if (rect) {
61969
+ hasViewports = true;
61970
+ x = Math.min(x, rect.x);
61971
+ y = Math.min(y, rect.y);
61972
+ width = Math.max(width, rect.x + rect.width);
61973
+ height = Math.max(height, rect.y + rect.height);
61974
+ }
61975
+ }
61976
+ if (!hasViewports) {
61977
+ return { x: 0, y: 0, width: 0, height: 0 };
61978
+ }
61979
+ return { x, y, width: width - x, height: height - y };
61939
61980
  }
61940
61981
  }
61941
61982
 
@@ -65551,6 +65592,9 @@ stores.inject(MyMetaStore, storeInstance);
65551
65592
  observe(owner, callbacks) {
65552
65593
  this.observers.set(owner, { owner, callbacks });
65553
65594
  }
65595
+ detachObserver(owner) {
65596
+ this.observers.delete(owner);
65597
+ }
65554
65598
  /**
65555
65599
  * Capture the stream for yourself
65556
65600
  */
@@ -65643,6 +65687,9 @@ stores.inject(MyMetaStore, storeInstance);
65643
65687
  observe(owner, callbacks) {
65644
65688
  this.stream.observe(owner, callbacks);
65645
65689
  }
65690
+ detachObserver(owner) {
65691
+ this.stream.detachObserver(owner);
65692
+ }
65646
65693
  release(owner) {
65647
65694
  if (this.stream.isListening(owner)) {
65648
65695
  this.stream.release(owner);
@@ -68862,9 +68909,9 @@ stores.inject(MyMetaStore, storeInstance);
68862
68909
  exports.tokenize = tokenize;
68863
68910
 
68864
68911
 
68865
- __info__.version = "17.4.19";
68866
- __info__.date = "2025-01-27T10:04:10.249Z";
68867
- __info__.hash = "f2a7840";
68912
+ __info__.version = "17.4.21";
68913
+ __info__.date = "2025-02-05T06:46:54.366Z";
68914
+ __info__.hash = "0c55e18";
68868
68915
 
68869
68916
 
68870
68917
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);