@odoo/o-spreadsheet 16.2.2 → 16.2.4

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.
@@ -1008,6 +1008,10 @@ function deepEquals(o1, o2) {
1008
1008
  }
1009
1009
  return true;
1010
1010
  }
1011
+ /** Check if the given array contains all the values of the other array. */
1012
+ function includesAll(arr, values) {
1013
+ return values.every((value) => arr.includes(value));
1014
+ }
1011
1015
  /**
1012
1016
  * Return an object with all the keys in the object that have a falsy value removed.
1013
1017
  */
@@ -1681,12 +1685,77 @@ const numberRepresentation = [];
1681
1685
  * - all digit stored in the decimal part of the number
1682
1686
  *
1683
1687
  * The 'maxDecimal' parameter allows to indicate the number of digits to not
1684
- * exceed in the decimal part, in which case digits are rounded
1688
+ * exceed in the decimal part, in which case digits are rounded.
1685
1689
  *
1686
- * Intl.Numberformat is used to properly handle all the roundings.
1687
- * e.g. 1234.7 with format ### (<> maxDecimals=0) should become 1235, not 1234
1688
1690
  **/
1689
1691
  function splitNumber(value, maxDecimals = MAX_DECIMAL_PLACES) {
1692
+ const asString = value.toString();
1693
+ if (asString.includes("e"))
1694
+ return splitNumberIntl(value, maxDecimals);
1695
+ if (Number.isInteger(value)) {
1696
+ return { integerDigits: asString, decimalDigits: undefined };
1697
+ }
1698
+ const indexOfDot = asString.indexOf(".");
1699
+ let integerDigits = asString.substring(0, indexOfDot);
1700
+ let decimalDigits = asString.substring(indexOfDot + 1);
1701
+ if (maxDecimals === 0) {
1702
+ if (Number(decimalDigits[0]) >= 5) {
1703
+ integerDigits = (Number(integerDigits) + 1).toString();
1704
+ }
1705
+ return { integerDigits, decimalDigits: undefined };
1706
+ }
1707
+ if (decimalDigits.length > maxDecimals) {
1708
+ const { integerDigits: roundedIntegerDigits, decimalDigits: roundedDecimalDigits } = limitDecimalDigits(decimalDigits, maxDecimals);
1709
+ decimalDigits = roundedDecimalDigits;
1710
+ if (roundedIntegerDigits !== "0") {
1711
+ integerDigits = (Number(integerDigits) + Number(roundedIntegerDigits)).toString();
1712
+ }
1713
+ }
1714
+ return { integerDigits, decimalDigits: removeTrailingZeroes(decimalDigits || "") };
1715
+ }
1716
+ /**
1717
+ * Return the given string minus the trailing "0" characters.
1718
+ *
1719
+ * @param numberString : a string of integers
1720
+ * @returns the numberString, minus the eventual zeroes at the end
1721
+ */
1722
+ function removeTrailingZeroes(numberString) {
1723
+ let i = numberString.length - 1;
1724
+ while (i >= 0 && numberString[i] === "0") {
1725
+ i--;
1726
+ }
1727
+ return numberString.slice(0, i + 1) || undefined;
1728
+ }
1729
+ /**
1730
+ * Limit the size of the decimal part of a number to the given number of digits.
1731
+ */
1732
+ function limitDecimalDigits(decimalDigits, maxDecimals) {
1733
+ let integerDigits = "0";
1734
+ let resultDecimalDigits = decimalDigits;
1735
+ // Note : we'd want to simply use number.toFixed() to handle the max digits & rounding,
1736
+ // but it has very strange behaviour. Ex: 12.345.toFixed(2) => "12.35", but 1.345.toFixed(2) => "1.34"
1737
+ let slicedDecimalDigits = decimalDigits.slice(0, maxDecimals);
1738
+ const i = maxDecimals;
1739
+ if (Number(Number(decimalDigits[i]) < 5)) {
1740
+ return { integerDigits, decimalDigits: slicedDecimalDigits };
1741
+ }
1742
+ // round up
1743
+ const slicedRoundedUp = (Number(slicedDecimalDigits) + 1).toString();
1744
+ if (slicedRoundedUp.length > slicedDecimalDigits.length) {
1745
+ integerDigits = (Number(integerDigits) + 1).toString();
1746
+ resultDecimalDigits = undefined;
1747
+ }
1748
+ else {
1749
+ resultDecimalDigits = slicedRoundedUp;
1750
+ }
1751
+ return { integerDigits, decimalDigits: resultDecimalDigits };
1752
+ }
1753
+ /**
1754
+ * Split numbers into decimal/integer digits using Intl.NumberFormat.
1755
+ * Supports numbers with a lot of digits that are transformed to scientific notation by
1756
+ * number.toString(), but is slow.
1757
+ */
1758
+ function splitNumberIntl(value, maxDecimals = MAX_DECIMAL_PLACES) {
1690
1759
  let formatter = numberRepresentation[maxDecimals];
1691
1760
  if (!formatter) {
1692
1761
  formatter = new Intl.NumberFormat("en-US", {
@@ -9135,6 +9204,11 @@ colMenuRegistry
9135
9204
  name: REMOVE_COLUMNS_NAME,
9136
9205
  sequence: 90,
9137
9206
  action: REMOVE_COLUMNS_ACTION,
9207
+ isVisible: (env) => {
9208
+ const sheetId = env.model.getters.getActiveSheetId();
9209
+ const selectedCols = env.model.getters.getElementsFromSelection("COL");
9210
+ return env.model.getters.canRemoveHeaders(sheetId, "COL", selectedCols);
9211
+ },
9138
9212
  })
9139
9213
  .add("clear_column", {
9140
9214
  name: DELETE_CONTENT_COLUMNS_NAME,
@@ -9147,9 +9221,8 @@ colMenuRegistry
9147
9221
  action: HIDE_COLUMNS_ACTION,
9148
9222
  isVisible: (env) => {
9149
9223
  const sheetId = env.model.getters.getActiveSheetId();
9150
- const hiddenCols = env.model.getters.getHiddenColsGroups(sheetId).flat();
9151
- return (env.model.getters.getNumberCols(sheetId) >
9152
- hiddenCols.length + env.model.getters.getElementsFromSelection("COL").length);
9224
+ const selectedCols = env.model.getters.getElementsFromSelection("COL");
9225
+ return env.model.getters.canRemoveHeaders(sheetId, "COL", selectedCols);
9153
9226
  },
9154
9227
  separator: true,
9155
9228
  })
@@ -9223,6 +9296,11 @@ rowMenuRegistry
9223
9296
  name: REMOVE_ROWS_NAME,
9224
9297
  sequence: 70,
9225
9298
  action: REMOVE_ROWS_ACTION,
9299
+ isVisible: (env) => {
9300
+ const sheetId = env.model.getters.getActiveSheetId();
9301
+ const selectedRows = env.model.getters.getElementsFromSelection("ROW");
9302
+ return env.model.getters.canRemoveHeaders(sheetId, "ROW", selectedRows);
9303
+ },
9226
9304
  })
