@odoo/o-spreadsheet 18.2.6 → 18.2.8

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.6
6
- * @date 2025-04-04T08:41:26.115Z
7
- * @hash faa00e2
5
+ * @version 18.2.8
6
+ * @date 2025-04-18T16:26:20.673Z
7
+ * @hash 5da9ddc
8
8
  */
9
9
 
10
10
  'use strict';
@@ -3575,6 +3575,7 @@ const coreTypes = new Set([
3575
3575
  "CLEAR_FORMATTING",
3576
3576
  "SET_BORDER",
3577
3577
  "SET_ZONE_BORDERS",
3578
+ "SET_BORDERS_ON_TARGET",
3578
3579
  /** CHART */
3579
3580
  "CREATE_CHART",
3580
3581
  "UPDATE_CHART",
@@ -6724,6 +6725,7 @@ class AbstractCellClipboardHandler extends ClipboardHandler {
6724
6725
  }
6725
6726
 
6726
6727
  class BorderClipboardHandler extends AbstractCellClipboardHandler {
6728
+ queuedBordersToAdd = {};
6727
6729
  copy(data) {
6728
6730
  const sheetId = data.sheetId;
6729
6731
  if (data.zones.length === 0) {
@@ -6754,6 +6756,7 @@ class BorderClipboardHandler extends AbstractCellClipboardHandler {
6754
6756
  const { left, top } = zones[0];
6755
6757
  this.pasteZone(sheetId, left, top, content.borders);
6756
6758
  }
6759
+ this.executeQueuedChanges(sheetId);
6757
6760
  }
6758
6761
  pasteZone(sheetId, col, row, borders) {
6759
6762
  for (const [r, rowBorders] of borders.entries()) {
@@ -6772,7 +6775,20 @@ class BorderClipboardHandler extends AbstractCellClipboardHandler {
6772
6775
  ...targetBorders,
6773
6776
  ...originBorders,
6774
6777
  };
6775
- this.dispatch("SET_BORDER", { ...target, border });
6778
+ const borderKey = JSON.stringify(border);
6779
+ if (!this.queuedBordersToAdd[borderKey]) {
6780
+ this.queuedBordersToAdd[borderKey] = [];
6781
+ }
6782
+ this.queuedBordersToAdd[borderKey].push(positionToZone(target));
6783
+ }
6784
+ executeQueuedChanges(pasteSheetTarget) {
6785
+ for (const borderKey in this.queuedBordersToAdd) {
6786
+ const zones = this.queuedBordersToAdd[borderKey];
6787
+ const border = JSON.parse(borderKey);
6788
+ const target = recomputeZones(zones, []);
6789
+ this.dispatch("SET_BORDERS_ON_TARGET", { sheetId: pasteSheetTarget, target, border });
6790
+ }
6791
+ this.queuedBordersToAdd = {};
6776
6792
  }
6777
6793
  }
6778
6794
 
@@ -6884,6 +6900,12 @@ function tokenizeString(chars) {
6884
6900
  }
6885
6901
  return null;
6886
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;
6887
6909
  const SYMBOL_CHARS = new Set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!$");
6888
6910
  /**
6889
6911
  * A "Symbol" is just basically any word-like element that can appear in a
@@ -6924,7 +6946,8 @@ function tokenizeSymbol(chars) {
6924
6946
  };
6925
6947
  }
6926
6948
  }
6927
- while (chars.current && SYMBOL_CHARS.has(chars.current)) {
6949
+ while (chars.current &&
6950
+ (SYMBOL_CHARS.has(chars.current) || chars.current.match(unicodeSymbolCharRegexp))) {
6928
6951
  result += chars.shift();
6929
6952
  }
6930
6953
  if (result.length) {
@@ -8712,12 +8735,13 @@ class ConditionalFormatClipboardHandler extends AbstractCellClipboardHandler {
8712
8735
  }
8713
8736
  pasteCf(origin, target, isCutOperation) {
8714
8737
  if (origin?.rules && origin.rules.length > 0) {
8738
+ const originZone = positionToZone(origin.position);
8715
8739
  const zone = positionToZone(target);
8716
8740
  for (const rule of origin.rules) {
8717
8741
  const toRemoveZones = [];
8718
8742
  if (isCutOperation) {
8719
8743
  //remove from current rule
8720
- toRemoveZones.push(positionToZone(origin.position));
8744
+ toRemoveZones.push(originZone);
8721
8745
  }
8722
8746
  if (origin.position.sheetId === target.sheetId) {
8723
8747
  this.adaptCFRules(origin.position.sheetId, rule, [zone], toRemoveZones);
@@ -8831,6 +8855,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
8831
8855
  pasteDataValidation(origin, target, isCutOperation) {
8832
8856
  if (origin) {
8833
8857
  const zone = positionToZone(target);
8858
+ const originZone = positionToZone(origin.position);
8834
8859
  const rule = origin.rule;
8835
8860
  if (!rule) {
8836
8861
  const targetRule = this.getters.getValidationRuleForCell(target);
@@ -8842,7 +8867,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
8842
8867
  }
8843
8868
  const toRemoveZone = [];
8844
8869
  if (isCutOperation) {
8845
- toRemoveZone.push(positionToZone(origin.position));
8870
+ toRemoveZone.push(originZone);
8846
8871
  }
8847
8872
  if (origin.position.sheetId === target.sheetId) {
8848
8873
  const copyToRule = this.getDataValidationRuleToCopyTo(target.sheetId, rule, false);
@@ -8902,7 +8927,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
8902
8927
  continue;
8903
8928
  }
8904
8929
  this.dispatch("ADD_DATA_VALIDATION_RULE", {
8905
- rule: dv,
8930
+ rule: { id: dv.id, criterion: dv.criterion, isBlocking: dv.isBlocking },
8906
8931
  ranges: newDvZones.map((zone) => this.getters.getRangeDataFromZone(sheetId, zone)),
8907
8932
  sheetId,
8908
8933
  });
@@ -9229,7 +9254,7 @@ function transformZone(zone, executed) {
9229
9254
  if (executed.type === "ADD_COLUMNS_ROWS") {
9230
9255
  return expandZoneOnInsertion(zone, executed.dimension === "COL" ? "left" : "top", executed.base, executed.position, executed.quantity);
9231
9256
  }
9232
- return { ...zone };
9257
+ return zone;
9233
9258
  }
9234
9259
  function transformRangeData(range, executed) {
9235
9260
  const deletedSheet = executed.type === "DELETE_SHEET" && executed.sheetId;
@@ -33620,6 +33645,12 @@ function isMacOS() {
33620
33645
  function isCtrlKey(ev) {
33621
33646
  return isMacOS() ? ev.metaKey : ev.ctrlKey;
33622
33647
  }
33648
+ /**
33649
+ * Detects if the current browser is Firefox
33650
+ */
33651
+ function isBrowserFirefox() {
33652
+ return /Firefox/i.test(navigator.userAgent);
33653
+ }
33623
33654
 
33624
33655
  /**
33625
33656
  * Repeatedly calls a callback function with a time delay between calls.
@@ -50415,39 +50446,6 @@ function useCellHovered(env, gridRef, callback) {
50415
50446
  }
50416
50447
  return hoveredPosition;
50417
50448
  }
50418
- function useTouchMove(gridRef, handler, canMoveUp) {
50419
- let x = null;
50420
- let y = null;
50421
- function onTouchStart(ev) {
50422
- if (ev.touches.length !== 1)
50423
- return;
50424
- x = ev.touches[0].clientX;
50425
- y = ev.touches[0].clientY;
50426
- }
50427
- function onTouchEnd() {
50428
- x = null;
50429
- y = null;
50430
- }
50431
- function onTouchMove(ev) {
50432
- if (ev.touches.length !== 1)
50433
- return;
50434
- // On mobile browsers, swiping down is often associated with "pull to refresh".
50435
- // We only want this behavior if the grid is already at the top.
50436
- // Otherwise we only want to move the canvas up, without triggering any refresh.
50437
- if (canMoveUp()) {
50438
- ev.preventDefault();
50439
- ev.stopPropagation();
50440
- }
50441
- const currentX = ev.touches[0].clientX;
50442
- const currentY = ev.touches[0].clientY;
50443
- handler(x - currentX, y - currentY);
50444
- x = currentX;
50445
- y = currentY;
50446
- }
50447
- useRefListener(gridRef, "touchstart", onTouchStart);
50448
- useRefListener(gridRef, "touchend", onTouchEnd);
50449
- useRefListener(gridRef, "touchmove", onTouchMove);
50450
- }
50451
50449
  class GridOverlay extends owl.Component {
50452
50450
  static template = "o-spreadsheet-GridOverlay";
50453
50451
  static props = {
@@ -50495,10 +50493,6 @@ class GridOverlay extends owl.Component {
50495
50493
  owl.onWillUnmount(() => {
50496
50494
  resizeObserver.disconnect();
50497
50495
  });
50498
- useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
50499
- const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
50500
- return scrollY > 0;
50501
- });
50502
50496
  this.cellPopovers = useStore(CellPopoverStore);
50503
50497
  this.paintFormatStore = useStore(PaintFormatStore);
50504
50498
  }
@@ -51970,6 +51964,73 @@ function useGridDrawing(refName, model, canvasSize) {
51970
51964
  }
51971
51965
  }
51972
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
+
51973
52034
  function useWheelHandler(handler) {
51974
52035
  function normalize(val, deltaMode) {
51975
52036
  return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
@@ -52310,7 +52371,7 @@ class HorizontalScrollBar extends owl.Component {
52310
52371
  left: `${this.props.leftOffset + x}px`,
52311
52372
  bottom: "0px",
52312
52373
  height: `${SCROLLBAR_WIDTH}px`,
52313
- right: `0px`,
52374
+ right: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
52314
52375
  };
52315
52376
  }
52316
52377
  onScroll(offset) {
@@ -52355,7 +52416,7 @@ class VerticalScrollBar extends owl.Component {
52355
52416
  top: `${this.props.topOffset + y}px`,
52356
52417
  right: "0px",
52357
52418
  width: `${SCROLLBAR_WIDTH}px`,
52358
- bottom: `0px`,
52419
+ bottom: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
52359
52420
  };
52360
52421
  }
52361
52422
  onScroll(offset) {
@@ -52591,6 +52652,10 @@ class Grid extends owl.Component {
52591
52652
  this.DOMFocusableElementStore.focusableElement?.focus();
52592
52653
  }
52593
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
+ });
52594
52659
  }
52595
52660
  onCellHovered({ col, row }) {
52596
52661
  this.hoveredCell.hover({ col, row });
@@ -53313,6 +53378,15 @@ class BordersPlugin extends CorePlugin {
53313
53378
  case "SET_BORDER":
53314
53379
  this.setBorder(cmd.sheetId, cmd.col, cmd.row, cmd.border);
53315
53380
  break;
53381
+ case "SET_BORDERS_ON_TARGET":
53382
+ for (const zone of cmd.target) {
53383
+ for (let row = zone.top; row <= zone.bottom; row++) {
53384
+ for (let col = zone.left; col <= zone.right; col++) {
53385
+ this.setBorder(cmd.sheetId, col, row, cmd.border);
53386
+ }
53387
+ }
53388
+ }
53389
+ break;
53316
53390
  case "SET_ZONE_BORDERS":
53317
53391
  if (cmd.border) {
53318
53392
  const target = cmd.target.map((zone) => this.getters.expandZone(cmd.sheetId, zone));
@@ -63075,25 +63149,6 @@ class AutofillPlugin extends UIPlugin {
63075
63149
  case "AUTOFILL_AUTO":
63076
63150
  this.autofillAuto();
63077
63151
  break;
63078
- case "AUTOFILL_CELL":
63079
- this.autoFillMerge(cmd.originCol, cmd.originRow, cmd.col, cmd.row);
63080
- const sheetId = this.getters.getActiveSheetId();
63081
- this.dispatch("UPDATE_CELL", {
63082
- sheetId,
63083
- col: cmd.col,
63084
- row: cmd.row,
63085
- style: cmd.style || null,
63086
- content: cmd.content || "",
63087
- format: cmd.format || "",
63088
- });
63089
- this.dispatch("SET_BORDER", {
63090
- sheetId,
63091
- col: cmd.col,
63092
- row: cmd.row,
63093
- border: cmd.border,
63094
- });
63095
- this.autofillCF(cmd.originCol, cmd.originRow, cmd.col, cmd.row);
63096
- this.autofillDV(cmd.originCol, cmd.originRow, cmd.col, cmd.row);
63097
63152
  }
63098
63153
  }
63099
63154
  // ---------------------------------------------------------------------------
@@ -63117,6 +63172,7 @@ class AutofillPlugin extends UIPlugin {
63117
63172
  }
63118
63173
  const source = this.getters.getSelectedZone();
63119
63174
  const target = this.autofillZone;
63175
+ const autofillCellsData = [];
63120
63176
  switch (this.direction) {
63121
63177
  case "down" /* DIRECTION.DOWN */:
63122
63178
  for (let col = source.left; col <= source.right; col++) {
@@ -63126,7 +63182,7 @@ class AutofillPlugin extends UIPlugin {
63126
63182
  }
63127
63183
  const generator = this.createGenerator(xcs);
63128
63184
  for (let row = target.top; row <= target.bottom; row++) {
63129
- this.computeNewCell(generator, col, row, apply);
63185
+ autofillCellsData.push(this.computeNewCell(generator, col, row));
63130
63186
  }
63131
63187
  }
63132
63188
  break;
@@ -63138,7 +63194,7 @@ class AutofillPlugin extends UIPlugin {
63138
63194
  }
63139
63195
  const generator = this.createGenerator(xcs);
63140
63196
  for (let row = target.bottom; row >= target.top; row--) {
63141
- this.computeNewCell(generator, col, row, apply);
63197
+ autofillCellsData.push(this.computeNewCell(generator, col, row));
63142
63198
  }
63143
63199
  }
63144
63200
  break;
@@ -63150,7 +63206,7 @@ class AutofillPlugin extends UIPlugin {
63150
63206
  }
63151
63207
  const generator = this.createGenerator(xcs);
63152
63208
  for (let col = target.right; col >= target.left; col--) {
63153
- this.computeNewCell(generator, col, row, apply);
63209
+ autofillCellsData.push(this.computeNewCell(generator, col, row));
63154
63210
  }
63155
63211
  }
63156
63212
  break;
@@ -63162,12 +63218,26 @@ class AutofillPlugin extends UIPlugin {
63162
63218
  }
63163
63219
  const generator = this.createGenerator(xcs);
63164
63220
  for (let col = target.left; col <= target.right; col++) {
63165
- this.computeNewCell(generator, col, row, apply);
63221
+ autofillCellsData.push(this.computeNewCell(generator, col, row));
63166
63222
  }
63167
63223
  }
63168
63224
  break;
63169
63225
  }
