@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.
@@ -526,7 +526,7 @@ function getItemId(item, itemsDic) {
526
526
  }
527
527
  // Generate new Id if the item didn't exist in the dictionary
528
528
  const ids = Object.keys(itemsDic);
529
- const maxId = ids.length === 0 ? 0 : Math.max(...ids.map((id) => parseInt(id, 10)));
529
+ const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
530
530
  itemsDic[maxId + 1] = item;
531
531
  return maxId + 1;
532
532
  }
@@ -617,7 +617,7 @@ function deepEquals(o1, o2) {
617
617
  if (typeof o1 !== typeof o2)
618
618
  return false;
619
619
  if (typeof o1 !== "object")
620
- return o1 === o2;
620
+ return false;
621
621
  // Objects can have different keys if the values are undefined
622
622
  const keys = new Set();
623
623
  Object.keys(o1).forEach((key) => keys.add(key));
@@ -742,6 +742,34 @@ function insertItemsAtIndex(array, items, index) {
742
742
  const newArray = [...array];
743
743
  newArray.splice(index, 0, ...items);
744
744
  return newArray;
745
+ }
746
+ /**
747
+ * Alternative to Math.max that works with large arrays.
748
+ * Typically useful for arrays bigger than 100k elements.
749
+ */
750
+ function largeMax(array) {
751
+ let len = array.length;
752
+ if (len < 100000)
753
+ return Math.max(...array);
754
+ let max = -Infinity;
755
+ while (len--) {
756
+ max = array[len] > max ? array[len] : max;
757
+ }
758
+ return max;
759
+ }
760
+ /**
761
+ * Alternative to Math.min that works with large arrays.
762
+ * Typically useful for arrays bigger than 100k elements.
763
+ */
764
+ function largeMin(array) {
765
+ let len = array.length;
766
+ if (len < 100000)
767
+ return Math.min(...array);
768
+ let min = +Infinity;
769
+ while (len--) {
770
+ min = array[len] < min ? array[len] : min;
771
+ }
772
+ return min;
745
773
  }
746
774
 
747
775
  const RBA_REGEX = /rgba?\(|\s+|\)/gi;
@@ -15773,6 +15801,7 @@ class LinkEditor extends owl.Component {
15773
15801
  this.save();
15774
15802
  }
15775
15803
  ev.stopPropagation();
15804
+ ev.preventDefault();
15776
15805
  break;
15777
15806
  case "Escape":
15778
15807
  this.cancel();
@@ -16338,10 +16367,10 @@ function aggregateDataForLabels(labels, datasets) {
16338
16367
  }
16339
16368
  }
16340
16369
  return {
16341
- labels: Object.keys(labelMap),
16370
+ labels: Array.from(labelSet),
16342
16371
  dataSetsValues: datasets.map((dataset, indexOfDataset) => ({
16343
16372
  ...dataset,
16344
- data: Object.values(labelMap).map((dataOfLabel) => dataOfLabel[indexOfDataset]),
16373
+ data: Array.from(labelSet).map((label) => labelMap[label][indexOfDataset]),
16345
16374
  })),
16346
16375
  };
16347
16376
  }
@@ -17062,7 +17091,7 @@ function getBestTimeUnitForScale(labels, format, locale) {
17062
17091
  return undefined;
17063
17092
  }
17064
17093
  const labelsTimestamps = labelDates.map((date) => date.getTime());
17065
- const period = Math.max(...labelsTimestamps) - Math.min(...labelsTimestamps);
17094
+ const period = largeMax(labelsTimestamps) - largeMin(labelsTimestamps);
17066
17095
  const minUnit = getFormatMinDisplayUnit(format);