9227
9305
  .add("clear_row", {
9228
9306
  name: DELETE_CONTENT_ROWS_NAME,
@@ -9235,9 +9313,8 @@ rowMenuRegistry
9235
9313
  action: HIDE_ROWS_ACTION,
9236
9314
  isVisible: (env) => {
9237
9315
  const sheetId = env.model.getters.getActiveSheetId();
9238
- const hiddenRows = env.model.getters.getHiddenRowsGroups(sheetId).flat();
9239
- return (env.model.getters.getNumberRows(sheetId) >
9240
- hiddenRows.length + env.model.getters.getElementsFromSelection("ROW").length);
9316
+ const selectedRows = env.model.getters.getElementsFromSelection("ROW");
9317
+ return env.model.getters.canRemoveHeaders(sheetId, "ROW", selectedRows);
9241
9318
  },
9242
9319
  separator: true,
9243
9320
  })
@@ -21973,8 +22050,8 @@ class Grid extends owl.Component {
21973
22050
  },
21974
22051
  "CTRL+END": () => {
21975
22052
  const sheetId = this.env.model.getters.getActiveSheetId();
21976
- const col = this.env.model.getters.findVisibleHeader(sheetId, "COL", range(0, this.env.model.getters.getNumberCols(sheetId)).reverse());
21977
- const row = this.env.model.getters.findVisibleHeader(sheetId, "ROW", range(0, this.env.model.getters.getNumberRows(sheetId)).reverse());
22053
+ const col = this.env.model.getters.findVisibleHeader(sheetId, "COL", this.env.model.getters.getNumberCols(sheetId) - 1, 0);
22054
+ const row = this.env.model.getters.findVisibleHeader(sheetId, "ROW", this.env.model.getters.getNumberRows(sheetId) - 1, 0);
21978
22055
  this.env.model.selection.selectCell(col, row);
21979
22056
  },
21980
22057
  "SHIFT+ ": () => {
@@ -22054,9 +22131,10 @@ class Grid extends owl.Component {
22054
22131
  this.focus();
22055
22132
  }
22056
22133
  focus() {
22134
+ var _a;
22057
22135
  if (!this.env.model.getters.getSelectedFigureId() &&
22058
22136
  this.env.model.getters.getEditionMode() === "inactive") {
22059
- this.hiddenInput.el.focus();
22137
+ (_a = this.hiddenInput.el) === null || _a === void 0 ? void 0 : _a.focus();
22060
22138
  }
22061
22139
  }
22062
22140
  get gridEl() {
@@ -25951,7 +26029,7 @@ function load(data, verboseImport) {
25951
26029
  }
25952
26030
  }
25953
26031
  }