63170
63226
  if (apply) {
63227
+ const bordersZones = {};
63228
+ const cfNewRanges = {};
63229
+ const dvNewZones = {};
63230
+ const sheetId = this.getters.getActiveSheetId();
63231
+ for (const data of autofillCellsData) {
63232
+ this.collectBordersData(data, bordersZones);
63233
+ this.autofillMerge(sheetId, data);
63234
+ this.autofillCell(sheetId, data);
63235
+ this.collectConditionalFormatsData(sheetId, data, cfNewRanges);
63236
+ this.collectDataValidationsData(sheetId, data, dvNewZones);
63237
+ }
63238
+ this.autofillBorders(sheetId, bordersZones);
63239
+ this.autofillConditionalFormats(sheetId, cfNewRanges);
63240
+ this.autofillDataValidations(sheetId, dvNewZones);
63171
63241
  this.autofillZone = undefined;
63172
63242
  this.selection.resizeAnchorZone(this.direction, this.steps);
63173
63243
  this.lastCellSelected = {};
@@ -63176,6 +63246,95 @@ class AutofillPlugin extends UIPlugin {
63176
63246
  this.tooltip = undefined;
63177
63247
  }
63178
63248
  }
63249
+ collectBordersData(data, bordersPositions) {
63250
+ const key = JSON.stringify(data.border);
63251
+ if (!(key in bordersPositions)) {
63252
+ bordersPositions[key] = [];
63253
+ }
63254
+ bordersPositions[key].push(positionToZone({ col: data.col, row: data.row }));
63255
+ }
63256
+ collectConditionalFormatsData(sheetId, data, cfNewRanges) {
63257
+ const { originCol, originRow, col, row } = data;
63258
+ const cfsAtOrigin = this.getters.getRulesByCell(sheetId, originCol, originRow);
63259
+ const xc = toXC(col, row);
63260
+ for (const cf of cfsAtOrigin) {
63261
+ if (!(cf.id in cfNewRanges)) {
63262
+ cfNewRanges[cf.id] = [];
63263
+ }
63264
+ cfNewRanges[cf.id].push(xc);
63265
+ }
63266
+ }
63267
+ collectDataValidationsData(sheetId, data, dvNewZones) {
63268
+ const { originCol, originRow, col, row } = data;
63269
+ const cellPosition = { sheetId, col: originCol, row: originRow };
63270
+ const dvsAtOrigin = this.getters.getValidationRuleForCell(cellPosition);
63271
+ if (!dvsAtOrigin) {
63272
+ return;
63273
+ }
63274
+ if (!(dvsAtOrigin.id in dvNewZones)) {
63275
+ dvNewZones[dvsAtOrigin.id] = [];
63276
+ }
63277
+ dvNewZones[dvsAtOrigin.id].push(positionToZone({ col, row }));
63278
+ }
63279
+ autofillCell(sheetId, data) {
63280
+ this.dispatch("UPDATE_CELL", {
63281
+ sheetId,
63282
+ col: data.col,
63283
+ row: data.row,
63284
+ content: data.content || "",
63285
+ style: data.style || null,
63286
+ format: data.format || "",
63287
+ });
63288
+ // Still usefull in odoo ATM to autofill field sync
63289
+ this.dispatch("AUTOFILL_CELL", data);
63290
+ }
63291
+ autofillBorders(sheetId, bordersPositions) {
63292
+ for (const stringifiedBorder in bordersPositions) {
63293
+ const border = stringifiedBorder === "undefined" ? undefined : JSON.parse(stringifiedBorder);
63294
+ this.dispatch("SET_BORDERS_ON_TARGET", {
63295
+ sheetId,
63296
+ border,
63297
+ target: recomputeZones(bordersPositions[stringifiedBorder]),
63298
+ });
63299
+ }
63300
+ }
63301
+ autofillConditionalFormats(sheetId, cfNewRanges) {
63302
+ for (const cfId in cfNewRanges) {
63303
+ const changes = cfNewRanges[cfId];
63304
+ const cf = this.getters.getConditionalFormats(sheetId).find((cf) => cf.id === cfId);
63305
+ if (!cf) {
63306
+ continue;
63307
+ }
63308
+ const newCfRanges = this.getters.getAdaptedCfRanges(sheetId, cf, changes.map(toZone), []);
63309
+ if (newCfRanges) {
63310
+ this.dispatch("ADD_CONDITIONAL_FORMAT", {
63311
+ cf: {
63312
+ id: cf.id,
63313
+ rule: cf.rule,
63314
+ stopIfTrue: cf.stopIfTrue,
63315
+ },
63316
+ ranges: newCfRanges,
63317
+ sheetId,
63318
+ });
63319
+ }
63320
+ }
63321
+ }
63322
+ autofillDataValidations(sheetId, dvNewZones) {
63323
+ for (const dvId in dvNewZones) {
63324
+ const changes = dvNewZones[dvId];
63325
+ const dvOrigin = this.getters.getDataValidationRule(sheetId, dvId);
63326
+ if (!dvOrigin) {
63327
+ continue;
63328
+ }
63329
+ const dvRangesXcs = dvOrigin.ranges.map((range) => range.zone);
63330
+ const newDvRanges = recomputeZones(dvRangesXcs.concat(changes), []);
63331
+ this.dispatch("ADD_DATA_VALIDATION_RULE", {
63332
+ rule: dvOrigin,
63333
+ ranges: newDvRanges.map((zone) => this.getters.getRangeDataFromZone(sheetId, zone)),
63334
+ sheetId,
63335
+ });
63336
+ }
63337
+ }
63179
63338
  /**
63180
63339
  * Select a cell which becomes the last cell of the autofillZone
63181
63340
  */
