@odoo/o-spreadsheet 16.4.27 → 16.4.29

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.
@@ -523,7 +523,7 @@
523
523
  }
524
524
  // Generate new Id if the item didn't exist in the dictionary
525
525
  const ids = Object.keys(itemsDic);
526
- const maxId = ids.length === 0 ? 0 : Math.max(...ids.map((id) => parseInt(id, 10)));
526
+ const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
527
527
  itemsDic[maxId + 1] = item;
528
528
  return maxId + 1;
529
529
  }
@@ -614,7 +614,7 @@
614
614
  if (typeof o1 !== typeof o2)
615
615
  return false;
616
616
  if (typeof o1 !== "object")
617
- return o1 === o2;
617
+ return false;
618
618
  // Objects can have different keys if the values are undefined
619
619
  const keys = new Set();
620
620
  Object.keys(o1).forEach((key) => keys.add(key));
@@ -739,6 +739,34 @@
739
739
  const newArray = [...array];
740
740
  newArray.splice(index, 0, ...items);
741
741
  return newArray;
742
+ }
743
+ /**
744
+ * Alternative to Math.max that works with large arrays.
745
+ * Typically useful for arrays bigger than 100k elements.
746
+ */
747
+ function largeMax(array) {
748
+ let len = array.length;
749
+ if (len < 100000)
750
+ return Math.max(...array);
751
+ let max = -Infinity;
752
+ while (len--) {
753
+ max = array[len] > max ? array[len] : max;
754
+ }
755
+ return max;
756
+ }
757
+ /**
758
+ * Alternative to Math.min that works with large arrays.
759
+ * Typically useful for arrays bigger than 100k elements.
760
+ */
761
+ function largeMin(array) {
762
+ let len = array.length;
763
+ if (len < 100000)
764
+ return Math.min(...array);
765
+ let min = +Infinity;
766
+ while (len--) {
767
+ min = array[len] < min ? array[len] : min;
768
+ }
769
+ return min;
742
770
  }
743
771
 
744
772
  const RBA_REGEX = /rgba?\(|\s+|\)/gi;
@@ -15770,6 +15798,7 @@
15770
15798
  this.save();
15771
15799
  }
15772
15800
  ev.stopPropagation();
15801
+ ev.preventDefault();
15773
15802
  break;
15774
15803
  case "Escape":
15775
15804
  this.cancel();
@@ -16335,10 +16364,10 @@
16335
16364
  }
16336
16365
  }
16337
16366
  return {
16338
- labels: Object.keys(labelMap),
16367
+ labels: Array.from(labelSet),
16339
16368
  dataSetsValues: datasets.map((dataset, indexOfDataset) => ({
16340
16369
  ...dataset,
16341
- data: Object.values(labelMap).map((dataOfLabel) => dataOfLabel[indexOfDataset]),
16370
+ data: Array.from(labelSet).map((label) => labelMap[label][indexOfDataset]),
16342
16371
  })),
16343
16372
  };
16344
16373
  }
@@ -17059,7 +17088,7 @@
17059
17088
  return undefined;
17060
17089
  }
17061
17090
  const labelsTimestamps = labelDates.map((date) => date.getTime());
17062
- const period = Math.max(...labelsTimestamps) - Math.min(...labelsTimestamps);
17091
+ const period = largeMax(labelsTimestamps) - largeMin(labelsTimestamps);
17063
17092
  const minUnit = getFormatMinDisplayUnit(format);
17064
17093
  if (UNIT_LENGTH.second >= UNIT_LENGTH[minUnit] && Milliseconds.inSeconds(period) < 180) {
17065
17094
  return "second";
@@ -17501,7 +17530,7 @@
17501
17530
  }
