@odoo/o-spreadsheet 16.1.8 → 16.1.10

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.
@@ -1023,6 +1023,10 @@ function deepEquals(o1, o2) {
1023
1023
  }
1024
1024
  return true;
1025
1025
  }
1026
+ /** Check if the given array contains all the values of the other array. */
1027
+ function includesAll(arr, values) {
1028
+ return values.every((value) => arr.includes(value));
1029
+ }
1026
1030
  /**
1027
1031
  * Return an object with all the keys in the object that have a falsy value removed.
1028
1032
  */
@@ -1662,12 +1666,77 @@ const numberRepresentation = [];
1662
1666
  * - all digit stored in the decimal part of the number
1663
1667
  *
1664
1668
  * The 'maxDecimal' parameter allows to indicate the number of digits to not
1665
- * exceed in the decimal part, in which case digits are rounded
1669
+ * exceed in the decimal part, in which case digits are rounded.
1666
1670
  *
1667
- * Intl.Numberformat is used to properly handle all the roundings.
1668
- * e.g. 1234.7 with format ### (<> maxDecimals=0) should become 1235, not 1234
1669
1671
  **/
1670
1672
  function splitNumber(value, maxDecimals = MAX_DECIMAL_PLACES) {
1673
+ const asString = value.toString();
1674
+ if (asString.includes("e"))
1675
+ return splitNumberIntl(value, maxDecimals);
1676
+ if (Number.isInteger(value)) {
1677
+ return { integerDigits: asString, decimalDigits: undefined };
1678
+ }
1679
+ const indexOfDot = asString.indexOf(".");
1680
+ let integerDigits = asString.substring(0, indexOfDot);
1681
+ let decimalDigits = asString.substring(indexOfDot + 1);
1682
+ if (maxDecimals === 0) {
1683
+ if (Number(decimalDigits[0]) >= 5) {
1684
+ integerDigits = (Number(integerDigits) + 1).toString();
1685
+ }
1686
+ return { integerDigits, decimalDigits: undefined };
1687
+ }
1688
+ if (decimalDigits.length > maxDecimals) {
1689
+ const { integerDigits: roundedIntegerDigits, decimalDigits: roundedDecimalDigits } = limitDecimalDigits(decimalDigits, maxDecimals);
1690
+ decimalDigits = roundedDecimalDigits;
1691
+ if (roundedIntegerDigits !== "0") {
1692
+ integerDigits = (Number(integerDigits) + Number(roundedIntegerDigits)).toString();
1693
+ }
1694
+ }
1695
+ return { integerDigits, decimalDigits: removeTrailingZeroes(decimalDigits || "") };
1696
+ }
1697
+ /**
1698
+ * Return the given string minus the trailing "0" characters.
1699
+ *
1700
+ * @param numberString : a string of integers
1701
+ * @returns the numberString, minus the eventual zeroes at the end
1702
+ */
1703
+ function removeTrailingZeroes(numberString) {
1704
+ let i = numberString.length - 1;
1705
+ while (i >= 0 && numberString[i] === "0") {
1706
+ i--;
1707
+ }
1708
+ return numberString.slice(0, i + 1) || undefined;
1709
+ }
1710
+ /**
1711
+ * Limit the size of the decimal part of a number to the given number of digits.
1712
+ */
1713
+ function limitDecimalDigits(decimalDigits, maxDecimals) {
1714
+ let integerDigits = "0";
1715
+ let resultDecimalDigits = decimalDigits;
1716
+ // Note : we'd want to simply use number.toFixed() to handle the max digits & rounding,
1717
+ // but it has very strange behaviour. Ex: 12.345.toFixed(2) => "12.35", but 1.345.toFixed(2) => "1.34"
1718
+ let slicedDecimalDigits = decimalDigits.slice(0, maxDecimals);
1719
+ const i = maxDecimals;
1720
+ if (Number(Number(decimalDigits[i]) < 5)) {
1721
+ return { integerDigits, decimalDigits: slicedDecimalDigits };
1722
+ }
1723
+ // round up
1724
+ const slicedRoundedUp = (Number(slicedDecimalDigits) + 1).toString();
1725
+ if (slicedRoundedUp.length > slicedDecimalDigits.length) {
1726
+ integerDigits = (Number(integerDigits) + 1).toString();
1727
+ resultDecimalDigits = undefined;
1728
+ }
1729
+ else {
1730
+ resultDecimalDigits = slicedRoundedUp;
1731
+ }
1732
+ return { integerDigits, decimalDigits: resultDecimalDigits };
1733
+ }
1734
+ /**
1735
+ * Split numbers into decimal/integer digits using Intl.NumberFormat.
1736
+ * Supports numbers with a lot of digits that are transformed to scientific notation by
1737
+ * number.toString(), but is slow.
1738
+ */
1739
+ function splitNumberIntl(value, maxDecimals = MAX_DECIMAL_PLACES) {
1671
1740
  let formatter = numberRepresentation[maxDecimals];
1672
1741
  if (!formatter) {
1673
1742
  formatter = new Intl.NumberFormat("en-US", {
@@ -3559,6 +3628,8 @@ exports.CommandResult = void 0;
3559
3628
  CommandResult[CommandResult["InvalidSelectionStep"] = 83] = "InvalidSelectionStep";
3560
3629
  CommandResult[CommandResult["DuplicatedChartId"] = 84] = "DuplicatedChartId";
3561
3630
  CommandResult[CommandResult["ChartDoesNotExist"] = 85] = "ChartDoesNotExist";
3631
+ CommandResult[CommandResult["InvalidHeaderIndex"] = 86] = "InvalidHeaderIndex";
3632
+ CommandResult[CommandResult["InvalidQuantity"] = 87] = "InvalidQuantity";
3562
3633
  })(exports.CommandResult || (exports.CommandResult = {}));
3563
3634
 
3564
3635
  var DIRECTION;
@@ -5906,13 +5977,16 @@ class Menu extends owl.Component {
5906
5977
  }
5907
5978
  });
