@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
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -3841,11 +3841,13 @@ const CellErrorType = {
3841
3841
  NullError: "#NULL!",
3842
3842
  };
3843
3843
  const errorTypes = new Set(Object.values(CellErrorType));
3844
- class EvaluationError extends Error {
3844
+ class EvaluationError {
3845
+ message;
3845
3846
  value;
3846
3847
  constructor(message = _t("Error"), value = CellErrorType.GenericError) {
3847
- super(message);
3848
+ this.message = message;
3848
3849
  this.value = value;
3850
+ this.message = message.toString();
3849
3851
  }
3850
3852
  }
3851
3853
  class BadExpressionError extends EvaluationError {
@@ -6898,6 +6900,12 @@ function tokenizeString(chars) {
6898
6900
  }
6899
6901
  return null;
6900
6902
  }
6903
+ /**
6904
+ - \p{L} is for any letter (from any language)
6905
+ - \p{N} is for any number
6906
+ - the u flag at the end is for unicode, which enables the `\p{...}` syntax
6907
+ */
6908
+ const unicodeSymbolCharRegexp = /\p{L}|\p{N}|_|\.|!|\$/u;
6901
6909
  const SYMBOL_CHARS = new Set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!$");
6902
6910
  /**
6903
6911
  * A "Symbol" is just basically any word-like element that can appear in a
@@ -6938,7 +6946,8 @@ function tokenizeSymbol(chars) {
6938
6946
  };
6939
6947
  }
6940
6948
  }
6941
- while (chars.current && SYMBOL_CHARS.has(chars.current)) {
6949
+ while (chars.current &&
6950
+ (SYMBOL_CHARS.has(chars.current) || chars.current.match(unicodeSymbolCharRegexp))) {
6942
6951
  result += chars.shift();
6943
6952
  }
6944
6953
  if (result.length) {
@@ -9245,7 +9254,7 @@ function transformZone(zone, executed) {
9245
9254
  if (executed.type === "ADD_COLUMNS_ROWS") {
9246
9255
  return expandZoneOnInsertion(zone, executed.dimension === "COL" ? "left" : "top", executed.base, executed.position, executed.quantity);
9247
9256
  }
9248
- return { ...zone };
9257
+ return zone;
9249
9258
  }
9250
9259
  function transformRangeData(range, executed) {
9251
9260
  const deletedSheet = executed.type === "DELETE_SHEET" && executed.sheetId;
@@ -13743,7 +13752,7 @@ const RANK = {
13743
13752
  }
13744
13753
  }
13745
13754
  if (!found) {
13746
- throw new NotAvailableError(_t("Value not found in the given data."));
13755
+ return new NotAvailableError(_t("Value not found in the given data."));
13747
13756
  }
13748
13757
  return rank;
13749
13758
  },
@@ -15483,7 +15492,7 @@ const UNIQUE = {
15483
15492
  result.push(row.data);
15484
15493
  }
15485
15494
  if (!result.length)
15486
- throw new EvaluationError(_t("No unique values found"));
15495
+ return new EvaluationError(_t("No unique values found"));
15487
15496
  return _byColumn ? result : transposeMatrix(result);
15488
15497
  },
15489
15498
  isExported: true,
@@ -19262,7 +19271,7 @@ const OFFSET = {
19262
19271
  }
19263
19272
  const _cellReference = cellReference?.value;
19264
19273
  if (!_cellReference) {
19265
- throw new Error("In this context, the function OFFSET needs to have a cell or range in parameter.");
19274
+ return new EvaluationError("In this context, the function OFFSET needs to have a cell or range in parameter.");
19266
19275
  }
19267
19276
  const zone = toZone(_cellReference);
19268
19277
  let offsetHeight = zone.bottom - zone.top + 1;
@@ -33636,6 +33645,12 @@ function isMacOS() {
33636
33645
  function isCtrlKey(ev) {
33637
33646
  return isMacOS() ? ev.metaKey : ev.ctrlKey;
33638
33647
  }
33648
+ /**
33649
+ * Detects if the current browser is Firefox
33650
+ */
33651
+ function isBrowserFirefox() {
33652
+ return /Firefox/i.test(navigator.userAgent);
33653
+ }
33639
33654
 
33640
33655
  /**
33641
33656
  * Repeatedly calls a callback function with a time delay between calls.
@@ -39102,7 +39117,7 @@ class ColorPicker extends Component {
39102
39117
  }
39103
39118
  setHexColor(ev) {
39104
39119
  // only support HEX code input
39105
- const val = ev.target.value.slice(0, 7);
39120
+ const val = ev.target.value.replace("##", "#").slice(0, 7);
39106
39121
  this.state.customHexColor = val;
39107
39122
  if (!isColorValid(val)) ;
39108
39123
  else {
@@ -50431,39 +50446,6 @@ function useCellHovered(env, gridRef, callback) {
50431
50446
  }
50432
50447
  return hoveredPosition;
50433
50448
  }
50434
- function useTouchMove(gridRef, handler, canMoveUp) {
50435
- let x = null;
50436
- let y = null;
50437
- function onTouchStart(ev) {
50438
- if (ev.touches.length !== 1)
50439
- return;
50440
- x = ev.touches[0].clientX;
50441
- y = ev.touches[0].clientY;
50442
- }
50443
- function onTouchEnd() {
50444
- x = null;
50445
- y = null;
50446
- }
50447
- function onTouchMove(ev) {
50448
- if (ev.touches.length !== 1)
50449
- return;
50450
- // On mobile browsers, swiping down is often associated with "pull to refresh".
50451
- // We only want this behavior if the grid is already at the top.
50452
- // Otherwise we only want to move the canvas up, without triggering any refresh.
50453
- if (canMoveUp()) {
50454
- ev.preventDefault();
50455
- ev.stopPropagation();
50456
- }
50457
- const currentX = ev.touches[0].clientX;
50458
- const currentY = ev.touches[0].clientY;
50459
- handler(x - currentX, y - currentY);
50460
- x = currentX;
50461
- y = currentY;
50462
- }
50463
- useRefListener(gridRef, "touchstart", onTouchStart);
50464
- useRefListener(gridRef, "touchend", onTouchEnd);
50465
- useRefListener(gridRef, "touchmove", onTouchMove);
50466
- }
50467
50449
  class GridOverlay extends Component {
50468
50450
  static template = "o-spreadsheet-GridOverlay";
50469
50451
  static props = {
@@ -50511,10 +50493,6 @@ class GridOverlay extends Component {
50511
50493
  onWillUnmount(() => {
50512
50494
  resizeObserver.disconnect();
50513
50495
  });
50514
- useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
50515
- const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
50516
- return scrollY > 0;
50517
- });
50518
50496
  this.cellPopovers = useStore(CellPopoverStore);
50519
50497
  this.paintFormatStore = useStore(PaintFormatStore);
50520
50498
  }
@@ -51986,6 +51964,73 @@ function useGridDrawing(refName, model, canvasSize) {
51986
51964
  }
51987
51965
  }
51988
51966
 
51967
+ const friction = 0.95;
51968
+ const verticalScrollFactor = 1;
51969
+ const horizontalScrollFactor = 1;
51970
+ function useTouchScroll(ref, updateScroll, canMoveUp) {
51971
+ let lastX = 0;
51972
+ let lastY = 0;
51973
+ let velocityX = 0;
51974
+ let velocityY = 0;
51975
+ let isMouseDown = false;
51976
+ let lastTime = 0;
51977
+ useRefListener(ref, "touchstart", onTouchStart, { capture: false });
51978
+ useRefListener(ref, "touchmove", onTouchMove, { capture: false });
51979
+ useRefListener(ref, "touchend", onTouchEnd, { capture: false });
51980
+ function onTouchStart(event) {
51981
+ isMouseDown = true;
51982
+ ({ clientX: lastX, clientY: lastY } = event.touches[0]);
51983
+ velocityX = 0;
51984
+ velocityY = 0;
51985
+ }
51986
+ function onTouchMove(event) {
51987
+ if (!isMouseDown)
51988
+ return;
51989
+ const currentTime = Date.now();
51990
+ const { clientX, clientY } = event.touches[0];
51991
+ let deltaX = lastX - clientX;
51992
+ let deltaY = lastY - clientY;
51993
+ const elapsedTime = currentTime - lastTime;
51994
+ velocityX = deltaX / elapsedTime;
51995
+ velocityY = deltaY / elapsedTime;
51996
+ lastX = clientX;
51997
+ lastY = clientY;
51998
+ lastTime = currentTime;
51999
+ if (canMoveUp()) {
52000
+ if (event.cancelable) {
52001
+ event.preventDefault();
52002
+ }
52003
+ event.stopPropagation();
52004
+ }
52005
+ updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
52006
+ }
52007
+ function onTouchEnd(ev) {
52008
+ isMouseDown = false;
52009
+ lastX = lastY = 0;
52010
+ requestAnimationFrame(scroll);
52011
+ }
52012
+ function scroll() {
52013
+ if (Math.abs(velocityX) < 0.05) {
52014
+ velocityX = 0;
52015
+ }
52016
+ if (Math.abs(velocityY) < 0.05) {
52017
+ velocityY = 0;
52018
+ }
52019
+ if (!velocityX && !velocityY) {
52020
+ return;
52021
+ }
52022
+ const currentTime = Date.now();
52023
+ const elapsedTime = Math.abs(currentTime - lastTime);
52024
+ const deltaX = velocityX * elapsedTime;
52025
+ const deltaY = velocityY * elapsedTime;
52026
+ updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
52027
+ lastTime = currentTime;
52028
+ velocityX *= friction;
52029
+ velocityY *= friction;
52030
+ requestAnimationFrame(scroll);
52031
+ }
52032
+ }
52033
+
51989
52034
  function useWheelHandler(handler) {
51990
52035
  function normalize(val, deltaMode) {
51991
52036
  return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
@@ -52326,7 +52371,7 @@ class HorizontalScrollBar extends Component {
52326
52371
  left: `${this.props.leftOffset + x}px`,
52327
52372
  bottom: "0px",
52328
52373
  height: `${SCROLLBAR_WIDTH}px`,
52329
- right: `0px`,
52374
+ right: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
52330
52375
  };
52331
52376
  }
52332
52377
  onScroll(offset) {
@@ -52371,7 +52416,7 @@ class VerticalScrollBar extends Component {
52371
52416
  top: `${this.props.topOffset + y}px`,
52372
52417
  right: "0px",
52373
52418
  width: `${SCROLLBAR_WIDTH}px`,
52374
- bottom: `0px`,
52419
+ bottom: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
52375
52420
  };
52376
52421
  }
52377
52422
  onScroll(offset) {
@@ -52607,6 +52652,10 @@ class Grid extends Component {
52607
52652
  this.DOMFocusableElementStore.focusableElement?.focus();
52608
52653
  }
52609
52654
  }, () => [this.sidePanel.isOpen]);
52655
+ useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
52656
+ const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
52657
+ return scrollY > 0;
52658
+ });
52610
52659
  }
52611
52660
  onCellHovered({ col, row }) {
52612
52661
  this.hoveredCell.hover({ col, row });
@@ -62286,6 +62335,16 @@ function withPivotPresentationLayer (PivotClass) {
62286
62335
  }
62287
62336
  return values;
62288
62337
  }
62338
+ else if (rowDomain.length === this.definition.rows.length &&
62339
+ colDomain.length &&
62340
+ colDomain.length < this.definition.columns.length) {
62341
+ const colSubTree = this.getSubTreeMatchingDomain(table.getColTree(), colDomain);
62342
+ const domains = this.treeToLeafDomains(colSubTree, colDomain);
62343
+ for (const domain of domains) {
62344
+ values.push(this._getPivotCellValueAndFormat(measure.id, rowDomain.concat(domain)));
62345
+ }
62346
+ return values;
62347
+ }
62289
62348
  else {
62290
62349
  const tree = table.getRowTree();
62291
62350
  const subTree = this.getSubTreeMatchingDomain(tree, rowDomain);
@@ -63852,10 +63911,8 @@ function mergeTransformation(toTransform, executed) {
63852
63911
  }
63853
63912
  const target = [];
63854
63913
  for (const zone1 of toTransform.target) {
63855
- for (const zone2 of executed.target) {
63856
- if (!overlap(zone1, zone2)) {
63857
- target.push({ ...zone1 });
63858
- }
63914
+ if (executed.target.every((zone2) => !overlap(zone1, zone2))) {
63915
+ target.push(zone1);
63859
63916
  }
63860
63917
  }
63861
63918
  if (target.length) {
@@ -67987,24 +68044,14 @@ class InternalViewport {
67987
68044
  first: this.boundaries.top,
67988
68045
  last: this.boundaries.bottom,
67989
68046
  });
67990
- const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
67991
- const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
67992
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
67993
- const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
67994
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
67995
- const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
68047
+ const { end: lastColEnd } = this.getters.getColDimensions(this.sheetId, lastCol);
68048
+ const { end: lastRowEnd } = this.getters.getRowDimensions(this.sheetId, lastRow);
67996
68049
  let width = lastColEnd - this.offsetCorrectionX;
67997
68050
  if (this.canScrollHorizontally) {
67998
- width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
67999
- Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
68000
- );
68001
68051
  width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
68002
68052
  }
68003
68053
  let height = lastRowEnd - this.offsetCorrectionY;
68004
68054
  if (this.canScrollVertically) {
68005
- height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
68006
- Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
68007
- );
68008
68055
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
68009
68056
  if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
68010
68057
  height += FOOTER_HEIGHT;
@@ -68569,8 +68616,8 @@ class SheetViewPlugin extends UIPlugin {
68569
68616
  const { width, height } = this.getMainViewportRect();
68570
68617
  const viewport = this.getMainInternalViewport(sheetId);
68571
68618
  return {
68572
- maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
68573
- maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
68619
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth),
68620
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight),
68574
68621
  };
68575
68622
  }
68576
68623
  getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
@@ -70092,6 +70139,10 @@ class SpreadsheetDashboard extends Component {
70092
70139
  this.hoveredCell.clear();
70093
70140
  });
70094
70141
  this.cellPopovers = useStore(CellPopoverStore);
70142
+ useTouchScroll(gridRef, this.moveCanvas.bind(this), () => {
70143
+ const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
70144
+ return scrollY > 0;
70145
+ });
70095
70146
  }
70096
70147
  onCellHovered({ col, row }) {
70097
70148
  this.hoveredCell.hover({ col, row });
@@ -71482,6 +71533,7 @@ css /* scss */ `
71482
71533
  > canvas {
71483
71534
  box-sizing: content-box;
71484
71535
  border-bottom: 1px solid #e2e3e3;
71536
+ border-right: 1px solid #e2e3e3;
71485
71537
  }
71486
71538
 
71487
71539
  .o-grid-overlay {
@@ -76143,6 +76195,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
76143
76195
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
76144
76196
 
76145
76197
 
76146
- __info__.version = "18.2.7";
76147
- __info__.date = "2025-04-14T17:19:31.011Z";
76148
- __info__.hash = "e187958";
76198
+ __info__.version = "18.2.9";
76199
+ __info__.date = "2025-04-25T08:06:52.677Z";
76200
+ __info__.hash = "3e88645";