17067
17096
  if (UNIT_LENGTH.second >= UNIT_LENGTH[minUnit] && Milliseconds.inSeconds(period) < 180) {
17068
17097
  return "second";
@@ -17504,7 +17533,7 @@ function getPieConfiguration(chart, labels, localeFormat) {
17504
17533
  }
17505
17534
  function getPieColors(colors, dataSetsValues) {
17506
17535
  const pieColors = [];
17507
- const maxLength = Math.max(...dataSetsValues.map((ds) => ds.data.length));
17536
+ const maxLength = largeMax(dataSetsValues.map((ds) => ds.data.length));
17508
17537
  for (let i = 0; i <= maxLength; i++) {
17509
17538
  pieColors.push(colors.next());
17510
17539
  }
@@ -18321,8 +18350,8 @@ const DELETE_CONTENT_ROWS_NAME = (env) => {
18321
18350
  let last;
18322
18351
  const activesRows = env.model.getters.getActiveRows();
18323
18352
  if (activesRows.size !== 0) {
18324
- first = Math.min(...activesRows);
18325
- last = Math.max(...activesRows);
18353
+ first = largeMin([...activesRows]);
18354
+ last = largeMax([...activesRows]);
18326
18355
  }
18327
18356
  else {
18328
18357
  const zone = env.model.getters.getSelectedZones()[0];
@@ -18350,8 +18379,8 @@ const DELETE_CONTENT_COLUMNS_NAME = (env) => {
18350
18379
  let last;
18351
18380
  const activeCols = env.model.getters.getActiveCols();
18352
18381
  if (activeCols.size !== 0) {
18353
- first = Math.min(...activeCols);
18354
- last = Math.max(...activeCols);
18382
+ first = largeMin([...activeCols]);
18383
+ last = largeMax([...activeCols]);
18355
18384
  }
18356
18385
  else {
18357
18386
  const zone = env.model.getters.getSelectedZones()[0];
@@ -18379,8 +18408,8 @@ const REMOVE_ROWS_NAME = (env) => {
18379
18408
  let last;
18380
18409
  const activesRows = env.model.getters.getActiveRows();
18381
18410
  if (activesRows.size !== 0) {
18382
- first = Math.min(...activesRows);
18383
- last = Math.max(...activesRows);
18411
+ first = largeMin([...activesRows]);
18412
+ last = largeMax([...activesRows]);
18384
18413
  }
18385
18414
  else {
18386
18415
  const zone = env.model.getters.getSelectedZones()[0];
@@ -18421,8 +18450,8 @@ const REMOVE_COLUMNS_NAME = (env) => {
18421
18450
  let last;
18422
18451
  const activeCols = env.model.getters.getActiveCols();
18423
18452
  if (activeCols.size !== 0) {
18424
- first = Math.min(...activeCols);
18425
- last = Math.max(...activeCols);
18453
+ first = largeMin([...activeCols]);
18454
+ last = largeMax([...activeCols]);
18426
18455
  }
18427
18456
  else {
18428
18457
  const zone = env.model.getters.getSelectedZones()[0];
@@ -18463,7 +18492,7 @@ const INSERT_ROWS_BEFORE_ACTION = (env) => {
18463
18492
  let row;
18464
18493
  let quantity;
18465
18494
  if (activeRows.size) {
18466
- row = Math.min(...activeRows);
18495
+ row = largeMin([...activeRows]);
18467
18496
  quantity = activeRows.size;
18468
18497
  }
18469
18498
  else {
@@ -18484,7 +18513,7 @@ const INSERT_ROWS_AFTER_ACTION = (env) => {
18484
18513
  let row;
18485
18514
  let quantity;
18486
18515
  if (activeRows.size) {
18487
- row = Math.max(...activeRows);
18516
+ row = largeMax([...activeRows]);
18488
18517
  quantity = activeRows.size;
18489
18518
  }
18490
18519
  else {
@@ -18505,7 +18534,7 @@ const INSERT_COLUMNS_BEFORE_ACTION = (env) => {
18505
18534
  let column;
18506
18535
  let quantity;
18507
18536
  if (activeCols.size) {
18508
- column = Math.min(...activeCols);
18537
+ column = largeMin([...activeCols]);
18509
18538
  quantity = activeCols.size;
18510
18539
  }
18511
18540
  else {
@@ -18526,7 +18555,7 @@ const INSERT_COLUMNS_AFTER_ACTION = (env) => {
18526
18555
  let column;
18527
18556
  let quantity;
18528
18557
  if (activeCols.size) {
18529
- column = Math.max(...activeCols);
18558
+ column = largeMax([...activeCols]);
18530
18559
  quantity = activeCols.size;
18531
18560
  }
18532
18561
  else {
@@ -24438,6 +24467,11 @@ class Composer extends owl.Component {
24438
24467
  }
24439
24468
  }
24440
24469
  }
24470
+ onContextMenu(ev) {
24471
+ if (this.env.model.getters.getEditionMode() === "inactive") {
24472
+ this.props.onInputContextMenu?.(ev);
24473
+ }
24474
+ }
24441
24475
  // ---------------------------------------------------------------------------
24442
24476
  // Private
24443
24477
  // ---------------------------------------------------------------------------
@@ -24662,6 +24696,7 @@ Composer.props = {
24662
24696
  onComposerCellFocused: { type: Function, optional: true },
24663
24697
  onComposerContentFocused: Function,
24664
24698
  isDefaultFocus: { type: Boolean, optional: true },
24699
+ onInputContextMenu: { type: Function, optional: true },
24665
24700
  };
24666
24701
 
24667
24702
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
@@ -24738,6 +24773,7 @@ class GridComposer extends owl.Component {
24738
24773
  isDefaultFocus: true,
24739
24774
  onComposerContentFocused: this.props.onComposerContentFocused,
24740
24775
  onComposerCellFocused: this.props.onComposerCellFocused,
24776
+ onInputContextMenu: this.props.onInputContextMenu,
24741
24777
  };
24742
24778
  }
24743
24779
  get containerStyle() {
@@ -24826,6 +24862,7 @@ GridComposer.props = {
24826
24862
  onComposerContentFocused: Function,
24827
24863
  gridDims: Object,
24828
24864
  onComposerCellFocused: Function,
24865
+ onInputContextMenu: Function,
24829
24866
  };
24830
24867
 
24831
24868
  const CSS$1 = css /* scss */ `
@@ -27175,8 +27212,8 @@ class Grid extends owl.Component {
27175
27212
  else if (this.env.model.getters.getActiveRows().has(row)) {
27176
27213
  type = "ROW";
27177
27214
  }
27178
- const { x, y, width, height } = this.env.model.getters.getVisibleRect(lastZone);
27179
- this.toggleContextMenu(type, x + width, y + height);
27215
+ const { x, y, width } = this.env.model.getters.getVisibleRect(lastZone);
27216
+ this.toggleContextMenu(type, this.canvasPosition.x + x + width, this.canvasPosition.y + y);
27180
27217
  }
27181
27218
  onCellRightClicked(col, row, { x, y }) {
27182
27219
  const zones = this.env.model.getters.getSelectedZones();
@@ -28466,29 +28503,12 @@ function convertWidthFromExcel(width) {
28466
28503
  return width;
28467
28504
  return Math.round((width / WIDTH_FACTOR) * 100) / 100;
28468
28505
  }
28469
- function convertBorderDescr(descr) {
28470
- if (!descr) {
28471
- return undefined;
28472
- }
28473
- return {
28474
- style: descr.style,
28475
- color: { rgb: descr.color },
28476
- };
28477
- }
28478
28506
  function extractStyle(cell, data) {
28479
28507
  let style = {};
28480
28508
  if (cell.style) {
28481
28509
  style = data.styles[cell.style];
28482
28510
  }
28483
28511
  const format = extractFormat(cell, data);
28484
- const exportedBorder = {};
28485
- if (cell.border) {
28486
- const border = data.borders[cell.border];
28487
- exportedBorder.left = convertBorderDescr(border.left);
28488
- exportedBorder.right = convertBorderDescr(border.right);
28489
- exportedBorder.bottom = convertBorderDescr(border.bottom);
28490
- exportedBorder.top = convertBorderDescr(border.top);
28491
- }
28492
28512
  const styles = {
28493
28513
  font: {
28494
28514
  size: style?.fontSize || DEFAULT_FONT_SIZE,
@@ -28502,7 +28522,7 @@ function extractStyle(cell, data) {
28502
28522
  }
28503
28523
  : { reservedAttribute: "none" },
28504
28524
  numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
28505
- border: exportedBorder || {},
28525
+ border: cell.border || 0,
28506
28526
  alignment: {
28507
28527
  horizontal: style.align,
28508
28528
  vertical: style.verticalAlign
@@ -28524,15 +28544,12 @@ function extractFormat(cell, data) {
28524
28544
  return undefined;
28525
28545
  }
28526
28546
  function normalizeStyle(construct, styles) {
28527
- const { id: fontId } = pushElement(styles["font"], construct.fonts);
28528
- const { id: fillId } = pushElement(styles["fill"], construct.fills);
28529
- const { id: borderId } = pushElement(styles["border"], construct.borders);
28530
28547
  // Normalize this
28531
28548
  const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
28532
28549
  const style = {
28533
- fontId,
28534
- fillId,
28535
- borderId,
28550
+ fontId: pushElement(styles.font, construct.fonts),
28551
+ fillId: pushElement(styles.fill, construct.fills),
28552
+ borderId: styles.border,
28536
28553
  numFmtId,
28537
28554
  alignment: {
28538
28555
  vertical: styles.alignment.vertical,
@@ -28540,8 +28557,7 @@ function normalizeStyle(construct, styles) {
28540
28557
  wrapText: styles.alignment.wrapText,
28541
28558
  },
28542
28559
  };
28543
- const { id } = pushElement(style, construct.styles);
28544
- return id;
28560
+ return pushElement(style, construct.styles);
28545
28561
  }
28546
28562
  function convertFormat(format, numFmtStructure) {
28547
28563
  if (!format) {
@@ -28549,8 +28565,7 @@ function convertFormat(format, numFmtStructure) {
28549
28565
  }
28550
28566
  let formatId = XLSX_FORMAT_MAP[format.format];
28551
28567
  if (!formatId) {
28552
- const { id } = pushElement(format, numFmtStructure);
28553
- formatId = id + FIRST_NUMFMT_ID;
28568
+ formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
28554
28569
  }
28555
28570
  return formatId;
28556
28571
  }
@@ -28575,20 +28590,15 @@ function addRelsToFile(relsFiles, path, rel) {
28575
28590
  return id;
28576
28591
  }
28577
28592
  function pushElement(property, propertyList) {
28578
- for (let [key, value] of Object.entries(propertyList)) {
28579
- if (JSON.stringify(value) === JSON.stringify(property)) {
28580
- return { id: parseInt(key, 10), list: propertyList };
28593
+ let len = propertyList.length;
28594
+ const operator = typeof property === "object" ? deepEquals : (a, b) => a === b;
28595
+ for (let i = 0; i < len; i++) {
28596
+ if (operator(property, propertyList[i])) {
28597
+ return i;
28581
28598
  }
28582
28599
  }
28583
- let elemId = propertyList.findIndex((elem) => JSON.stringify(elem) === JSON.stringify(property));
28584
- if (elemId === -1) {
28585
- propertyList.push(property);
28586
- elemId = propertyList.length - 1;
28587
- }
28588
- return {
28589
- id: elemId,
28590
- list: propertyList,
28591
- };
28600
+ propertyList[propertyList.length] = property;
28601
+ return propertyList.length - 1;
28592
28602
  }
28593
28603
  const chartIds = [];
28594
28604
  /**
@@ -29040,7 +29050,7 @@ function convertHyperlink(link, cellValue, warningManager) {
29040
29050
  function getSheetDims(sheet) {
29041
29051
  const dims = [0, 0];
29042
29052
  for (let row of sheet.rows) {
29043
- dims[0] = Math.max(dims[0], ...row.cells.map((cell) => toCartesian(cell.xc).col));
29053
+ dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
29044
29054
  dims[1] = Math.max(dims[1], row.index);
29045
29055
  }
29046
29056
  dims[0] = Math.max(dims[0], EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
@@ -29309,7 +29319,25 @@ function parseXML(xmlString, mimeType = "text/xml") {
29309
29319
  }
29310
29320
  return document;
29311
29321
  }
29312
- function getDefaultXLSXStructure() {
29322
+ function convertBorderDescr(descr) {
29323
+ if (!descr) {
29324
+ return undefined;
29325
+ }
29326
+ return {
29327
+ style: descr.style,
29328
+ color: { rgb: descr.color },
29329
+ };
29330
+ }
29331
+ function getDefaultXLSXStructure(data) {
29332
+ const xlsxBorders = Object.values(data.borders).map((border) => {
29333
+ return {
29334
+ left: convertBorderDescr(border.left),
29335
+ right: convertBorderDescr(border.right),
29336
+ bottom: convertBorderDescr(border.bottom),
29337
+ top: convertBorderDescr(border.top),
29338
+ };
29339
+ });
29340
+ const borders = [{}, ...xlsxBorders];
29313
29341
  return {
29314
29342
  relsFiles: [],
29315
29343
  sharedStrings: [],
@@ -29332,7 +29360,7 @@ function getDefaultXLSXStructure() {
29332
29360
  },
29333
29361
  ],
29334
29362
  fills: [{ reservedAttribute: "none" }, { reservedAttribute: "gray125" }],
29335
- borders: [{}],
29363
+ borders,
29336
29364
  numFmts: [],
29337
29365
  dxfs: [],
29338
29366
  };
@@ -33397,7 +33425,17 @@ class FiltersPlugin extends CorePlugin {
33397
33425
  }
33398
33426
  }
33399
33427
  exportForExcel(data) {
33400
- this.export(data);
33428
+ for (const sheet of data.sheets) {
33429
+ for (const filterTable of this.getFilterTables(sheet.id)) {
33430
+ if (zoneToDimension(filterTable.zone).numberOfRows === 1) {
33431
+ continue;
33432
+ }
33433
+ sheet.filterTables.push({
33434
+ range: zoneToXc(filterTable.zone),
33435
+ filters: [],
33436
+ });
33437
+ }
33438
+ }
33401
33439
  }
33402
33440
  }
33403
33441
 
@@ -33537,7 +33575,7 @@ class HeaderVisibilityPlugin extends CorePlugin {
33537
33575
  if (hiddenElements.size >= elements) {
33538
33576
  return 69 /* CommandResult.TooManyHiddenElements */;
33539
33577
  }
33540
- else if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
33578
+ else if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
33541
33579
  return 89 /* CommandResult.InvalidHeaderIndex */;
33542
33580
  }
33543
33581
  else {
@@ -34331,8 +34369,8 @@ class RangeAdapter {
34331
34369
  let newRange = range;
34332
34370
  let changeType = "NONE";
34333
34371
  for (let group of groups) {
34334
- const min = Math.min(...group);
34335
- const max = Math.max(...group);
34372
+ const min = largeMin(group);
34373
+ const max = largeMax(group);
34336
34374
  if (range.zone[start] <= min && min <= range.zone[end]) {
34337
34375
  const toRemove = Math.min(range.zone[end], max) - min + 1;
34338
34376
  changeType = "RESIZE";
@@ -34759,7 +34797,7 @@ class SheetPlugin extends CorePlugin {
34759
34797
  const elements = cmd.dimension === "COL"
34760
34798
  ? this.getNumberCols(cmd.sheetId)
34761
34799
  : this.getNumberRows(cmd.sheetId);
34762
- if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
34800
+ if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
34763
34801
  return 89 /* CommandResult.InvalidHeaderIndex */;
34764
34802
  }
34765
34803
  else if (this.checkElementsIncludeAllNonFrozenHeaders(cmd.sheetId, cmd.dimension, cmd.elements)) {
@@ -36691,7 +36729,9 @@ class Evaluator {
36691
36729
  this.blockedArrayFormulas = new Set();
36692
36730
  this.spreadingRelations = new SpreadingRelation();
36693
36731
  this.formulaDependencies = lazy(() => {
36694
- const dependencies = [...this.getAllCells()].flatMap((positionId) => this.getDirectDependencies(positionId).map((range) => ({
36732
+ const dependencies = [...this.getAllCells()].flatMap((positionId) => this.getDirectDependencies(positionId)
36733
+ .filter((range) => !range.invalidSheetName && !range.invalidXc)
36734
+ .map((range) => ({
36695
36735
  data: positionId,
36696
36736
  boundingBox: {
36697
36737
  zone: range.zone,
@@ -37635,13 +37675,13 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
37635
37675
  .map((cell) => cell.value);
37636
37676
  switch (threshold.type) {
37637
37677
  case "value":
37638
- const result = functionName === "max" ? Math.max(...rangeValues) : Math.min(...rangeValues);
37678
+ const result = functionName === "max" ? largeMax(rangeValues) : largeMin(rangeValues);
37639
37679
  return result;
37640
37680
  case "number":
37641
37681
  return Number(threshold.value);
37642
37682
  case "percentage":
37643
- const min = Math.min(...rangeValues);
37644
- const max = Math.max(...rangeValues);
37683
+ const min = largeMin(rangeValues);
37684
+ const max = largeMax(rangeValues);
37645
37685
  const delta = max - min;
37646
37686
  return min + (delta * Number(threshold.value)) / 100;
37647
37687
  case "percentile":
@@ -38524,13 +38564,13 @@ class AutomaticSumPlugin extends UIPlugin {
38524
38564
  const cells = this.getters.getEvaluatedCellsInZone(sheet.id, zone);
38525
38565
  const cellPositions = range(end, -1, -1);
38526
38566
  const invalidCells = cellPositions.filter((position) => cells[position] && !cells[position].isAutoSummable);
38527
- const maxValidPosition = Math.max(...invalidCells);
38567
+ const maxValidPosition = largeMax(invalidCells);
38528
38568
  const numberSequences = groupConsecutive(cellPositions.filter((position) => this.isNumber(cells[position])));
38529
38569
  const firstSequence = numberSequences[0] || [];
38530
- if (Math.max(...firstSequence) < maxValidPosition) {
38570
+ if (largeMax(firstSequence) < maxValidPosition) {
38531
38571
  return Infinity;
38532
38572
  }
38533
- return Math.min(...firstSequence);
38573
+ return largeMin(firstSequence);
38534
38574
  }
38535
38575
  shouldFindData(sheetId, zone) {
38536
38576
  return this.getters.isEmpty(sheetId, zone) || this.getters.isSingleCellOrMerge(sheetId, zone);
@@ -40119,7 +40159,7 @@ class RendererPlugin extends UIPlugin {
40119
40159
  * column of the current viewport
40120
40160
  */
40121
40161
  getColDimensionsInViewport(sheetId, col) {
40122
- const left = Math.min(...this.getters.getSheetViewVisibleCols());
40162
+ const left = largeMin(this.getters.getSheetViewVisibleCols());
40123
40163
  const start = this.getters.getColRowOffsetInViewport("COL", left, col);
40124
40164
  const size = this.getters.getColSize(sheetId, col);
40125
40165
  const isColHidden = this.getters.isColHidden(sheetId, col);
@@ -40134,7 +40174,7 @@ class RendererPlugin extends UIPlugin {
40134
40174
  * of the current viewport
40135
40175
  */
40136
40176
  getRowDimensionsInViewport(sheetId, row) {
40137
- const top = Math.min(...this.getters.getSheetViewVisibleRows());
40177
+ const top = largeMin(this.getters.getSheetViewVisibleRows());
40138
40178
  const start = this.getters.getColRowOffsetInViewport("ROW", top, row);
40139
40179
  const size = this.getters.getRowSize(sheetId, row);
40140
40180
  const isRowHidden = this.getters.isRowHidden(sheetId, row);
@@ -41631,7 +41671,7 @@ class SheetUIPlugin extends UIPlugin {
41631
41671
  getColMaxWidth(sheetId, index) {
41632
41672
  const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
41633
41673
  const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
41634
- return Math.max(0, ...sizes);
41674
+ return Math.max(0, largeMax(sizes));
41635
41675
  }
41636
41676
  /**
41637
41677
  * Check that any "sheetId" in the command matches an existing
@@ -42933,7 +42973,7 @@ class ClipboardOsState extends ClipboardCellsAbstractState {
42933
42973
  }
42934
42974
  getPasteZone(target) {
42935
42975
  const height = this.values.length;
42936
- const width = Math.max(...this.values.map((a) => a.length));
42976
+ const width = largeMax(this.values.map((a) => a.length));
42937
42977
  const { left: activeCol, top: activeRow } = target[0];
42938
42978
  return {
42939
42979
  top: activeRow,
@@ -45226,13 +45266,14 @@ class SheetViewPlugin extends UIPlugin {
45226
45266
  }
45227
45267
  }
45228
45268
  handleEvent(event) {
45269
+ const sheetId = this.getters.getActiveSheetId();
45229
45270
  if (event.options.scrollIntoView) {
45230
45271
  let { col, row } = findCellInNewZone(event.previousAnchor.zone, event.anchor.zone);
45231
45272
  if (event.mode === "updateAnchor") {
45232
45273
  const oldZone = event.previousAnchor.zone;
45233
45274
  const newZone = event.anchor.zone;
45234
45275
  // altering a zone should not move the viewport in a dimension that wasn't changed
45235
- const { top, bottom, left, right } = this.getters.getActiveMainViewport();
45276
+ const { top, bottom, left, right } = this.getMainInternalViewport(sheetId);
45236
45277
  if (oldZone.left === newZone.left && oldZone.right === newZone.right) {
45237
45278
  col = left > col || col > right ? left : col;
45238
45279
  }
@@ -45240,7 +45281,6 @@ class SheetViewPlugin extends UIPlugin {
45240
45281
  row = top > row || row > bottom ? top : row;
45241
45282
  }
45242
45283
  }
45243
- const sheetId = this.getters.getActiveSheetId();
45244
45284
  col = Math.min(col, this.getters.getNumberCols(sheetId) - 1);
45245
45285
  row = Math.min(row, this.getters.getNumberRows(sheetId) - 1);
45246
45286
  this.refreshViewport(this.getters.getActiveSheetId(), { col, row });
@@ -45266,16 +45306,16 @@ class SheetViewPlugin extends UIPlugin {
45266
45306
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
45267
45307
  break;
45268
45308
  case "SHIFT_VIEWPORT_DOWN":
45269
- const { top } = this.getActiveMainViewport();
45270
45309
  const sheetId = this.getters.getActiveSheetId();
45271
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).start + this.sheetViewHeight);
45272
- this.shiftVertically(shiftedOffsetY);
45310
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
45311
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
45312
+ this.shiftVertically(topRowDims.start + viewportHeight - offsetCorrectionY);
45273
45313
  break;
45274
45314
  case "SHIFT_VIEWPORT_UP": {
45275
- const { top } = this.getActiveMainViewport();
45276
45315
  const sheetId = this.getters.getActiveSheetId();
45277
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).end - this.sheetViewHeight);
45278
- this.shiftVertically(shiftedOffsetY);
45316
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
45317
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
45318
+ this.shiftVertically(topRowDims.end - offsetCorrectionY - viewportHeight);
45279
45319
  break;
45280
45320
  }
45281
45321
  case "REMOVE_COLUMNS_ROWS":
@@ -45637,17 +45677,6 @@ class SheetViewPlugin extends UIPlugin {
45637
45677
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
45638
45678
  Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
45639
45679
  }
45640
- /**
45641
- * Clip the vertical offset within the allowed range.
45642
- * Not above the sheet, nor below the sheet.
45643
- */
45644
- clipOffsetY(offsetY) {
45645
- const { height } = this.getMainViewportRect();
45646
- const maxOffset = height - this.sheetViewHeight;
45647
- offsetY = Math.min(offsetY, maxOffset);
45648
- offsetY = Math.max(offsetY, 0);
45649
- return offsetY;
45650
- }
45651
45680
  getViewportOffset(sheetId) {
45652
45681
  return {
45653
45682
  x: this.viewports[sheetId]?.bottomRight.offsetScrollbarX || 0,
@@ -45703,12 +45732,15 @@ class SheetViewPlugin extends UIPlugin {
45703
45732
  * viewport top.
45704
45733
  */
45705
45734
  shiftVertically(offset) {
45706
- const { top } = this.getActiveMainViewport();
45735
+ const sheetId = this.getters.getActiveSheetId();
45736
+ const { top } = this.getMainInternalViewport(sheetId);
45707
45737
  const { scrollX } = this.getActiveSheetScrollInfo();
45708
45738
  this.setSheetViewOffset(scrollX, offset);
45709
45739
  const { anchor } = this.getters.getSelection();
45710
- const deltaRow = this.getActiveMainViewport().top - top;
45711
- this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
45740
+ if (anchor.cell.row >= this.getters.getPaneDivisions(sheetId).ySplit) {
45741
+ const deltaRow = this.getMainInternalViewport(sheetId).top - top;
45742
+ this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
45743
+ }
45712
45744
  }
45713
45745
  getVisibleFigures() {
45714
45746
  const sheetId = this.getters.getActiveSheetId();
@@ -46154,12 +46186,14 @@ class BottomBarSheet extends owl.Component {
46154
46186
  this.editionState = "initializing";
46155
46187
  }
46156
46188
  stopEdition() {
46157
- if (!this.state.isEditing)
46189
+ const input = this.sheetNameRef.el;
46190
+ if (!this.state.isEditing || !input)
46158
46191
  return;
46159
46192
  this.state.isEditing = false;
46160
46193
  this.editionState = "initializing";
46161
- this.sheetNameRef.el?.blur();
46194
+ input.blur();
46162
46195
  const inputValue = this.getInputContent() || "";
46196
+ input.innerText = inputValue;
46163
46197
  interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
46164
46198
  }
46165
46199
  cancelEdition() {
@@ -46621,7 +46655,7 @@ class BottomBar extends owl.Component {
46621
46655
  this.sheetListRef.el.scrollTo({ top: 0, left: scroll, behavior: "smooth" });
46622
46656
  }
46623
46657
  onSheetMouseDown(sheetId, event) {
46624
- if (event.button !== 0)
46658
+ if (event.button !== 0 || this.env.model.getters.isReadonly())
46625
46659
  return;
46626
46660
  this.closeMenu();
46627
46661
  const mouseX = event.clientX;
@@ -49825,7 +49859,7 @@ function addLineChart(chart) {
49825
49859
  }
49826
49860
  function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
49827
49861
  const colors = new ChartColors();
49828
- const maxLength = Math.max(...chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
49862
+ const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
49829
49863
  const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
49830
49864
  const dataSetsNodes = [];
49831
49865
  for (const [dsIndex, dataset] of Object.entries(chart.dataSets).reverse()) {
@@ -49963,8 +49997,7 @@ function addContent(content, sharedStrings, forceString = false) {
49963
49997
  attrs.push(["t", "b"]);
49964
49998
  }
49965
49999
  else if (forceString || !isNumber(value, DEFAULT_LOCALE)) {
49966
- const { id } = pushElement(content, sharedStrings);
49967
- value = id.toString();
50000
+ value = pushElement(content, sharedStrings);
49968
50001
  attrs.push(["t", "s"]);
49969
50002
  }
49970
50003
  return { attrs, node: escapeXml /*xml*/ `<v>${value}</v>` };
@@ -50089,8 +50122,7 @@ function addCellIsRule(cf, rule, dxfs) {
50089
50122
  if (rule.style.fillColor) {
50090
50123
  dxf.fill = { fgColor: { rgb: rule.style.fillColor } };
50091
50124
  }
50092
- const { id } = pushElement(dxf, dxfs);
50093
- ruleAttributes.push(["dxfId", id]);
50125
+ ruleAttributes.push(["dxfId", pushElement(dxf, dxfs)]);
50094
50126
  return escapeXml /*xml*/ `
50095
50127
  <conditionalFormatting sqref="${cf.ranges.join(" ")}">
50096
50128
  <cfRule ${formatAttributes(ruleAttributes)}>
@@ -50899,7 +50931,7 @@ function addSheetViews(sheet) {
50899
50931
  */
50900
50932
  function getXLSX(data) {
50901
50933
  const files = [];
50902
- const construct = getDefaultXLSXStructure();
50934
+ const construct = getDefaultXLSXStructure(data);
50903
50935
  files.push(createWorkbook(data, construct));
50904
50936
  files.push(...createWorksheets(data, construct));
50905
50937
  files.push(createStylesSheet(construct));
@@ -51754,6 +51786,6 @@ exports.setTranslationMethod = setTranslationMethod;
51754
51786
  exports.tokenize = tokenize;
51755
51787
 
51756
51788
 
51757
- __info__.version = '16.4.27';
51758
- __info__.date = '2024-03-25T09:41:12.743Z';
51759
- __info__.hash = '42e4252';
51789
+ __info__.version = '16.4.29';
51790
+ __info__.date = '2024-04-10T12:19:13.935Z';
51791
+ __info__.hash = 'c022445';
@@ -4819,11 +4819,6 @@ declare class SheetViewPlugin extends UIPlugin {
4819
4819
  private resizeSheetView;
4820
4820
  private recomputeViewports;
4821
4821
  private setSheetViewOffset;
4822
- /**
4823
- * Clip the vertical offset within the allowed range.
4824
- * Not above the sheet, nor below the sheet.
4825
- */
4826
- private clipOffsetY;
4827
4822
  private getViewportOffset;
4828
4823
  private resetViewports;
4829
4824
  /**
@@ -6689,6 +6684,7 @@ interface ComposerProps {
6689
6684
  delimitation?: DOMDimension;
6690
6685
  onComposerContentFocused: () => void;
6691
6686
  onComposerCellFocused?: (content: String) => void;
6687
+ onInputContextMenu?: (event: MouseEvent) => void;
6692
6688
  isDefaultFocus?: boolean;
6693
6689
  }
6694
6690
  interface ComposerState$1 {
@@ -6759,6 +6755,7 @@ declare class Composer extends Component<ComposerProps, SpreadsheetChildEnv> {
6759
6755
  onMousedown(ev: MouseEvent): void;
6760
6756
  onClick(): void;
6761
6757
  onDblClick(): void;
6758
+ onContextMenu(ev: MouseEvent): void;
6762
6759
  private processContent;
6763
6760
  /**
6764
6761
  * Get the HTML content corresponding to the current composer token, divided by lines.
@@ -6937,6 +6934,7 @@ interface Props$5 {
6937
6934
  onComposerContentFocused: () => void;
6938
6935
  onComposerCellFocused: () => void;
6939
6936
  gridDims: DOMDimension;
6937
+ onInputContextMenu: (event: MouseEvent) => void;
6940
6938
  }
6941
6939
  /**
6942
6940
  * This component is a composer which positions itself on the grid at the anchor cell.