5908
5979
  }
5980
+ get visibleMenuItems() {
5981
+ return this.props.menuItems.filter((x) => x.isVisible(this.env));
5982
+ }
5909
5983
  get subMenuPosition() {
5910
5984
  const position = Object.assign({}, this.subMenu.position);
5911
5985
  position.y -= this.subMenu.scrollOffset || 0;
5912
5986
  return position;
5913
5987
  }
5914
5988
  get menuHeight() {
5915
- const menuItems = this.props.menuItems;
5989
+ const menuItems = this.visibleMenuItems;
5916
5990
  let menuItemsHeight = this.getMenuItemsHeight(menuItems);
5917
5991
  // We don't display separator at the end of a menu
5918
5992
  if (menuItems[menuItems.length - 1].separator) {
@@ -5954,7 +6028,7 @@ class Menu extends owl.Component {
5954
6028
  * and the menu item at a given index.
5955
6029
  */
5956
6030
  subMenuVerticalPosition(menuIndex) {
5957
- const menusAbove = this.props.menuItems.slice(0, menuIndex);
6031
+ const menusAbove = this.visibleMenuItems.slice(0, menuIndex);
5958
6032
  return this.position.y + this.getMenuItemsHeight(menusAbove) + MENU_VERTICAL_PADDING;
5959
6033
  }
5960
6034
  onExternalClick(ev) {
@@ -6126,7 +6200,7 @@ class ChartFigure extends owl.Component {
6126
6200
  openContextMenu(position) {
6127
6201
  const registry = this.getMenuItemRegistry();
6128
6202
  this.menuState.isOpen = true;
6129
- this.menuState.menuItems = registry.getAll().filter((x) => x.isVisible(this.env));
6203
+ this.menuState.menuItems = registry.getAll();
6130
6204
  this.menuState.position = position;
6131
6205
  }
6132
6206
  get chartComponent() {
@@ -7257,6 +7331,11 @@ colMenuRegistry
7257
7331
  name: REMOVE_COLUMNS_NAME,
7258
7332
  sequence: 90,
7259
7333
  action: REMOVE_COLUMNS_ACTION,
7334
+ isVisible: (env) => {
7335
+ const sheetId = env.model.getters.getActiveSheetId();
7336
+ const selectedCols = env.model.getters.getElementsFromSelection("COL");
7337
+ return env.model.getters.canRemoveHeaders(sheetId, "COL", selectedCols);
7338
+ },
7260
7339
  })
7261
7340
  .add("clear_column", {
7262
7341
  name: DELETE_CONTENT_COLUMNS_NAME,
@@ -7269,9 +7348,8 @@ colMenuRegistry
7269
7348
  action: HIDE_COLUMNS_ACTION,
7270
7349
  isVisible: (env) => {
7271
7350
  const sheetId = env.model.getters.getActiveSheetId();
7272
- const hiddenCols = env.model.getters.getHiddenColsGroups(sheetId).flat();
7273
- return (env.model.getters.getNumberCols(sheetId) >
7274
- hiddenCols.length + env.model.getters.getElementsFromSelection("COL").length);
7351
+ const selectedCols = env.model.getters.getElementsFromSelection("COL");
7352
+ return env.model.getters.canRemoveHeaders(sheetId, "COL", selectedCols);
7275
7353
  },
7276
7354
  separator: true,
7277
7355
  })
@@ -7345,6 +7423,11 @@ rowMenuRegistry
7345
7423
  name: REMOVE_ROWS_NAME,
7346
7424
  sequence: 70,
7347
7425
  action: REMOVE_ROWS_ACTION,
7426
+ isVisible: (env) => {
7427
+ const sheetId = env.model.getters.getActiveSheetId();
7428
+ const selectedRows = env.model.getters.getElementsFromSelection("ROW");
7429
+ return env.model.getters.canRemoveHeaders(sheetId, "ROW", selectedRows);
7430
+ },
7348
7431
  })
7349
7432
  .add("clear_row", {
7350
7433
  name: DELETE_CONTENT_ROWS_NAME,
@@ -7357,9 +7440,8 @@ rowMenuRegistry
7357
7440
  action: HIDE_ROWS_ACTION,
7358
7441
  isVisible: (env) => {
7359
7442
  const sheetId = env.model.getters.getActiveSheetId();
7360
- const hiddenRows = env.model.getters.getHiddenRowsGroups(sheetId).flat();
7361
- return (env.model.getters.getNumberRows(sheetId) >
7362
- hiddenRows.length + env.model.getters.getElementsFromSelection("ROW").length);
7443
+ const selectedRows = env.model.getters.getElementsFromSelection("ROW");
7444
+ return env.model.getters.canRemoveHeaders(sheetId, "ROW", selectedRows);
7363
7445
  },
7364
7446
  separator: true,
7365
7447
  })
@@ -14417,7 +14499,7 @@ const POW = {
14417
14499
  base (number) ${_lt("The number to raise to the exponent power.")}
14418
14500
  exponent (number) ${_lt("The exponent to raise base to.")}
14419
14501
  `),
14420
- returns: ["BOOLEAN"],
14502
+ returns: ["NUMBER"],
14421
14503
  compute: function (base, exponent) {
14422
14504
  return POWER.compute(base, exponent);
14423
14505
  },
@@ -16932,14 +17014,31 @@ class ContentEditableHelper {
16932
17014
  * */
16933
17015
  getCurrentSelection() {
16934
17016
  let { startElement, endElement, startSelectionOffset, endSelectionOffset } = this.getStartAndEndSelection();
16935
- let startSizeBefore = this.findSizeBeforeElement(startElement);
16936
- let endSizeBefore = this.findSizeBeforeElement(endElement);
17017
+ let startSizeBefore = this.findSelectionIndex(startElement, startSelectionOffset);
17018
+ let endSizeBefore = this.findSelectionIndex(endElement, endSelectionOffset);
16937
17019
  return {
16938
- start: startSizeBefore + startSelectionOffset,
16939
- end: endSizeBefore + endSelectionOffset,
17020
+ start: startSizeBefore,
17021
+ end: endSizeBefore,
16940
17022
  };
16941
17023
  }
16942
- findSizeBeforeElement(nodeToFind) {
17024
+ /**
17025
+ * Computes the text 'index' inside this.el based on the currently selected node and its offset.
17026
+ * The selected node is either a Text node or an Element node.
17027
+ *
17028
+ * case 1 -Text node:
17029
+ * the offset is the number of characters from the start of the node. We have to add this offset to the
17030
+ * content length of all previous nodes.
17031
+ *
17032
+ * case 2 - Element node:
17033
+ * the offset is the number of child nodes before the selected node. We have to add the content length of
17034
+ * all the bnodes prior to the selected node as well as the content of the child node before the offset.
17035
+ *
17036
+ * See the MDN documentation for more details.
17037
+ * https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
17038
+ * https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
17039
+ *
17040
+ */
17041
+ findSelectionIndex(nodeToFind, nodeOffset) {
16943
17042
  let it = this.iterateChildren(this.el);
16944
17043
  let usedCharacters = 0;
16945
17044
  let current = it.next();
@@ -16951,6 +17050,19 @@ class ContentEditableHelper {
16951
17050
  }
16952
17051
  current = it.next();
16953
17052
  }
17053
+ if (current.value === nodeToFind) {
17054
+ if (!current.value.hasChildNodes()) {
17055
+ usedCharacters += nodeOffset;
17056
+ }
17057
+ else {
17058
+ const children = [...current.value.childNodes].slice(0, nodeOffset);
17059
+ for (const child of children) {
17060
+ if (!child.textContent)
17061
+ continue;
17062
+ usedCharacters += child.textContent.length;
17063
+ }
17064
+ }
17065
+ }
16954
17066
  return usedCharacters;
16955
17067
  }
16956
17068
  getStartAndEndSelection() {
@@ -23542,8 +23654,8 @@ class Grid extends owl.Component {
23542
23654
  },
23543
23655
  "CTRL+END": () => {
23544
23656
  const sheetId = this.env.model.getters.getActiveSheetId();
23545
- const col = this.env.model.getters.findVisibleHeader(sheetId, "COL", range(0, this.env.model.getters.getNumberCols(sheetId)).reverse());
23546
- const row = this.env.model.getters.findVisibleHeader(sheetId, "ROW", range(0, this.env.model.getters.getNumberRows(sheetId)).reverse());
23657
+ const col = this.env.model.getters.findVisibleHeader(sheetId, "COL", this.env.model.getters.getNumberCols(sheetId) - 1, 0);
23658
+ const row = this.env.model.getters.findVisibleHeader(sheetId, "ROW", this.env.model.getters.getNumberRows(sheetId) - 1, 0);
23547
23659
  this.env.model.selection.selectCell(col, row);
23548
23660
  },
23549
23661
  "SHIFT+ ": () => {
@@ -23623,9 +23735,10 @@ class Grid extends owl.Component {
23623
23735
  this.focus();
23624
23736
  }
23625
23737
  focus() {
23738
+ var _a;
23626
23739
  if (!this.env.model.getters.getSelectedFigureId() &&
23627
23740
  this.env.model.getters.getEditionMode() === "inactive") {
23628
- this.hiddenInput.el.focus();
23741
+ (_a = this.hiddenInput.el) === null || _a === void 0 ? void 0 : _a.focus();
23629
23742
  }
23630
23743
  }
23631
23744
  get gridEl() {
@@ -23826,9 +23939,7 @@ class Grid extends owl.Component {
23826
23939
  }
23827
23940
  this.menuState.isOpen = true;
23828
23941
  this.menuState.position = { x, y };
23829
- this.menuState.menuItems = registries$1[type]
23830
- .getAll()
23831
- .filter((item) => !item.isVisible || item.isVisible(this.env));
23942
+ this.menuState.menuItems = registries$1[type].getAll();
23832
23943
  }
23833
23944
  copy(cut, ev) {
23834
23945
  if (!this.gridEl.contains(document.activeElement)) {
@@ -25082,7 +25193,7 @@ function extractStyle(cell, data) {
25082
25193
  if (cell.style) {
25083
25194
  style = data.styles[cell.style];
25084
25195
  }
25085
- const format = cell.format ? data.formats[cell.format] : undefined;
25196
+ const format = extractFormat(cell, data);
25086
25197
  const exportedBorder = {};
25087
25198
  if (cell.border) {
25088
25199
  const border = data.borders[cell.border];
@@ -25116,6 +25227,22 @@ function extractStyle(cell, data) {
25116
25227
  styles.font["italic"] = !!(style === null || style === void 0 ? void 0 : style.italic) || undefined;
25117
25228
  return styles;
25118
25229
  }
25230
+ function extractFormat(cell, data) {
25231
+ if (cell.format) {
25232
+ return data.formats[cell.format];
25233
+ }
25234
+ if (cell.isFormula) {
25235
+ const tokens = tokenize(cell.content || "");
25236
+ const functions = functionRegistry.content;
25237
+ const isExported = tokens
25238
+ .filter((tk) => tk.type === "FUNCTION")
25239
+ .every((tk) => functions[tk.value.toUpperCase()].isExported);
25240
+ if (!isExported) {
25241
+ return cell.computedFormat;
25242
+ }
25243
+ }
25244
+ return undefined;
25245
+ }
25119
25246
  function normalizeStyle(construct, styles) {
25120
25247
  const { id: fontId } = pushElement(styles["font"], construct.fonts);
25121
25248
  const { id: fillId } = pushElement(styles["fill"], construct.fills);
@@ -27197,7 +27324,7 @@ function load(data, verboseImport) {
27197
27324
  }
27198
27325
  }
27199
27326
  }
27200
- data = JSON.parse(JSON.stringify(data));
27327
+ data = deepCopy(data);
27201
27328
  // apply migrations, if needed
27202
27329
  if ("version" in data) {
27203
27330
  if (data.version < CURRENT_VERSION) {
@@ -29857,7 +29984,7 @@ class HeaderVisibilityPlugin extends CorePlugin {
29857
29984
  allowDispatch(cmd) {
29858
29985
  switch (cmd.type) {
29859
29986
  case "HIDE_COLUMNS_ROWS": {
29860
- if (!this.hiddenHeaders[cmd.sheetId]) {
29987
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
29861
29988
  return 27 /* CommandResult.InvalidSheetId */;
29862
29989
  }
29863
29990
  const hiddenGroup = cmd.dimension === "COL"
@@ -29866,10 +29993,25 @@ class HeaderVisibilityPlugin extends CorePlugin {
29866
29993
  const elements = cmd.dimension === "COL"
29867
29994
  ? this.getters.getNumberCols(cmd.sheetId)
29868
29995
  : this.getters.getNumberRows(cmd.sheetId);
29869
- return (hiddenGroup || []).flat().concat(cmd.elements).length < elements
29870
- ? 0 /* CommandResult.Success */
29871
- : 66 /* CommandResult.TooManyHiddenElements */;
29996
+ const hiddenElements = new Set((hiddenGroup || []).flat().concat(cmd.elements));
29997
+ if (hiddenElements.size >= elements) {
29998
+ return 66 /* CommandResult.TooManyHiddenElements */;
29999
+ }
30000
+ else if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
30001
+ return 86 /* CommandResult.InvalidHeaderIndex */;
30002
+ }
30003
+ else {
30004
+ return 0 /* CommandResult.Success */;
30005
+ }
29872
30006
  }
30007
+ case "REMOVE_COLUMNS_ROWS":
30008
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
30009
+ return 27 /* CommandResult.InvalidSheetId */;
30010
+ }
30011
+ if (!this.canRemoveHeaders(cmd.sheetId, cmd.dimension, cmd.elements)) {
30012
+ return 8 /* CommandResult.NotEnoughElements */;
30013
+ }
30014
+ return 0 /* CommandResult.Success */;
29873
30015
  }
29874
30016
  return 0 /* CommandResult.Success */;
29875
30017
  }
@@ -29916,6 +30058,10 @@ class HeaderVisibilityPlugin extends CorePlugin {
29916
30058
  }
29917
30059
  return;
29918
30060
  }
30061
+ canRemoveHeaders(sheetId, dimension, elements) {
30062
+ const visibleHeaders = this.getAllVisibleHeaders(sheetId, dimension);
30063
+ return !includesAll(elements, visibleHeaders);
30064
+ }
29919
30065
  isRowHiddenByUser(sheetId, index) {
29920
30066
  return this.hiddenHeaders[sheetId].ROW[index];
29921
30067
  }
@@ -29960,6 +30106,9 @@ class HeaderVisibilityPlugin extends CorePlugin {
29960
30106
  }
29961
30107
  return consecutiveIndexes;
29962
30108
  }
30109
+ getAllVisibleHeaders(sheetId, dimension) {
30110
+ return range(0, this.hiddenHeaders[sheetId][dimension].length).filter((i) => !this.hiddenHeaders[sheetId][dimension][i]);
30111
+ }
29963
30112
  import(data) {
29964
30113
  var _a, _b;
29965
30114
  for (let sheet of data.sheets) {
@@ -30007,6 +30156,7 @@ class HeaderVisibilityPlugin extends CorePlugin {
30007
30156
  }
30008
30157
  }
30009
30158
  HeaderVisibilityPlugin.getters = [
30159
+ "canRemoveHeaders",
30010
30160
  "getHiddenColsGroups",
30011
30161
  "getHiddenRowsGroups",
30012
30162
  "isRowHiddenByUser",
@@ -31016,13 +31166,27 @@ class SheetPlugin extends CorePlugin {
31016
31166
  return this.orderedSheetIds.length > 1
31017
31167
  ? 0 /* CommandResult.Success */
31018
31168
  : 9 /* CommandResult.NotEnoughSheets */;
31169
+ case "ADD_COLUMNS_ROWS":
31170
+ const elements = cmd.dimension === "COL"
31171
+ ? this.getNumberCols(cmd.sheetId)
31172
+ : this.getNumberRows(cmd.sheetId);
31173
+ if (cmd.base < 0 || cmd.base > elements) {
31174
+ return 86 /* CommandResult.InvalidHeaderIndex */;
31175
+ }
31176
+ else if (cmd.quantity <= 0) {
31177
+ return 87 /* CommandResult.InvalidQuantity */;
31178
+ }
31179
+ return 0 /* CommandResult.Success */;
31019
31180
  case "REMOVE_COLUMNS_ROWS": {
31020
- const length = cmd.dimension === "COL"
31181
+ const elements = cmd.dimension === "COL"
31021
31182
  ? this.getNumberCols(cmd.sheetId)
31022
31183
  : this.getNumberRows(cmd.sheetId);
31023
- return length > cmd.elements.length
31024
- ? 0 /* CommandResult.Success */
31025
- : 8 /* CommandResult.NotEnoughElements */;
31184
+ if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
31185
+ return 86 /* CommandResult.InvalidHeaderIndex */;
31186
+ }
31187
+ else {
31188
+ return 0 /* CommandResult.Success */;
31189
+ }
31026
31190
  }
31027
31191
  case "FREEZE_ROWS": {
31028
31192
  return this.checkValidations(cmd, this.checkRowFreezeQuantity, this.checkRowFreezeOverlapMerge);
@@ -31494,7 +31658,7 @@ class SheetPlugin extends CorePlugin {
31494
31658
  duplicateSheet(fromId, toId) {
31495
31659
  const sheet = this.getSheet(fromId);
31496
31660
  const toName = this.getDuplicateSheetName(sheet.name);
31497
- const newSheet = JSON.parse(JSON.stringify(sheet));
31661
+ const newSheet = deepCopy(sheet);
31498
31662
  newSheet.id = toId;
31499
31663
  newSheet.name = toName;
31500
31664
  for (let col = 0; col <= newSheet.numberOfCols; col++) {
@@ -31621,10 +31785,10 @@ class SheetPlugin extends CorePlugin {
31621
31785
  }
31622
31786
  }
31623
31787
  moveCellOnColumnsDeletion(sheet, deletedColumn) {
31624
- for (let [index, row] of Object.entries(sheet.rows)) {
31625
- const rowIndex = parseInt(index, 10);
31788
+ for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
31789
+ const row = sheet.rows[rowIndex];
31626
31790
  for (let i in row.cells) {
31627
- const colIndex = parseInt(i, 10);
31791
+ const colIndex = Number(i);
31628
31792
  const cellId = row.cells[i];
31629
31793
  if (cellId) {
31630
31794
  if (colIndex === deletedColumn) {
@@ -31651,11 +31815,11 @@ class SheetPlugin extends CorePlugin {
31651
31815
  */
31652
31816
  moveCellsOnAddition(sheet, addedElement, quantity, dimension) {
31653
31817
  const commands = [];
31654
- for (const [index, row] of Object.entries(sheet.rows)) {
31655
- const rowIndex = parseInt(index, 10);
31818
+ for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
31819
+ const row = sheet.rows[rowIndex];
31656
31820
  if (dimension !== "rows" || rowIndex >= addedElement) {
31657
31821
  for (let i in row.cells) {
31658
- const colIndex = parseInt(i, 10);
31822
+ const colIndex = Number(i);
31659
31823
  const cellId = row.cells[i];
31660
31824
  if (cellId) {
31661
31825
  if (dimension === "rows" || colIndex >= addedElement) {
@@ -31685,11 +31849,11 @@ class SheetPlugin extends CorePlugin {
31685
31849
  */
31686
31850
  moveCellOnRowsDeletion(sheet, deleteFromRow, deleteToRow) {
31687
31851
  const numberRows = deleteToRow - deleteFromRow + 1;
31688
- for (let [index, row] of Object.entries(sheet.rows)) {
31689
- const rowIndex = parseInt(index, 10);
31852
+ for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
31853
+ const row = sheet.rows[rowIndex];
31690
31854
  if (rowIndex >= deleteFromRow && rowIndex <= deleteToRow) {
31691
31855
  for (let i in row.cells) {
31692
- const colIndex = parseInt(i, 10);
31856
+ const colIndex = Number(i);
31693
31857
  const cellId = row.cells[i];
31694
31858
  if (cellId) {
31695
31859
  this.dispatch("CLEAR_CELL", {
@@ -31702,7 +31866,7 @@ class SheetPlugin extends CorePlugin {
31702
31866
  }
31703
31867
  if (rowIndex > deleteToRow) {
31704
31868
  for (let i in row.cells) {
31705
- const colIndex = parseInt(i, 10);
31869
+ const colIndex = Number(i);
31706
31870
  const cellId = row.cells[i];
31707
31871
  if (cellId) {
31708
31872
  this.dispatch("UPDATE_CELL_POSITION", {
@@ -31720,7 +31884,7 @@ class SheetPlugin extends CorePlugin {
31720
31884
  const rows = [];
31721
31885
  const cellsQueue = sheet.rows.map((row) => row.cells);
31722
31886
  for (let i in sheet.rows) {
31723
- if (parseInt(i, 10) === index) {
31887
+ if (Number(i) === index) {
31724
31888
  continue;
31725
31889
  }
31726
31890
  rows.push({
@@ -32272,8 +32436,12 @@ class EvaluationPlugin extends UIPlugin {
32272
32436
  const cell = this.getters.getCell(position);
32273
32437
  if (cell) {
32274
32438
  const exportedCellData = sheet.cells[xc];
32275
- exportedCellData.value = this.getEvaluatedCell(position).value;
32439
+ const evaluatedCell = this.getEvaluatedCell(position);
32440
+ exportedCellData.value = evaluatedCell.value;
32276
32441
  exportedCellData.isFormula = cell.isFormula && !this.isBadExpression(cell.content);
32442
+ if (cell.format !== evaluatedCell.format) {
32443
+ exportedCellData.computedFormat = evaluatedCell.format;
32444
+ }
32277
32445
  }
32278
32446
  }
32279
32447
  }
@@ -32863,13 +33031,11 @@ class FilterEvaluationPlugin extends UIPlugin {
32863
33031
  return Boolean(id && ((_b = (_a = this.filterValues[sheetId]) === null || _a === void 0 ? void 0 : _a[id]) === null || _b === void 0 ? void 0 : _b.length));
32864
33032
  }
32865
33033
  intersectZoneWithViewport(sheetId, zone) {
32866
- const colsRange = range(zone.left, zone.right + 1);
32867
- const rowsRange = range(zone.top, zone.bottom + 1);
32868
33034
  return {
32869
- left: this.getters.findVisibleHeader(sheetId, "COL", colsRange),
32870
- right: this.getters.findVisibleHeader(sheetId, "COL", colsRange.reverse()),
32871
- top: this.getters.findVisibleHeader(sheetId, "ROW", rowsRange),
32872
- bottom: this.getters.findVisibleHeader(sheetId, "ROW", rowsRange.reverse()),
33035
+ left: this.getters.findVisibleHeader(sheetId, "COL", zone.left, zone.right),
33036
+ right: this.getters.findVisibleHeader(sheetId, "COL", zone.right, zone.left),
33037
+ top: this.getters.findVisibleHeader(sheetId, "ROW", zone.top, zone.bottom),
33038
+ bottom: this.getters.findVisibleHeader(sheetId, "ROW", zone.bottom, zone.top),
32873
33039
  };
32874
33040
  }
32875
33041
  updateFilter({ col, row, values, sheetId }) {
@@ -34975,13 +35141,33 @@ class HeaderVisibilityUIPlugin extends UIPlugin {
34975
35141
  getNextVisibleCellPosition({ sheetId, col, row }) {
34976
35142
  return {
34977
35143
  sheetId,
34978
- col: this.findVisibleHeader(sheetId, "COL", range(col, this.getters.getNumberCols(sheetId))),
34979
- row: this.findVisibleHeader(sheetId, "ROW", range(row, this.getters.getNumberRows(sheetId))),
35144
+ col: this.findVisibleHeader(sheetId, "COL", col, this.getters.getNumberCols(sheetId) - 1),
35145
+ row: this.findVisibleHeader(sheetId, "ROW", row, this.getters.getNumberRows(sheetId) - 1),
34980
35146
  };
34981
35147
  }
34982
- findVisibleHeader(sheetId, dimension, indexes) {
34983
- return indexes.find((index) => this.getters.doesHeaderExist(sheetId, dimension, index) &&
34984
- !this.isHeaderHidden(sheetId, dimension, index));
35148
+ /**
35149
+ * Find the first visible header in the range [`from` => `to`].
35150
+ *
35151
+ * Both `from` and `to` are inclusive.
35152
+ */
35153
+ findVisibleHeader(sheetId, dimension, from, to) {
35154
+ if (from <= to) {
35155
+ for (let i = from; i <= to; i++) {
35156
+ if (this.getters.doesHeaderExist(sheetId, dimension, i) &&
35157
+ !this.isHeaderHidden(sheetId, dimension, i)) {
35158
+ return i;
35159
+ }
35160
+ }
35161
+ }
35162
+ if (from > to) {
35163
+ for (let i = from; i >= to; i--) {
35164
+ if (this.getters.doesHeaderExist(sheetId, dimension, i) &&
35165
+ !this.isHeaderHidden(sheetId, dimension, i)) {
35166
+ return i;
35167
+ }
35168
+ }
35169
+ }
35170
+ return undefined;
34985
35171
  }
34986
35172
  findLastVisibleColRowIndex(sheetId, dimension, { last, first }) {
34987
35173
  const lastVisibleIndex = range(last, first, -1).find((index) => !this.isHeaderHidden(sheetId, dimension, index));
@@ -34989,7 +35175,7 @@ class HeaderVisibilityUIPlugin extends UIPlugin {
34989
35175
  }
34990
35176
  findFirstVisibleColRowIndex(sheetId, dimension) {
34991
35177
  const numberOfHeaders = this.getters.getNumberHeaders(sheetId, dimension);
34992
- for (let i = 0; i < numberOfHeaders - 1; i++) {
35178
+ for (let i = 0; i < numberOfHeaders; i++) {
34993
35179
  if (dimension === "COL" && !this.isColHidden(sheetId, i)) {
34994
35180
  return i;
34995
35181
  }
@@ -39216,7 +39402,7 @@ class BottomBar extends owl.Component {
39216
39402
  }
39217
39403
  openContextMenu(x, y, registry, menuId) {
39218
39404
  this.menuState.isOpen = true;
39219
- this.menuState.menuItems = registry.getAll().filter((x) => x.isVisible(this.env));
39405
+ this.menuState.menuItems = registry.getAll();
39220
39406
  this.menuState.position = { x, y };
39221
39407
  this.menuState.menuId = menuId;
39222
39408
  }
@@ -40023,7 +40209,7 @@ class TopBar extends owl.Component {
40023
40209
  const { left, top, height } = ev.target.getBoundingClientRect();
40024
40210
  this.state.menuState.isOpen = true;
40025
40211
  this.state.menuState.position = { x: left, y: top + height };
40026
- this.state.menuState.menuItems = getMenuChildren(menu, this.env).filter((item) => !item.isVisible || item.isVisible(this.env));
40212
+ this.state.menuState.menuItems = getMenuChildren(menu, this.env);
40027
40213
  this.state.menuState.parentMenu = menu;
40028
40214
  this.isSelectingMenu = true;
40029
40215
  this.openedEl = ev.target;
@@ -40066,9 +40252,7 @@ class TopBar extends owl.Component {
40066
40252
  this.style.align = this.style.align || cell.defaultAlign;
40067
40253
  this.fillColor = this.style.fillColor || "#ffffff";
40068
40254
  this.textColor = this.style.textColor || "#000000";
40069
- this.menus = topbarMenuRegistry
40070
- .getAll()
40071
- .filter((item) => !item.isVisible || item.isVisible(this.env));
40255
+ this.menus = topbarMenuRegistry.getAll();
40072
40256
  }
40073
40257
  getMenuName(menu) {
40074
40258
  return getMenuName(menu, this.env);
@@ -41782,8 +41966,8 @@ class SelectionStreamProcessor {
41782
41966
  }
41783
41967
  const { left, right, top, bottom } = zone;
41784
41968
  const sheetId = this.getters.getActiveSheetId();
41785
- const refCol = this.getters.findVisibleHeader(sheetId, "COL", range(left, right + 1));
41786
- const refRow = this.getters.findVisibleHeader(sheetId, "ROW", range(top, bottom + 1));
41969
+ const refCol = this.getters.findVisibleHeader(sheetId, "COL", left, right);
41970
+ const refRow = this.getters.findVisibleHeader(sheetId, "ROW", top, bottom);
41787
41971
  if (refRow === undefined || refCol === undefined) {
41788
41972
  return 17 /* CommandResult.SelectionOutOfBound */;
41789
41973
  }
@@ -41858,10 +42042,10 @@ class SelectionStreamProcessor {
41858
42042
  const { col: anchorCol, row: anchorRow } = anchor.cell;
41859
42043
  return {
41860
42044
  col: this.getters.isColHidden(sheetId, anchorCol)
41861
- ? this.getters.findVisibleHeader(sheetId, "COL", range(left, right + 1)) || anchorCol
42045
+ ? this.getters.findVisibleHeader(sheetId, "COL", left, right) || anchorCol
41862
42046
  : anchorCol,
41863
42047
  row: this.getters.isRowHidden(sheetId, anchorRow)
41864
- ? this.getters.findVisibleHeader(sheetId, "ROW", range(top, bottom + 1)) || anchorRow
42048
+ ? this.getters.findVisibleHeader(sheetId, "ROW", top, bottom) || anchorRow
41865
42049
  : anchorRow,
41866
42050
  };
41867
42051
  }
@@ -42435,12 +42619,9 @@ function addFormula(cell) {
42435
42619
  else {
42436
42620
  // Shouldn't we always output the value then ?
42437
42621
  const value = cell.value;
42438
- // what if value = 0? Is this condition correct?
42439
- if (value) {
42440
- const type = getCellType(value);
42441
- attrs.push(["t", type]);
42442
- node = escapeXml /*xml*/ `<v>${value}</v>`;
42443
- }
42622
+ const type = getCellType(value);
42623
+ attrs.push(["t", type]);
42624
+ node = escapeXml /*xml*/ `<v>${value}</v>`;
42444
42625
  return { attrs, node };
42445
42626
  }
42446
42627
  }
@@ -43542,6 +43723,8 @@ class Model extends EventBus {
43542
43723
  * Internal status of the model. Important for command handling coordination
43543
43724
  */
43544
43725
  this.status = 0 /* Status.Ready */;
43726
+ this.handlers = [];
43727
+ this.coreHandlers = [];
43545
43728
  /**
43546
43729
  * The dispatch method is the only entry point to manipulate data in the model.
43547
43730
  * This is through this method that commands are dispatched most of the time
@@ -43646,6 +43829,8 @@ class Model extends EventBus {
43646
43829
  this.uuidGenerator.setIsFastStrategy(true);
43647
43830
  // Initiate stream processor
43648
43831
  this.selection = new SelectionStreamProcessor(this.getters);
43832
+ this.coreHandlers.push(this.range);
43833
+ this.handlers.push(this.range);
43649
43834
  this.corePluginConfig = this.setupCorePluginConfig();
43650
43835
  this.uiPluginConfig = this.setupUiPluginConfig();
43651
43836
  // registering plugins
@@ -43654,15 +43839,23 @@ class Model extends EventBus {
43654
43839
  }
43655
43840
  Object.assign(this.getters, this.coreGetters);
43656
43841
  for (let Plugin of statefulUIPluginRegistry.getAll()) {
43657
- this.statefulUIPlugins.push(this.setupUiPlugin(Plugin));
43842
+ const plugin = this.setupUiPlugin(Plugin);
43843
+ this.statefulUIPlugins.push(plugin);
43844
+ this.handlers.push(plugin);
43658
43845
  }
43659
43846
  for (let Plugin of coreViewsPluginRegistry.getAll()) {
43660
- this.coreViewsPlugins.push(this.setupUiPlugin(Plugin));
43847
+ const plugin = this.setupUiPlugin(Plugin);
43848
+ this.coreViewsPlugins.push(plugin);
43849
+ this.handlers.push(plugin);
43850
+ this.coreHandlers.push(plugin);
43661
43851
  }
43662
43852
  for (let Plugin of featurePluginRegistry.getAll()) {
43663
- this.featurePlugins.push(this.setupUiPlugin(Plugin));
43853
+ const plugin = this.setupUiPlugin(Plugin);
43854
+ this.featurePlugins.push(plugin);
43855
+ this.handlers.push(plugin);
43664
43856
  }
43665
43857
  this.uuidGenerator.setIsFastStrategy(false);
43858
+ this.handlers.push(this.history);
43666
43859
  // starting plugins
43667
43860
  this.dispatch("START");
43668
43861
  // Model should be the last permanent subscriber in the list since he should render
@@ -43684,12 +43877,6 @@ class Model extends EventBus {
43684
43877
  // by owl, since we do not rely on reactivity
43685
43878
  owl.markRaw(this);
43686
43879
  }
43687
- get handlers() {
43688
- return [this.range, ...this.corePlugins, ...this.allUIPlugins, this.history];
43689
- }
43690
- get allUIPlugins() {
43691
- return [...this.statefulUIPlugins, ...this.coreViewsPlugins, ...this.featurePlugins];
43692
- }
43693
43880
  joinSession() {
43694
43881
  this.session.join(this.config.client);
43695
43882
  }
@@ -43731,6 +43918,8 @@ class Model extends EventBus {
43731
43918
  }
43732
43919
  plugin.import(data);
43733
43920
  this.corePlugins.push(plugin);
43921
+ this.coreHandlers.push(plugin);
43922
+ this.handlers.push(plugin);
43734
43923
  }
43735
43924
  onRemoteRevisionReceived({ commands }) {
43736
43925
  for (let command of commands) {
@@ -43873,7 +44062,7 @@ class Model extends EventBus {
43873
44062
  }
43874
44063
  }
43875
44064
  data.revisionId = this.session.getRevisionId() || DEFAULT_REVISION_ID;
43876
- data = JSON.parse(JSON.stringify(data));
44065
+ data = deepCopy(data);
43877
44066
  return data;
43878
44067
  }
43879
44068
  updateMode(mode) {
@@ -43901,7 +44090,7 @@ class Model extends EventBus {
43901
44090
  handler.exportForExcel(data);
43902
44091
  }
43903
44092
  }
43904
- data = JSON.parse(JSON.stringify(data));
44093
+ data = deepCopy(data);
43905
44094
  return getXLSX(data);
43906
44095
  }
43907
44096
  garbageCollectExternalResources() {
@@ -44042,6 +44231,6 @@ exports.setTranslationMethod = setTranslationMethod;
44042
44231
  exports.tokenize = tokenize;
44043
44232
 
44044
44233
 
44045
- __info__.version = '16.1.8';
44046
- __info__.date = '2023-04-14T12:46:41.355Z';
44047
- __info__.hash = '4399770';
44234
+ __info__.version = '16.1.10';
44235
+ __info__.date = '2023-04-28T12:24:14.323Z';
44236
+ __info__.hash = '9632927';