17502
17531
  function getPieColors(colors, dataSetsValues) {
17503
17532
  const pieColors = [];
17504
- const maxLength = Math.max(...dataSetsValues.map((ds) => ds.data.length));
17533
+ const maxLength = largeMax(dataSetsValues.map((ds) => ds.data.length));
17505
17534
  for (let i = 0; i <= maxLength; i++) {
17506
17535
  pieColors.push(colors.next());
17507
17536
  }
@@ -18318,8 +18347,8 @@
18318
18347
  let last;
18319
18348
  const activesRows = env.model.getters.getActiveRows();
18320
18349
  if (activesRows.size !== 0) {
18321
- first = Math.min(...activesRows);
18322
- last = Math.max(...activesRows);
18350
+ first = largeMin([...activesRows]);
18351
+ last = largeMax([...activesRows]);
18323
18352
  }
18324
18353
  else {
18325
18354
  const zone = env.model.getters.getSelectedZones()[0];
@@ -18347,8 +18376,8 @@
18347
18376
  let last;
18348
18377
  const activeCols = env.model.getters.getActiveCols();
18349
18378
  if (activeCols.size !== 0) {
18350
- first = Math.min(...activeCols);
18351
- last = Math.max(...activeCols);
18379
+ first = largeMin([...activeCols]);
18380
+ last = largeMax([...activeCols]);
18352
18381
  }
18353
18382
  else {
18354
18383
  const zone = env.model.getters.getSelectedZones()[0];
@@ -18376,8 +18405,8 @@
18376
18405
  let last;
18377
18406
  const activesRows = env.model.getters.getActiveRows();
18378
18407
  if (activesRows.size !== 0) {
18379
- first = Math.min(...activesRows);
18380
- last = Math.max(...activesRows);
18408
+ first = largeMin([...activesRows]);
18409
+ last = largeMax([...activesRows]);
18381
18410
  }
18382
18411
  else {
18383
18412
  const zone = env.model.getters.getSelectedZones()[0];
@@ -18418,8 +18447,8 @@
18418
18447
  let last;
18419
18448
  const activeCols = env.model.getters.getActiveCols();
18420
18449
  if (activeCols.size !== 0) {
18421
- first = Math.min(...activeCols);
18422
- last = Math.max(...activeCols);
18450
+ first = largeMin([...activeCols]);
18451
+ last = largeMax([...activeCols]);
18423
18452
  }
18424
18453
  else {
18425
18454
  const zone = env.model.getters.getSelectedZones()[0];
@@ -18460,7 +18489,7 @@
18460
18489
  let row;
18461
18490
  let quantity;
18462
18491
  if (activeRows.size) {
18463
- row = Math.min(...activeRows);
18492
+ row = largeMin([...activeRows]);
18464
18493
  quantity = activeRows.size;
18465
18494
  }
18466
18495
  else {
@@ -18481,7 +18510,7 @@
18481
18510
  let row;
18482
18511
  let quantity;
18483
18512
  if (activeRows.size) {
18484
- row = Math.max(...activeRows);
18513
+ row = largeMax([...activeRows]);
18485
18514
  quantity = activeRows.size;
18486
18515
  }
18487
18516
  else {
@@ -18502,7 +18531,7 @@
18502
18531
  let column;
18503
18532
  let quantity;
18504
18533
  if (activeCols.size) {
18505
- column = Math.min(...activeCols);
18534
+ column = largeMin([...activeCols]);
18506
18535
  quantity = activeCols.size;
18507
18536
  }
18508
18537
  else {
@@ -18523,7 +18552,7 @@
18523
18552
  let column;
18524
18553
  let quantity;
18525
18554
  if (activeCols.size) {
18526
- column = Math.max(...activeCols);
18555
+ column = largeMax([...activeCols]);
18527
18556
  quantity = activeCols.size;
18528
18557
  }
18529
18558
  else {
@@ -24435,6 +24464,11 @@
24435
24464
  }
24436
24465
  }
24437
24466
  }
24467
+ onContextMenu(ev) {
24468
+ if (this.env.model.getters.getEditionMode() === "inactive") {
24469
+ this.props.onInputContextMenu?.(ev);
24470
+ }
24471
+ }
24438
24472
  // ---------------------------------------------------------------------------
24439
24473
  // Private
24440
24474
  // ---------------------------------------------------------------------------
@@ -24659,6 +24693,7 @@
24659
24693
  onComposerCellFocused: { type: Function, optional: true },
24660
24694
  onComposerContentFocused: Function,
24661
24695
  isDefaultFocus: { type: Boolean, optional: true },
24696
+ onInputContextMenu: { type: Function, optional: true },
24662
24697
  };
24663
24698
 
24664
24699
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
@@ -24735,6 +24770,7 @@
24735
24770
  isDefaultFocus: true,
24736
24771
  onComposerContentFocused: this.props.onComposerContentFocused,
24737
24772
  onComposerCellFocused: this.props.onComposerCellFocused,
24773
+ onInputContextMenu: this.props.onInputContextMenu,
24738
24774
  };
24739
24775
  }
24740
24776
  get containerStyle() {
@@ -24823,6 +24859,7 @@
24823
24859
  onComposerContentFocused: Function,
24824
24860
  gridDims: Object,
24825
24861
  onComposerCellFocused: Function,
24862
+ onInputContextMenu: Function,
24826
24863
  };
24827
24864
 
24828
24865
  const CSS$1 = css /* scss */ `
@@ -27172,8 +27209,8 @@
27172
27209
  else if (this.env.model.getters.getActiveRows().has(row)) {
27173
27210
  type = "ROW";
27174
27211
  }
27175
- const { x, y, width, height } = this.env.model.getters.getVisibleRect(lastZone);
27176
- this.toggleContextMenu(type, x + width, y + height);
27212
+ const { x, y, width } = this.env.model.getters.getVisibleRect(lastZone);
27213
+ this.toggleContextMenu(type, this.canvasPosition.x + x + width, this.canvasPosition.y + y);
27177
27214
  }
27178
27215
  onCellRightClicked(col, row, { x, y }) {
27179
27216
  const zones = this.env.model.getters.getSelectedZones();
@@ -28463,29 +28500,12 @@
28463
28500
  return width;
28464
28501
  return Math.round((width / WIDTH_FACTOR) * 100) / 100;
28465
28502
  }
28466
- function convertBorderDescr(descr) {
28467
- if (!descr) {
28468
- return undefined;
28469
- }
28470
- return {
28471
- style: descr.style,
28472
- color: { rgb: descr.color },
28473
- };
28474
- }
28475
28503
  function extractStyle(cell, data) {
28476
28504
  let style = {};
28477
28505
  if (cell.style) {
28478
28506
  style = data.styles[cell.style];
28479
28507
  }
28480
28508
  const format = extractFormat(cell, data);
28481
- const exportedBorder = {};
28482
- if (cell.border) {
28483
- const border = data.borders[cell.border];
28484
- exportedBorder.left = convertBorderDescr(border.left);
28485
- exportedBorder.right = convertBorderDescr(border.right);
28486
- exportedBorder.bottom = convertBorderDescr(border.bottom);
28487
- exportedBorder.top = convertBorderDescr(border.top);
28488
- }
28489
28509
  const styles = {
28490
28510
  font: {
28491
28511
  size: style?.fontSize || DEFAULT_FONT_SIZE,
@@ -28499,7 +28519,7 @@
28499
28519
  }
28500
28520
  : { reservedAttribute: "none" },
28501
28521
  numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
28502
- border: exportedBorder || {},
28522
+ border: cell.border || 0,
28503
28523
  alignment: {
28504
28524
  horizontal: style.align,
28505
28525
  vertical: style.verticalAlign
@@ -28521,15 +28541,12 @@
28521
28541
  return undefined;
28522
28542
  }
28523
28543
  function normalizeStyle(construct, styles) {
28524
- const { id: fontId } = pushElement(styles["font"], construct.fonts);
28525
- const { id: fillId } = pushElement(styles["fill"], construct.fills);
28526
- const { id: borderId } = pushElement(styles["border"], construct.borders);
28527
28544
  // Normalize this
28528
28545
  const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
28529
28546
  const style = {
28530
- fontId,
28531
- fillId,
28532
- borderId,
28547
+ fontId: pushElement(styles.font, construct.fonts),
28548
+ fillId: pushElement(styles.fill, construct.fills),
28549
+ borderId: styles.border,
28533
28550
  numFmtId,
28534
28551
  alignment: {
28535
28552
  vertical: styles.alignment.vertical,
@@ -28537,8 +28554,7 @@
28537
28554
  wrapText: styles.alignment.wrapText,
28538
28555
  },
28539
28556
  };
28540
- const { id } = pushElement(style, construct.styles);
28541
- return id;
28557
+ return pushElement(style, construct.styles);
28542
28558
  }
28543
28559
  function convertFormat(format, numFmtStructure) {
28544
28560
  if (!format) {
@@ -28546,8 +28562,7 @@
28546
28562
  }
28547
28563
  let formatId = XLSX_FORMAT_MAP[format.format];
28548
28564
  if (!formatId) {
28549
- const { id } = pushElement(format, numFmtStructure);
28550
- formatId = id + FIRST_NUMFMT_ID;
28565
+ formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
28551
28566
  }
28552
28567
  return formatId;
28553
28568
  }
@@ -28572,20 +28587,15 @@
28572
28587
  return id;
28573
28588
  }
28574
28589
  function pushElement(property, propertyList) {
28575
- for (let [key, value] of Object.entries(propertyList)) {
28576
- if (JSON.stringify(value) === JSON.stringify(property)) {
28577
- return { id: parseInt(key, 10), list: propertyList };
28590
+ let len = propertyList.length;
28591
+ const operator = typeof property === "object" ? deepEquals : (a, b) => a === b;
28592
+ for (let i = 0; i < len; i++) {
28593
+ if (operator(property, propertyList[i])) {
28594
+ return i;
28578
28595
  }
28579
28596
  }
28580
- let elemId = propertyList.findIndex((elem) => JSON.stringify(elem) === JSON.stringify(property));
28581
- if (elemId === -1) {
28582
- propertyList.push(property);
28583
- elemId = propertyList.length - 1;
28584
- }
28585
- return {
28586
- id: elemId,
28587
- list: propertyList,
28588
- };
28597
+ propertyList[propertyList.length] = property;
28598
+ return propertyList.length - 1;
28589
28599
  }
28590
28600
  const chartIds = [];
28591
28601
  /**
@@ -29037,7 +29047,7 @@
29037
29047
  function getSheetDims(sheet) {
29038
29048
  const dims = [0, 0];
29039
29049
  for (let row of sheet.rows) {
29040
- dims[0] = Math.max(dims[0], ...row.cells.map((cell) => toCartesian(cell.xc).col));
29050
+ dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
29041
29051
  dims[1] = Math.max(dims[1], row.index);
29042
29052
  }
29043
29053
  dims[0] = Math.max(dims[0], EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
@@ -29306,7 +29316,25 @@
29306
29316
  }
29307
29317
  return document;
29308
29318
  }
29309
- function getDefaultXLSXStructure() {
29319
+ function convertBorderDescr(descr) {
29320
+ if (!descr) {
29321
+ return undefined;
29322
+ }
29323
+ return {
29324
+ style: descr.style,
29325
+ color: { rgb: descr.color },
29326
+ };
29327
+ }
29328
+ function getDefaultXLSXStructure(data) {
29329
+ const xlsxBorders = Object.values(data.borders).map((border) => {
29330
+ return {
29331
+ left: convertBorderDescr(border.left),
29332
+ right: convertBorderDescr(border.right),
29333
+ bottom: convertBorderDescr(border.bottom),
29334
+ top: convertBorderDescr(border.top),
29335
+ };
29336
+ });
29337
+ const borders = [{}, ...xlsxBorders];
29310
29338
  return {
29311
29339
  relsFiles: [],
29312
29340
  sharedStrings: [],
@@ -29329,7 +29357,7 @@
29329
29357
  },
29330
29358
  ],
29331
29359
  fills: [{ reservedAttribute: "none" }, { reservedAttribute: "gray125" }],
29332
- borders: [{}],
29360
+ borders,
29333
29361
  numFmts: [],
29334
29362
  dxfs: [],
29335
29363
  };
@@ -33394,7 +33422,17 @@
33394
33422
  }
33395
33423
  }
33396
33424
  exportForExcel(data) {
33397
- this.export(data);
33425
+ for (const sheet of data.sheets) {
33426
+ for (const filterTable of this.getFilterTables(sheet.id)) {
33427
+ if (zoneToDimension(filterTable.zone).numberOfRows === 1) {
33428
+ continue;
33429
+ }
33430
+ sheet.filterTables.push({
33431
+ range: zoneToXc(filterTable.zone),
33432
+ filters: [],
33433
+ });
33434
+ }
33435
+ }
33398
33436
  }
33399
33437
  }
33400
33438
 
@@ -33534,7 +33572,7 @@
33534
33572
  if (hiddenElements.size >= elements) {
33535
33573
  return 69 /* CommandResult.TooManyHiddenElements */;
33536
33574
  }
33537
- else if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
33575
+ else if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
33538
33576
  return 89 /* CommandResult.InvalidHeaderIndex */;
33539
33577
  }
33540
33578
  else {
@@ -34328,8 +34366,8 @@
34328
34366
  let newRange = range;
34329
34367
  let changeType = "NONE";
34330
34368
  for (let group of groups) {
34331
- const min = Math.min(...group);
34332
- const max = Math.max(...group);
34369
+ const min = largeMin(group);
34370
+ const max = largeMax(group);
34333
34371
  if (range.zone[start] <= min && min <= range.zone[end]) {
34334
34372
  const toRemove = Math.min(range.zone[end], max) - min + 1;
34335
34373
  changeType = "RESIZE";
@@ -34756,7 +34794,7 @@
34756
34794
  const elements = cmd.dimension === "COL"
34757
34795
  ? this.getNumberCols(cmd.sheetId)
34758
34796
  : this.getNumberRows(cmd.sheetId);
34759
- if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
34797
+ if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
34760
34798
  return 89 /* CommandResult.InvalidHeaderIndex */;
34761
34799
  }
34762
34800
  else if (this.checkElementsIncludeAllNonFrozenHeaders(cmd.sheetId, cmd.dimension, cmd.elements)) {
@@ -36688,7 +36726,9 @@
36688
36726
  this.blockedArrayFormulas = new Set();
36689
36727
  this.spreadingRelations = new SpreadingRelation();
36690
36728
  this.formulaDependencies = lazy(() => {
36691
- const dependencies = [...this.getAllCells()].flatMap((positionId) => this.getDirectDependencies(positionId).map((range) => ({
36729
+ const dependencies = [...this.getAllCells()].flatMap((positionId) => this.getDirectDependencies(positionId)
36730
+ .filter((range) => !range.invalidSheetName && !range.invalidXc)
36731
+ .map((range) => ({
36692
36732
  data: positionId,
36693
36733
  boundingBox: {
36694
36734
  zone: range.zone,
@@ -37632,13 +37672,13 @@
37632
37672
  .map((cell) => cell.value);
37633
37673
  switch (threshold.type) {
37634
37674
  case "value":
37635
- const result = functionName === "max" ? Math.max(...rangeValues) : Math.min(...rangeValues);
37675
+ const result = functionName === "max" ? largeMax(rangeValues) : largeMin(rangeValues);
37636
37676
  return result;
37637
37677
  case "number":
37638
37678
  return Number(threshold.value);
37639
37679
  case "percentage":
37640
- const min = Math.min(...rangeValues);
37641
- const max = Math.max(...rangeValues);
37680
+ const min = largeMin(rangeValues);
37681
+ const max = largeMax(rangeValues);
37642
37682
  const delta = max - min;
37643
37683
  return min + (delta * Number(threshold.value)) / 100;
37644
37684
  case "percentile":
@@ -38521,13 +38561,13 @@
38521
38561
  const cells = this.getters.getEvaluatedCellsInZone(sheet.id, zone);
38522
38562
  const cellPositions = range(end, -1, -1);
38523
38563
  const invalidCells = cellPositions.filter((position) => cells[position] && !cells[position].isAutoSummable);
38524
- const maxValidPosition = Math.max(...invalidCells);
38564
+ const maxValidPosition = largeMax(invalidCells);
38525
38565
  const numberSequences = groupConsecutive(cellPositions.filter((position) => this.isNumber(cells[position])));
38526
38566
  const firstSequence = numberSequences[0] || [];
38527
- if (Math.max(...firstSequence) < maxValidPosition) {
38567
+ if (largeMax(firstSequence) < maxValidPosition) {
38528
38568
  return Infinity;
38529
38569
  }
38530
- return Math.min(...firstSequence);
38570
+ return largeMin(firstSequence);
38531
38571
  }
38532
38572
  shouldFindData(sheetId, zone) {
38533
38573
  return this.getters.isEmpty(sheetId, zone) || this.getters.isSingleCellOrMerge(sheetId, zone);
@@ -40116,7 +40156,7 @@
40116
40156
  * column of the current viewport
40117
40157
  */
40118
40158
  getColDimensionsInViewport(sheetId, col) {
40119
- const left = Math.min(...this.getters.getSheetViewVisibleCols());
40159
+ const left = largeMin(this.getters.getSheetViewVisibleCols());
40120
40160
  const start = this.getters.getColRowOffsetInViewport("COL", left, col);
40121
40161
  const size = this.getters.getColSize(sheetId, col);
40122
40162
  const isColHidden = this.getters.isColHidden(sheetId, col);
@@ -40131,7 +40171,7 @@
40131
40171
  * of the current viewport
40132
40172
  */
40133
40173
  getRowDimensionsInViewport(sheetId, row) {
40134
- const top = Math.min(...this.getters.getSheetViewVisibleRows());
40174
+ const top = largeMin(this.getters.getSheetViewVisibleRows());
40135
40175
  const start = this.getters.getColRowOffsetInViewport("ROW", top, row);
40136
40176
  const size = this.getters.getRowSize(sheetId, row);
40137
40177
  const isRowHidden = this.getters.isRowHidden(sheetId, row);
@@ -41628,7 +41668,7 @@
41628
41668
  getColMaxWidth(sheetId, index) {
41629
41669
  const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
41630
41670
  const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
41631
- return Math.max(0, ...sizes);
41671
+ return Math.max(0, largeMax(sizes));
41632
41672
  }
41633
41673
  /**
41634
41674
  * Check that any "sheetId" in the command matches an existing
@@ -42930,7 +42970,7 @@
42930
42970
  }
42931
42971
  getPasteZone(target) {
42932
42972
  const height = this.values.length;
42933
- const width = Math.max(...this.values.map((a) => a.length));
42973
+ const width = largeMax(this.values.map((a) => a.length));
42934
42974
  const { left: activeCol, top: activeRow } = target[0];
42935
42975
  return {
42936
42976
  top: activeRow,
@@ -45223,13 +45263,14 @@
45223
45263
  }
45224
45264
  }
45225
45265
  handleEvent(event) {
45266
+ const sheetId = this.getters.getActiveSheetId();
45226
45267
  if (event.options.scrollIntoView) {
45227
45268
  let { col, row } = findCellInNewZone(event.previousAnchor.zone, event.anchor.zone);
45228
45269
  if (event.mode === "updateAnchor") {
45229
45270
  const oldZone = event.previousAnchor.zone;
45230
45271
  const newZone = event.anchor.zone;
45231
45272
  // altering a zone should not move the viewport in a dimension that wasn't changed
45232
- const { top, bottom, left, right } = this.getters.getActiveMainViewport();
45273
+ const { top, bottom, left, right } = this.getMainInternalViewport(sheetId);
45233
45274
  if (oldZone.left === newZone.left && oldZone.right === newZone.right) {
45234
45275
  col = left > col || col > right ? left : col;
45235
45276
  }
@@ -45237,7 +45278,6 @@
45237
45278
  row = top > row || row > bottom ? top : row;
45238
45279
  }
45239
45280
  }
45240
- const sheetId = this.getters.getActiveSheetId();
45241
45281
  col = Math.min(col, this.getters.getNumberCols(sheetId) - 1);
45242
45282
  row = Math.min(row, this.getters.getNumberRows(sheetId) - 1);
45243
45283
  this.refreshViewport(this.getters.getActiveSheetId(), { col, row });
@@ -45263,16 +45303,16 @@
45263
45303
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
45264
45304
  break;
45265
45305
  case "SHIFT_VIEWPORT_DOWN":
45266
- const { top } = this.getActiveMainViewport();
45267
45306
  const sheetId = this.getters.getActiveSheetId();
45268
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).start + this.sheetViewHeight);
45269
- this.shiftVertically(shiftedOffsetY);
45307
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
45308
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
45309
+ this.shiftVertically(topRowDims.start + viewportHeight - offsetCorrectionY);
45270
45310
  break;
45271
45311
  case "SHIFT_VIEWPORT_UP": {
45272
- const { top } = this.getActiveMainViewport();
45273
45312
  const sheetId = this.getters.getActiveSheetId();
45274
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).end - this.sheetViewHeight);
45275
- this.shiftVertically(shiftedOffsetY);
45313
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
45314
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
45315
+ this.shiftVertically(topRowDims.end - offsetCorrectionY - viewportHeight);
45276
45316
  break;
45277
45317
  }
45278
45318
  case "REMOVE_COLUMNS_ROWS":
@@ -45634,17 +45674,6 @@
45634
45674
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
45635
45675
  Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
45636
45676
  }
45637
- /**
45638
- * Clip the vertical offset within the allowed range.
45639
- * Not above the sheet, nor below the sheet.
45640
- */
45641
- clipOffsetY(offsetY) {
45642
- const { height } = this.getMainViewportRect();
45643
- const maxOffset = height - this.sheetViewHeight;
45644
- offsetY = Math.min(offsetY, maxOffset);
45645
- offsetY = Math.max(offsetY, 0);
45646
- return offsetY;
45647
- }
45648
45677
  getViewportOffset(sheetId) {
45649
45678
  return {
45650
45679
  x: this.viewports[sheetId]?.bottomRight.offsetScrollbarX || 0,
@@ -45700,12 +45729,15 @@
45700
45729
  * viewport top.
45701
45730
  */
45702
45731
  shiftVertically(offset) {
45703
- const { top } = this.getActiveMainViewport();
45732
+ const sheetId = this.getters.getActiveSheetId();
45733
+ const { top } = this.getMainInternalViewport(sheetId);
45704
45734
  const { scrollX } = this.getActiveSheetScrollInfo();
45705
45735
  this.setSheetViewOffset(scrollX, offset);
45706
45736
  const { anchor } = this.getters.getSelection();
45707
- const deltaRow = this.getActiveMainViewport().top - top;
45708
- this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
45737
+ if (anchor.cell.row >= this.getters.getPaneDivisions(sheetId).ySplit) {
45738
+ const deltaRow = this.getMainInternalViewport(sheetId).top - top;
45739
+ this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
45740
+ }
45709
45741
  }
45710
45742
  getVisibleFigures() {
45711
45743
  const sheetId = this.getters.getActiveSheetId();
@@ -46151,12 +46183,14 @@
46151
46183
  this.editionState = "initializing";
46152
46184
  }
46153
46185
  stopEdition() {
46154
- if (!this.state.isEditing)
46186
+ const input = this.sheetNameRef.el;
46187
+ if (!this.state.isEditing || !input)
46155
46188
  return;
46156
46189
  this.state.isEditing = false;
46157
46190
  this.editionState = "initializing";
46158
- this.sheetNameRef.el?.blur();
46191
+ input.blur();
46159
46192
  const inputValue = this.getInputContent() || "";
46193
+ input.innerText = inputValue;
46160
46194
  interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
46161
46195
  }
46162
46196
  cancelEdition() {
@@ -46618,7 +46652,7 @@
46618
46652
  this.sheetListRef.el.scrollTo({ top: 0, left: scroll, behavior: "smooth" });
46619
46653
  }
46620
46654
  onSheetMouseDown(sheetId, event) {
46621
- if (event.button !== 0)
46655
+ if (event.button !== 0 || this.env.model.getters.isReadonly())
46622
46656
  return;
46623
46657
  this.closeMenu();
46624
46658
  const mouseX = event.clientX;
@@ -49822,7 +49856,7 @@
49822
49856
  }
49823
49857
  function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
49824
49858
  const colors = new ChartColors();
49825
- const maxLength = Math.max(...chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
49859
+ const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
49826
49860
  const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
49827
49861
  const dataSetsNodes = [];
49828
49862
  for (const [dsIndex, dataset] of Object.entries(chart.dataSets).reverse()) {
@@ -49960,8 +49994,7 @@
49960
49994
  attrs.push(["t", "b"]);
49961
49995
  }
49962
49996
  else if (forceString || !isNumber(value, DEFAULT_LOCALE)) {
49963
- const { id } = pushElement(content, sharedStrings);
49964
- value = id.toString();
49997
+ value = pushElement(content, sharedStrings);
49965
49998
  attrs.push(["t", "s"]);
49966
49999
  }
49967
50000
  return { attrs, node: escapeXml /*xml*/ `<v>${value}</v>` };
@@ -50086,8 +50119,7 @@
50086
50119
  if (rule.style.fillColor) {
50087
50120
  dxf.fill = { fgColor: { rgb: rule.style.fillColor } };
50088
50121
  }
50089
- const { id } = pushElement(dxf, dxfs);
50090
- ruleAttributes.push(["dxfId", id]);
50122
+ ruleAttributes.push(["dxfId", pushElement(dxf, dxfs)]);
50091
50123
  return escapeXml /*xml*/ `
50092
50124
  <conditionalFormatting sqref="${cf.ranges.join(" ")}">
50093
50125
  <cfRule ${formatAttributes(ruleAttributes)}>
@@ -50896,7 +50928,7 @@
50896
50928
  */
50897
50929
  function getXLSX(data) {
50898
50930
  const files = [];
50899
- const construct = getDefaultXLSXStructure();
50931
+ const construct = getDefaultXLSXStructure(data);
50900
50932
  files.push(createWorkbook(data, construct));
50901
50933
  files.push(...createWorksheets(data, construct));
50902
50934
  files.push(createStylesSheet(construct));
@@ -51753,9 +51785,9 @@
51753
51785
  Object.defineProperty(exports, '__esModule', { value: true });
51754
51786
 
51755
51787
 
51756
- __info__.version = '16.4.27';
51757
- __info__.date = '2024-03-25T09:41:12.743Z';
51758
- __info__.hash = '42e4252';
51788
+ __info__.version = '16.4.29';
51789
+ __info__.date = '2024-04-10T12:19:13.935Z';
51790
+ __info__.hash = 'c022445';
51759
51791
 
51760
51792
 
51761
51793
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);