@odoo/o-spreadsheet 16.3.30 → 16.3.33

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.
@@ -1016,7 +1016,7 @@ function getItemId(item, itemsDic) {
1016
1016
  }
1017
1017
  // Generate new Id if the item didn't exist in the dictionary
1018
1018
  const ids = Object.keys(itemsDic);
1019
- const maxId = ids.length === 0 ? 0 : Math.max(...ids.map((id) => parseInt(id, 10)));
1019
+ const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
1020
1020
  itemsDic[maxId + 1] = item;
1021
1021
  return maxId + 1;
1022
1022
  }
@@ -1123,7 +1123,7 @@ function deepEquals(o1, o2) {
1123
1123
  if (typeof o1 !== typeof o2)
1124
1124
  return false;
1125
1125
  if (typeof o1 !== "object")
1126
- return o1 === o2;
1126
+ return false;
1127
1127
  // Objects can have different keys if the values are undefined
1128
1128
  const keys = new Set();
1129
1129
  Object.keys(o1).forEach((key) => keys.add(key));
@@ -1208,6 +1208,34 @@ function isConsecutive(iterable) {
1208
1208
  }
1209
1209
  }
1210
1210
  return true;
1211
+ }
1212
+ /**
1213
+ * Alternative to Math.max that works with large arrays.
1214
+ * Typically useful for arrays bigger than 100k elements.
1215
+ */
1216
+ function largeMax(array) {
1217
+ let len = array.length;
1218
+ if (len < 100000)
1219
+ return Math.max(...array);
1220
+ let max = -Infinity;
1221
+ while (len--) {
1222
+ max = array[len] > max ? array[len] : max;
1223
+ }
1224
+ return max;
1225
+ }
1226
+ /**
1227
+ * Alternative to Math.min that works with large arrays.
1228
+ * Typically useful for arrays bigger than 100k elements.
1229
+ */
1230
+ function largeMin(array) {
1231
+ let len = array.length;
1232
+ if (len < 100000)
1233
+ return Math.min(...array);
1234
+ let min = +Infinity;
1235
+ while (len--) {
1236
+ min = array[len] < min ? array[len] : min;
1237
+ }
1238
+ return min;
1211
1239
  }
1212
1240
 
1213
1241
  const RBA_REGEX = /rgba?\(|\s+|\)/gi;
@@ -6254,6 +6282,7 @@ class LinkEditor extends Component {
6254
6282
  this.save();
6255
6283
  }
6256
6284
  ev.stopPropagation();
6285
+ ev.preventDefault();
6257
6286
  break;
6258
6287
  case "Escape":
6259
6288
  this.cancel();
@@ -6819,10 +6848,10 @@ function aggregateDataForLabels(labels, datasets) {
6819
6848
  }
6820
6849
  }
6821
6850
  return {
6822
- labels: Object.keys(labelMap),
6851
+ labels: Array.from(labelSet),
6823
6852
  dataSetsValues: datasets.map((dataset, indexOfDataset) => ({
6824
6853
  ...dataset,
6825
- data: Object.values(labelMap).map((dataOfLabel) => dataOfLabel[indexOfDataset]),
6854
+ data: Array.from(labelSet).map((label) => labelMap[label][indexOfDataset]),
6826
6855
  })),
6827
6856
  };
6828
6857
  }
@@ -7539,7 +7568,7 @@ function getBestTimeUnitForScale(labels, format) {
7539
7568
  return undefined;
7540
7569
  }
7541
7570
  const labelsTimestamps = labelDates.map((date) => date.getTime());
7542
- const period = Math.max(...labelsTimestamps) - Math.min(...labelsTimestamps);
7571
+ const period = largeMax(labelsTimestamps) - largeMin(labelsTimestamps);
7543
7572
  const minUnit = getFormatMinDisplayUnit(format);
