@odoo/o-spreadsheet 18.0.13 → 18.0.15

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.0.13
6
- * @date 2025-01-31T07:59:17.481Z
7
- * @hash f505971
5
+ * @version 18.0.15
6
+ * @date 2025-02-10T08:59:22.993Z
7
+ * @hash 5b19f88
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -766,9 +766,16 @@
766
766
  }
767
767
  return true;
768
768
  }
769
- /** Check if the given array contains all the values of the other array. */
769
+ /**
770
+ * Check if the given array contains all the values of the other array.
771
+ * It makes the assumption that both array do not contain duplicates.
772
+ */
770
773
  function includesAll(arr, values) {
771
- return values.every((value) => arr.includes(value));
774
+ if (arr.length < values.length) {
775
+ return false;
776
+ }
777
+ const set = new Set(arr);
778
+ return values.every((value) => set.has(value));
772
779
  }
773
780
  /**
774
781
  * Return an object with all the keys in the object that have a falsy value removed.
@@ -18383,19 +18390,20 @@ stores.inject(MyMetaStore, storeInstance);
18383
18390
  description: _t("Horizontal lookup"),
18384
18391
  args: [
18385
18392
  arg("search_key (string, number, boolean)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18386
- 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.")),
18393
+ 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.")),
18387
18394
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18388
18395
  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.")),
18389
18396
  ],
18390
18397
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18391
18398
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18392
- assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18399
+ const _range = toMatrix(range);
18400
+ assert(() => 1 <= _index && _index <= _range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18393
18401
  const getValueFromRange = (range, index) => range[index][0].value;
18394
18402
  const _isSorted = toBoolean(isSorted.value);
18395
18403
  const colIndex = _isSorted
18396
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
18397
- : linearSearch(range, searchKey, "wildcard", range.length, getValueFromRange, this.lookupCaches);
18398
- const col = range[colIndex];
18404
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
18405
+ : linearSearch(range, searchKey, "wildcard", _range.length, getValueFromRange, this.lookupCaches);
18406
+ const col = _range[colIndex];
18399
18407
  if (col === undefined) {
18400
18408
  return valueNotAvailable(searchKey);
18401
18409
  }
@@ -18487,35 +18495,37 @@ stores.inject(MyMetaStore, storeInstance);
18487
18495
  description: _t("Look up a value."),
18488
18496
  args: [
18489
18497
  arg("search_key (string, number, boolean)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18490
- 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.")),
18491
- 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.")),
18498
+ 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.")),
18499
+ 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.")),
18492
18500
  ],
18493
18501
  compute: function (searchKey, searchArray, resultRange) {
18494
- let nbCol = searchArray.length;
18495
- let nbRow = searchArray[0].length;
18502
+ const _searchArray = toMatrix(searchArray);
18503
+ const _resultRange = toMatrix(resultRange);
18504
+ let nbCol = _searchArray.length;
18505
+ let nbRow = _searchArray[0].length;
18496
18506
  const verticalSearch = nbRow >= nbCol;
18497
18507
  const getElement = verticalSearch
18498
18508
  ? (range, index) => range[0][index].value
18499
18509
  : (range, index) => range[index][0].value;
18500
18510
  const rangeLength = verticalSearch ? nbRow : nbCol;
18501
- const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
18511
+ const index = dichotomicSearch(_searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
18502
18512
  if (index === -1 ||
18503
- (verticalSearch && searchArray[0][index] === undefined) ||
18504
- (!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
18513
+ (verticalSearch && _searchArray[0][index] === undefined) ||
18514
+ (!verticalSearch && _searchArray[index][nbRow - 1] === undefined)) {
18505
18515
  return valueNotAvailable(searchKey);
18506
18516
  }
18507
- if (resultRange === undefined) {
18508
- return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
18517
+ if (_resultRange[0].length === 0) {
18518
+ return verticalSearch ? _searchArray[nbCol - 1][index] : _searchArray[index][nbRow - 1];
18509
18519
  }
18510
- nbCol = resultRange.length;
18511
- nbRow = resultRange[0].length;
18520
+ nbCol = _resultRange.length;
18521
+ nbRow = _resultRange[0].length;
18512
18522
  assert(() => nbCol === 1 || nbRow === 1, _t("The result_range must be a single row or a single column."));
18513
18523
  if (nbCol > 1) {
18514
18524
  assert(() => index <= nbCol - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range row value %s.", (index + 1).toString()));
18515
- return resultRange[index][0];
18525
+ return _resultRange[index][0];
18516
18526
  }
18517
18527
  assert(() => index <= nbRow - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range column value %s.", (index + 1).toString()));
18518
- return resultRange[0][index];
18528
+ return _resultRange[0][index];
18519
18529
  },
18520
18530
  isExported: true,
18521
18531
  };
@@ -18532,28 +18542,29 @@ stores.inject(MyMetaStore, storeInstance);
18532
18542
  ],
18533
18543
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
18534
18544
  let _searchType = toNumber(searchType, this.locale);
18535
- const nbCol = range.length;
18536
- const nbRow = range[0].length;
18545
+ const _range = toMatrix(range);
18546
+ const nbCol = _range.length;
18547
+ const nbRow = _range[0].length;
18537
18548
  assert(() => nbCol === 1 || nbRow === 1, _t("The range must be a single row or a single column."));
18538
18549
  let index = -1;
18539
18550
  const getElement = nbCol === 1
18540
- ? (range, index) => range[0][index].value
18541
- : (range, index) => range[index][0].value;
18542
- const rangeLen = nbCol === 1 ? range[0].length : range.length;
18551
+ ? (_range, index) => _range[0][index].value
18552
+ : (_range, index) => _range[index][0].value;
18553
+ const rangeLen = nbCol === 1 ? _range[0].length : _range.length;
18543
18554
  _searchType = Math.sign(_searchType);
18544
18555
  switch (_searchType) {
18545
18556
  case 1:
18546
- index = dichotomicSearch(range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18557
+ index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18547
18558
  break;
18548
18559
  case 0:
18549
- index = linearSearch(range, searchKey, "wildcard", rangeLen, getElement, this.lookupCaches);
18560
+ index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement, this.lookupCaches);
18550
18561
  break;
18551
18562
  case -1:
18552
- index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18563
+ index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18553
18564
  break;
18554
18565
  }
18555
- if ((nbCol === 1 && range[0][index] === undefined) ||
18556
- (nbCol !== 1 && range[index] === undefined)) {
18566
+ if ((nbCol === 1 && _range[0][index] === undefined) ||
18567
+ (nbCol !== 1 && _range[index] === undefined)) {
18557
18568
  return valueNotAvailable(searchKey);
18558
18569
  }
18559
18570
  return index + 1;
@@ -18608,13 +18619,14 @@ stores.inject(MyMetaStore, storeInstance);
18608
18619
  ],
18609
18620
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18610
18621
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18611
- assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18622
+ const _range = toMatrix(range);
18623
+ assert(() => 1 <= _index && _index <= _range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18612
18624
  const getValueFromRange = (range, index) => range[0][index].value;
18613
18625
  const _isSorted = toBoolean(isSorted.value);
18614
18626
  const rowIndex = _isSorted
18615
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
18616
- : linearSearch(range, searchKey, "wildcard", range[0].length, getValueFromRange, this.lookupCaches);
18617
- const value = range[_index - 1][rowIndex];
18627
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
18628
+ : linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange, this.lookupCaches);
18629
+ const value = _range[_index - 1][rowIndex];
18618
18630
  if (value === undefined) {
18619
18631
  return valueNotAvailable(searchKey);
18620
18632
  }
@@ -18651,27 +18663,29 @@ stores.inject(MyMetaStore, storeInstance);
18651
18663
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18652
18664
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18653
18665
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
18654
- assert(() => lookupRange.length === 1 || lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18666
+ const _lookupRange = toMatrix(lookupRange);
18667
+ const _returnRange = toMatrix(returnRange);
18668
+ assert(() => _lookupRange.length === 1 || _lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18655
18669
  assert(() => [-1, 1, -2, 2].includes(_searchMode), _t("search_mode should be a value in [-1, 1, -2, 2]."));
18656
18670
  assert(() => [-1, 0, 1, 2].includes(_matchMode), _t("match_mode should be a value in [-1, 0, 1, 2]."));
18657
- const lookupDirection = lookupRange.length === 1 ? "col" : "row";
18671
+ const lookupDirection = _lookupRange.length === 1 ? "col" : "row";
18658
18672
  assert(() => !(_matchMode === 2 && [-2, 2].includes(_searchMode)), _t("the search and match mode combination is not supported for XLOOKUP evaluation."));
18659
18673
  assert(() => lookupDirection === "col"
18660
- ? returnRange[0].length === lookupRange[0].length
18661
- : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18674
+ ? _returnRange[0].length === _lookupRange[0].length
18675
+ : _returnRange.length === _lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18662
18676
  const getElement = lookupDirection === "col"
18663
18677
  ? (range, index) => range[0][index].value
18664
18678
  : (range, index) => range[index][0].value;
18665
- const rangeLen = lookupDirection === "col" ? lookupRange[0].length : lookupRange.length;
18679
+ const rangeLen = lookupDirection === "col" ? _lookupRange[0].length : _lookupRange.length;
18666
18680
  const mode = MATCH_MODE[_matchMode];
18667
18681
  const reverseSearch = _searchMode === -1;
18668
18682
  const index = _searchMode === 2 || _searchMode === -2
18669
- ? dichotomicSearch(lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18670
- : linearSearch(lookupRange, searchKey, mode, rangeLen, getElement, this.lookupCaches, reverseSearch);
18683
+ ? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18684
+ : linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, this.lookupCaches, reverseSearch);
18671
18685
  if (index !== -1) {
18672
18686
  return lookupDirection === "col"
18673
- ? returnRange.map((col) => [col[index]])
18674
- : [returnRange[index]];
18687
+ ? _returnRange.map((col) => [col[index]])
18688
+ : [_returnRange[index]];
18675
18689
  }
18676
18690
  if (defaultValue === undefined) {
18677
18691
  return valueNotAvailable(searchKey);
@@ -39249,8 +39263,8 @@ stores.inject(MyMetaStore, storeInstance);
39249
39263
  document.body.style.cursor = "move";
39250
39264
  state.draggedItemId = args.draggedItemId;
39251
39265
  const container = direction === "horizontal"
39252
- ? new HorizontalContainer(args.containerEl)
39253
- : new VerticalContainer(args.containerEl);
39266
+ ? new HorizontalContainer(args.scrollableContainerEl)
39267
+ : new VerticalContainer(args.scrollableContainerEl);
39254
39268
  dndHelper = new DOMDndHelper({
39255
39269
  ...args,
39256
39270
  container,
@@ -39261,8 +39275,8 @@ stores.inject(MyMetaStore, storeInstance);
39261
39275
  const stopListening = startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
39262
39276
  cleanupFns.push(stopListening);
39263
39277
  const onScroll = dndHelper.onScroll.bind(dndHelper);
39264
- args.containerEl.addEventListener("scroll", onScroll);
39265
- cleanupFns.push(() => args.containerEl.removeEventListener("scroll", onScroll));
39278
+ args.scrollableContainerEl.addEventListener("scroll", onScroll);
39279
+ cleanupFns.push(() => args.scrollableContainerEl.removeEventListener("scroll", onScroll));
39266
39280
  cleanupFns.push(dndHelper.destroy.bind(dndHelper));
39267
39281
  };
39268
39282
  owl.onWillUnmount(() => {
@@ -39726,7 +39740,7 @@ stores.inject(MyMetaStore, storeInstance);
39726
39740
  draggedItemId: cf.id,
39727
39741
  initialMousePosition: event.clientY,
39728
39742
  items: items,
39729
- containerEl: this.cfListRef.el,
39743
+ scrollableContainerEl: this.cfListRef.el,
39730
39744
  onDragEnd: (cfId, finalIndex) => this.onDragEnd(cfId, finalIndex),
39731
39745
  });
39732
39746
  }
@@ -42710,6 +42724,7 @@ stores.inject(MyMetaStore, storeInstance);
42710
42724
  unusedGranularities: Object,
42711
42725
  dateGranularities: Array,
42712
42726
  datetimeGranularities: Array,
42727
+ getScrollableContainerEl: { type: Function, optional: true },
42713
42728
  pivotId: String,
42714
42729
  };
42715
42730
  dimensionsRef = owl.useRef("pivot-dimensions");
@@ -42743,7 +42758,7 @@ stores.inject(MyMetaStore, storeInstance);
42743
42758
  draggedItemId: dimension.nameWithGranularity,
42744
42759
  initialMousePosition: event.clientY,
42745
42760
  items: draggableItems,
42746
- containerEl: this.dimensionsRef.el,
42761
+ scrollableContainerEl: this.props.getScrollableContainerEl?.() || this.dimensionsRef.el,
42747
42762
  onDragEnd: (dimensionName, finalIndex) => {
42748
42763
  const originalIndex = draggableIds.findIndex((id) => id === dimensionName);
42749
42764
  if (originalIndex === finalIndex) {
@@ -42792,7 +42807,7 @@ stores.inject(MyMetaStore, storeInstance);
42792
42807
  draggedItemId: measure.id,
42793
42808
  initialMousePosition: event.clientY,
42794
42809
  items: draggableItems,
42795
- containerEl: this.dimensionsRef.el,
42810
+ scrollableContainerEl: this.props.getScrollableContainerEl?.() || this.dimensionsRef.el,
42796
42811
  onDragEnd: (measureName, finalIndex) => {
42797
42812
  const originalIndex = draggableIds.findIndex((id) => id === measureName);
42798
42813
  if (originalIndex === finalIndex) {
@@ -44420,6 +44435,7 @@ stores.inject(MyMetaStore, storeInstance);
44420
44435
  };
44421
44436
  store;
44422
44437
  state;
44438
+ pivotSidePanelRef = owl.useRef("pivotSidePanel");
44423
44439
  setup() {
44424
44440
  this.store = useLocalStore(PivotSidePanelStore, this.props.pivotId);
44425
44441
  this.state = owl.useState({
@@ -44448,6 +44464,9 @@ stores.inject(MyMetaStore, storeInstance);
44448
44464
  get definition() {
44449
44465
  return this.store.definition;
44450
44466
  }
44467
+ getScrollableContainerEl() {
44468
+ return this.pivotSidePanelRef.el;
44469
+ }
44451
44470
  onSelectionChanged(ranges) {
44452
44471
  this.state.rangeHasChanged = true;
44453
44472
  this.state.range = ranges[0];
@@ -48477,11 +48496,10 @@ stores.inject(MyMetaStore, storeInstance);
48477
48496
  switch (layer) {
48478
48497
  case "Background":
48479
48498
  this.drawGlobalBackground(renderingContext);
48480
- for (const zone of this.getters.getAllActiveViewportsZones()) {
48499
+ for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
48481
48500
  const { ctx } = renderingContext;
48482
48501
  ctx.save();
48483
48502
  ctx.beginPath();
48484
- const rect = this.getters.getVisibleRect(zone);
48485
48503
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
48486
48504
  ctx.clip();
48487
48505
  const boxes = this.getGridBoxes(zone);
@@ -48757,10 +48775,8 @@ stores.inject(MyMetaStore, storeInstance);
48757
48775
  const { ctx, thinLineWidth } = renderingContext;
48758
48776
  const visibleCols = this.getters.getSheetViewVisibleCols();
48759
48777
  const left = visibleCols[0];
48760
- const right = visibleCols[visibleCols.length - 1];
48761
48778
  const visibleRows = this.getters.getSheetViewVisibleRows();
48762
48779
  const top = visibleRows[0];
48763
- const bottom = visibleRows[visibleRows.length - 1];
48764
48780
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
48765
48781
  const selection = this.getters.getSelectedZones();
48766
48782
  const selectedCols = getZonesCols(selection);
@@ -48776,7 +48792,7 @@ stores.inject(MyMetaStore, storeInstance);
48776
48792
  ctx.lineWidth = thinLineWidth;
48777
48793
  ctx.strokeStyle = "#333";
48778
48794
  // Columns headers background
48779
- for (let col = left; col <= right; col++) {
48795
+ for (const col of visibleCols) {
48780
48796
  const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
48781
48797
  const { x, width } = this.getters.getVisibleRect(colZone);
48782
48798
  const isColActive = activeCols.has(col);
@@ -48793,7 +48809,7 @@ stores.inject(MyMetaStore, storeInstance);
48793
48809
  ctx.fillRect(x, 0, width, HEADER_HEIGHT);
48794
48810
  }
48795
48811
  // Rows headers background
48796
- for (let row = top; row <= bottom; row++) {
48812
+ for (const row of visibleRows) {
48797
48813
  const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
48798
48814
  const { y, height } = this.getters.getVisibleRect(rowZone);
48799
48815
  const isRowActive = activeRows.has(row);
@@ -48819,21 +48835,21 @@ stores.inject(MyMetaStore, storeInstance);
48819
48835
  ctx.stroke();
48820
48836
  ctx.beginPath();
48821
48837
  // column text + separator
48822
- for (const i of visibleCols) {
48823
- const colSize = this.getters.getColSize(sheetId, i);
48824
- const colName = numberToLetters(i);
48825
- ctx.fillStyle = activeCols.has(i) ? "#fff" : TEXT_HEADER_COLOR;
48826
- let colStart = this.getHeaderOffset("COL", left, i);
48838
+ for (const col of visibleCols) {
48839
+ const colSize = this.getters.getColSize(sheetId, col);
48840
+ const colName = numberToLetters(col);
48841
+ ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
48842
+ let colStart = this.getHeaderOffset("COL", left, col);
48827
48843
  ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
48828
48844
  ctx.moveTo(colStart + colSize, 0);
48829
48845
  ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
48830
48846
  }
48831
48847
  // row text + separator
48832
- for (const i of visibleRows) {
48833
- const rowSize = this.getters.getRowSize(sheetId, i);
48834
- ctx.fillStyle = activeRows.has(i) ? "#fff" : TEXT_HEADER_COLOR;
48835
- let rowStart = this.getHeaderOffset("ROW", top, i);
48836
- ctx.fillText(String(i + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
48848
+ for (const row of visibleRows) {
48849
+ const rowSize = this.getters.getRowSize(sheetId, row);
48850
+ ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
48851
+ let rowStart = this.getHeaderOffset("ROW", top, row);
48852
+ ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
48837
48853
  ctx.moveTo(0, rowStart + rowSize);
48838
48854
  ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
48839
48855
  }
@@ -49133,6 +49149,9 @@ stores.inject(MyMetaStore, storeInstance);
49133
49149
  canvas.width = width * dpr;
49134
49150
  canvas.height = height * dpr;
49135
49151
  canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
49152
+ if (width === 0 || height === 0) {
49153
+ return;
49154
+ }
49136
49155
  // Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
49137
49156
  // are the edges of the squares. If you draw a one-unit-wide line between whole-number
49138
49157
  // coordinates, it will overlap opposite sides of the pixel square, and the resulting
@@ -50704,7 +50723,7 @@ stores.inject(MyMetaStore, storeInstance);
50704
50723
  getCommonSides(border1, border2) {
50705
50724
  const commonBorder = {};
50706
50725
  for (let side of ["top", "bottom", "left", "right"]) {
50707
- if (border1[side] && border1[side] === border2[side]) {
50726
+ if (border1[side] && deepEquals(border1[side], border2[side])) {
50708
50727
  commonBorder[side] = border1[side];
50709
50728
  }
50710
50729
  }
@@ -64974,8 +64993,17 @@ stores.inject(MyMetaStore, storeInstance);
64974
64993
  this.getters = getters;
64975
64994
  this.sheetId = sheetId;
64976
64995
  this.boundaries = boundaries;
64977
- this.viewportWidth = sizeInGrid.width;
64978
- this.viewportHeight = sizeInGrid.height;
64996
+ if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
64997
+ throw new Error("Viewport size cannot be negative");
64998
+ }
64999
+ this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
65000
+ this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
65001
+ this.top = boundaries.top;
65002
+ this.bottom = boundaries.bottom;
65003
+ this.left = boundaries.left;
65004
+ this.right = boundaries.right;
65005
+ this.offsetX = offsets.x;
65006
+ this.offsetY = offsets.y;
64979
65007
  this.offsetScrollbarX = offsets.x;
64980
65008
  this.offsetScrollbarY = offsets.y;
64981
65009
  this.canScrollVertically = options.canScrollVertically;
@@ -65018,9 +65046,9 @@ stores.inject(MyMetaStore, storeInstance);
65018
65046
  Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
65019
65047
  );
65020
65048
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
65021
- }
65022
- if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
65023
- height += FOOTER_HEIGHT;
65049
+ if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
65050
+ height += FOOTER_HEIGHT;
65051
+ }
65024
65052
  }
65025
65053
  return { width, height };
65026
65054
  }
@@ -65161,6 +65189,9 @@ stores.inject(MyMetaStore, storeInstance);
65161
65189
  !this.getters.isRowHidden(this.sheetId, row));
65162
65190
  }
65163
65191
  searchHeaderIndex(dimension, position, startIndex = 0) {
65192
+ if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
65193
+ return -1;
65194
+ }
65164
65195
  const sheetId = this.sheetId;
65165
65196
  const headers = this.getters.getNumberHeaders(sheetId, dimension);
65166
65197
  // using a binary search:
@@ -65197,7 +65228,7 @@ stores.inject(MyMetaStore, storeInstance);
65197
65228
  this.adjustViewportZoneY();
65198
65229
  }
65199
65230
  /** Corrects the viewport's horizontal offset based on the current structure
65200
- * To make sure that at least on column is visible inside the viewport.
65231
+ * To make sure that at least one column is visible inside the viewport.
65201
65232
  */