@@ -63254,22 +63413,20 @@ class AutofillPlugin extends UIPlugin {
63254
63413
  /**
63255
63414
  * Generate the next cell
63256
63415
  */
63257
- computeNewCell(generator, col, row, apply) {
63416
+ computeNewCell(generator, col, row) {
63258
63417
  const { cellData, tooltip, origin } = generator.next();
63259
63418
  const { content, style, border, format } = cellData;
63260
63419
  this.tooltip = tooltip;
63261
- if (apply) {
63262
- this.dispatch("AUTOFILL_CELL", {
63263
- originCol: origin.col,
63264
- originRow: origin.row,
63265
- col,
63266
- row,
63267
- content,
63268
- style,
63269
- border,
63270
- format,
63271
- });
63272
- }
63420
+ return {
63421
+ originCol: origin.col,
63422
+ originRow: origin.row,
63423
+ col,
63424
+ row,
63425
+ content,
63426
+ style,
63427
+ border,
63428
+ format,
63429
+ };
63273
63430
  }
63274
63431
  /**
63275
63432
  * Get the rule associated to the current cell
@@ -63337,8 +63494,8 @@ class AutofillPlugin extends UIPlugin {
63337
63494
  ? position[first].value
63338
63495
  : position[second].value;
63339
63496
  }
63340
- autoFillMerge(originCol, originRow, col, row) {
63341
- const sheetId = this.getters.getActiveSheetId();
63497
+ autofillMerge(sheetId, data) {
63498
+ const { originCol, originRow, col, row } = data;
63342
63499
  const position = { sheetId, col, row };
63343
63500
  const originPosition = { sheetId, col: originCol, row: originRow };
63344
63501
  if (this.getters.isInMerge(position) && !this.getters.isInMerge(originPosition)) {
@@ -63365,35 +63522,6 @@ class AutofillPlugin extends UIPlugin {
63365
63522
  });
63366
63523
  }
63367
63524
  }
63368
- autofillCF(originCol, originRow, col, row) {
63369
- const sheetId = this.getters.getActiveSheetId();
63370
- const cfOrigin = this.getters.getRulesByCell(sheetId, originCol, originRow);
63371
- for (const cf of cfOrigin) {
63372
- const newCfRanges = this.getters.getAdaptedCfRanges(sheetId, cf, [positionToZone({ col, row })], []);
63373
- if (newCfRanges) {
63374
- this.dispatch("ADD_CONDITIONAL_FORMAT", {
63375
- cf: deepCopy(cf),
63376
- ranges: newCfRanges,
63377
- sheetId,
63378
- });
63379
- }
63380
- }
63381
- }
63382
- autofillDV(originCol, originRow, col, row) {
63383
- const sheetId = this.getters.getActiveSheetId();
63384
- const cellPosition = { sheetId, col: originCol, row: originRow };
63385
- const dvOrigin = this.getters.getValidationRuleForCell(cellPosition);
63386
- if (!dvOrigin) {
63387
- return;
63388
- }
63389
- const dvRangesZones = dvOrigin.ranges.map((range) => range.zone);
63390
- const newDvRanges = recomputeZones(dvRangesZones.concat(positionToZone({ col, row })), []);
63391
- this.dispatch("ADD_DATA_VALIDATION_RULE", {
63392
- rule: dvOrigin,
63393
- ranges: newDvRanges.map((zone) => this.getters.getRangeDataFromZone(sheetId, zone)),
63394
- sheetId,
63395
- });
63396
- }
63397
63525
  // ---------------------------------------------------------------------------
63398
63526
  // Grid rendering
63399
63527
  // ---------------------------------------------------------------------------
@@ -63773,10 +63901,8 @@ function mergeTransformation(toTransform, executed) {
63773
63901
  }
63774
63902
  const target = [];
63775
63903
  for (const zone1 of toTransform.target) {
63776
- for (const zone2 of executed.target) {
63777
- if (!overlap(zone1, zone2)) {
63778
- target.push({ ...zone1 });
63779
- }
63904
+ if (executed.target.every((zone2) => !overlap(zone1, zone2))) {
63905
+ target.push(zone1);
63780
63906
  }
63781
63907
  }
63782
63908
  if (target.length) {
@@ -67908,24 +68034,14 @@ class InternalViewport {
67908
68034
  first: this.boundaries.top,
67909
68035
  last: this.boundaries.bottom,
67910
68036
  });
67911
- const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
67912
- const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
67913
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
67914
- const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
67915
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
67916
- const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
68037
+ const { end: lastColEnd } = this.getters.getColDimensions(this.sheetId, lastCol);
68038
+ const { end: lastRowEnd } = this.getters.getRowDimensions(this.sheetId, lastRow);
67917
68039
  let width = lastColEnd - this.offsetCorrectionX;
67918
68040
  if (this.canScrollHorizontally) {
67919
- width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
67920
- Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
67921
- );
67922
68041
  width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
67923
68042
  }
67924
68043
  let height = lastRowEnd - this.offsetCorrectionY;
67925
68044
  if (this.canScrollVertically) {
67926
- height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
67927
- Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
67928
- );
67929
68045
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
67930
68046
  if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
67931
68047
  height += FOOTER_HEIGHT;
@@ -68490,8 +68606,8 @@ class SheetViewPlugin extends UIPlugin {
68490
68606
  const { width, height } = this.getMainViewportRect();
68491
68607
  const viewport = this.getMainInternalViewport(sheetId);
68492
68608
  return {
68493
- maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
68494
- maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
68609
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth),
68610
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight),
68495
68611
  };
68496
68612
  }
68497
68613
  getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
@@ -70013,6 +70129,10 @@ class SpreadsheetDashboard extends owl.Component {
70013
70129
  this.hoveredCell.clear();
70014
70130
  });
70015
70131
  this.cellPopovers = useStore(CellPopoverStore);
70132
+ useTouchScroll(gridRef, this.moveCanvas.bind(this), () => {
70133
+ const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
70134
+ return scrollY > 0;
70135
+ });
70016
70136
  }
70017
70137
  onCellHovered({ col, row }) {
70018
70138
  this.hoveredCell.hover({ col, row });
@@ -71403,6 +71523,7 @@ css /* scss */ `
71403
71523
  > canvas {
71404
71524
  box-sizing: content-box;
71405
71525
  border-bottom: 1px solid #e2e3e3;
71526
+ border-right: 1px solid #e2e3e3;
71406
71527
  }
71407
71528
 
71408
71529
  .o-grid-overlay {
@@ -76109,6 +76230,6 @@ exports.tokenColors = tokenColors;
76109
76230
  exports.tokenize = tokenize;
76110
76231
 
76111
76232
 
76112
- __info__.version = "18.2.6";
76113
- __info__.date = "2025-04-04T08:41:26.115Z";
76114
- __info__.hash = "faa00e2";
76233
+ __info__.version = "18.2.8";
76234
+ __info__.date = "2025-04-18T16:26:20.673Z";
76235
+ __info__.hash = "5da9ddc";