25954
- data = JSON.parse(JSON.stringify(data));
26032
+ data = deepCopy(data);
25955
26033
  // apply migrations, if needed
25956
26034
  if ("version" in data) {
25957
26035
  if (data.version < CURRENT_VERSION) {
@@ -29394,7 +29472,7 @@ class HeaderVisibilityPlugin extends CorePlugin {
29394
29472
  allowDispatch(cmd) {
29395
29473
  switch (cmd.type) {
29396
29474
  case "HIDE_COLUMNS_ROWS": {
29397
- if (!this.hiddenHeaders[cmd.sheetId]) {
29475
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
29398
29476
  return 27 /* CommandResult.InvalidSheetId */;
29399
29477
  }
29400
29478
  const hiddenGroup = cmd.dimension === "COL"
@@ -29407,6 +29485,14 @@ class HeaderVisibilityPlugin extends CorePlugin {
29407
29485
  ? 0 /* CommandResult.Success */
29408
29486
  : 66 /* CommandResult.TooManyHiddenElements */;
29409
29487
  }
29488
+ case "REMOVE_COLUMNS_ROWS":
29489
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
29490
+ return 27 /* CommandResult.InvalidSheetId */;
29491
+ }
29492
+ if (!this.canRemoveHeaders(cmd.sheetId, cmd.dimension, cmd.elements)) {
29493
+ return 8 /* CommandResult.NotEnoughElements */;
29494
+ }
29495
+ return 0 /* CommandResult.Success */;
29410
29496
  }
29411
29497
  return 0 /* CommandResult.Success */;
29412
29498
  }
@@ -29453,6 +29539,10 @@ class HeaderVisibilityPlugin extends CorePlugin {
29453
29539
  }
29454
29540
  return;
29455
29541
  }
29542
+ canRemoveHeaders(sheetId, dimension, elements) {
29543
+ const visibleHeaders = this.getAllVisibleHeaders(sheetId, dimension);
29544
+ return !includesAll(elements, visibleHeaders);
29545
+ }
29456
29546
  isRowHiddenByUser(sheetId, index) {
29457
29547
  return this.hiddenHeaders[sheetId].ROW[index];
29458
29548
  }
@@ -29497,6 +29587,9 @@ class HeaderVisibilityPlugin extends CorePlugin {
29497
29587
  }
29498
29588
  return consecutiveIndexes;
29499
29589
  }
29590
+ getAllVisibleHeaders(sheetId, dimension) {
29591
+ return range(0, this.hiddenHeaders[sheetId][dimension].length).filter((i) => !this.hiddenHeaders[sheetId][dimension][i]);
29592
+ }
29500
29593
  import(data) {
29501
29594
  var _a, _b;
29502
29595
  for (let sheet of data.sheets) {
@@ -29544,6 +29637,7 @@ class HeaderVisibilityPlugin extends CorePlugin {
29544
29637
  }
29545
29638
  }
29546
29639
  HeaderVisibilityPlugin.getters = [
29640
+ "canRemoveHeaders",
29547
29641
  "getHiddenColsGroups",
29548
29642
  "getHiddenRowsGroups",
29549
29643
  "isRowHiddenByUser",
@@ -30562,14 +30656,6 @@ class SheetPlugin extends CorePlugin {
30562
30656
  return this.orderedSheetIds.length > 1
30563
30657
  ? 0 /* CommandResult.Success */
30564
30658
  : 9 /* CommandResult.NotEnoughSheets */;
30565
- case "REMOVE_COLUMNS_ROWS": {
30566
- const length = cmd.dimension === "COL"
30567
- ? this.getNumberCols(cmd.sheetId)
30568
- : this.getNumberRows(cmd.sheetId);
30569
- return length > cmd.elements.length
30570
- ? 0 /* CommandResult.Success */
30571
- : 8 /* CommandResult.NotEnoughElements */;
30572
- }
30573
30659
  case "FREEZE_ROWS": {
30574
30660
  return this.checkValidations(cmd, this.checkRowFreezeQuantity, this.checkRowFreezeOverlapMerge);
30575
30661
  }
@@ -31036,7 +31122,7 @@ class SheetPlugin extends CorePlugin {
31036
31122
  duplicateSheet(fromId, toId) {
31037
31123
  const sheet = this.getSheet(fromId);
31038
31124
  const toName = this.getDuplicateSheetName(sheet.name);
31039
- const newSheet = JSON.parse(JSON.stringify(sheet));
31125
+ const newSheet = deepCopy(sheet);
31040
31126
  newSheet.id = toId;
31041
31127
  newSheet.name = toName;
31042
31128
  for (let col = 0; col <= newSheet.numberOfCols; col++) {
@@ -31163,10 +31249,10 @@ class SheetPlugin extends CorePlugin {
31163
31249
  }
31164
31250
  }
31165
31251
  moveCellOnColumnsDeletion(sheet, deletedColumn) {
31166
- for (let [index, row] of Object.entries(sheet.rows)) {
31167
- const rowIndex = parseInt(index, 10);
31252
+ for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
31253
+ const row = sheet.rows[rowIndex];
31168
31254
  for (let i in row.cells) {
31169
- const colIndex = parseInt(i, 10);
31255
+ const colIndex = Number(i);
31170
31256
  const cellId = row.cells[i];
31171
31257
  if (cellId) {
31172
31258
  if (colIndex === deletedColumn) {
@@ -31193,11 +31279,11 @@ class SheetPlugin extends CorePlugin {
31193
31279
  */
31194
31280
  moveCellsOnAddition(sheet, addedElement, quantity, dimension) {
31195
31281
  const commands = [];
31196
- for (const [index, row] of Object.entries(sheet.rows)) {
31197
- const rowIndex = parseInt(index, 10);
31282
+ for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
31283
+ const row = sheet.rows[rowIndex];
31198
31284
  if (dimension !== "rows" || rowIndex >= addedElement) {
31199
31285
  for (let i in row.cells) {
31200
- const colIndex = parseInt(i, 10);
31286
+ const colIndex = Number(i);
31201
31287
  const cellId = row.cells[i];
31202
31288
  if (cellId) {
31203
31289
  if (dimension === "rows" || colIndex >= addedElement) {
@@ -31227,11 +31313,11 @@ class SheetPlugin extends CorePlugin {
31227
31313
  */
31228
31314
  moveCellOnRowsDeletion(sheet, deleteFromRow, deleteToRow) {
31229
31315
  const numberRows = deleteToRow - deleteFromRow + 1;
31230
- for (let [index, row] of Object.entries(sheet.rows)) {
31231
- const rowIndex = parseInt(index, 10);
31316
+ for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
31317
+ const row = sheet.rows[rowIndex];
31232
31318
  if (rowIndex >= deleteFromRow && rowIndex <= deleteToRow) {
31233
31319
  for (let i in row.cells) {
31234
- const colIndex = parseInt(i, 10);
31320
+ const colIndex = Number(i);
31235
31321
  const cellId = row.cells[i];
31236
31322
  if (cellId) {
31237
31323
  this.dispatch("CLEAR_CELL", {
@@ -31244,7 +31330,7 @@ class SheetPlugin extends CorePlugin {
31244
31330
  }
31245
31331
  if (rowIndex > deleteToRow) {
31246
31332
  for (let i in row.cells) {
31247
- const colIndex = parseInt(i, 10);
31333
+ const colIndex = Number(i);
31248
31334
  const cellId = row.cells[i];
31249
31335
  if (cellId) {
31250
31336
  this.dispatch("UPDATE_CELL_POSITION", {
@@ -31262,7 +31348,7 @@ class SheetPlugin extends CorePlugin {
31262
31348
  const rows = [];
31263
31349
  const cellsQueue = sheet.rows.map((row) => row.cells);
31264
31350
  for (let i in sheet.rows) {
31265
- if (parseInt(i, 10) === index) {
31351
+ if (Number(i) === index) {
31266
31352
  continue;
31267
31353
  }
31268
31354
  rows.push({
@@ -32433,13 +32519,11 @@ class FilterEvaluationPlugin extends UIPlugin {
32433
32519
  return Boolean(id && ((_b = (_a = this.filterValues[sheetId]) === null || _a === void 0 ? void 0 : _a[id]) === null || _b === void 0 ? void 0 : _b.length));
32434
32520
  }
32435
32521
  intersectZoneWithViewport(sheetId, zone) {
32436
- const colsRange = range(zone.left, zone.right + 1);
32437
- const rowsRange = range(zone.top, zone.bottom + 1);
32438
32522
  return {
32439
- left: this.getters.findVisibleHeader(sheetId, "COL", colsRange),
32440
- right: this.getters.findVisibleHeader(sheetId, "COL", colsRange.reverse()),
32441
- top: this.getters.findVisibleHeader(sheetId, "ROW", rowsRange),
32442
- bottom: this.getters.findVisibleHeader(sheetId, "ROW", rowsRange.reverse()),
32523
+ left: this.getters.findVisibleHeader(sheetId, "COL", zone.left, zone.right),
32524
+ right: this.getters.findVisibleHeader(sheetId, "COL", zone.right, zone.left),
32525
+ top: this.getters.findVisibleHeader(sheetId, "ROW", zone.top, zone.bottom),
32526
+ bottom: this.getters.findVisibleHeader(sheetId, "ROW", zone.bottom, zone.top),
32443
32527
  };
32444
32528
  }
32445
32529
  updateFilter({ col, row, values, sheetId }) {
@@ -32643,48 +32727,66 @@ class InternalViewport {
32643
32727
  this.adjustPositionY(row);
32644
32728
  }
32645
32729
  }
32646
- adjustPositionX(col) {
32730
+ adjustPositionX(targetCol) {
32647
32731
  const sheetId = this.sheetId;
32648
- const { start, end } = this.getters.getColDimensions(sheetId, col);
32649
- while (end > this.offsetX + this.offsetCorrectionX + this.viewportWidth &&
32650
- this.offsetX + this.offsetCorrectionX < start) {
32651
- this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
32652
- this.offsetScrollbarX = this.offsetX;
32653
- this.adjustViewportZoneX();
32654
- }
32655
- while (col < this.left) {
32656
- let leftCol;
32657
- for (leftCol = this.left; leftCol >= 0; leftCol--) {
32658
- if (!this.getters.isColHidden(sheetId, leftCol)) {
32732
+ const { end } = this.getters.getColDimensions(sheetId, targetCol);
32733
+ const maxCol = this.getters.getNumberCols(sheetId);
32734
+ if (this.offsetX + this.offsetCorrectionX + this.viewportWidth < end) {
32735
+ for (let col = this.left; this.offsetX + this.offsetCorrectionX + this.viewportWidth < end; col++) {
32736
+ if (col > maxCol) {
32659
32737
  break;
32660
32738
  }
32739
+ if (this.getters.isColHidden(sheetId, col)) {
32740
+ continue;
32741
+ }
32742
+ this.offsetX = this.getters.getColDimensions(sheetId, col).end - this.offsetCorrectionX;
32743
+ this.offsetScrollbarX = this.offsetX;
32744
+ this.adjustViewportZoneX();
32745
+ }
32746
+ }
32747
+ else if (this.left > targetCol) {
32748
+ for (let col = this.left; col >= targetCol; col--) {
32749
+ if (col < 0) {
32750
+ break;
32751
+ }
32752
+ if (this.getters.isColHidden(sheetId, col)) {
32753
+ continue;
32754
+ }
32755
+ this.offsetX = this.getters.getColDimensions(sheetId, col).start - this.offsetCorrectionX;
32756
+ this.offsetScrollbarX = this.offsetX;
32757
+ this.adjustViewportZoneX();
32661
32758
  }
32662
- this.offsetX =
32663
- this.getters.getColDimensions(sheetId, leftCol - 1).start - this.offsetCorrectionX;
32664
- this.offsetScrollbarX = this.offsetX;
32665
- this.adjustViewportZoneX();
32666
32759
  }
32667
32760
  }
32668
- adjustPositionY(row) {
32761
+ adjustPositionY(targetRow) {
32669
32762
  const sheetId = this.sheetId;
32670
- while (this.getters.getRowDimensions(sheetId, row).end >
32671
- this.offsetY + this.viewportHeight + this.offsetCorrectionY &&
32672
- this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
32673
- this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
32674
- this.offsetScrollbarY = this.offsetY;
32675
- this.adjustViewportZoneY();
32676
- }
32677
- while (row < this.top) {
32678
- let topRow;
32679
- for (topRow = this.top; topRow >= 0; topRow--) {
32680
- if (!this.getters.isRowHidden(sheetId, topRow)) {
32763
+ const { end } = this.getters.getRowDimensions(sheetId, targetRow);
32764
+ const maxRow = this.getters.getNumberRows(sheetId);
32765
+ if (this.offsetY + this.viewportHeight + this.offsetCorrectionY < end) {
32766
+ for (let row = this.top; this.offsetY + this.viewportHeight + this.offsetCorrectionY < end; row++) {
32767
+ if (row > maxRow) {
32681
32768
  break;
32682
32769
  }
32770
+ if (this.getters.isRowHidden(sheetId, row)) {
32771
+ continue;
32772
+ }
32773
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).end - this.offsetCorrectionY;
32774
+ this.offsetScrollbarY = this.offsetY;
32775
+ this.adjustViewportZoneY();
32776
+ }
32777
+ }
32778
+ else if (this.top > targetRow) {
32779
+ for (let row = this.top; row >= targetRow; row--) {
32780
+ if (row < 0) {
32781
+ break;
32782
+ }
32783
+ if (this.getters.isRowHidden(sheetId, row)) {
32784
+ continue;
32785
+ }
32786
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).start - this.offsetCorrectionY;
32787
+ this.offsetScrollbarY = this.offsetY;
32788
+ this.adjustViewportZoneY();
32683
32789
  }
32684
- this.offsetY =
32685
- this.getters.getRowDimensions(sheetId, topRow - 1).start - this.offsetCorrectionY;
32686
- this.offsetScrollbarY = this.offsetY;
32687
- this.adjustViewportZoneY();
32688
32790
  }
32689
32791
  }
32690
32792
  setViewportOffset(offsetX, offsetY) {
@@ -34528,13 +34630,33 @@ class HeaderVisibilityUIPlugin extends UIPlugin {
34528
34630
  getNextVisibleCellPosition({ sheetId, col, row }) {
34529
34631
  return {
34530
34632
  sheetId,
34531
- col: this.findVisibleHeader(sheetId, "COL", range(col, this.getters.getNumberCols(sheetId))),
34532
- row: this.findVisibleHeader(sheetId, "ROW", range(row, this.getters.getNumberRows(sheetId))),
34633
+ col: this.findVisibleHeader(sheetId, "COL", col, this.getters.getNumberCols(sheetId) - 1),
34634
+ row: this.findVisibleHeader(sheetId, "ROW", row, this.getters.getNumberRows(sheetId) - 1),
34533
34635
  };
34534
34636
  }
34535
- findVisibleHeader(sheetId, dimension, indexes) {
34536
- return indexes.find((index) => this.getters.doesHeaderExist(sheetId, dimension, index) &&
34537
- !this.isHeaderHidden(sheetId, dimension, index));
34637
+ /**
34638
+ * Find the first visible header in the range [`from` => `to`].
34639
+ *
34640
+ * Both `from` and `to` are inclusive.
34641
+ */
34642
+ findVisibleHeader(sheetId, dimension, from, to) {
34643
+ if (from <= to) {
34644
+ for (let i = from; i <= to; i++) {
34645
+ if (this.getters.doesHeaderExist(sheetId, dimension, i) &&
34646
+ !this.isHeaderHidden(sheetId, dimension, i)) {
34647
+ return i;
34648
+ }
34649
+ }
34650
+ }
34651
+ if (from > to) {
34652
+ for (let i = from; i >= to; i--) {
34653
+ if (this.getters.doesHeaderExist(sheetId, dimension, i) &&
34654
+ !this.isHeaderHidden(sheetId, dimension, i)) {
34655
+ return i;
34656
+ }
34657
+ }
34658
+ }
34659
+ return undefined;
34538
34660
  }
34539
34661
  findLastVisibleColRowIndex(sheetId, dimension, { last, first }) {
34540
34662
  const lastVisibleIndex = range(last, first, -1).find((index) => !this.isHeaderHidden(sheetId, dimension, index));
@@ -34542,7 +34664,7 @@ class HeaderVisibilityUIPlugin extends UIPlugin {
34542
34664
  }
34543
34665
  findFirstVisibleColRowIndex(sheetId, dimension) {
34544
34666
  const numberOfHeaders = this.getters.getNumberHeaders(sheetId, dimension);
34545
- for (let i = 0; i < numberOfHeaders - 1; i++) {
34667
+ for (let i = 0; i < numberOfHeaders; i++) {
34546
34668
  if (dimension === "COL" && !this.isColHidden(sheetId, i)) {
34547
34669
  return i;
34548
34670
  }
@@ -42746,8 +42868,8 @@ class SelectionStreamProcessorImpl {
42746
42868
  }
42747
42869
  const { left, right, top, bottom } = zone;
42748
42870
  const sheetId = this.getters.getActiveSheetId();
42749
- const refCol = this.getters.findVisibleHeader(sheetId, "COL", range(left, right + 1));
42750
- const refRow = this.getters.findVisibleHeader(sheetId, "ROW", range(top, bottom + 1));
42871
+ const refCol = this.getters.findVisibleHeader(sheetId, "COL", left, right);
42872
+ const refRow = this.getters.findVisibleHeader(sheetId, "ROW", top, bottom);
42751
42873
  if (refRow === undefined || refCol === undefined) {
42752
42874
  return 17 /* CommandResult.SelectionOutOfBound */;
42753
42875
  }
@@ -42822,10 +42944,10 @@ class SelectionStreamProcessorImpl {
42822
42944
  const { col: anchorCol, row: anchorRow } = anchor.cell;
42823
42945
  return {
42824
42946
  col: this.getters.isColHidden(sheetId, anchorCol)
42825
- ? this.getters.findVisibleHeader(sheetId, "COL", range(left, right + 1)) || anchorCol
42947
+ ? this.getters.findVisibleHeader(sheetId, "COL", left, right) || anchorCol
42826
42948
  : anchorCol,
42827
42949
  row: this.getters.isRowHidden(sheetId, anchorRow)
42828
- ? this.getters.findVisibleHeader(sheetId, "ROW", range(top, bottom + 1)) || anchorRow
42950
+ ? this.getters.findVisibleHeader(sheetId, "ROW", top, bottom) || anchorRow
42829
42951
  : anchorRow,
42830
42952
  };
42831
42953
  }
@@ -44575,6 +44697,8 @@ class Model extends EventBus {
44575
44697
  * Internal status of the model. Important for command handling coordination
44576
44698
  */
44577
44699
  this.status = 0 /* Status.Ready */;
44700
+ this.handlers = [];
44701
+ this.coreHandlers = [];
44578
44702
  /**
44579
44703
  * The dispatch method is the only entry point to manipulate data in the model.
44580
44704
  * This is through this method that commands are dispatched most of the time
@@ -44679,6 +44803,8 @@ class Model extends EventBus {
44679
44803
  this.uuidGenerator.setIsFastStrategy(true);
44680
44804
  // Initiate stream processor
44681
44805
  this.selection = new SelectionStreamProcessorImpl(this.getters);
44806
+ this.coreHandlers.push(this.range);
44807
+ this.handlers.push(this.range);
44682
44808
  this.corePluginConfig = this.setupCorePluginConfig();
44683
44809
  this.uiPluginConfig = this.setupUiPluginConfig();
44684
44810
  // registering plugins
@@ -44687,15 +44813,23 @@ class Model extends EventBus {
44687
44813
  }
44688
44814
  Object.assign(this.getters, this.coreGetters);
44689
44815
  for (let Plugin of statefulUIPluginRegistry.getAll()) {
44690
- this.statefulUIPlugins.push(this.setupUiPlugin(Plugin));
44816
+ const plugin = this.setupUiPlugin(Plugin);
44817
+ this.statefulUIPlugins.push(plugin);
44818
+ this.handlers.push(plugin);
44691
44819
  }
44692
44820
  for (let Plugin of coreViewsPluginRegistry.getAll()) {
44693
- this.coreViewsPlugins.push(this.setupUiPlugin(Plugin));
44821
+ const plugin = this.setupUiPlugin(Plugin);
44822
+ this.coreViewsPlugins.push(plugin);
44823
+ this.handlers.push(plugin);
44824
+ this.coreHandlers.push(plugin);
44694
44825
  }
44695
44826
  for (let Plugin of featurePluginRegistry.getAll()) {
44696
- this.featurePlugins.push(this.setupUiPlugin(Plugin));
44827
+ const plugin = this.setupUiPlugin(Plugin);
44828
+ this.featurePlugins.push(plugin);
44829
+ this.handlers.push(plugin);
44697
44830
  }
44698
44831
  this.uuidGenerator.setIsFastStrategy(false);
44832
+ this.handlers.push(this.history);
44699
44833
  // starting plugins
44700
44834
  this.dispatch("START");
44701
44835
  // Model should be the last permanent subscriber in the list since he should render
@@ -44717,12 +44851,6 @@ class Model extends EventBus {
44717
44851
  // by owl, since we do not rely on reactivity
44718
44852
  owl.markRaw(this);
44719
44853
  }
44720
- get handlers() {
44721
- return [this.range, ...this.corePlugins, ...this.allUIPlugins, this.history];
44722
- }
44723
- get allUIPlugins() {
44724
- return [...this.statefulUIPlugins, ...this.coreViewsPlugins, ...this.featurePlugins];
44725
- }
44726
44854
  joinSession() {
44727
44855
  this.session.join(this.config.client);
44728
44856
  }
@@ -44764,6 +44892,8 @@ class Model extends EventBus {
44764
44892
  }
44765
44893
  plugin.import(data);
44766
44894
  this.corePlugins.push(plugin);
44895
+ this.coreHandlers.push(plugin);
44896
+ this.handlers.push(plugin);
44767
44897
  }
44768
44898
  onRemoteRevisionReceived({ commands }) {
44769
44899
  for (let command of commands) {
@@ -44906,7 +45036,7 @@ class Model extends EventBus {
44906
45036
  }
44907
45037
  }
44908
45038
  data.revisionId = this.session.getRevisionId() || DEFAULT_REVISION_ID;
44909
- data = JSON.parse(JSON.stringify(data));
45039
+ data = deepCopy(data);
44910
45040
  return data;
44911
45041
  }
44912
45042
  updateMode(mode) {
@@ -44934,7 +45064,7 @@ class Model extends EventBus {
44934
45064
  handler.exportForExcel(data);
44935
45065
  }
44936
45066
  }
44937
- data = JSON.parse(JSON.stringify(data));
45067
+ data = deepCopy(data);
44938
45068
  return getXLSX(data);
44939
45069
  }
44940
45070
  garbageCollectExternalResources() {
@@ -45074,6 +45204,6 @@ exports.setTranslationMethod = setTranslationMethod;
45074
45204
  exports.tokenize = tokenize;
45075
45205
 
45076
45206
 
45077
- __info__.version = '16.2.2';
45078
- __info__.date = '2023-04-13T08:29:22.236Z';
45079
- __info__.hash = 'a38f31a';
45207
+ __info__.version = '16.2.4';
45208
+ __info__.date = '2023-04-21T07:30:02.765Z';
45209
+ __info__.hash = '7169d69';
@@ -984,9 +984,9 @@ declare class Model extends EventBus<any> implements CommandDispatcher {
984
984
  */
985
985
  private coreGetters;
986
986
  uuidGenerator: UuidGenerator;
987
+ private readonly handlers;
988
+ private readonly coreHandlers;
987
989
  constructor(data?: any, config?: Partial<ModelConfig>, stateUpdateMessages?: StateUpdateMessage[], uuidGenerator?: UuidGenerator, verboseImport?: boolean);
988
- get handlers(): CommandHandler<Command>[];
989
- get allUIPlugins(): UIPlugin[];
990
990
  joinSession(): void;
991
991
  leaveSession(): void;
992
992
  private setupUiPlugin;
@@ -3384,14 +3384,16 @@ declare class HeaderSizePlugin extends CorePlugin<HeaderSizeState> implements He
3384
3384
  }
3385
3385
 
3386
3386
  declare class HeaderVisibilityPlugin extends CorePlugin {
3387
- static getters: readonly ["getHiddenColsGroups", "getHiddenRowsGroups", "isRowHiddenByUser", "isColHiddenByUser"];
3387
+ static getters: readonly ["canRemoveHeaders", "getHiddenColsGroups", "getHiddenRowsGroups", "isRowHiddenByUser", "isColHiddenByUser"];
3388
3388
  private readonly hiddenHeaders;
3389
- allowDispatch(cmd: Command): CommandResult.Success | CommandResult.InvalidSheetId | CommandResult.TooManyHiddenElements;
3389
+ allowDispatch(cmd: Command): CommandResult.Success | CommandResult.NotEnoughElements | CommandResult.InvalidSheetId | CommandResult.TooManyHiddenElements;
3390
3390
  handle(cmd: Command): void;
3391
+ canRemoveHeaders(sheetId: UID, dimension: Dimension, elements: HeaderIndex[]): boolean;
3391
3392
  isRowHiddenByUser(sheetId: UID, index: HeaderIndex): boolean;
3392
3393
  isColHiddenByUser(sheetId: UID, index: HeaderIndex): boolean;
3393
3394
  getHiddenColsGroups(sheetId: UID): ConsecutiveIndexes[];
3394
3395
  getHiddenRowsGroups(sheetId: UID): ConsecutiveIndexes[];
3396
+ private getAllVisibleHeaders;
3395
3397
  import(data: WorkbookData): void;
3396
3398
  exportForExcel(data: ExcelWorkbookData): void;
3397
3399
  export(data: WorkbookData): void;
@@ -3844,8 +3846,8 @@ declare class InternalViewport {
3844
3846
  * until it contains the cell completely.
3845
3847
  */
3846
3848
  adjustPosition(position?: Position$1): void;
3847
- adjustPositionX(col: HeaderIndex): void;
3848
- adjustPositionY(row: HeaderIndex): void;
3849
+ adjustPositionX(targetCol: HeaderIndex): void;
3850
+ adjustPositionY(targetRow: HeaderIndex): void;
3849
3851
  setViewportOffset(offsetX: Pixel, offsetY: Pixel): void;
3850
3852
  adjustViewportZone(): void;
3851
3853
  /**
@@ -4199,7 +4201,12 @@ declare class HeaderVisibilityUIPlugin extends UIPlugin {
4199
4201
  isColHidden(sheetId: UID, index: number): boolean;
4200
4202
  isHeaderHidden(sheetId: UID, dimension: Dimension, index: number): boolean;
4201
4203
  getNextVisibleCellPosition({ sheetId, col, row }: CellPosition): CellPosition;
4202
- findVisibleHeader(sheetId: UID, dimension: Dimension, indexes: number[]): number | undefined;
4204
+ /**
4205
+ * Find the first visible header in the range [`from` => `to`].
4206
+ *
4207
+ * Both `from` and `to` are inclusive.
4208
+ */
4209
+ findVisibleHeader(sheetId: UID, dimension: Dimension, from: number, to: number): number | undefined;
4203
4210
  findLastVisibleColRowIndex(sheetId: UID, dimension: Dimension, { last, first }: {
4204
4211
  first: HeaderIndex;
4205
4212
  last: HeaderIndex;