65202
65233
  adjustViewportOffsetX() {
65203
65234
  if (this.canScrollHorizontally) {
@@ -65209,7 +65240,7 @@ stores.inject(MyMetaStore, storeInstance);
65209
65240
  this.adjustViewportZoneX();
65210
65241
  }
65211
65242
  /** Corrects the viewport's vertical offset based on the current structure
65212
- * To make sure that at least on row is visible inside the viewport.
65243
+ * To make sure that at least one row is visible inside the viewport.
65213
65244
  */
65214
65245
  adjustViewportOffsetY() {
65215
65246
  if (this.canScrollVertically) {
@@ -65226,11 +65257,14 @@ stores.inject(MyMetaStore, storeInstance);
65226
65257
  const sheetId = this.sheetId;
65227
65258
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
65228
65259
  this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
65260
+ if (!this.viewportWidth) {
65261
+ return;
65262
+ }
65229
65263
  if (this.left === -1) {
65230
65264
  this.left = this.boundaries.left;
65231
65265
  }
65232
65266
  if (this.right === -1) {
65233
- this.right = this.getters.getNumberCols(sheetId) - 1;
65267
+ this.right = this.boundaries.right;
65234
65268
  }
65235
65269
  this.offsetX =
65236
65270
  this.getters.getColDimensions(sheetId, this.left).start -
@@ -65242,11 +65276,14 @@ stores.inject(MyMetaStore, storeInstance);
65242
65276
  const sheetId = this.sheetId;
65243
65277
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
65244
65278
  this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
65279
+ if (!this.viewportHeight) {
65280
+ return;
65281
+ }
65245
65282
  if (this.top === -1) {
65246
65283
  this.top = this.boundaries.top;
65247
65284
  }
65248
65285
  if (this.bottom === -1) {
65249
- this.bottom = this.getters.getNumberRows(sheetId) - 1;
65286
+ this.bottom = this.boundaries.bottom;
65250
65287
  }
65251
65288
  this.offsetY =
65252
65289
  this.getters.getRowDimensions(sheetId, this.top).start -
@@ -65320,7 +65357,7 @@ stores.inject(MyMetaStore, storeInstance);
65320
65357
  "isPositionVisible",
65321
65358
  "getColDimensionsInViewport",
65322
65359
  "getRowDimensionsInViewport",
65323
- "getAllActiveViewportsZones",
65360
+ "getAllActiveViewportsZonesAndRect",
65324
65361
  "getRect",
65325
65362
  ];
65326
65363
  viewports = {};
@@ -65553,12 +65590,12 @@ stores.inject(MyMetaStore, storeInstance);
65553
65590
  const sheetId = this.getters.getActiveSheetId();
65554
65591
  const viewports = this.getSubViewports(sheetId);
65555
65592
  //TODO ake another commit to eimprove this
65556
- return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
65593
+ return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
65557
65594
  }
65558
65595
  getSheetViewVisibleRows() {
65559
65596
  const sheetId = this.getters.getActiveSheetId();
65560
65597
  const viewports = this.getSubViewports(sheetId);
65561
- return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
65598
+ return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
65562
65599
  }
65563
65600
  /**
65564
65601
  * Get the positions of all the cells that are visible in the viewport, taking merges into account.
@@ -65601,19 +65638,19 @@ stores.inject(MyMetaStore, storeInstance);
65601
65638
  maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
65602
65639
  };
65603
65640
  }
65604
- getColRowOffsetInViewport(dimension, referenceIndex, index) {
65605
- const sheetId = this.getters.getActiveSheetId();
65606
- const visibleCols = this.getters.getSheetViewVisibleCols();
65607
- const visibleRows = this.getters.getSheetViewVisibleRows();
65608
- if (index < referenceIndex) {
65609
- return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
65641
+ getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
65642
+ if (targetHeaderIndex < referenceHeaderIndex) {
65643
+ return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
65610
65644
  }
65645
+ const sheetId = this.getters.getActiveSheetId();
65646
+ const visibleHeaders = dimension === "COL"
65647
+ ? this.getters.getSheetViewVisibleCols()
65648
+ : this.getters.getSheetViewVisibleRows();
65649
+ const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
65650
+ const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
65651
+ const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
65611
65652
  let offset = 0;
65612
- const visibleIndexes = dimension === "COL" ? visibleCols : visibleRows;
65613
- for (let i = referenceIndex; i < index; i++) {
65614
- if (!visibleIndexes.includes(i)) {
65615
- continue;
65616
- }
65653
+ for (const i of relevantIndexes) {
65617
65654
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
65618
65655
  }
65619
65656
  return offset;
@@ -65660,7 +65697,7 @@ stores.inject(MyMetaStore, storeInstance);
65660
65697
  }
65661
65698
  return { canEdgeScroll, direction, delay };
65662
65699
  }
65663
- getEdgeScrollRow(y, previousY, tartingY) {
65700
+ getEdgeScrollRow(y, previousY, startingY) {
65664
65701
  let canEdgeScroll = false;
65665
65702
  let direction = 0;
65666
65703
  let delay = 0;
@@ -65681,7 +65718,7 @@ stores.inject(MyMetaStore, storeInstance);
65681
65718
  delay = scrollDelay(y - height);
65682
65719
  direction = 1;
65683
65720
  }
65684
- else if (y < offsetCorrectionY && tartingY >= offsetCorrectionY && currentOffsetY > 0) {
65721
+ else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
65685
65722
  // 2
65686
65723
  canEdgeScroll = true;
65687
65724
  delay = scrollDelay(offsetCorrectionY - y);
@@ -65707,13 +65744,7 @@ stores.inject(MyMetaStore, storeInstance);
65707
65744
  */
65708
65745
  getVisibleRectWithoutHeaders(zone) {
65709
65746
  const sheetId = this.getters.getActiveSheetId();
65710
- const viewportRects = this.getSubViewports(sheetId)
65711
- .map((viewport) => viewport.getVisibleRect(zone))
65712
- .filter(isDefined);
65713
- if (viewportRects.length === 0) {
65714
- return { x: 0, y: 0, width: 0, height: 0 };
65715
- }
65716
- return this.recomposeRect(viewportRects);
65747
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
65717
65748
  }
65718
65749
  /**
65719
65750
  * Computes the actual size and position (:Rect) of the zone on the canvas
@@ -65721,13 +65752,7 @@ stores.inject(MyMetaStore, storeInstance);
65721
65752
  */
65722
65753
  getRect(zone) {
65723
65754
  const sheetId = this.getters.getActiveSheetId();
65724
- const viewportRects = this.getSubViewports(sheetId)
65725
- .map((viewport) => viewport.getFullRect(zone))
65726
- .filter(isDefined);
65727
- if (viewportRects.length === 0) {
65728
- return { x: 0, y: 0, width: 0, height: 0 };
65729
- }
65730
- const rect = this.recomposeRect(viewportRects);
65755
+ const rect = this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
65731
65756
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
65732
65757
  }
65733
65758
  /**
@@ -65772,9 +65797,18 @@ stores.inject(MyMetaStore, storeInstance);
65772
65797
  end: start + (isRowHidden ? 0 : size),
65773
65798
  };
65774
65799
  }
65775
- getAllActiveViewportsZones() {
65800
+ getAllActiveViewportsZonesAndRect() {
65776
65801
  const sheetId = this.getters.getActiveSheetId();
65777
- return this.getSubViewports(sheetId);
65802
+ return this.getSubViewports(sheetId).map((viewport) => {
65803
+ return {
65804
+ zone: viewport,
65805
+ rect: {
65806
+ x: viewport.offsetCorrectionX + this.gridOffsetX,
65807
+ y: viewport.offsetCorrectionY + this.gridOffsetY,
65808
+ ...viewport.getMaxSize(),
65809
+ },
65810
+ };
65811
+ });
65778
65812
  }
65779
65813
  // ---------------------------------------------------------------------------
65780
65814
  // Private
@@ -65833,12 +65867,11 @@ stores.inject(MyMetaStore, storeInstance);
65833
65867
  }
65834
65868
  /** gets rid of deprecated sheetIds */
65835
65869
  cleanViewports() {
65836
- const sheetIds = this.getters.getSheetIds();
65837
- for (let sheetId of Object.keys(this.viewports)) {
65838
- if (!sheetIds.includes(sheetId)) {
65839
- delete this.viewports[sheetId];
65840
- }
65870
+ const newViewport = {};
65871
+ for (const sheetId of this.getters.getSheetIds()) {
65872
+ newViewport[sheetId] = this.viewports[sheetId];
65841
65873
  }
65874
+ this.viewports = newViewport;
65842
65875
  }
65843
65876
  resizeSheetView(height, width, gridOffsetX = 0, gridOffsetY = 0) {
65844
65877
  this.sheetViewHeight = height;
@@ -65848,7 +65881,7 @@ stores.inject(MyMetaStore, storeInstance);
65848
65881
  this.recomputeViewports();
65849
65882
  }
65850
65883
  recomputeViewports() {
65851
- for (let sheetId of Object.keys(this.viewports)) {
65884
+ for (const sheetId of this.getters.getSheetIds()) {
65852
65885
  this.resetViewports(sheetId);
65853
65886
  }
65854
65887
  }
@@ -65870,8 +65903,10 @@ stores.inject(MyMetaStore, storeInstance);
65870
65903
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
65871
65904
  const nCols = this.getters.getNumberCols(sheetId);
65872
65905
  const nRows = this.getters.getNumberRows(sheetId);
65873
- const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
65874
- const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
65906
+ const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
65907
+ const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
65908
+ const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
65909
+ const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
65875
65910
  const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
65876
65911
  const canScrollHorizontally = xRatio < 1.0;
65877
65912
  const canScrollVertically = yRatio < 1.0;
@@ -65882,14 +65917,14 @@ stores.inject(MyMetaStore, storeInstance);
65882
65917
  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 })) ||
