@odoo/o-spreadsheet 16.0.24 → 16.0.27

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.
@@ -621,13 +621,6 @@
621
621
  }
622
622
 
623
623
  //------------------------------------------------------------------------------
624
- /**
625
- * Stringify an object, like JSON.stringify, except that the first level of keys
626
- * is ordered.
627
- */
628
- function stringify(obj) {
629
- return JSON.stringify(obj, Object.keys(obj).sort());
630
- }
631
624
  /**
632
625
  * Remove quotes from a quoted string
633
626
  * ```js
@@ -929,7 +922,7 @@
929
922
  */
930
923
  function getItemId(item, itemsDic) {
931
924
  for (let [key, value] of Object.entries(itemsDic)) {
932
- if (stringify(value) === stringify(item)) {
925
+ if (deepEquals(value, item)) {
933
926
  return parseInt(key, 10);
934
927
  }
935
928
  }
@@ -1065,6 +1058,22 @@
1065
1058
  if (!matrix.length)
1066
1059
  return matrix;
1067
1060
  return matrix[0].map((_, i) => matrix.map((row) => row[i]));
1061
+ }
1062
+ /**
1063
+ * Creates a version of the function that's memoized on the value of its first
1064
+ * argument, if any.
1065
+ */
1066
+ function memoize(func) {
1067
+ const cache = new Map();
1068
+ const funcName = func.name ? func.name + " (memoized)" : "memoized";
1069
+ return {
1070
+ [funcName](...args) {
1071
+ if (!cache.has(args[0])) {
1072
+ cache.set(args[0], func(...args));
1073
+ }
1074
+ return cache.get(args[0]);
1075
+ },
1076
+ }[funcName];
1068
1077
  }
1069
1078
 
1070
1079
  const RBA_REGEX = /rgba?\(|\s+|\)/gi;
@@ -1344,8 +1353,10 @@
1344
1353
  const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
1345
1354
  // Same as above, but matches the exact string (nothing before or after)
1346
1355
  const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
1347
- /** Reference of a column header (eg. A, AB) */
1348
- const colHeader = new RegExp(/^([A-Z]{1,3})+$/, "i");
1356
+ /** Reference of a column header (eg. A, AB, $A) */
1357
+ const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
1358
+ /** Reference of a row header (eg. 1, $1) */
1359
+ const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
1349
1360
  /** Reference of a column (eg. A, $CA, Sheet1!B) */
1350
1361
  const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
1351
1362
  /** Reference of a row (eg. 1, 59, Sheet1!9) */
@@ -1375,6 +1386,9 @@
1375
1386
  function isColHeader(str) {
1376
1387
  return colHeader.test(str);
1377
1388
  }
1389
+ function isRowHeader(str) {
1390
+ return rowHeader.test(str);
1391
+ }
1378
1392
  /**
1379
1393
  * Return true if the given xc is the reference of a single cell,
1380
1394
  * without any specified sheet (e.g. A1)
@@ -2075,18 +2089,10 @@
2075
2089
  if (isFullCol) {
2076
2090
  parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2077
2091
  parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2078
- if (zone.left === zone.right) {
2079
- parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
2080
- parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
2081
- }
2082
2092
  }
2083
2093
  if (isFullRow) {
2084
2094
  parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
2085
2095
  parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
2086
- if (zone.top === zone.bottom) {
2087
- parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2088
- parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2089
- }
2090
2096
  }
2091
2097
  return parts;
2092
2098
  }
@@ -3302,6 +3308,7 @@
3302
3308
  CommandResult[CommandResult["ChartDoesNotExist"] = 84] = "ChartDoesNotExist";
3303
3309
  CommandResult[CommandResult["InvalidHeaderIndex"] = 85] = "InvalidHeaderIndex";
3304
3310
  CommandResult[CommandResult["InvalidQuantity"] = 86] = "InvalidQuantity";
3311
+ CommandResult[CommandResult["NoChanges"] = 87] = "NoChanges";
3305
3312
  })(exports.CommandResult || (exports.CommandResult = {}));
3306
3313
 
3307
3314
  function isMatrix(x) {
@@ -3877,6 +3884,7 @@
3877
3884
  return node.description ? node.description : "";
3878
3885
  }
3879
3886
 
3887
+ const macRegex = /Mac/i;
3880
3888
  /**
3881
3889
  * Return true if the event was triggered from
3882
3890
  * a child element.
@@ -3894,6 +3902,17 @@
3894
3902
  }
3895
3903
  function getOpenedMenus() {
3896
3904
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
3905
+ }
3906
+ function isMacOS() {
3907
+ return Boolean(macRegex.test(navigator.userAgent));
3908
+ }
3909
+ /**
3910
+ * @param {KeyboardEvent | MouseEvent} ev
3911
+ * @returns Returns true if the event was triggered with the "ctrl" modifier pressed.
3912
+ * On Mac, this is the "meta" or "command" key.
3913
+ */
3914
+ function isCtrlKey(ev) {
3915
+ return isMacOS() ? ev.metaKey : ev.ctrlKey;
3897
3916
  }
3898
3917
 
3899
3918
  /**
@@ -10977,12 +10996,12 @@
10977
10996
  }
10978
10997
  }
10979
10998
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
10980
- function normalizeString(str) {
10999
+ const normalizeString = memoize(function normalizeString(str) {
10981
11000
  return str
10982
11001
  .toLowerCase()
10983
11002
  .normalize("NFD")
10984
11003
  .replace(/[\u0300-\u036f]/g, "");
10985
- }
11004
+ });
10986
11005
  /**
10987
11006
  * Normalize a value.
10988
11007
  * If the cell value is a string, this will set it to lowercase and replacing accent letters with plain letters
@@ -18557,7 +18576,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
18557
18576
  SPACE: goTo(State.RightRef),
18558
18577
  NUMBER: goTo(State.Found),
18559
18578
  REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
18560
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
18579
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
18561
18580
  },
18562
18581
  [State.RightColumnRef]: {
18563
18582
  SPACE: goTo(State.RightColumnRef),
@@ -18568,6 +18587,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
18568
18587
  SPACE: goTo(State.RightRowRef),
18569
18588
  NUMBER: goTo(State.Found),
18570
18589
  REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
18590
+ SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
18571
18591
  },
18572
18592
  [State.Found]: {},
18573
18593
  };
@@ -19077,6 +19097,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
19077
19097
  return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
19078
19098
  case "colrow":
19079
19099
  indexOfNumber = xc.search(/[0-9]/);
19100
+ if (indexOfNumber === -1 || indexOfNumber === 0) {
19101
+ // no row number (eg. A) or no column (eg. 1)
19102
+ return "$" + xc;
19103
+ }
19080
19104
  xc = xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
19081
19105
  return "$" + xc;
19082
19106
  case "none":
@@ -21458,7 +21482,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
21458
21482
  return;
21459
21483
  }
21460
21484
  const [col, row] = this.getCartesianCoordinates(ev);
21461
- this.props.onCellClicked(col, row, { shiftKey: ev.shiftKey, ctrlKey: ev.ctrlKey });
21485
+ this.props.onCellClicked(col, row, {
21486
+ expandZone: ev.shiftKey,
21487
+ addZone: isCtrlKey(ev),
21488
+ });
21462
21489
  }
21463
21490
  onDoubleClick(ev) {
21464
21491
  const [col, row] = this.getCartesianCoordinates(ev);
@@ -21530,6 +21557,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
21530
21557
  draggerShadowThickness: 0,
21531
21558
  delta: 0,
21532
21559
  base: 0,
21560
+ position: "before",
21533
21561
  });
21534
21562
  }
21535
21563
  _computeHandleDisplay(ev) {
@@ -21655,11 +21683,13 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
21655
21683
  this.state.draggerLinePosition = dimensions.start;
21656
21684
  this.state.draggerShadowPosition = dimensions.start;
21657
21685
  this.state.base = elementIndex;
21686
+ this.state.position = "before";
21658
21687
  }
21659
21688
  else if (this._getSelectedZoneEnd() < elementIndex) {
21660
21689
  this.state.draggerLinePosition = dimensions.end;
21661
21690
  this.state.draggerShadowPosition = dimensions.end - this.state.draggerShadowThickness;
21662
- this.state.base = elementIndex + 1;
21691
+ this.state.base = elementIndex;
21692
+ this.state.position = "after";
21663
21693
  }
21664
21694
  else {
21665
21695
  this.state.draggerLinePosition = startDimensions.start;
@@ -21683,7 +21713,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
21683
21713
  this._increaseSelection(index);
21684
21714
  }
21685
21715
  else {
21686
- this._selectElement(index, ev.ctrlKey);
21716
+ this._selectElement(index, isCtrlKey(ev));
21687
21717
  }
21688
21718
  this.lastSelectedElementIndex = index;
21689
21719
  const mouseMoveSelect = (col, row) => {
@@ -21696,7 +21726,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
21696
21726
  const mouseUpSelect = () => {
21697
21727
  this.state.isSelecting = false;
21698
21728
  this.lastSelectedElementIndex = null;
21699
- this.env.model.dispatch(ev.ctrlKey ? "PREPARE_SELECTION_INPUT_EXPANSION" : "STOP_SELECTION_INPUT");
21729
+ this.env.model.dispatch(isCtrlKey(ev) ? "PREPARE_SELECTION_INPUT_EXPANSION" : "STOP_SELECTION_INPUT");
21700
21730
  this._computeGrabDisplay(ev);
21701
21731
  };
21702
21732
  dragAndDropBeyondTheViewport(this.env, mouseMoveSelect, mouseUpSelect);
@@ -21837,13 +21867,14 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
21837
21867
  dimension: "COL",
21838
21868
  base: this.state.base,
21839
21869
  elements,
21870
+ position: this.state.position,
21840
21871
  });
21841
21872
  if (!result.isSuccessful && result.reasons.includes(2 /* CommandResult.WillRemoveExistingMerge */)) {
21842
21873
  this.env.raiseError(MergeErrorMessage);
21843
21874
  }