7544
7573
  if (UNIT_LENGTH.second >= UNIT_LENGTH[minUnit] && Milliseconds.inSeconds(period) < 180) {
7545
7574
  return "second";
@@ -7979,7 +8008,7 @@ function getPieConfiguration(chart, labels, dataSetFormat) {
7979
8008
  }
7980
8009
  function getPieColors(colors, dataSetsValues) {
7981
8010
  const pieColors = [];
7982
- const maxLength = Math.max(...dataSetsValues.map((ds) => ds.data.length));
8011
+ const maxLength = largeMax(dataSetsValues.map((ds) => ds.data.length));
7983
8012
  for (let i = 0; i <= maxLength; i++) {
7984
8013
  pieColors.push(colors.next());
7985
8014
  }
@@ -8942,8 +8971,8 @@ const DELETE_CONTENT_ROWS_NAME = (env) => {
8942
8971
  let last;
8943
8972
  const activesRows = env.model.getters.getActiveRows();
8944
8973
  if (activesRows.size !== 0) {
8945
- first = Math.min(...activesRows);
8946
- last = Math.max(...activesRows);
8974
+ first = largeMin([...activesRows]);
8975
+ last = largeMax([...activesRows]);
8947
8976
  }
8948
8977
  else {
8949
8978
  const zone = env.model.getters.getSelectedZones()[0];
@@ -8971,8 +9000,8 @@ const DELETE_CONTENT_COLUMNS_NAME = (env) => {
8971
9000
  let last;
8972
9001
  const activeCols = env.model.getters.getActiveCols();
8973
9002
  if (activeCols.size !== 0) {
8974
- first = Math.min(...activeCols);
8975
- last = Math.max(...activeCols);
9003
+ first = largeMin([...activeCols]);
9004
+ last = largeMax([...activeCols]);
8976
9005
  }
8977
9006
  else {
8978
9007
  const zone = env.model.getters.getSelectedZones()[0];
@@ -9000,8 +9029,8 @@ const REMOVE_ROWS_NAME = (env) => {
9000
9029
  let last;
9001
9030
  const activesRows = env.model.getters.getActiveRows();
9002
9031
  if (activesRows.size !== 0) {
9003
- first = Math.min(...activesRows);
9004
- last = Math.max(...activesRows);
9032
+ first = largeMin([...activesRows]);
9033
+ last = largeMax([...activesRows]);
9005
9034
  }
9006
9035
  else {
9007
9036
  const zone = env.model.getters.getSelectedZones()[0];
@@ -9042,8 +9071,8 @@ const REMOVE_COLUMNS_NAME = (env) => {
9042
9071
  let last;
9043
9072
  const activeCols = env.model.getters.getActiveCols();
9044
9073
  if (activeCols.size !== 0) {
9045
- first = Math.min(...activeCols);
9046
- last = Math.max(...activeCols);
9074
+ first = largeMin([...activeCols]);
9075
+ last = largeMax([...activeCols]);
9047
9076
  }
9048
9077
  else {
9049
9078
  const zone = env.model.getters.getSelectedZones()[0];
@@ -9126,7 +9155,7 @@ const INSERT_ROWS_BEFORE_ACTION = (env) => {
9126
9155
  let row;
9127
9156
  let quantity;
9128
9157
  if (activeRows.size) {
9129
- row = Math.min(...activeRows);
9158
+ row = largeMin([...activeRows]);
9130
9159
  quantity = activeRows.size;
9131
9160
  }
9132
9161
  else {
@@ -9158,7 +9187,7 @@ const INSERT_ROWS_AFTER_ACTION = (env) => {
9158
9187
  let row;
9159
9188
  let quantity;
9160
9189
  if (activeRows.size) {
9161
- row = Math.max(...activeRows);
9190
+ row = largeMax([...activeRows]);
9162
9191
  quantity = activeRows.size;
9163
9192
  }
9164
9193
  else {
@@ -9203,7 +9232,7 @@ const INSERT_COLUMNS_BEFORE_ACTION = (env) => {
9203
9232
  let column;
9204
9233
  let quantity;
9205
9234
  if (activeCols.size) {
9206
- column = Math.min(...activeCols);
9235
+ column = largeMin([...activeCols]);
9207
9236
  quantity = activeCols.size;
9208
9237
  }
9209
9238
  else {
@@ -9237,7 +9266,7 @@ const INSERT_COLUMNS_AFTER_ACTION = (env) => {
9237
9266
  let column;
9238
9267
  let quantity;
9239
9268
  if (activeCols.size) {
9240
- column = Math.max(...activeCols);
9269
+ column = largeMax([...activeCols]);
9241
9270
  quantity = activeCols.size;
9242
9271
  }
9243
9272
  else {
@@ -9442,9 +9471,12 @@ const INSERT_LINK_NAME = (env) => {
9442
9471
  // Filters action
9443
9472
  //------------------------------------------------------------------------------
9444
9473
  const FILTERS_CREATE_FILTER_TABLE = (env) => {
9474
+ const zones = env.model.getters.getSelectedZones();
9475
+ if (zones.length === 1 && getZoneArea(zones[0]) === 1) {
9476
+ env.model.selection.selectTableAroundSelection();
9477
+ }
9445
9478
  const sheetId = env.model.getters.getActiveSheetId();
9446
- const selection = env.model.getters.getSelection().zones;
9447
- interactiveAddFilter(env, sheetId, selection);
9479
+ interactiveAddFilter(env, sheetId, env.model.getters.getSelectedZones());
9448
9480
  };
9449
9481
  const FILTERS_REMOVE_FILTER_TABLE = (env) => {
9450
9482
  const sheetId = env.model.getters.getActiveSheetId();
@@ -21308,6 +21340,11 @@ class Composer extends Component {
21308
21340
  onBlur() {
21309
21341
  this.isKeyStillDown = false;
21310
21342
  }
21343
+ onContextMenu(ev) {
21344
+ if (this.env.model.getters.getEditionMode() === "inactive") {
21345
+ this.props.onInputContextMenu?.(ev);
21346
+ }
21347
+ }
21311
21348
  // ---------------------------------------------------------------------------
21312
21349
  // Private
21313
21350
  // ---------------------------------------------------------------------------
@@ -21529,6 +21566,7 @@ Composer.props = {
21529
21566
  onComposerCellFocused: { type: Function, optional: true },
21530
21567
  onComposerContentFocused: Function,
21531
21568
  isDefaultFocus: { type: Boolean, optional: true },
21569
+ onInputContextMenu: { type: Function, optional: true },
21532
21570
  };
21533
21571
 
21534
21572
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
@@ -21605,6 +21643,7 @@ class GridComposer extends Component {
21605
21643
  isDefaultFocus: true,
21606
21644
  onComposerContentFocused: this.props.onComposerContentFocused,
21607
21645
  onComposerCellFocused: this.props.onComposerCellFocused,
21646
+ onInputContextMenu: this.props.onInputContextMenu,
21608
21647
  };
21609
21648
  }
21610
21649
  get containerStyle() {
@@ -21693,6 +21732,7 @@ GridComposer.props = {
21693
21732
  onComposerContentFocused: Function,
21694
21733
  gridDims: Object,
21695
21734
  onComposerCellFocused: Function,
21735
+ onInputContextMenu: Function,
21696
21736
  };
21697
21737
 
21698
21738
  const CSS$1 = css /* scss */ `
@@ -24028,8 +24068,8 @@ class Grid extends Component {
24028
24068
  else if (this.env.model.getters.getActiveRows().has(row)) {
24029
24069
  type = "ROW";
24030
24070
  }
24031
- const { x, y, width, height } = this.env.model.getters.getVisibleRect(lastZone);
24032
- this.toggleContextMenu(type, x + width, y + height);
24071
+ const { x, y, width } = this.env.model.getters.getVisibleRect(lastZone);
24072
+ this.toggleContextMenu(type, this.canvasPosition.x + x + width, this.canvasPosition.y + y);
24033
24073
  }
24034
24074
  onCellRightClicked(col, row, { x, y }) {
24035
24075
  const zones = this.env.model.getters.getSelectedZones();
@@ -26356,29 +26396,12 @@ function convertWidthFromExcel(width) {
26356
26396
  return width;
26357
26397
  return Math.round((width / WIDTH_FACTOR) * 100) / 100;
26358
26398
  }
26359
- function convertBorderDescr(descr) {
26360
- if (!descr) {
26361
- return undefined;
26362
- }
26363
- return {
26364
- style: descr.style,
26365
- color: { rgb: descr.color },
26366
- };
26367
- }
26368
26399
  function extractStyle(cell, data) {
26369
26400
  let style = {};
26370
26401
  if (cell.style) {
26371
26402
  style = data.styles[cell.style];
26372
26403
  }
26373
26404
  const format = extractFormat(cell, data);
26374
- const exportedBorder = {};
26375
- if (cell.border) {
26376
- const border = data.borders[cell.border];
26377
- exportedBorder.left = convertBorderDescr(border.left);
26378
- exportedBorder.right = convertBorderDescr(border.right);
26379
- exportedBorder.bottom = convertBorderDescr(border.bottom);
26380
- exportedBorder.top = convertBorderDescr(border.top);
26381
- }
26382
26405
  const styles = {
26383
26406
  font: {
26384
26407
  size: style?.fontSize || DEFAULT_FONT_SIZE,
@@ -26392,7 +26415,7 @@ function extractStyle(cell, data) {
26392
26415
  }
26393
26416
  : { reservedAttribute: "none" },
26394
26417
  numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
26395
- border: exportedBorder || {},
26418
+ border: cell.border || 0,
26396
26419
  alignment: {
26397
26420
  horizontal: style.align,
26398
26421
  vertical: style.verticalAlign
@@ -26424,15 +26447,12 @@ function extractFormat(cell, data) {
26424
26447
  return undefined;
26425
26448
  }
26426
26449
  function normalizeStyle(construct, styles) {
26427
- const { id: fontId } = pushElement(styles["font"], construct.fonts);
26428
- const { id: fillId } = pushElement(styles["fill"], construct.fills);
26429
- const { id: borderId } = pushElement(styles["border"], construct.borders);
26430
26450
  // Normalize this
26431
26451
  const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
26432
26452
  const style = {
26433
- fontId,
26434
- fillId,
26435
- borderId,
26453
+ fontId: pushElement(styles.font, construct.fonts),
26454
+ fillId: pushElement(styles.fill, construct.fills),
26455
+ borderId: styles.border,
26436
26456
  numFmtId,
26437
26457
  alignment: {
26438
26458
  vertical: styles.alignment.vertical,
@@ -26440,8 +26460,7 @@ function normalizeStyle(construct, styles) {
26440
26460
  wrapText: styles.alignment.wrapText,
26441
26461
  },
26442
26462
  };
26443
- const { id } = pushElement(style, construct.styles);
26444
- return id;
26463
+ return pushElement(style, construct.styles);
26445
26464
  }
26446
26465
  function convertFormat(format, numFmtStructure) {
26447
26466
  if (!format) {
@@ -26449,8 +26468,7 @@ function convertFormat(format, numFmtStructure) {
26449
26468
  }
26450
26469
  let formatId = XLSX_FORMAT_MAP[format.format];
26451
26470
  if (!formatId) {
26452
- const { id } = pushElement(format, numFmtStructure);
26453
- formatId = id + FIRST_NUMFMT_ID;
26471
+ formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
26454
26472
  }
26455
26473
  return formatId;
26456
26474
  }
@@ -26475,20 +26493,15 @@ function addRelsToFile(relsFiles, path, rel) {
26475
26493
  return id;
26476
26494
  }
26477
26495
  function pushElement(property, propertyList) {
26478
- for (let [key, value] of Object.entries(propertyList)) {
26479
- if (JSON.stringify(value) === JSON.stringify(property)) {
26480
- return { id: parseInt(key, 10), list: propertyList };
26496
+ let len = propertyList.length;
26497
+ const operator = typeof property === "object" ? deepEquals : (a, b) => a === b;
26498
+ for (let i = 0; i < len; i++) {
26499
+ if (operator(property, propertyList[i])) {
26500
+ return i;
26481
26501
  }
26482
26502
  }
26483
- let elemId = propertyList.findIndex((elem) => JSON.stringify(elem) === JSON.stringify(property));
26484
- if (elemId === -1) {
26485
- propertyList.push(property);
26486
- elemId = propertyList.length - 1;
26487
- }
26488
- return {
26489
- id: elemId,
26490
- list: propertyList,
26491
- };
26503
+ propertyList[propertyList.length] = property;
26504
+ return propertyList.length - 1;
26492
26505
  }
26493
26506
  const chartIds = [];
26494
26507
  /**
@@ -26925,7 +26938,7 @@ function convertHyperlink(link, cellValue, warningManager) {
26925
26938
  function getSheetDims(sheet) {
26926
26939
  const dims = [0, 0];
26927
26940
  for (let row of sheet.rows) {
26928
- dims[0] = Math.max(dims[0], ...row.cells.map((cell) => toCartesian(cell.xc).col));
26941
+ dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
26929
26942
  dims[1] = Math.max(dims[1], row.index);
26930
26943
  }
26931
26944
  dims[0] = Math.max(dims[0], EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
@@ -27194,7 +27207,25 @@ function parseXML(xmlString, mimeType = "text/xml") {
27194
27207
  }
27195
27208
  return document;
27196
27209
  }
27197
- function getDefaultXLSXStructure() {
27210
+ function convertBorderDescr(descr) {
27211
+ if (!descr) {
27212
+ return undefined;
27213
+ }
27214
+ return {
27215
+ style: descr.style,
27216
+ color: { rgb: descr.color },
27217
+ };
27218
+ }
27219
+ function getDefaultXLSXStructure(data) {
27220
+ const xlsxBorders = Object.values(data.borders).map((border) => {
27221
+ return {
27222
+ left: convertBorderDescr(border.left),
27223
+ right: convertBorderDescr(border.right),
27224
+ bottom: convertBorderDescr(border.bottom),
27225
+ top: convertBorderDescr(border.top),
27226
+ };
27227
+ });
27228
+ const borders = [{}, ...xlsxBorders];
27198
27229
  return {
27199
27230
  relsFiles: [],
27200
27231
  sharedStrings: [],
@@ -27217,7 +27248,7 @@ function getDefaultXLSXStructure() {
27217
27248
  },
27218
27249
  ],
27219
27250
  fills: [{ reservedAttribute: "none" }, { reservedAttribute: "gray125" }],
27220
- borders: [{}],
27251
+ borders,
27221
27252
  numFmts: [],
27222
27253
  dxfs: [],
27223
27254
  };
@@ -31168,7 +31199,17 @@ class FiltersPlugin extends CorePlugin {
31168
31199
  }
31169
31200
  }
31170
31201
  exportForExcel(data) {
31171
- this.export(data);
31202
+ for (const sheet of data.sheets) {
31203
+ for (const filterTable of this.getFilterTables(sheet.id)) {
31204
+ if (zoneToDimension(filterTable.zone).numberOfRows === 1) {
31205
+ continue;
31206
+ }
31207
+ sheet.filterTables.push({
31208
+ range: zoneToXc(filterTable.zone),
31209
+ filters: [],
31210
+ });
31211
+ }
31212
+ }
31172
31213
  }
31173
31214
  }
31174
31215
 
@@ -31212,7 +31253,7 @@ class HeaderSizePlugin extends CorePlugin {
31212
31253
  for (let headerIndex of [...cmd.elements].sort((a, b) => b - a)) {
31213
31254
  sizes.splice(headerIndex, 1);
31214
31255
  }
31215
- const min = Math.min(...cmd.elements);
31256
+ const min = largeMin(cmd.elements);
31216
31257
  sizes = sizes.map((size, row) => {
31217
31258
  if (cmd.dimension === "ROW" && row >= min) {
31218
31259
  // invalidate sizes
@@ -31439,7 +31480,7 @@ class HeaderVisibilityPlugin extends CorePlugin {
31439
31480
  if (hiddenElements.size >= elements) {
31440
31481
  return 67 /* CommandResult.TooManyHiddenElements */;
31441
31482
  }
31442
- else if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
31483
+ else if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
31443
31484
  return 87 /* CommandResult.InvalidHeaderIndex */;
31444
31485
  }
31445
31486
  else {
@@ -32212,8 +32253,8 @@ class RangeAdapter {
32212
32253
  let newRange = range;
32213
32254
  let changeType = "NONE";
32214
32255
  for (let group of groups) {
32215
- const min = Math.min(...group);
32216
- const max = Math.max(...group);
32256
+ const min = largeMin(group);
32257
+ const max = largeMax(group);
32217
32258
  if (range.zone[start] <= min && min <= range.zone[end]) {
32218
32259
  const toRemove = Math.min(range.zone[end], max) - min + 1;
32219
32260
  changeType = "RESIZE";
@@ -32644,7 +32685,7 @@ class SheetPlugin extends CorePlugin {
32644
32685
  const elements = cmd.dimension === "COL"
32645
32686
  ? this.getNumberCols(cmd.sheetId)
32646
32687
  : this.getNumberRows(cmd.sheetId);
32647
- if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
32688
+ if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
32648
32689
  return 87 /* CommandResult.InvalidHeaderIndex */;
32649
32690
  }
32650
32691
  else if (this.checkElementsIncludeAllNonFrozenHeaders(cmd.sheetId, cmd.dimension, cmd.elements)) {
@@ -34146,13 +34187,13 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
34146
34187
  .map((cell) => cell.value);
34147
34188
  switch (threshold.type) {
34148
34189
  case "value":
34149
- const result = functionName === "max" ? Math.max(...rangeValues) : Math.min(...rangeValues);
34190
+ const result = functionName === "max" ? largeMax(rangeValues) : largeMin(rangeValues);
34150
34191
  return result;
34151
34192
  case "number":
34152
34193
  return Number(threshold.value);
34153
34194
  case "percentage":
34154
- const min = Math.min(...rangeValues);
34155
- const max = Math.max(...rangeValues);
34195
+ const min = largeMin(rangeValues);
34196
+ const max = largeMax(rangeValues);
34156
34197
  const delta = max - min;
34157
34198
  return min + (delta * Number(threshold.value)) / 100;
34158
34199
  case "percentile":
@@ -35036,12 +35077,13 @@ class SheetViewPlugin extends UIPlugin {
35036
35077
  case "AlterZone":
35037
35078
  break;
35038
35079
  case "ZonesSelected":
35080
+ const sheetId = this.getters.getActiveSheetId();
35039
35081
  let { col, row } = findCellInNewZone(event.previousAnchor.zone, event.anchor.zone);
35040
35082
  if (event.mode === "updateAnchor") {
35041
35083
  const oldZone = event.previousAnchor.zone;
35042
35084
  const newZone = event.anchor.zone;
35043
35085
  // altering a zone should not move the viewport in a dimension that wasn't changed
35044
- const { top, bottom, left, right } = this.getters.getActiveMainViewport();
35086
+ const { top, bottom, left, right } = this.getMainInternalViewport(sheetId);
35045
35087
  if (oldZone.left === newZone.left && oldZone.right === newZone.right) {
35046
35088
  col = left > col || col > right ? left : col;
35047
35089
  }
@@ -35049,10 +35091,9 @@ class SheetViewPlugin extends UIPlugin {
35049
35091
  row = top > row || row > bottom ? top : row;
35050
35092
  }
35051
35093
  }
35052
- const sheetId = this.getters.getActiveSheetId();
35053
35094
  col = Math.min(col, this.getters.getNumberCols(sheetId) - 1);
35054
35095
  row = Math.min(row, this.getters.getNumberRows(sheetId) - 1);
35055
- this.refreshViewport(this.getters.getActiveSheetId(), { col, row });
35096
+ this.refreshViewport(sheetId, { col, row });
35056
35097
  break;
35057
35098
  }
35058
35099
  }
@@ -35076,16 +35117,16 @@ class SheetViewPlugin extends UIPlugin {
35076
35117
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
35077
35118
  break;
35078
35119
  case "SHIFT_VIEWPORT_DOWN":
35079
- const { top } = this.getActiveMainViewport();
35080
35120
  const sheetId = this.getters.getActiveSheetId();
35081
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).start + this.sheetViewHeight);
35082
- this.shiftVertically(shiftedOffsetY);
35121
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
35122
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
35123
+ this.shiftVertically(topRowDims.start + viewportHeight - offsetCorrectionY);
35083
35124
  break;
35084
35125
  case "SHIFT_VIEWPORT_UP": {
35085
- const { top } = this.getActiveMainViewport();
35086
35126
  const sheetId = this.getters.getActiveSheetId();
35087
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).end - this.sheetViewHeight);
35088
- this.shiftVertically(shiftedOffsetY);
35127
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
35128
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
35129
+ this.shiftVertically(topRowDims.end - offsetCorrectionY - viewportHeight);
35089
35130
  break;
35090
35131
  }
35091
35132
  case "REMOVE_COLUMNS_ROWS":
@@ -35447,17 +35488,6 @@ class SheetViewPlugin extends UIPlugin {
35447
35488
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
35448
35489
  Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
35449
35490
  }
35450
- /**
35451
- * Clip the vertical offset within the allowed range.
35452
- * Not above the sheet, nor below the sheet.
35453
- */
35454
- clipOffsetY(offsetY) {
35455
- const { height } = this.getMainViewportRect();
35456
- const maxOffset = height - this.sheetViewHeight;
35457
- offsetY = Math.min(offsetY, maxOffset);
35458
- offsetY = Math.max(offsetY, 0);
35459
- return offsetY;
35460
- }
35461
35491
  getViewportOffset(sheetId) {
35462
35492
  return {
35463
35493
  x: this.viewports[sheetId]?.bottomRight.offsetScrollbarX || 0,
@@ -35513,12 +35543,15 @@ class SheetViewPlugin extends UIPlugin {
35513
35543
  * viewport top.
35514
35544
  */
35515
35545
  shiftVertically(offset) {
35516
- const { top } = this.getActiveMainViewport();
35546
+ const sheetId = this.getters.getActiveSheetId();
35547
+ const { top } = this.getMainInternalViewport(sheetId);
35517
35548
  const { scrollX } = this.getActiveSheetScrollInfo();
35518
35549
  this.setSheetViewOffset(scrollX, offset);
35519
35550
  const { anchor } = this.getters.getSelection();
35520
- const deltaRow = this.getActiveMainViewport().top - top;
35521
- this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
35551
+ if (anchor.cell.row >= this.getters.getPaneDivisions(sheetId).ySplit) {
35552
+ const deltaRow = this.getMainInternalViewport(sheetId).top - top;
35553
+ this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
35554
+ }
35522
35555
  }
35523
35556
  getVisibleFigures() {
35524
35557
  const sheetId = this.getters.getActiveSheetId();
@@ -36102,13 +36135,13 @@ class AutomaticSumPlugin extends UIPlugin {
36102
36135
  const cells = this.getters.getEvaluatedCellsInZone(sheet.id, zone);
36103
36136
  const cellPositions = range(end, -1, -1);
36104
36137
  const invalidCells = cellPositions.filter((position) => cells[position] && !cells[position].isAutoSummable);
36105
- const maxValidPosition = Math.max(...invalidCells);
36138
+ const maxValidPosition = largeMax(invalidCells);
36106
36139
  const numberSequences = groupConsecutive(cellPositions.filter((position) => this.isNumber(cells[position])));
36107
36140
  const firstSequence = numberSequences[0] || [];
36108
- if (Math.max(...firstSequence) < maxValidPosition) {
36141
+ if (largeMax(firstSequence) < maxValidPosition) {
36109
36142
  return Infinity;
36110
36143
  }
36111
- return Math.min(...firstSequence);
36144
+ return largeMin(firstSequence);
36112
36145
  }
36113
36146
  shouldFindData(sheetId, zone) {
36114
36147
  return this.getters.isEmpty(sheetId, zone) || this.getters.isSingleCellOrMerge(sheetId, zone);
@@ -37693,7 +37726,7 @@ class RendererPlugin extends UIPlugin {
37693
37726
  * column of the current viewport
37694
37727
  */
37695
37728
  getColDimensionsInViewport(sheetId, col) {
37696
- const left = Math.min(...this.getters.getSheetViewVisibleCols());
37729
+ const left = largeMin(this.getters.getSheetViewVisibleCols());
37697
37730
  const start = this.getters.getColRowOffsetInViewport("COL", left, col);
37698
37731
  const size = this.getters.getColSize(sheetId, col);
37699
37732
  const isColHidden = this.getters.isColHidden(sheetId, col);
@@ -37708,7 +37741,7 @@ class RendererPlugin extends UIPlugin {
37708
37741
  * of the current viewport
37709
37742
  */
37710
37743
  getRowDimensionsInViewport(sheetId, row) {
37711
- const top = Math.min(...this.getters.getSheetViewVisibleRows());
37744
+ const top = largeMin(this.getters.getSheetViewVisibleRows());
37712
37745
  const start = this.getters.getColRowOffsetInViewport("ROW", top, row);
37713
37746
  const size = this.getters.getRowSize(sheetId, row);
37714
37747
  const isRowHidden = this.getters.isRowHidden(sheetId, row);
@@ -39236,7 +39269,7 @@ class SheetUIPlugin extends UIPlugin {
39236
39269
  getColMaxWidth(sheetId, index) {
39237
39270
  const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
39238
39271
  const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
39239
- return Math.max(0, ...sizes);
39272
+ return Math.max(0, largeMax(sizes));
39240
39273
  }
39241
39274
  splitWordToSpecificWidth(ctx, word, width, style) {
39242
39275
  const wordWidth = computeTextWidth(ctx, word, style);
@@ -42499,12 +42532,14 @@ class BottomBarSheet extends Component {
42499
42532
  this.editionState = "initializing";
42500
42533
  }
42501
42534
  stopEdition() {
42502
- if (!this.state.isEditing)
42535
+ const input = this.sheetNameRef.el;
42536
+ if (!this.state.isEditing || !input)
42503
42537
  return;
42504
42538
  this.state.isEditing = false;
42505
42539
  this.editionState = "initializing";
42506
- this.sheetNameRef.el?.blur();
42540
+ input.blur();
42507
42541
  const inputValue = this.getInputContent() || "";
42542
+ input.innerText = inputValue;
42508
42543
  interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
42509
42544
  }
42510
42545
  cancelEdition() {
@@ -42965,7 +43000,7 @@ class BottomBar extends Component {
42965
43000
  this.sheetListRef.el.scrollTo({ top: 0, left: scroll, behavior: "smooth" });
42966
43001
  }
42967
43002
  onSheetMouseDown(sheetId, event) {
42968
- if (event.button !== 0)
43003
+ if (event.button !== 0 || this.env.model.getters.isReadonly())
42969
43004
  return;
42970
43005
  this.closeMenu();
42971
43006
  const mouseX = event.clientX;
@@ -43066,7 +43101,6 @@ css /* scss */ `
43066
43101
  cursor: pointer;
43067
43102
  }
43068
43103
  `;
43069
- let tKey = 1;
43070
43104
  class SpreadsheetDashboard extends Component {
43071
43105
  static template = "o-spreadsheet-SpreadsheetDashboard";
43072
43106
  static components = {
@@ -43144,13 +43178,9 @@ class SpreadsheetDashboard extends Component {
43144
43178
  coordinates: rect,
43145
43179
  position: { col, row },
43146
43180
  action,
43147
- // we can't rely on position only because a row or a column could
43148
- // be inserted at any time.
43149
- tKey: `${tKey}-${col}-${row}`,
43150
43181
  });
43151
43182
  }
43152
43183
  }
43153
- tKey++;
43154
43184
  return cells;
43155
43185
  }
43156
43186
  getClickableAction(position) {
@@ -46139,7 +46169,7 @@ function addLineChart(chart) {
46139
46169
  }
46140
46170
  function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
46141
46171
  const colors = new ChartColors();
46142
- const maxLength = Math.max(...chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
46172
+ const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
46143
46173
  const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
46144
46174
  const dataSetsNodes = [];
46145
46175
  for (const [dsIndex, dataset] of Object.entries(chart.dataSets).reverse()) {
@@ -46288,8 +46318,7 @@ function addContent(content, sharedStrings, forceString = false) {
46288
46318
  attrs.push(["t", "b"]);
46289
46319
  }
46290
46320
  else if (forceString || !isNumber(value)) {
46291
- const { id } = pushElement(content, sharedStrings);
46292
- value = id.toString();
46321
+ value = pushElement(content, sharedStrings);
46293
46322
  attrs.push(["t", "s"]);
46294
46323
  }
46295
46324
  return { attrs, node: escapeXml /*xml*/ `<v>${value}</v>` };
@@ -46414,8 +46443,7 @@ function addCellIsRule(cf, rule, dxfs) {
46414
46443
  if (rule.style.fillColor) {
46415
46444
  dxf.fill = { fgColor: { rgb: rule.style.fillColor } };
46416
46445
  }
46417
- const { id } = pushElement(dxf, dxfs);
46418
- ruleAttributes.push(["dxfId", id]);
46446
+ ruleAttributes.push(["dxfId", pushElement(dxf, dxfs)]);
46419
46447
  return escapeXml /*xml*/ `
46420
46448
  <conditionalFormatting sqref="${cf.ranges.join(" ")}">
46421
46449
  <cfRule ${formatAttributes(ruleAttributes)}>
@@ -47219,7 +47247,7 @@ function addSheetViews(sheet) {
47219
47247
  */
47220
47248
  function getXLSX(data) {
47221
47249
  const files = [];
47222
- const construct = getDefaultXLSXStructure();
47250
+ const construct = getDefaultXLSXStructure(data);
47223
47251
  files.push(createWorkbook(data, construct));
47224
47252
  files.push(...createWorksheets(data, construct));
47225
47253
  files.push(createStylesSheet(construct));
@@ -48032,6 +48060,6 @@ function addFunction(functionName, functionDescription) {
48032
48060
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
48033
48061
 
48034
48062
 
48035
- __info__.version = '16.3.30';
48036
- __info__.date = '2024-03-25T09:36:48.685Z';
48037
- __info__.hash = '0d2ee33';
48063
+ __info__.version = '16.3.33';
48064
+ __info__.date = '2024-04-18T16:36:40.811Z';
48065
+ __info__.hash = '89f04ea';