@odoo/o-spreadsheet 18.2.7 → 18.2.9

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.2.7
6
- * @date 2025-04-14T17:19:31.011Z
7
- * @hash e187958
5
+ * @version 18.2.9
6
+ * @date 2025-04-25T08:06:52.677Z
7
+ * @hash 3e88645
8
8
  */
9
9
 
10
10
  'use strict';
@@ -3843,11 +3843,13 @@ const CellErrorType = {
3843
3843
  NullError: "#NULL!",
3844
3844
  };
3845
3845
  const errorTypes = new Set(Object.values(CellErrorType));
3846
- class EvaluationError extends Error {
3846
+ class EvaluationError {
3847
+ message;
3847
3848
  value;
3848
3849
  constructor(message = _t("Error"), value = CellErrorType.GenericError) {
3849
- super(message);
3850
+ this.message = message;
3850
3851
  this.value = value;
3852
+ this.message = message.toString();
3851
3853
  }
3852
3854
  }
3853
3855
  class BadExpressionError extends EvaluationError {
@@ -6900,6 +6902,12 @@ function tokenizeString(chars) {
6900
6902
  }
6901
6903
  return null;
6902
6904
  }
6905
+ /**
6906
+ - \p{L} is for any letter (from any language)
6907
+ - \p{N} is for any number
6908
+ - the u flag at the end is for unicode, which enables the `\p{...}` syntax
6909
+ */
6910
+ const unicodeSymbolCharRegexp = /\p{L}|\p{N}|_|\.|!|\$/u;
6903
6911
  const SYMBOL_CHARS = new Set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!$");
6904
6912
  /**
6905
6913
  * A "Symbol" is just basically any word-like element that can appear in a
@@ -6940,7 +6948,8 @@ function tokenizeSymbol(chars) {
6940
6948
  };
6941
6949
  }
6942
6950
  }
6943
- while (chars.current && SYMBOL_CHARS.has(chars.current)) {
6951
+ while (chars.current &&
6952
+ (SYMBOL_CHARS.has(chars.current) || chars.current.match(unicodeSymbolCharRegexp))) {
6944
6953
  result += chars.shift();
6945
6954
  }
6946
6955
  if (result.length) {
@@ -9247,7 +9256,7 @@ function transformZone(zone, executed) {
9247
9256
  if (executed.type === "ADD_COLUMNS_ROWS") {
9248
9257
  return expandZoneOnInsertion(zone, executed.dimension === "COL" ? "left" : "top", executed.base, executed.position, executed.quantity);
9249
9258
  }
9250
- return { ...zone };
9259
+ return zone;
9251
9260
  }
9252
9261
  function transformRangeData(range, executed) {
9253
9262
  const deletedSheet = executed.type === "DELETE_SHEET" && executed.sheetId;
@@ -13745,7 +13754,7 @@ const RANK = {
13745
13754
  }
13746
13755
  }
13747
13756
  if (!found) {
13748
- throw new NotAvailableError(_t("Value not found in the given data."));
13757
+ return new NotAvailableError(_t("Value not found in the given data."));
13749
13758
  }
13750
13759
  return rank;
13751
13760
  },
@@ -15485,7 +15494,7 @@ const UNIQUE = {
15485
15494
  result.push(row.data);
15486
15495
  }
15487
15496
  if (!result.length)
15488
- throw new EvaluationError(_t("No unique values found"));
15497
+ return new EvaluationError(_t("No unique values found"));
15489
15498
  return _byColumn ? result : transposeMatrix(result);
15490
15499
  },
15491
15500
  isExported: true,
@@ -19264,7 +19273,7 @@ const OFFSET = {
19264
19273
  }
19265
19274
  const _cellReference = cellReference?.value;
19266
19275
  if (!_cellReference) {
19267
- throw new Error("In this context, the function OFFSET needs to have a cell or range in parameter.");
19276
+ return new EvaluationError("In this context, the function OFFSET needs to have a cell or range in parameter.");
19268
19277
  }
19269
19278
  const zone = toZone(_cellReference);
19270
19279
  let offsetHeight = zone.bottom - zone.top + 1;
@@ -33638,6 +33647,12 @@ function isMacOS() {
33638
33647
  function isCtrlKey(ev) {
33639
33648
  return isMacOS() ? ev.metaKey : ev.ctrlKey;
33640
33649
  }
33650
+ /**
33651
+ * Detects if the current browser is Firefox
33652
+ */
33653
+ function isBrowserFirefox() {
33654
+ return /Firefox/i.test(navigator.userAgent);
33655
+ }
33641
33656
 
33642
33657
  /**
33643
33658
  * Repeatedly calls a callback function with a time delay between calls.
@@ -39104,7 +39119,7 @@ class ColorPicker extends owl.Component {
39104
39119
  }
39105
39120
  setHexColor(ev) {
39106
39121
  // only support HEX code input
39107
- const val = ev.target.value.slice(0, 7);
39122
+ const val = ev.target.value.replace("##", "#").slice(0, 7);
39108
39123
  this.state.customHexColor = val;
39109
39124
  if (!isColorValid(val)) ;
39110
39125
  else {
@@ -50433,39 +50448,6 @@ function useCellHovered(env, gridRef, callback) {
50433
50448
  }
50434
50449
  return hoveredPosition;
50435
50450
  }
50436
- function useTouchMove(gridRef, handler, canMoveUp) {
50437
- let x = null;
50438
- let y = null;
50439
- function onTouchStart(ev) {
50440
- if (ev.touches.length !== 1)
50441
- return;
50442
- x = ev.touches[0].clientX;
50443
- y = ev.touches[0].clientY;
50444
- }
50445
- function onTouchEnd() {
50446
- x = null;
50447
- y = null;
50448
- }
50449
- function onTouchMove(ev) {
50450
- if (ev.touches.length !== 1)
50451
- return;
50452
- // On mobile browsers, swiping down is often associated with "pull to refresh".
50453
- // We only want this behavior if the grid is already at the top.
50454
- // Otherwise we only want to move the canvas up, without triggering any refresh.
50455
- if (canMoveUp()) {
50456
- ev.preventDefault();
50457
- ev.stopPropagation();
50458
- }
50459
- const currentX = ev.touches[0].clientX;
50460
- const currentY = ev.touches[0].clientY;
50461
- handler(x - currentX, y - currentY);
50462
- x = currentX;
50463
- y = currentY;
50464
- }
50465
- useRefListener(gridRef, "touchstart", onTouchStart);
50466
- useRefListener(gridRef, "touchend", onTouchEnd);
50467
- useRefListener(gridRef, "touchmove", onTouchMove);
50468
- }
50469
50451
  class GridOverlay extends owl.Component {
50470
50452
  static template = "o-spreadsheet-GridOverlay";
50471
50453
  static props = {
@@ -50513,10 +50495,6 @@ class GridOverlay extends owl.Component {
50513
50495
  owl.onWillUnmount(() => {
50514
50496
  resizeObserver.disconnect();
50515
50497
  });
50516
- useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
50517
- const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
50518
- return scrollY > 0;
50519
- });
50520
50498
  this.cellPopovers = useStore(CellPopoverStore);
50521
50499
  this.paintFormatStore = useStore(PaintFormatStore);
50522
50500
  }
@@ -51988,6 +51966,73 @@ function useGridDrawing(refName, model, canvasSize) {
51988
51966
  }
51989
51967
  }
51990
51968
 
51969
+ const friction = 0.95;
51970
+ const verticalScrollFactor = 1;
51971
+ const horizontalScrollFactor = 1;
51972
+ function useTouchScroll(ref, updateScroll, canMoveUp) {
51973
+ let lastX = 0;
51974
+ let lastY = 0;
51975
+ let velocityX = 0;
51976
+ let velocityY = 0;
51977
+ let isMouseDown = false;
51978
+ let lastTime = 0;
51979
+ useRefListener(ref, "touchstart", onTouchStart, { capture: false });
51980
+ useRefListener(ref, "touchmove", onTouchMove, { capture: false });
51981
+ useRefListener(ref, "touchend", onTouchEnd, { capture: false });
51982
+ function onTouchStart(event) {
51983
+ isMouseDown = true;
51984
+ ({ clientX: lastX, clientY: lastY } = event.touches[0]);
51985
+ velocityX = 0;
51986
+ velocityY = 0;
51987
+ }
51988
+ function onTouchMove(event) {
51989
+ if (!isMouseDown)
51990
+ return;
51991
+ const currentTime = Date.now();
51992
+ const { clientX, clientY } = event.touches[0];
51993
+ let deltaX = lastX - clientX;
51994
+ let deltaY = lastY - clientY;
51995
+ const elapsedTime = currentTime - lastTime;
51996
+ velocityX = deltaX / elapsedTime;
51997
+ velocityY = deltaY / elapsedTime;
51998
+ lastX = clientX;
51999
+ lastY = clientY;
52000
+ lastTime = currentTime;
52001
+ if (canMoveUp()) {
52002
+ if (event.cancelable) {
52003
+ event.preventDefault();
52004
+ }
52005
+ event.stopPropagation();
52006
+ }
52007
+ updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
52008
+ }
52009
+ function onTouchEnd(ev) {
52010
+ isMouseDown = false;
52011
+ lastX = lastY = 0;
52012
+ requestAnimationFrame(scroll);
52013
+ }
52014
+ function scroll() {
52015
+ if (Math.abs(velocityX) < 0.05) {
52016
+ velocityX = 0;
52017
+ }
52018
+ if (Math.abs(velocityY) < 0.05) {
52019
+ velocityY = 0;
52020
+ }
52021
+ if (!velocityX && !velocityY) {
52022
+ return;
52023
+ }
52024
+ const currentTime = Date.now();
52025
+ const elapsedTime = Math.abs(currentTime - lastTime);
52026
+ const deltaX = velocityX * elapsedTime;
52027
+ const deltaY = velocityY * elapsedTime;
52028
+ updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
52029
+ lastTime = currentTime;
52030
+ velocityX *= friction;
52031
+ velocityY *= friction;
52032
+ requestAnimationFrame(scroll);
52033
+ }
52034
+ }
52035
+
51991
52036
  function useWheelHandler(handler) {
51992
52037
  function normalize(val, deltaMode) {
51993
52038
  return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
@@ -52328,7 +52373,7 @@ class HorizontalScrollBar extends owl.Component {
52328
52373
  left: `${this.props.leftOffset + x}px`,
52329
52374
  bottom: "0px",
52330
52375
  height: `${SCROLLBAR_WIDTH}px`,
52331
- right: `0px`,
52376
+ right: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
52332
52377
  };
52333
52378
  }
52334
52379
  onScroll(offset) {
@@ -52373,7 +52418,7 @@ class VerticalScrollBar extends owl.Component {
52373
52418
  top: `${this.props.topOffset + y}px`,
52374
52419
  right: "0px",
52375
52420
  width: `${SCROLLBAR_WIDTH}px`,
52376
- bottom: `0px`,
52421
+ bottom: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
52377
52422
  };
52378
52423
  }
52379
52424
  onScroll(offset) {
@@ -52609,6 +52654,10 @@ class Grid extends owl.Component {
52609
52654
  this.DOMFocusableElementStore.focusableElement?.focus();
52610
52655
  }
52611
52656
  }, () => [this.sidePanel.isOpen]);
52657
+ useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
52658
+ const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
52659
+ return scrollY > 0;
52660
+ });
52612
52661
  }
52613
52662
  onCellHovered({ col, row }) {
52614
52663
  this.hoveredCell.hover({ col, row });
@@ -62288,6 +62337,16 @@ function withPivotPresentationLayer (PivotClass) {
62288
62337
  }
62289
62338
  return values;
62290
62339
  }
62340
+ else if (rowDomain.length === this.definition.rows.length &&
62341
+ colDomain.length &&
62342
+ colDomain.length < this.definition.columns.length) {
62343
+ const colSubTree = this.getSubTreeMatchingDomain(table.getColTree(), colDomain);
62344
+ const domains = this.treeToLeafDomains(colSubTree, colDomain);
62345
+ for (const domain of domains) {
62346
+ values.push(this._getPivotCellValueAndFormat(measure.id, rowDomain.concat(domain)));
62347
+ }
62348
+ return values;
62349
+ }
62291
62350
  else {
62292
62351
  const tree = table.getRowTree();
62293
62352
  const subTree = this.getSubTreeMatchingDomain(tree, rowDomain);
@@ -63854,10 +63913,8 @@ function mergeTransformation(toTransform, executed) {
63854
63913
  }
63855
63914
  const target = [];
63856
63915
  for (const zone1 of toTransform.target) {
63857
- for (const zone2 of executed.target) {
63858
- if (!overlap(zone1, zone2)) {
63859
- target.push({ ...zone1 });
63860
- }
63916
+ if (executed.target.every((zone2) => !overlap(zone1, zone2))) {
63917
+ target.push(zone1);
63861
63918
  }
63862
63919
  }
63863
63920
  if (target.length) {
@@ -67989,24 +68046,14 @@ class InternalViewport {
67989
68046
  first: this.boundaries.top,
67990
68047
  last: this.boundaries.bottom,
67991
68048
  });
67992
- const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
67993
- const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
67994
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
67995
- const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
67996
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
67997
- const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
68049
+ const { end: lastColEnd } = this.getters.getColDimensions(this.sheetId, lastCol);
68050
+ const { end: lastRowEnd } = this.getters.getRowDimensions(this.sheetId, lastRow);
67998
68051
  let width = lastColEnd - this.offsetCorrectionX;
67999
68052
  if (this.canScrollHorizontally) {
68000
- width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
68001
- Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
68002
- );
68003
68053
  width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
68004
68054
  }
68005
68055
  let height = lastRowEnd - this.offsetCorrectionY;
68006
68056
  if (this.canScrollVertically) {
68007
- height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
68008
- Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
68009
- );
68010
68057
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
68011
68058
  if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
68012
68059
  height += FOOTER_HEIGHT;
@@ -68571,8 +68618,8 @@ class SheetViewPlugin extends UIPlugin {
68571
68618
  const { width, height } = this.getMainViewportRect();
68572
68619
  const viewport = this.getMainInternalViewport(sheetId);
68573
68620
  return {
68574
- maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
68575
- maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
68621
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth),
68622
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight),
68576
68623
  };
68577
68624
  }
68578
68625
  getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
@@ -70094,6 +70141,10 @@ class SpreadsheetDashboard extends owl.Component {
70094
70141
  this.hoveredCell.clear();
70095
70142
  });
70096
70143
  this.cellPopovers = useStore(CellPopoverStore);
70144
+ useTouchScroll(gridRef, this.moveCanvas.bind(this), () => {
70145
+ const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
70146
+ return scrollY > 0;
70147
+ });
70097
70148
  }
70098
70149
  onCellHovered({ col, row }) {
70099
70150
  this.hoveredCell.hover({ col, row });
@@ -71484,6 +71535,7 @@ css /* scss */ `
71484
71535
  > canvas {
71485
71536
  box-sizing: content-box;
71486
71537
  border-bottom: 1px solid #e2e3e3;
71538
+ border-right: 1px solid #e2e3e3;
71487
71539
  }
71488
71540
 
71489
71541
  .o-grid-overlay {
@@ -76190,6 +76242,6 @@ exports.tokenColors = tokenColors;
76190
76242
  exports.tokenize = tokenize;
76191
76243
 
76192
76244
 
76193
- __info__.version = "18.2.7";
76194
- __info__.date = "2025-04-14T17:19:31.011Z";
76195
- __info__.hash = "e187958";
76245
+ __info__.version = "18.2.9";
76246
+ __info__.date = "2025-04-25T08:06:52.677Z";
76247
+ __info__.hash = "3e88645";
@@ -11676,7 +11676,8 @@ declare const CellErrorType: {
11676
11676
  readonly GenericError: "#ERROR";
11677
11677
  readonly NullError: "#NULL!";
11678
11678
  };
11679
- declare class EvaluationError extends Error {
11679
+ declare class EvaluationError {
11680
+ readonly message: string;
11680
11681
  readonly value: string;
11681
11682
  constructor(message?: string, value?: string);
11682
11683
  }