21844
21875
  }
21845
- _selectElement(index, ctrlKey) {
21846
- this.env.model.selection.selectColumn(index, ctrlKey ? "newAnchor" : "overrideSelection");
21876
+ _selectElement(index, addDistinctHeader) {
21877
+ this.env.model.selection.selectColumn(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
21847
21878
  }
21848
21879
  _increaseSelection(index) {
21849
21880
  this.env.model.selection.selectColumn(index, "updateAnchor");
@@ -22006,13 +22037,14 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22006
22037
  dimension: "ROW",
22007
22038
  base: this.state.base,
22008
22039
  elements,
22040
+ position: this.state.position,
22009
22041
  });
22010
22042
  if (!result.isSuccessful && result.reasons.includes(2 /* CommandResult.WillRemoveExistingMerge */)) {
22011
22043
  this.env.raiseError(MergeErrorMessage);
22012
22044
  }
22013
22045
  }
22014
- _selectElement(index, ctrlKey) {
22015
- this.env.model.selection.selectRow(index, ctrlKey ? "newAnchor" : "overrideSelection");
22046
+ _selectElement(index, addDistinctHeader) {
22047
+ this.env.model.selection.selectRow(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
22016
22048
  }
22017
22049
  _increaseSelection(index) {
22018
22050
  this.env.model.selection.selectRow(index, "updateAnchor");
@@ -22108,8 +22140,8 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22108
22140
  return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
22109
22141
  }
22110
22142
  const onMouseWheel = (ev) => {
22111
- const deltaX = normalize(ev.shiftKey ? ev.deltaY : ev.deltaX, ev.deltaMode);
22112
- const deltaY = normalize(ev.shiftKey ? ev.deltaX : ev.deltaY, ev.deltaMode);
22143
+ const deltaX = normalize(ev.shiftKey && !isMacOS() ? ev.deltaY : ev.deltaX, ev.deltaMode);
22144
+ const deltaY = normalize(ev.shiftKey && !isMacOS() ? ev.deltaX : ev.deltaY, ev.deltaMode);
22113
22145
  handler(deltaX, deltaY);
22114
22146
  };
22115
22147
  return onMouseWheel;
@@ -22703,18 +22735,18 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22703
22735
  // ---------------------------------------------------------------------------
22704
22736
  // Zone selection with mouse
22705
22737
  // ---------------------------------------------------------------------------
22706
- onCellClicked(col, row, { ctrlKey, shiftKey }) {
22707
- if (ctrlKey) {
22738
+ onCellClicked(col, row, { addZone, expandZone }) {
22739
+ if (addZone) {
22708
22740
  this.env.model.dispatch("PREPARE_SELECTION_INPUT_EXPANSION");
22709
22741
  }
22710
22742
  this.closeOpenedPopover();
22711
22743
  if (this.env.model.getters.getEditionMode() === "editing") {
22712
22744
  this.env.model.dispatch("STOP_EDITION");
22713
22745
  }
22714
- if (shiftKey) {
22746
+ if (expandZone) {
22715
22747
  this.env.model.selection.setAnchorCorner(col, row);
22716
22748
  }
22717
- else if (ctrlKey) {
22749
+ else if (addZone) {
22718
22750
  this.env.model.selection.addCellToSelection(col, row);
22719
22751
  }
22720
22752
  else {
@@ -22768,10 +22800,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22768
22800
  };
22769
22801
  const direction = arrowMap[ev.key];
22770
22802
  if (ev.shiftKey) {
22771
- this.env.model.selection.resizeAnchorZone(direction, ev.ctrlKey ? "end" : 1);
22803
+ this.env.model.selection.resizeAnchorZone(direction, isCtrlKey(ev) ? "end" : 1);
22772
22804
  }
22773
22805
  else {
22774
- this.env.model.selection.moveAnchorCell(direction, ev.ctrlKey ? "end" : 1);
22806
+ this.env.model.selection.moveAnchorCell(direction, isCtrlKey(ev) ? "end" : 1);
22775
22807
  }
22776
22808
  if (this.env.model.getters.isPaintingFormat()) {
22777
22809
  this.env.model.dispatch("PASTE", {
@@ -22785,9 +22817,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22785
22817
  return;
22786
22818
  }
22787
22819
  let keyDownString = "";
22788
- if (ev.ctrlKey)
22789
- keyDownString += "CTRL+";
22790
- if (ev.metaKey)
22820
+ if (isCtrlKey(ev))
22791
22821
  keyDownString += "CTRL+";
22792
22822
  if (ev.altKey)
22793
22823
  keyDownString += "ALT+";
@@ -27102,6 +27132,14 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
27102
27132
  // ---------------------------------------------------------------------------
27103
27133
  // Command Handling
27104
27134
  // ---------------------------------------------------------------------------
27135
+ allowDispatch(cmd) {
27136
+ switch (cmd.type) {
27137
+ case "SET_BORDER":
27138
+ return this.checkBordersUnchanged(cmd);
27139
+ default:
27140
+ return 0 /* CommandResult.Success */;
27141
+ }
27142
+ }
27105
27143
  handle(cmd) {
27106
27144
  switch (cmd.type) {
27107
27145
  case "ADD_MERGE":
@@ -27497,6 +27535,15 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
27497
27535
  this.setBorders(sheetId, [{ ...zone, left: right }], "right");
27498
27536
  }
27499
27537
  }
27538
+ checkBordersUnchanged(cmd) {
27539
+ var _a, _b, _c, _d;
27540
+ const currentBorder = this.getCellBorder(cmd.sheetId, cmd.col, cmd.row);
27541
+ 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);
27542
+ if ((!currentBorder && areAllNewBordersUndefined) || deepEquals(currentBorder, cmd.border)) {
27543
+ return 87 /* CommandResult.NoChanges */;
27544
+ }
27545
+ return 0 /* CommandResult.Success */;
27546
+ }
27500
27547
  // ---------------------------------------------------------------------------
27501
27548
  // Import/Export
27502
27549
  // ---------------------------------------------------------------------------
@@ -27532,7 +27579,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
27532
27579
  */
27533
27580
  function getBorderId(border) {
27534
27581
  for (let [key, value] of Object.entries(borders)) {
27535
- if (stringify(value) === stringify(border)) {
27582
+ if (deepEquals(value, border)) {
27536
27583
  return parseInt(key, 10);
27537
27584
  }
27538
27585
  }
@@ -27575,6 +27622,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
27575
27622
  class CellPlugin extends CorePlugin {
27576
27623
  constructor() {
27577
27624
  super(...arguments);
27625
+ this.nextId = 1;
27578
27626
  this.cells = {};
27579
27627
  this.createCell = cellFactory(this.getters);
27580
27628
  }
@@ -27600,8 +27648,9 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
27600
27648
  allowDispatch(cmd) {
27601
27649
  switch (cmd.type) {
27602
27650
  case "UPDATE_CELL":
27651
+ return this.checkCellOutOfSheet(cmd);
27603
27652
  case "CLEAR_CELL":
27604
- return this.checkCellOutOfSheet(cmd.sheetId, cmd.col, cmd.row);
27653
+ return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
27605
27654
  default:
27606
27655
  return 0 /* CommandResult.Success */;
27607
27656
  }
@@ -27742,7 +27791,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
27742
27791
  importCell(sheetId, cellData, normalizedStyles, normalizedFormats) {
27743
27792
  const style = (cellData.style && normalizedStyles[cellData.style]) || undefined;
27744
27793
  const format = (cellData.format && normalizedFormats[cellData.format]) || undefined;
27745
- const cellId = this.uuidGenerator.uuidv4();
27794
+ const cellId = this.getNextUid();
27746
27795
  const properties = { format, style };
27747
27796
  return this.createCell(cellId, (cellData === null || cellData === void 0 ? void 0 : cellData.content) || "", properties, sheetId);
27748
27797
  }
@@ -27773,14 +27822,9 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
27773
27822
  */
27774
27823
  getCellById(cellId) {
27775
27824
  // this must be as fast as possible
27776
- for (const sheetId in this.cells) {
27777
- const sheet = this.cells[sheetId];
27778
- const cell = sheet[cellId];
27779
- if (cell) {
27780
- return cell;
27781
- }
27782
- }
27783
- return undefined;
27825
+ const position = this.getters.getCellPosition(cellId);
27826
+ const sheet = this.cells[position.sheetId];
27827
+ return sheet[cellId];
27784
27828
  }
27785
27829
  /*
27786
27830
  * Reconstructs the original formula string based on a normalized form and its dependencies
@@ -27888,6 +27932,11 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
27888
27932
  }
27889
27933
  return format;
27890
27934
  }
27935
+ getNextUid() {
27936
+ const id = this.nextId.toString();
27937
+ this.history.update("nextId", this.nextId + 1);
27938
+ return id;
27939
+ }
27891
27940
  updateCell(sheetId, col, row, after) {
27892
27941
  var _a;
27893
27942
  const before = this.getters.getCell(sheetId, col, row);
@@ -27926,7 +27975,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
27926
27975
  }
27927
27976
  return;
27928
27977
  }
27929
- const cellId = (before === null || before === void 0 ? void 0 : before.id) || this.uuidGenerator.uuidv4();
27978
+ const cellId = (before === null || before === void 0 ? void 0 : before.id) || this.getNextUid();
27930
27979
  const didContentChange = hasContent;
27931
27980
  const properties = { format, style };
27932
27981
  const cell = this.createCell(cellId, afterContent, properties, sheetId);
@@ -27940,13 +27989,23 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
27940
27989
  this.history.update("cells", sheetId, cell.id, cell);
27941
27990
  this.dispatch("UPDATE_CELL_POSITION", { cellId: cell.id, col, row, sheetId });
27942
27991
  }
27943
- checkCellOutOfSheet(sheetId, col, row) {
27992
+ checkCellOutOfSheet(cmd) {
27993
+ const { sheetId, col, row } = cmd;
27944
27994
  const sheet = this.getters.tryGetSheet(sheetId);
27945
27995
  if (!sheet)
27946
27996
  return 27 /* CommandResult.InvalidSheetId */;
27947
27997
  const sheetZone = this.getters.getSheetZone(sheetId);
27948
27998
  return isInside(col, row, sheetZone) ? 0 /* CommandResult.Success */ : 18 /* CommandResult.TargetOutOfSheet */;
27949
27999
  }
28000
+ checkUselessClearCell(cmd) {
28001
+ const cell = this.getters.getCell(cmd.sheetId, cmd.col, cmd.row);
28002
+ if (!cell)
28003
+ return 87 /* CommandResult.NoChanges */;
28004
+ if (!cell.content && !cell.style && !cell.format) {
28005
+ return 87 /* CommandResult.NoChanges */;
28006
+ }
28007
+ return 0 /* CommandResult.Success */;
28008
+ }
27950
28009
  }
27951
28010
  CellPlugin.getters = [
27952
28011
  "zoneToXC",
@@ -29898,7 +29957,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
29898
29957
  const elements = cmd.dimension === "COL"
29899
29958
  ? this.getNumberCols(cmd.sheetId)
29900
29959
  : this.getNumberRows(cmd.sheetId);
29901
- if (cmd.base < 0 || cmd.base > elements) {
29960
+ if (cmd.base < 0 || cmd.base >= elements) {
29902
29961
  return 85 /* CommandResult.InvalidHeaderIndex */;
29903
29962
  }
29904
29963
  else if (cmd.quantity <= 0) {
@@ -30511,10 +30570,13 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
30511
30570
  // begin with the end.
30512
30571
  rows.sort((a, b) => b - a);
30513
30572
  for (let group of groupConsecutive(rows)) {
30573
+ // indexes are sorted in the descending order
30574
+ const from = group[group.length - 1];
30575
+ const to = group[0];
30514
30576
  // Move the cells.
30515
- this.moveCellOnRowsDeletion(sheet, group[group.length - 1], group[0]);
30516
- // Effectively delete the element and recompute the left-right/top-bottom.
30517
- group.map((row) => this.updateRowsStructureOnDeletion(row, sheet));
30577
+ this.moveCellOnRowsDeletion(sheet, from, to);
30578
+ // Effectively delete the rows
30579
+ this.updateRowsStructureOnDeletion(sheet, from, to);
30518
30580
  }
30519
30581
  const count = rows.filter((row) => row < sheet.panes.ySplit).length;
30520
30582
  if (count) {
@@ -30536,8 +30598,6 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
30536
30598
  this.addEmptyRows(sheet, quantity);
30537
30599
  // Move the cells.
30538
30600
  this.moveCellsOnAddition(sheet, index, quantity, "rows");
30539
- // Recompute the left-right/top-bottom.
30540
- this.updateRowsStructureOnAddition(sheet, row, quantity);
30541
30601
  if (index < sheet.panes.ySplit) {
30542
30602
  this.setPaneDivisions(sheet.id, sheet.panes.ySplit + quantity, "ROW");
30543
30603
  }
@@ -30638,35 +30698,20 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
30638
30698
  }
30639
30699
  }
30640
30700
  }
30641
- updateRowsStructureOnDeletion(index, sheet) {
30701
+ updateRowsStructureOnDeletion(sheet, deleteFromRow, deleteToRow) {
30642
30702
  const rows = [];
30643
- const cellsQueue = sheet.rows.map((row) => row.cells);
30703
+ const cellsQueue = sheet.rows.map((row) => row.cells).reverse();
30644
30704
  for (let i in sheet.rows) {
30645
- if (Number(i) === index) {
30705
+ const row = Number(i);
30706
+ if (row >= deleteFromRow && row <= deleteToRow) {
30646
30707
  continue;
30647
30708
  }
30648
30709
  rows.push({
30649
- cells: cellsQueue.shift(),
30710
+ cells: cellsQueue.pop(),
30650
30711
  });
30651
30712
  }
30652
30713
  this.history.update("sheets", sheet.id, "rows", rows);
30653
30714
  }
30654
- /**
30655
- * Update the rows of the sheet after an addition:
30656
- * - Rename the rows
30657
- *
30658
- * @param sheet Sheet on which the deletion occurs
30659
- * @param addedRow Index of the added row
30660
- * @param rowsToAdd Number of the rows to add
30661
- */
30662
- updateRowsStructureOnAddition(sheet, addedRow, rowsToAdd) {
30663
- const rows = [];
30664
- const cellsQueue = sheet.rows.map((row) => row.cells);
30665
- sheet.rows.forEach(() => rows.push({
30666
- cells: cellsQueue.shift(),
30667
- }));
30668
- this.history.update("sheets", sheet.id, "rows", rows);
30669
- }
30670
30715
  /**
30671
30716
  * Add empty rows at the end of the rows
30672
30717
  *
@@ -32533,13 +32578,18 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32533
32578
  // Getters
32534
32579
  // ---------------------------------------------------------------------------
32535
32580
  evaluateFormula(formulaString, sheetId = this.getters.getActiveSheetId()) {
32536
- const compiledFormula = compile(formulaString);
32537
- const params = this.getCompilationParameters(() => { });
32538
- const ranges = [];
32539
- for (let xc of compiledFormula.dependencies) {
32540
- ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
32581
+ try {
32582
+ const compiledFormula = compile(formulaString);
32583
+ const params = this.getCompilationParameters(() => { });
32584
+ const ranges = [];
32585
+ for (let xc of compiledFormula.dependencies) {
32586
+ ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
32587
+ }
32588
+ return compiledFormula.execute(ranges, ...params).value;
32589
+ }
32590
+ catch (error) {
32591
+ return error instanceof EvaluationError ? error.errorType : CellErrorType.GenericError;
32541
32592
  }
32542
- return compiledFormula.execute(ranges, ...params).value;
32543
32593
  }
32544
32594
  /**
32545
32595
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -32655,6 +32705,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32655
32705
  }
32656
32706
  return cell.evaluated;
32657
32707
  }
32708
+ const rangeCache = {};
32658
32709
  /**
32659
32710
  * Return the values of the cell(s) used in reference, but always in the format of a range even
32660
32711
  * if a single cell is referenced. It is a list of col values. This is useful for the formulas that describe parameters as
@@ -32671,21 +32722,26 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32671
32722
  // Performance issue: Avoid fetching data on positions that are out of the spreadsheet
32672
32723
  // e.g. A1:ZZZ9999 in a sheet with 10 cols and 10 rows should ignore everything past J10 and return a 10x10 array
32673
32724
  const sheetZone = getters.getSheetZone(sheetId);
32674
- const result = [];
32675
32725
  const zone = intersection(range.zone, sheetZone);
32676
32726
  if (!zone) {
32677
- result.push([]);
32678
- return result;
32727
+ return [[]];
32728
+ }
32729
+ const { top, left, bottom, right } = zone;
32730
+ const cacheKey = `${sheetId}-${top}-${left}-${bottom}-${right}`;
32731
+ if (cacheKey in rangeCache) {
32732
+ return rangeCache[cacheKey];
32679
32733
  }
32734
+ const result = new Array(right - left + 1);
32680
32735
  // Performance issue: nested loop is faster than a map here
32681
- for (let col = zone.left; col <= zone.right; col++) {
32682
- const rowValues = [];
32683
- for (let row = zone.top; row <= zone.bottom; row++) {
32736
+ for (let col = left; col <= right; col++) {
32737
+ const rowValues = new Array(bottom - top + 1);
32738
+ for (let row = top; row <= bottom; row++) {
32684
32739
  const cell = evalContext.getters.getCell(range.sheetId, col, row);
32685
- rowValues.push(cell ? getEvaluatedCell(cell) : undefined);
32740
+ rowValues[row - top] = cell ? getEvaluatedCell(cell) : undefined;
32686
32741
  }
32687
- result.push(rowValues);
32742
+ result[col - left] = rowValues;
32688
32743
  }
32744
+ rangeCache[cacheKey] = result;
32689
32745
  return result;
32690
32746
  }
32691
32747
  /**
@@ -32935,39 +32991,34 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32935
32991
  this.computedIcons[activeSheetId] = {};
32936
32992
  const computedStyle = this.computedStyles[activeSheetId];
32937
32993
  for (let cf of this.getters.getConditionalFormats(activeSheetId).reverse()) {
32938
- try {
32939
- switch (cf.rule.type) {
32940
- case "ColorScaleRule":
32941
- for (let range of cf.ranges) {
32942
- this.applyColorScale(range, cf.rule);
32943
- }
32944
- break;
32945
- case "IconSetRule":
32946
- for (let range of cf.ranges) {
32947
- this.applyIcon(range, cf.rule);
32948
- }
32949
- break;
32950
- default:
32951
- for (let ref of cf.ranges) {
32952
- const zone = this.getters.getRangeFromSheetXC(activeSheetId, ref).zone;
32953
- for (let row = zone.top; row <= zone.bottom; row++) {
32954
- for (let col = zone.left; col <= zone.right; col++) {
32955
- const pr = this.rulePredicate[cf.rule.type];
32956
- let cell = this.getters.getCell(activeSheetId, col, row);
32957
- if (pr && pr(cell, cf.rule)) {
32958
- if (!computedStyle[col])
32959
- computedStyle[col] = [];
32960
- // we must combine all the properties of all the CF rules applied to the given cell
32961
- computedStyle[col][row] = Object.assign(((_a = computedStyle[col]) === null || _a === void 0 ? void 0 : _a[row]) || {}, cf.rule.style);
32962
- }
32994
+ switch (cf.rule.type) {
32995
+ case "ColorScaleRule":
32996
+ for (let range of cf.ranges) {
32997
+ this.applyColorScale(range, cf.rule);
32998
+ }
32999
+ break;
33000
+ case "IconSetRule":
33001
+ for (let range of cf.ranges) {
33002
+ this.applyIcon(range, cf.rule);
33003
+ }
33004
+ break;
33005
+ default:
33006
+ for (let ref of cf.ranges) {
33007
+ const zone = this.getters.getRangeFromSheetXC(activeSheetId, ref).zone;
33008
+ for (let row = zone.top; row <= zone.bottom; row++) {
33009
+ for (let col = zone.left; col <= zone.right; col++) {
33010
+ const pr = this.rulePredicate[cf.rule.type];
33011
+ let cell = this.getters.getCell(activeSheetId, col, row);
33012
+ if (pr && pr(cell, cf.rule)) {
33013
+ if (!computedStyle[col])
33014
+ computedStyle[col] = [];
33015
+ // we must combine all the properties of all the CF rules applied to the given cell
33016
+ computedStyle[col][row] = Object.assign(((_a = computedStyle[col]) === null || _a === void 0 ? void 0 : _a[row]) || {}, cf.rule.style);
32963
33017
  }
32964
33018
  }
32965
33019
  }
32966
- break;
32967
- }
32968
- }
32969
- catch (_) {
32970
- // we don't care about the errors within the evaluation of a rule
33020
+ }
33021
+ break;
32971
33022
  }
32972
33023
  }
32973
33024
  }
@@ -32991,7 +33042,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32991
33042
  return percentile(rangeValues, Number(threshold.value) / 100, true);
32992
33043
  case "formula":
32993
33044
  const value = threshold.value && this.getters.evaluateFormula(threshold.value);
32994
- return !(value instanceof Promise) ? value : null;
33045
+ return typeof value === "number" ? value : null;
32995
33046
  default:
32996
33047
  return null;
32997
33048
  }
@@ -34939,7 +34990,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
34939
34990
  sheetId: cmd.sheetId,
34940
34991
  base: cmd.base,
34941
34992
  quantity: thickness,
34942
- position: "before",
34993
+ position: cmd.position,
34943
34994
  });
34944
34995
  const isCol = cmd.dimension === "COL";
34945
34996
  const start = cmd.elements[0];
@@ -34956,12 +35007,13 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
34956
35007
  },
34957
35008
  ];
34958
35009
  const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
35010
+ const base = isBasedBefore ? cmd.base : cmd.base + 1;
34959
35011
  const pasteTarget = [
34960
35012
  {
34961
- left: isCol ? cmd.base : 0,
34962
- right: isCol ? cmd.base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
34963
- top: !isCol ? cmd.base : 0,
34964
- bottom: !isCol ? cmd.base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
35013
+ left: isCol ? base : 0,
35014
+ right: isCol ? base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
35015
+ top: !isCol ? base : 0,
35016
+ bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
34965
35017
  },
34966
35018
  ];
34967
35019
  state.paste(pasteTarget, { selectTarget: true });
@@ -34998,6 +35050,11 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
34998
35050
  doesElementsHaveCommonMerges(id, cmd.base - 1, cmd.base)) {
34999
35051
  return 2 /* CommandResult.WillRemoveExistingMerge */;
35000
35052
  }
35053
+ const headers = [cmd.base, ...cmd.elements];
35054
+ const maxHeaderValue = isCol ? this.getters.getNumberCols(id) : this.getters.getNumberRows(id);
35055
+ if (headers.some((h) => h < 0 || h >= maxHeaderValue)) {
35056
+ return 85 /* CommandResult.InvalidHeaderIndex */;
35057
+ }
35001
35058
  return 0 /* CommandResult.Success */;
35002
35059
  }
35003
35060
  //-------------------------------------------
@@ -39064,7 +39121,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
39064
39121
  }
39065
39122
  onKeydown(ev) {
39066
39123
  let keyDownString = "";
39067
- if (ev.ctrlKey || ev.metaKey) {
39124
+ if (isCtrlKey(ev)) {
39068
39125
  keyDownString += "CTRL+";
39069
39126
  }
39070
39127
  keyDownString += ev.key.toUpperCase();
@@ -39908,9 +39965,9 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
39908
39965
  * Apply the changes of the given HistoryChange to the state
39909
39966
  */
39910
39967
  function applyChange(change, target) {
39911
- let val = change.root;
39912
- let key = change.path[change.path.length - 1];
39913
- for (let pathIndex = 0; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
39968
+ let val = change.path[0];
39969
+ const key = change.path[change.path.length - 1];
39970
+ for (let pathIndex = 1; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
39914
39971
  const p = change.path[pathIndex];
39915
39972
  if (val[p] === undefined) {
39916
39973
  const nextPath = change.path[pathIndex + 1];
@@ -41040,13 +41097,14 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
41040
41097
  }
41041
41098
  addChange(...args) {
41042
41099
  const val = args.pop();
41043
- const [root, ...path] = args;
41100
+ const root = args[0];
41044
41101
  let value = root;
41045
- let key = path[path.length - 1];
41046
- for (let pathIndex = 0; pathIndex <= path.length - 2; pathIndex++) {
41047
- const p = path[pathIndex];
41102
+ let key = args[args.length - 1];
41103
+ const pathLength = args.length - 2;
41104
+ for (let pathIndex = 1; pathIndex <= pathLength; pathIndex++) {
41105
+ const p = args[pathIndex];
41048
41106
  if (value[p] === undefined) {
41049
- const nextPath = path[pathIndex + 1];
41107
+ const nextPath = args[pathIndex + 1];
41050
41108
  value[p] = createEmptyStructure(nextPath);
41051
41109
  }
41052
41110
  value = value[p];
@@ -41055,8 +41113,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
41055
41113
  return;
41056
41114
  }
41057
41115
  this.changes.push({
41058
- root,
41059
- path,
41116
+ path: args,
41060
41117
  before: value[key],
41061
41118
  after: val,
41062
41119
  });
@@ -42790,7 +42847,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
42790
42847
  */
42791
42848
  checkDispatchAllowed(command) {
42792
42849
  const results = this.handlers.map((handler) => handler.allowDispatch(command));
42793
- return new DispatchResult(results.flat());
42850
+ if (results.some((r) => r !== 0 /* CommandResult.Success */)) {
42851
+ return new DispatchResult(results.flat());
42852
+ }
42853
+ return DispatchResult.Success;
42794
42854
  }
42795
42855
  finalize() {
42796
42856
  this.status = 3 /* Status.Finalizing */;
@@ -43010,9 +43070,9 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
43010
43070
  Object.defineProperty(exports, '__esModule', { value: true });
43011
43071
 
43012
43072
 
43013
- __info__.version = '16.0.24';
43014
- __info__.date = '2023-11-16T11:56:55.435Z';
43015
- __info__.hash = 'e0d7313';
43073
+ __info__.version = '16.0.27';
43074
+ __info__.date = '2024-01-04T12:19:11.487Z';
43075
+ __info__.hash = '54006f6';
43016
43076
 
43017
43077
 
43018
43078
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);