@odoo/o-spreadsheet 16.2.22 → 16.2.24

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.
@@ -603,13 +603,6 @@ function getYearFrac(startDate, endDate, _dayCountConvention) {
603
603
  }
604
604
 
605
605
  //------------------------------------------------------------------------------
606
- /**
607
- * Stringify an object, like JSON.stringify, except that the first level of keys
608
- * is ordered.
609
- */
610
- function stringify(obj) {
611
- return JSON.stringify(obj, Object.keys(obj).sort());
612
- }
613
606
  /**
614
607
  * Remove quotes from a quoted string
615
608
  * ```js
@@ -909,7 +902,7 @@ function isObjectEmptyRecursive(argument) {
909
902
  */
910
903
  function getItemId(item, itemsDic) {
911
904
  for (let [key, value] of Object.entries(itemsDic)) {
912
- if (stringify(value) === stringify(item)) {
905
+ if (deepEquals(value, item)) {
913
906
  return parseInt(key, 10);
914
907
  }
915
908
  }
@@ -975,6 +968,22 @@ function lazy(fn) {
975
968
  lazyValue.map = (callback) => lazy(() => callback(lazyValue()));
976
969
  return lazyValue;
977
970
  }
971
+ /**
972
+ * Creates a version of the function that's memoized on the value of its first
973
+ * argument, if any.
974
+ */
975
+ function memoize(func) {
976
+ const cache = new Map();
977
+ const funcName = func.name ? func.name + " (memoized)" : "memoized";
978
+ return {
979
+ [funcName](...args) {
980
+ if (!cache.has(args[0])) {
981
+ cache.set(args[0], func(...args));
982
+ }
983
+ return cache.get(args[0]);
984
+ },
985
+ }[funcName];
986
+ }
978
987
  /**
979
988
  * Find the next defined value after the given index in an array of strings. If there is no defined value
980
989
  * after the index, return the closest defined value before the index. Return an empty string if no
@@ -1353,8 +1362,10 @@ function isSameColor(color1, color2) {
1353
1362
  const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
1354
1363
  // Same as above, but matches the exact string (nothing before or after)
1355
1364
  const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
1356
- /** Reference of a column header (eg. A, AB) */
1357
- const colHeader = new RegExp(/^([A-Z]{1,3})+$/, "i");
1365
+ /** Reference of a column header (eg. A, AB, $A) */
1366
+ const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
1367
+ /** Reference of a row header (eg. 1, $1) */
1368
+ const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
1358
1369
  /** Reference of a column (eg. A, $CA, Sheet1!B) */
1359
1370
  const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
1360
1371
  /** Reference of a row (eg. 1, 59, Sheet1!9) */
@@ -1384,6 +1395,9 @@ function isRowReference(xc) {
1384
1395
  function isColHeader(str) {
1385
1396
  return colHeader.test(str);
1386
1397
  }
1398
+ function isRowHeader(str) {
1399
+ return rowHeader.test(str);
1400
+ }
1387
1401
  /**
1388
1402
  * Return true if the given xc is the reference of a single cell,
1389
1403
  * without any specified sheet (e.g. A1)
@@ -2173,18 +2187,10 @@ class RangeImpl {
2173
2187
  if (isFullCol) {
2174
2188
  parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2175
2189
  parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2176
- if (zone.left === zone.right) {
2177
- parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
2178
- parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
2179
- }
2180
2190
  }
2181
2191
  if (isFullRow) {
2182
2192
  parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
2183
2193
  parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
2184
- if (zone.top === zone.bottom) {
2185
- parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2186
- parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2187
- }
2188
2194
  }
2189
2195
  return parts;
2190
2196
  }
@@ -3572,12 +3578,12 @@ function toString(value) {
3572
3578
  }
3573
3579
  }
3574
3580
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
3575
- function normalizeString(str) {
3581
+ const normalizeString = memoize(function normalizeString(str) {
3576
3582
  return str
3577
3583
  .toLowerCase()
3578
3584
  .normalize("NFD")
3579
3585
  .replace(/[\u0300-\u036f]/g, "");
3580
- }
3586
+ });
3581
3587
  /**
3582
3588
  * Normalize a value.
3583
3589
  * If the cell value is a string, this will set it to lowercase and replacing accent letters with plain letters
@@ -4301,6 +4307,7 @@ var CommandResult;
4301
4307
  CommandResult[CommandResult["ChartDoesNotExist"] = 85] = "ChartDoesNotExist";
4302
4308
  CommandResult[CommandResult["InvalidHeaderIndex"] = 86] = "InvalidHeaderIndex";
4303
4309
  CommandResult[CommandResult["InvalidQuantity"] = 87] = "InvalidQuantity";
4310
+ CommandResult[CommandResult["NoChanges"] = 88] = "NoChanges";
4304
4311
  })(CommandResult || (CommandResult = {}));
4305
4312
 
4306
4313
  function isMatrix(x) {
@@ -5082,6 +5089,9 @@ function setElementScrollTop(el, scroll) {
5082
5089
  }
5083
5090
  function getOpenedMenus() {
5084
5091
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
5092
+ }
5093
+ function isMacOS() {
5094
+ return navigator.userAgent.toUpperCase().indexOf("MAC") >= 0;
5085
5095
  }
5086
5096
 
5087
5097
  /**
@@ -21125,6 +21135,7 @@ class AbstractResizer extends Component {
21125
21135
  draggerShadowThickness: 0,
21126
21136
  delta: 0,
21127
21137
  base: 0,
21138
+ position: "before",
21128
21139
  });
21129
21140
  }
21130
21141
  _computeHandleDisplay(ev) {
@@ -21250,11 +21261,13 @@ class AbstractResizer extends Component {
21250
21261
  this.state.draggerLinePosition = dimensions.start;
21251
21262
  this.state.draggerShadowPosition = dimensions.start;
21252
21263
  this.state.base = elementIndex;
21264
+ this.state.position = "before";
21253
21265
  }
21254
21266
  else if (this._getSelectedZoneEnd() < elementIndex) {
21255
21267
  this.state.draggerLinePosition = dimensions.end;
21256
21268
  this.state.draggerShadowPosition = dimensions.end - this.state.draggerShadowThickness;
21257
- this.state.base = elementIndex + 1;
21269
+ this.state.base = elementIndex;
21270
+ this.state.position = "after";
21258
21271
  }
21259
21272
  else {
21260
21273
  this.state.draggerLinePosition = startDimensions.start;
@@ -21435,6 +21448,7 @@ class ColResizer extends AbstractResizer {
21435
21448
  dimension: "COL",
21436
21449
  base: this.state.base,
21437
21450
  elements,
21451
+ position: this.state.position,
21438
21452
  });
21439
21453
  if (!result.isSuccessful && result.reasons.includes(2 /* CommandResult.WillRemoveExistingMerge */)) {
21440
21454
  this.env.raiseError(MergeErrorMessage);
@@ -21607,6 +21621,7 @@ class RowResizer extends AbstractResizer {
21607
21621
  dimension: "ROW",
21608
21622
  base: this.state.base,
21609
21623
  elements,
21624
+ position: this.state.position,
21610
21625
  });
21611
21626
  if (!result.isSuccessful && result.reasons.includes(2 /* CommandResult.WillRemoveExistingMerge */)) {
21612
21627
  this.env.raiseError(MergeErrorMessage);
@@ -21715,8 +21730,8 @@ function useWheelHandler(handler) {
21715
21730
  return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
21716
21731
  }
21717
21732
  const onMouseWheel = (ev) => {
21718
- const deltaX = normalize(ev.shiftKey ? ev.deltaY : ev.deltaX, ev.deltaMode);
21719
- const deltaY = normalize(ev.shiftKey ? ev.deltaX : ev.deltaY, ev.deltaMode);
21733
+ const deltaX = normalize(ev.shiftKey && !isMacOS() ? ev.deltaY : ev.deltaX, ev.deltaMode);
21734
+ const deltaY = normalize(ev.shiftKey && !isMacOS() ? ev.deltaX : ev.deltaY, ev.deltaMode);
21720
21735
  handler(deltaX, deltaY);
21721
21736
  };
21722
21737
  return onMouseWheel;
@@ -24304,7 +24319,7 @@ const machine = {
24304
24319
  SPACE: goTo(State.RightRef),
24305
24320
  NUMBER: goTo(State.Found),
24306
24321
  REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
24307
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
24322
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
24308
24323
  },
24309
24324
  [State.RightColumnRef]: {
24310
24325
  SPACE: goTo(State.RightColumnRef),
@@ -24315,6 +24330,7 @@ const machine = {
24315
24330
  SPACE: goTo(State.RightRowRef),
24316
24331
  NUMBER: goTo(State.Found),
24317
24332
  REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
24333
+ SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
24318
24334
  },
24319
24335
  [State.Found]: {},
24320
24336
  };
@@ -27516,6 +27532,14 @@ class BordersPlugin extends CorePlugin {
27516
27532
  // ---------------------------------------------------------------------------
27517
27533
  // Command Handling
27518
27534
  // ---------------------------------------------------------------------------
27535
+ allowDispatch(cmd) {
27536
+ switch (cmd.type) {
27537
+ case "SET_BORDER":
27538
+ return this.checkBordersUnchanged(cmd);
27539
+ default:
27540
+ return 0 /* CommandResult.Success */;
27541
+ }
27542
+ }
27519
27543
  handle(cmd) {
27520
27544
  switch (cmd.type) {
27521
27545
  case "ADD_MERGE":
@@ -27911,6 +27935,15 @@ class BordersPlugin extends CorePlugin {
27911
27935
  this.setBorders(sheetId, [{ ...zone, left: right }], "right");
27912
27936
  }
27913
27937
  }
27938
+ checkBordersUnchanged(cmd) {
27939
+ var _a, _b, _c, _d;
27940
+ const currentBorder = this.getCellBorder(cmd);
27941
+ const areAllNewBordersUndefined = !((_a = cmd.border) === null || _a === void 0 ? void 0 : _a.bottom) && !((_b = cmd.border) === null || _b === void 0 ? void 0 : _b.left) && !((_c = cmd.border) === null || _c === void 0 ? void 0 : _c.right) && !((_d = cmd.border) === null || _d === void 0 ? void 0 : _d.top);
27942
+ if ((!currentBorder && areAllNewBordersUndefined) || deepEquals(currentBorder, cmd.border)) {
27943
+ return 88 /* CommandResult.NoChanges */;
27944
+ }
27945
+ return 0 /* CommandResult.Success */;
27946
+ }
27914
27947
  // ---------------------------------------------------------------------------
27915
27948
  // Import/Export
27916
27949
  // ---------------------------------------------------------------------------
@@ -27946,7 +27979,7 @@ class BordersPlugin extends CorePlugin {
27946
27979
  */
27947
27980
  function getBorderId(border) {
27948
27981
  for (let [key, value] of Object.entries(borders)) {
27949
- if (stringify(value) === stringify(border)) {
27982
+ if (deepEquals(value, border)) {
27950
27983
  return parseInt(key, 10);
27951
27984
  }
27952
27985
  }
@@ -28013,8 +28046,9 @@ class CellPlugin extends CorePlugin {
28013
28046
  allowDispatch(cmd) {
28014
28047
  switch (cmd.type) {
28015
28048
  case "UPDATE_CELL":
28049
+ return this.checkCellOutOfSheet(cmd);
28016
28050
  case "CLEAR_CELL":
28017
- return this.checkCellOutOfSheet(cmd.sheetId, cmd.col, cmd.row);
28051
+ return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
28018
28052
  default:
28019
28053
  return 0 /* CommandResult.Success */;
28020
28054
  }
@@ -28173,14 +28207,9 @@ class CellPlugin extends CorePlugin {
28173
28207
  */
28174
28208
  getCellById(cellId) {
28175
28209
  // this must be as fast as possible
28176
- for (const sheetId in this.cells) {
28177
- const sheet = this.cells[sheetId];
28178
- const cell = sheet[cellId];
28179
- if (cell) {
28180
- return cell;
28181
- }
28182
- }
28183
- return undefined;
28210
+ const position = this.getters.getCellPosition(cellId);
28211
+ const sheet = this.cells[position.sheetId];
28212
+ return sheet[cellId];
28184
28213
  }
28185
28214
  /*
28186
28215
  * Reconstructs the original formula string based on a normalized form and its dependencies
@@ -28418,13 +28447,23 @@ class CellPlugin extends CorePlugin {
28418
28447
  dependencies: [],
28419
28448
  };
28420
28449
  }
28421
- checkCellOutOfSheet(sheetId, col, row) {
28450
+ checkCellOutOfSheet(cmd) {
28451
+ const { sheetId, col, row } = cmd;
28422
28452
  const sheet = this.getters.tryGetSheet(sheetId);
28423
28453
  if (!sheet)
28424
28454
  return 27 /* CommandResult.InvalidSheetId */;
28425
28455
  const sheetZone = this.getters.getSheetZone(sheetId);
28426
28456
  return isInside(col, row, sheetZone) ? 0 /* CommandResult.Success */ : 18 /* CommandResult.TargetOutOfSheet */;
28427
28457
  }
28458
+ checkUselessClearCell(cmd) {
28459
+ const cell = this.getters.getCell(cmd);
28460
+ if (!cell)
28461
+ return 88 /* CommandResult.NoChanges */;
28462
+ if (!cell.content && !cell.style && !cell.format) {
28463
+ return 88 /* CommandResult.NoChanges */;
28464
+ }
28465
+ return 0 /* CommandResult.Success */;
28466
+ }
28428
28467
  }
28429
28468
  CellPlugin.getters = [
28430
28469
  "zoneToXC",
@@ -30894,7 +30933,7 @@ class SheetPlugin extends CorePlugin {
30894
30933
  const elements = cmd.dimension === "COL"
30895
30934
  ? this.getNumberCols(cmd.sheetId)
30896
30935
  : this.getNumberRows(cmd.sheetId);
30897
- if (cmd.base < 0 || cmd.base > elements) {
30936
+ if (cmd.base < 0 || cmd.base >= elements) {
30898
30937
  return 86 /* CommandResult.InvalidHeaderIndex */;
30899
30938
  }
30900
30939
  else if (cmd.quantity <= 0) {
@@ -31490,10 +31529,13 @@ class SheetPlugin extends CorePlugin {
31490
31529
  // begin with the end.
31491
31530
  rows.sort((a, b) => b - a);
31492
31531
  for (let group of groupConsecutive(rows)) {
31532
+ // indexes are sorted in the descending order
31533
+ const from = group[group.length - 1];
31534
+ const to = group[0];
31493
31535
  // Move the cells.
31494
- this.moveCellOnRowsDeletion(sheet, group[group.length - 1], group[0]);
31495
- // Effectively delete the element and recompute the left-right/top-bottom.
31496
- group.map((row) => this.updateRowsStructureOnDeletion(row, sheet));
31536
+ this.moveCellOnRowsDeletion(sheet, from, to);
31537
+ // Effectively delete the rows
31538
+ this.updateRowsStructureOnDeletion(sheet, from, to);
31497
31539
  }
31498
31540
  const count = rows.filter((row) => row < sheet.panes.ySplit).length;
31499
31541
  if (count) {
@@ -31515,8 +31557,6 @@ class SheetPlugin extends CorePlugin {
31515
31557
  this.addEmptyRows(sheet, quantity);
31516
31558
  // Move the cells.
31517
31559
  this.moveCellsOnAddition(sheet, index, quantity, "rows");
31518
- // Recompute the left-right/top-bottom.
31519
- this.updateRowsStructureOnAddition(sheet, row, quantity);
31520
31560
  if (index < sheet.panes.ySplit) {
31521
31561
  this.setPaneDivisions(sheet.id, sheet.panes.ySplit + quantity, "ROW");
31522
31562
  }
@@ -31617,35 +31657,20 @@ class SheetPlugin extends CorePlugin {
31617
31657
  }
31618
31658
  }
31619
31659
  }
31620
- updateRowsStructureOnDeletion(index, sheet) {
31660
+ updateRowsStructureOnDeletion(sheet, deleteFromRow, deleteToRow) {
31621
31661
  const rows = [];
31622
- const cellsQueue = sheet.rows.map((row) => row.cells);
31662
+ const cellsQueue = sheet.rows.map((row) => row.cells).reverse();
31623
31663
  for (let i in sheet.rows) {
31624
- if (Number(i) === index) {
31664
+ const row = Number(i);
31665
+ if (row >= deleteFromRow && row <= deleteToRow) {
31625
31666
  continue;
31626
31667
  }
31627
31668
  rows.push({
31628
- cells: cellsQueue.shift(),
31669
+ cells: cellsQueue.pop(),
31629
31670
  });
31630
31671
  }
31631
31672
  this.history.update("sheets", sheet.id, "rows", rows);
31632
31673
  }
31633
- /**
31634
- * Update the rows of the sheet after an addition:
31635
- * - Rename the rows
31636
- *
31637
- * @param sheet Sheet on which the deletion occurs
31638
- * @param addedRow Index of the added row
31639
- * @param rowsToAdd Number of the rows to add
31640
- */
31641
- updateRowsStructureOnAddition(sheet, addedRow, rowsToAdd) {
31642
- const rows = [];
31643
- const cellsQueue = sheet.rows.map((row) => row.cells);
31644
- sheet.rows.forEach(() => rows.push({
31645
- cells: cellsQueue.shift(),
31646
- }));
31647
- this.history.update("sheets", sheet.id, "rows", rows);
31648
- }
31649
31674
  /**
31650
31675
  * Add empty rows at the end of the rows
31651
31676
  *
@@ -32129,6 +32154,7 @@ class EvaluationPlugin extends UIPlugin {
32129
32154
  }
32130
32155
  return evaluatedCell;
32131
32156
  };
32157
+ const rangeCache = {};
32132
32158
  /**
32133
32159
  * Return the values of the cell(s) used in reference, but always in the format of a range even
32134
32160
  * if a single cell is referenced. It is a list of col values. This is useful for the formulas that describe parameters as
@@ -32145,21 +32171,26 @@ class EvaluationPlugin extends UIPlugin {
32145
32171
  // Performance issue: Avoid fetching data on positions that are out of the spreadsheet
32146
32172
  // e.g. A1:ZZZ9999 in a sheet with 10 cols and 10 rows should ignore everything past J10 and return a 10x10 array
32147
32173
  const sheetZone = getters.getSheetZone(sheetId);
32148
- const result = [];
32149
32174
  const zone = intersection(range.zone, sheetZone);
32150
32175
  if (!zone) {
32151
- result.push([]);
32152
- return result;
32176
+ return [[]];
32177
+ }
32178
+ const { top, left, bottom, right } = zone;
32179
+ const cacheKey = `${sheetId}-${top}-${left}-${bottom}-${right}`;
32180
+ if (cacheKey in rangeCache) {
32181
+ return rangeCache[cacheKey];
32153
32182
  }
32183
+ const result = new Array(right - left + 1);
32154
32184
  // Performance issue: nested loop is faster than a map here
32155
- for (let col = zone.left; col <= zone.right; col++) {
32156
- const rowValues = [];
32157
- for (let row = zone.top; row <= zone.bottom; row++) {
32185
+ for (let col = left; col <= right; col++) {
32186
+ const rowValues = new Array(bottom - top + 1);
32187
+ for (let row = top; row <= bottom; row++) {
32158
32188
  const cell = evalContext.getters.getCell({ sheetId: range.sheetId, col, row });
32159
- rowValues.push(cell ? getEvaluatedCell(cell) : undefined);
32189
+ rowValues[row - top] = cell ? getEvaluatedCell(cell) : undefined;
32160
32190
  }
32161
- result.push(rowValues);
32191
+ result[col - left] = rowValues;
32162
32192
  }
32193
+ rangeCache[cacheKey] = result;
32163
32194
  return result;
32164
32195
  }
32165
32196
  /**
@@ -34067,24 +34098,27 @@ class AutofillPlugin extends UIPlugin {
34067
34098
  * autofiller
34068
34099
  */
34069
34100
  autofillAuto() {
34101
+ var _a, _b;
34070
34102
  const zone = this.getters.getSelectedZone();
34071
34103
  const sheetId = this.getters.getActiveSheetId();
34072
34104
  let col = zone.left;
34073
34105
  let row = zone.bottom;
34074
34106
  if (col > 0) {
34075
- let left = this.getters.getEvaluatedCell({ sheetId, col: col - 1, row });
34076
- while (left.type !== CellValueType.empty) {
34107
+ let leftPosition = { sheetId, col: col - 1, row };
34108
+ while (this.getters.getEvaluatedCell(leftPosition).type !== CellValueType.empty ||
34109
+ ((_a = this.getters.getCell(leftPosition)) === null || _a === void 0 ? void 0 : _a.content)) {
34077
34110
  row += 1;
34078
- left = this.getters.getEvaluatedCell({ sheetId, col: col - 1, row });
34111
+ leftPosition = { sheetId, col: col - 1, row };
34079
34112
  }
34080
34113
  }
34081
34114
  if (row === zone.bottom) {
34082
34115
  col = zone.right;
34083
34116
  if (col <= this.getters.getNumberCols(sheetId)) {
34084
- let right = this.getters.getEvaluatedCell({ sheetId, col: col + 1, row });
34085
- while (right.type !== CellValueType.empty) {
34117
+ let rightPosition = { sheetId, col: col + 1, row };
34118
+ while (this.getters.getEvaluatedCell(rightPosition).type !== CellValueType.empty ||
34119
+ ((_b = this.getters.getCell(rightPosition)) === null || _b === void 0 ? void 0 : _b.content)) {
34086
34120
  row += 1;
34087
- right = this.getters.getEvaluatedCell({ sheetId, col: col + 1, row });
34121
+ rightPosition = { sheetId, col: col + 1, row };
34088
34122
  }
34089
34123
  }
34090
34124
  }
@@ -38402,6 +38436,10 @@ function setXcToReferenceType(xc, referenceType) {
38402
38436
  return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
38403
38437
  case "colrow":
38404
38438
  indexOfNumber = xc.search(/[0-9]/);
38439
+ if (indexOfNumber === -1 || indexOfNumber === 0) {
38440
+ // no row number (eg. A) or no column (eg. 1)
38441
+ return "$" + xc;
38442
+ }
38405
38443
  xc = xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
38406
38444
  return "$" + xc;
38407
38445
  case "none":
@@ -39543,7 +39581,7 @@ class GridSelectionPlugin extends UIPlugin {
39543
39581
  sheetId: cmd.sheetId,
39544
39582
  base: cmd.base,
39545
39583
  quantity: thickness,
39546
- position: "before",
39584
+ position: cmd.position,
39547
39585
  });
39548
39586
  const isCol = cmd.dimension === "COL";
39549
39587
  const start = cmd.elements[0];
@@ -39560,12 +39598,13 @@ class GridSelectionPlugin extends UIPlugin {
39560
39598
  },
39561
39599
  ];
39562
39600
  const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
39601
+ const base = isBasedBefore ? cmd.base : cmd.base + 1;
39563
39602
  const pasteTarget = [
39564
39603
  {
39565
- left: isCol ? cmd.base : 0,
39566
- right: isCol ? cmd.base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
39567
- top: !isCol ? cmd.base : 0,
39568
- bottom: !isCol ? cmd.base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
39604
+ left: isCol ? base : 0,
39605
+ right: isCol ? base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
39606
+ top: !isCol ? base : 0,
39607
+ bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
39569
39608
  },
39570
39609
  ];
39571
39610
  state.paste(pasteTarget, { selectTarget: true });
@@ -39602,6 +39641,11 @@ class GridSelectionPlugin extends UIPlugin {
39602
39641
  doesElementsHaveCommonMerges(id, cmd.base - 1, cmd.base)) {
39603
39642
  return 2 /* CommandResult.WillRemoveExistingMerge */;
39604
39643
  }
39644
+ const headers = [cmd.base, ...cmd.elements];
39645
+ const maxHeaderValue = isCol ? this.getters.getNumberCols(id) : this.getters.getNumberRows(id);
39646
+ if (headers.some((h) => h < 0 || h >= maxHeaderValue)) {
39647
+ return 86 /* CommandResult.InvalidHeaderIndex */;
39648
+ }
39605
39649
  return 0 /* CommandResult.Success */;
39606
39650
  }
39607
39651
  //-------------------------------------------
@@ -42686,9 +42730,9 @@ function revertChanges(revisions) {
42686
42730
  * Apply the changes of the given HistoryChange to the state
42687
42731
  */
42688
42732
  function applyChange(change, target) {
42689
- let val = change.root;
42690
- let key = change.path[change.path.length - 1];
42691
- for (let pathIndex = 0; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
42733
+ let val = change.path[0];
42734
+ const key = change.path[change.path.length - 1];
42735
+ for (let pathIndex = 1; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
42692
42736
  const p = change.path[pathIndex];
42693
42737
  if (val[p] === undefined) {
42694
42738
  const nextPath = change.path[pathIndex + 1];
@@ -43445,13 +43489,14 @@ class StateObserver {
43445
43489
  }
43446
43490
  addChange(...args) {
43447
43491
  const val = args.pop();
43448
- const [root, ...path] = args;
43492
+ const root = args[0];
43449
43493
  let value = root;
43450
- let key = path[path.length - 1];
43451
- for (let pathIndex = 0; pathIndex <= path.length - 2; pathIndex++) {
43452
- const p = path[pathIndex];
43494
+ let key = args[args.length - 1];
43495
+ const pathLength = args.length - 2;
43496
+ for (let pathIndex = 1; pathIndex <= pathLength; pathIndex++) {
43497
+ const p = args[pathIndex];
43453
43498
  if (value[p] === undefined) {
43454
- const nextPath = path[pathIndex + 1];
43499
+ const nextPath = args[pathIndex + 1];
43455
43500
  value[p] = createEmptyStructure(nextPath);
43456
43501
  }
43457
43502
  value = value[p];
@@ -43460,8 +43505,7 @@ class StateObserver {
43460
43505
  return;
43461
43506
  }
43462
43507
  this.changes.push({
43463
- root,
43464
- path,
43508
+ path: args,
43465
43509
  before: value[key],
43466
43510
  after: val,
43467
43511
  });
@@ -45313,7 +45357,10 @@ class Model extends EventBus {
45313
45357
  */
45314
45358
  checkDispatchAllowed(command) {
45315
45359
  const results = this.handlers.map((handler) => handler.allowDispatch(command));
45316
- return new DispatchResult(results.flat());
45360
+ if (results.some((r) => r !== 0 /* CommandResult.Success */)) {
45361
+ return new DispatchResult(results.flat());
45362
+ }
45363
+ return DispatchResult.Success;
45317
45364
  }
45318
45365
  finalize() {
45319
45366
  this.status = 3 /* Status.Finalizing */;
@@ -45512,6 +45559,6 @@ function addFunction(functionName, functionDescription) {
45512
45559
  export { AbstractChart, CommandResult, CorePlugin, DATETIME_FORMAT, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, links, load, parse, readonlyAllowedCommands, registries, setTranslationMethod, tokenize };
45513
45560
 
45514
45561
 
45515
- __info__.version = '16.2.22';
45516
- __info__.date = '2023-11-16T11:57:01.482Z';
45517
- __info__.hash = 'b78d5dd';
45562
+ __info__.version = '16.2.24';
45563
+ __info__.date = '2023-12-05T09:37:14.992Z';
45564
+ __info__.hash = '7b1a35c';