65883
65918
  undefined,
65884
65919
  topRight: (ySplit &&
65885
- 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 })) ||
65920
+ 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 })) ||
65886
65921
  undefined,
65887
65922
  bottomLeft: (xSplit &&
65888
- 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 })) ||
65923
+ 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 })) ||
65889
65924
  undefined,
65890
65925
  bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
65891
- width: this.sheetViewWidth - colOffset,
65892
- height: this.sheetViewHeight - rowOffset,
65926
+ width: unfrozenWidth,
65927
+ height: unfrozenHeight,
65893
65928
  }, { canScrollHorizontally, canScrollVertically }, {
65894
65929
  x: canScrollHorizontally ? previousOffset.x : 0,
65895
65930
  y: canScrollVertically ? previousOffset.y : 0,
@@ -65966,12 +66001,26 @@ stores.inject(MyMetaStore, storeInstance);
65966
66001
  const height = this.sheetViewHeight + this.gridOffsetY;
65967
66002
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
65968
66003
  }
65969
- recomposeRect(viewportRects) {
65970
- const x = Math.min(...viewportRects.map((rect) => rect.x));
65971
- const y = Math.min(...viewportRects.map((rect) => rect.y));
65972
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
65973
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
65974
- return { x, y, width, height };
66004
+ mapViewportsToRect(sheetId, rectCallBack) {
66005
+ let x = Infinity;
66006
+ let y = Infinity;
66007
+ let width = 0;
66008
+ let height = 0;
66009
+ let hasViewports = false;
66010
+ for (const viewport of this.getSubViewports(sheetId)) {
66011
+ const rect = rectCallBack(viewport);
66012
+ if (rect) {
66013
+ hasViewports = true;
66014
+ x = Math.min(x, rect.x);
66015
+ y = Math.min(y, rect.y);
66016
+ width = Math.max(width, rect.x + rect.width);
66017
+ height = Math.max(height, rect.y + rect.height);
66018
+ }
66019
+ }
66020
+ if (!hasViewports) {
66021
+ return { x: 0, y: 0, width: 0, height: 0 };
66022
+ }
66023
+ return { x, y, width: width - x, height: height - y };
65975
66024
  }
65976
66025
  }
65977
66026
 
@@ -66967,7 +67016,7 @@ stores.inject(MyMetaStore, storeInstance);
66967
67016
  draggedItemId: sheetId,
66968
67017
  initialMousePosition: event.clientX,
66969
67018
  items: sheets,
66970
- containerEl: this.sheetListRef.el,
67019
+ scrollableContainerEl: this.sheetListRef.el,
66971
67020
  onDragEnd: (sheetId, finalIndex) => this.onDragEnd(sheetId, finalIndex),
66972
67021
  });
66973
67022
  }
@@ -73132,9 +73181,9 @@ stores.inject(MyMetaStore, storeInstance);
73132
73181
  exports.tokenize = tokenize;
73133
73182
 
73134
73183
 
73135
- __info__.version = "18.0.13";
73136
- __info__.date = "2025-01-31T07:59:17.481Z";
73137
- __info__.hash = "f505971";
73184
+ __info__.version = "18.0.15";
73185
+ __info__.date = "2025-02-10T08:59:22.993Z";
73186
+ __info__.hash = "5b19f88";
73138
73187
 
73139
73188
 
73140
73189
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);