@odoo/o-spreadsheet 16.0.59 → 16.0.60

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.
@@ -22427,6 +22427,9 @@ function useGridDrawing(refName, model, canvasSize) {
22427
22427
  canvas.width = width * dpr;
22428
22428
  canvas.height = height * dpr;
22429
22429
  canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
22430
+ if (width === 0 || height === 0) {
22431
+ return;
22432
+ }
22430
22433
  // Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
22431
22434
  // are the edges of the squares. If you draw a one-unit-wide line between whole-number
22432
22435
  // coordinates, it will overlap opposite sides of the pixel square, and the resulting
@@ -34630,10 +34633,8 @@ class RendererPlugin extends UIPlugin {
34630
34633
  const { ctx, thinLineWidth } = renderingContext;
34631
34634
  const visibleCols = this.getters.getSheetViewVisibleCols();
34632
34635
  const left = visibleCols[0];
34633
- const right = visibleCols[visibleCols.length - 1];
34634
34636
  const visibleRows = this.getters.getSheetViewVisibleRows();
34635
34637
  const top = visibleRows[0];
34636
- const bottom = visibleRows[visibleRows.length - 1];
34637
34638
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
34638
34639
  const selection = this.getters.getSelectedZones();
34639
34640
  const selectedCols = getZonesCols(selection);
@@ -34649,7 +34650,7 @@ class RendererPlugin extends UIPlugin {
34649
34650
  ctx.lineWidth = thinLineWidth;
34650
34651
  ctx.strokeStyle = "#333";
34651
34652
  // Columns headers background
34652
- for (let col = left; col <= right; col++) {
34653
+ for (const col of visibleCols) {
34653
34654
  const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
34654
34655
  const { x, width } = this.getters.getVisibleRect(colZone);
34655
34656
  const colHasFilter = this.getters.doesZonesContainFilter(sheetId, [colZone]);
@@ -34669,7 +34670,7 @@ class RendererPlugin extends UIPlugin {
34669
34670
  ctx.fillRect(x, 0, width, HEADER_HEIGHT);
34670
34671
  }
34671
34672
  // Rows headers background
34672
- for (let row = top; row <= bottom; row++) {
34673
+ for (const row of visibleRows) {
34673
34674
  const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
34674
34675
  const { y, height } = this.getters.getVisibleRect(rowZone);
34675
34676
  const rowHasFilter = this.getters.doesZonesContainFilter(sheetId, [rowZone]);
@@ -34698,21 +34699,21 @@ class RendererPlugin extends UIPlugin {
34698
34699
  ctx.stroke();
34699
34700
  ctx.beginPath();
34700
34701
  // column text + separator
34701
- for (const i of visibleCols) {
34702
- const colSize = this.getters.getColSize(sheetId, i);
34703
- const colName = numberToLetters(i);
34704
- ctx.fillStyle = activeCols.has(i) ? "#fff" : TEXT_HEADER_COLOR;
34705
- let colStart = this.getHeaderOffset("COL", left, i);
34702
+ for (const col of visibleCols) {
34703
+ const colSize = this.getters.getColSize(sheetId, col);
34704
+ const colName = numberToLetters(col);
34705
+ ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
34706
+ let colStart = this.getHeaderOffset("COL", left, col);
34706
34707
  ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
34707
34708
  ctx.moveTo(colStart + colSize, 0);
34708
34709
  ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
34709
34710
  }
34710
34711
  // row text + separator
34711
- for (const i of visibleRows) {
34712
- const rowSize = this.getters.getRowSize(sheetId, i);
34713
- ctx.fillStyle = activeRows.has(i) ? "#fff" : TEXT_HEADER_COLOR;
34714
- let rowStart = this.getHeaderOffset("ROW", top, i);
34715
- ctx.fillText(String(i + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
34712
+ for (const row of visibleRows) {
34713
+ const rowSize = this.getters.getRowSize(sheetId, row);
34714
+ ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
34715
+ let rowStart = this.getHeaderOffset("ROW", top, row);
34716
+ ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
34716
34717
  ctx.moveTo(0, rowStart + rowSize);
34717
34718
  ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
34718
34719
  }
@@ -36800,8 +36801,17 @@ class InternalViewport {
36800
36801
  this.getters = getters;
36801
36802
  this.sheetId = sheetId;
36802
36803
  this.boundaries = boundaries;
36803
- this.viewportWidth = sizeInGrid.width;
36804
- this.viewportHeight = sizeInGrid.height;
36804
+ if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
36805
+ throw new Error("Viewport size cannot be negative");
36806
+ }
36807
+ this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
36808
+ this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
36809
+ this.top = boundaries.top;
36810
+ this.bottom = boundaries.bottom;
36811
+ this.left = boundaries.left;
36812
+ this.right = boundaries.right;
36813
+ this.offsetX = offsets.x;
36814
+ this.offsetY = offsets.y;
36805
36815
  this.offsetScrollbarX = offsets.x;
36806
36816
  this.offsetScrollbarY = offsets.y;
36807
36817
  this.canScrollVertically = options.canScrollVertically;
@@ -36990,6 +37000,9 @@ class InternalViewport {
36990
37000
  }
36991
37001
  // PRIVATE
36992
37002
  searchHeaderIndex(dimension, position, startIndex = 0, absolute = false) {
37003
+ if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
37004
+ return -1;
37005
+ }
36993
37006
  let size = 0;
36994
37007
  const sheetId = this.sheetId;
36995
37008
  const headers = this.getters.getNumberHeaders(sheetId, dimension);
@@ -37028,7 +37041,7 @@ class InternalViewport {
37028
37041
  this.adjustViewportZoneY();
37029
37042
  }
37030
37043
  /** Corrects the viewport's horizontal offset based on the current structure
37031
- * To make sure that at least on column is visible inside the viewport.
37044
+ * To make sure that at least one column is visible inside the viewport.
37032
37045
  */
37033
37046
  adjustViewportOffsetX() {
37034
37047
  if (this.canScrollHorizontally) {
@@ -37045,7 +37058,7 @@ class InternalViewport {
37045
37058
  this.adjustViewportZoneX();
37046
37059
  }
37047
37060
  /** Corrects the viewport's vertical offset based on the current structure
37048
- * To make sure that at least on row is visible inside the viewport.
37061
+ * To make sure that at least one row is visible inside the viewport.
37049
37062
  */
37050
37063
  adjustViewportOffsetY() {
37051
37064
  if (this.canScrollVertically) {
@@ -37067,11 +37080,14 @@ class InternalViewport {
37067
37080
  const sheetId = this.sheetId;
37068
37081
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
37069
37082
  this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
37083
+ if (!this.viewportWidth) {
37084
+ return;
37085
+ }
37070
37086
  if (this.left === -1) {
37071
37087
  this.left = this.boundaries.left;
37072
37088
  }
37073
37089
  if (this.right === -1) {
37074
- this.right = this.getters.getNumberCols(sheetId) - 1;
37090
+ this.right = this.boundaries.right;
37075
37091
  }
37076
37092
  this.offsetX =
37077
37093
  this.getters.getColDimensions(sheetId, this.left).start -
@@ -37083,11 +37099,14 @@ class InternalViewport {
37083
37099
  const sheetId = this.sheetId;
37084
37100
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
37085
37101
  this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
37102
+ if (!this.viewportHeight) {
37103
+ return;
37104
+ }
37086
37105
  if (this.top === -1) {
37087
37106
  this.top = this.boundaries.top;
37088
37107
  }
37089
37108
  if (this.bottom === -1) {
37090
- this.bottom = this.getters.getNumberRows(sheetId) - 1;
37109
+ this.bottom = this.boundaries.bottom;
37091
37110
  }
37092
37111
  this.offsetY =
37093
37112
  this.getters.getRowDimensions(sheetId, this.top).start -
@@ -37339,12 +37358,12 @@ class SheetViewPlugin extends UIPlugin {
37339
37358
  getSheetViewVisibleCols() {
37340
37359
  const sheetId = this.getters.getActiveSheetId();
37341
37360
  const viewports = this.getSubViewports(sheetId);
37342
- return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
37361
+ return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
37343
37362
  }
37344
37363
  getSheetViewVisibleRows() {
37345
37364
  const sheetId = this.getters.getActiveSheetId();
37346
37365
  const viewports = this.getSubViewports(sheetId);
37347
- return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
37366
+ return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
37348
37367
  }
37349
37368
  /**
37350
37369
  * Return the main viewport maximum size relative to the client size.
@@ -37367,19 +37386,19 @@ class SheetViewPlugin extends UIPlugin {
37367
37386
  maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
37368
37387
  };
37369
37388
  }
37370
- getColRowOffsetInViewport(dimension, referenceIndex, index) {
37371
- const sheetId = this.getters.getActiveSheetId();
37372
- const visibleCols = this.getters.getSheetViewVisibleCols();
37373
- const visibleRows = this.getters.getSheetViewVisibleRows();
37374
- if (index < referenceIndex) {
37375
- return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
37389
+ getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
37390
+ if (targetHeaderIndex < referenceHeaderIndex) {
37391
+ return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
37376
37392
  }
37393
+ const sheetId = this.getters.getActiveSheetId();
37394
+ const visibleHeaders = dimension === "COL"
37395
+ ? this.getters.getSheetViewVisibleCols()
37396
+ : this.getters.getSheetViewVisibleRows();
37397
+ const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
37398
+ const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
37399
+ const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
37377
37400
  let offset = 0;
37378
- const visibleIndexes = dimension === "COL" ? visibleCols : visibleRows;
37379
- for (let i = referenceIndex; i < index; i++) {
37380
- if (!visibleIndexes.includes(i)) {
37381
- continue;
37382
- }
37401
+ for (const i of relevantIndexes) {
37383
37402
  offset +=
37384
37403
  dimension === "COL"
37385
37404
  ? this.getters.getColSize(sheetId, i)
@@ -37429,7 +37448,7 @@ class SheetViewPlugin extends UIPlugin {
37429
37448
  }
37430
37449
  return { canEdgeScroll, direction, delay };
37431
37450
  }
37432
- getEdgeScrollRow(y, previousY, tartingY) {
37451
+ getEdgeScrollRow(y, previousY, startingY) {
37433
37452
  let canEdgeScroll = false;
37434
37453
  let direction = 0;
37435
37454
  let delay = 0;
@@ -37450,7 +37469,7 @@ class SheetViewPlugin extends UIPlugin {
37450
37469
  delay = scrollDelay(y - height);
37451
37470
  direction = 1;
37452
37471
  }
37453
- else if (y < offsetCorrectionY && tartingY >= offsetCorrectionY && currentOffsetY > 0) {
37472
+ else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
37454
37473
  // 2
37455
37474
  canEdgeScroll = true;
37456
37475
  delay = scrollDelay(offsetCorrectionY - y);
@@ -37469,13 +37488,7 @@ class SheetViewPlugin extends UIPlugin {
37469
37488
  */
37470
37489
  getVisibleRect(zone) {
37471
37490
  const sheetId = this.getters.getActiveSheetId();
37472
- const viewportRects = this.getSubViewports(sheetId)
37473
- .map((viewport) => viewport.getVisibleRect(zone))
37474
- .filter(isDefined$1);
37475
- if (viewportRects.length === 0) {
37476
- return { x: 0, y: 0, width: 0, height: 0 };
37477
- }
37478
- return this.recomposeRect(viewportRects);
37491
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
37479
37492
  }
37480
37493
  /**
37481
37494
  * Computes the actual size and position (:Rect) of the zone on the canvas
@@ -37483,13 +37496,7 @@ class SheetViewPlugin extends UIPlugin {
37483
37496
  */
37484
37497
  getRect(zone) {
37485
37498
  const sheetId = this.getters.getActiveSheetId();
37486
- const viewportRects = this.getSubViewports(sheetId)
37487
- .map((viewport) => viewport.getFullRect(zone))
37488
- .filter(isDefined$1);
37489
- if (viewportRects.length === 0) {
37490
- return { x: 0, y: 0, width: 0, height: 0 };
37491
- }
37492
- return this.recomposeRect(viewportRects);
37499
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
37493
37500
  }
37494
37501
  /**
37495
37502
  * Returns the position of the MainViewport relatively to the start of the grid (without headers)
@@ -37558,12 +37565,11 @@ class SheetViewPlugin extends UIPlugin {
37558
37565
  }
37559
37566
  /** gets rid of deprecated sheetIds */
37560
37567
  cleanViewports() {
37561
- const sheetIds = this.getters.getSheetIds();
37562
- for (let sheetId of Object.keys(this.viewports)) {
37563
- if (!sheetIds.includes(sheetId)) {
37564
- delete this.viewports[sheetId];
37565
- }
37568
+ const newViewport = {};
37569
+ for (const sheetId of this.getters.getSheetIds()) {
37570
+ newViewport[sheetId] = this.viewports[sheetId];
37566
37571
  }
37572
+ this.viewports = newViewport;
37567
37573
  }
37568
37574
  resetSheetViews() {
37569
37575
  this.cleanViewports();
@@ -37584,14 +37590,14 @@ class SheetViewPlugin extends UIPlugin {
37584
37590
  this.recomputeViewports();
37585
37591
  }
37586
37592
  recomputeViewports() {
37587
- for (let sheetId of Object.keys(this.viewports)) {
37593
+ for (const sheetId of this.getters.getSheetIds()) {
37588
37594
  this.resetViewports(sheetId);
37589
37595
  }
37590
37596
  }
37591
37597
  setSheetViewOffset(offsetX, offsetY) {
37592
37598
  const sheetId = this.getters.getActiveSheetId();
37593
37599
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
37594
- Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
37600
+ this.getSubViewports(sheetId).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
37595
37601
  }
37596
37602
  getViewportOffset(sheetId) {
37597
37603
  var _a, _b;
@@ -37607,8 +37613,10 @@ class SheetViewPlugin extends UIPlugin {
37607
37613
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
37608
37614
  const nCols = this.getters.getNumberCols(sheetId);
37609
37615
  const nRows = this.getters.getNumberRows(sheetId);
37610
- const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
37611
- const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
37616
+ const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
37617
+ const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
37618
+ const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
37619
+ const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
37612
37620
  const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
37613
37621
  const canScrollHorizontally = xRatio < 1.0;
37614
37622
  const canScrollVertically = yRatio < 1.0;
@@ -37619,14 +37627,14 @@ class SheetViewPlugin extends UIPlugin {
37619
37627
  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 })) ||
37620
37628
  undefined,
37621
37629
  topRight: (ySplit &&
37622
- 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 })) ||
37630
+ 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 })) ||
37623
37631
  undefined,
37624
37632
  bottomLeft: (xSplit &&
37625
- 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 })) ||
37633
+ 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 })) ||
37626
37634
  undefined,
37627
37635
  bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
37628
- width: this.sheetViewWidth - colOffset,
37629
- height: this.sheetViewHeight - rowOffset,
37636
+ width: unfrozenWidth,
37637
+ height: unfrozenHeight,
37630
37638
  }, { canScrollHorizontally, canScrollVertically }, {
37631
37639
  x: canScrollHorizontally ? previousOffset.x : 0,
37632
37640
  y: canScrollVertically ? previousOffset.y : 0,
@@ -37638,7 +37646,7 @@ class SheetViewPlugin extends UIPlugin {
37638
37646
  * Adjust the viewport such that the anchor position is visible
37639
37647
  */
37640
37648
  refreshViewport(sheetId, anchorPosition) {
37641
- Object.values(this.getSubViewports(sheetId)).forEach((viewport) => {
37649
+ this.getSubViewports(sheetId).forEach((viewport) => {
37642
37650
  viewport.adjustViewportZone();
37643
37651
  viewport.adjustPosition(anchorPosition);
37644
37652
  });
@@ -37689,16 +37697,30 @@ class SheetViewPlugin extends UIPlugin {
37689
37697
  const height = this.sheetViewHeight + this.gridOffsetY;
37690
37698
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
37691
37699
  }
37692
- recomposeRect(viewportRects) {
37693
- const x = Math.min(...viewportRects.map((rect) => rect.x));
37694
- const y = Math.min(...viewportRects.map((rect) => rect.y));
37695
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
37696
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
37700
+ mapViewportsToRect(sheetId, rectCallBack) {
37701
+ let x = Infinity;
37702
+ let y = Infinity;
37703
+ let width = 0;
37704
+ let height = 0;
37705
+ let hasViewports = false;
37706
+ for (const viewport of this.getSubViewports(sheetId)) {
37707
+ const rect = rectCallBack(viewport);
37708
+ if (rect) {
37709
+ hasViewports = true;
37710
+ x = Math.min(x, rect.x);
37711
+ y = Math.min(y, rect.y);
37712
+ width = Math.max(width, rect.x + rect.width);
37713
+ height = Math.max(height, rect.y + rect.height);
37714
+ }
37715
+ }
37716
+ if (!hasViewports) {
37717
+ return { x: 0, y: 0, width: 0, height: 0 };
37718
+ }
37697
37719
  return {
37698
37720
  x: x + this.gridOffsetX,
37699
37721
  y: y + this.gridOffsetY,
37700
- width,
37701
- height,
37722
+ width: width - x,
37723
+ height: height - y,
37702
37724
  };
37703
37725
  }
37704
37726
  }
@@ -43536,6 +43558,6 @@ function addFunction(functionName, functionDescription) {
43536
43558
  export { AbstractChart, CommandResult, CorePlugin, DATETIME_FORMAT, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, cellTypes, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, load, parse, readonlyAllowedCommands, registries, setTranslationMethod, tokenize };
43537
43559
 
43538
43560
 
43539
- __info__.version = '16.0.59';
43540
- __info__.date = '2025-01-29T06:24:17.486Z';
43541
- __info__.hash = '0897f45';
43561
+ __info__.version = '16.0.60';
43562
+ __info__.date = '2025-02-05T06:44:04.651Z';
43563
+ __info__.hash = 'd098699';