@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.
@@ -1020,7 +1020,7 @@ function getItemId(item, itemsDic) {
1020
1020
  }
1021
1021
  // Generate new Id if the item didn't exist in the dictionary
1022
1022
  const ids = Object.keys(itemsDic);
1023
- const maxId = ids.length === 0 ? 0 : Math.max(...ids.map((id) => parseInt(id, 10)));
1023
+ const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
1024
1024
  itemsDic[maxId + 1] = item;
1025
1025
  return maxId + 1;
1026
1026
  }
@@ -1127,7 +1127,7 @@ function deepEquals(o1, o2) {
1127
1127
  if (typeof o1 !== typeof o2)
1128
1128
  return false;
1129
1129
  if (typeof o1 !== "object")
1130
- return o1 === o2;
1130
+ return false;
1131
1131
  // Objects can have different keys if the values are undefined
1132
1132
  const keys = new Set();
1133
1133
  Object.keys(o1).forEach((key) => keys.add(key));
@@ -1212,6 +1212,34 @@ function isConsecutive(iterable) {
1212
1212
  }
1213
1213
  }
1214
1214
  return true;
1215
+ }
1216
+ /**
1217
+ * Alternative to Math.max that works with large arrays.
1218
+ * Typically useful for arrays bigger than 100k elements.
1219
+ */
1220
+ function largeMax(array) {
1221
+ let len = array.length;
1222
+ if (len < 100000)
1223
+ return Math.max(...array);
1224
+ let max = -Infinity;
1225
+ while (len--) {
1226
+ max = array[len] > max ? array[len] : max;
1227
+ }
1228
+ return max;
1229
+ }
1230
+ /**
1231
+ * Alternative to Math.min that works with large arrays.
1232
+ * Typically useful for arrays bigger than 100k elements.
1233
+ */
1234
+ function largeMin(array) {
1235
+ let len = array.length;
1236
+ if (len < 100000)
1237
+ return Math.min(...array);
1238
+ let min = +Infinity;
1239
+ while (len--) {
1240
+ min = array[len] < min ? array[len] : min;
1241
+ }
1242
+ return min;
1215
1243
  }
1216
1244
 
1217
1245
  const RBA_REGEX = /rgba?\(|\s+|\)/gi;
@@ -6258,6 +6286,7 @@ class LinkEditor extends owl.Component {
6258
6286
  this.save();
6259
6287
  }
6260
6288
  ev.stopPropagation();
6289
+ ev.preventDefault();
6261
6290
  break;
6262
6291
  case "Escape":
6263
6292
  this.cancel();
@@ -6823,10 +6852,10 @@ function aggregateDataForLabels(labels, datasets) {
6823
6852
  }
6824
6853
  }
6825
6854
  return {
6826
- labels: Object.keys(labelMap),
6855
+ labels: Array.from(labelSet),
6827
6856
  dataSetsValues: datasets.map((dataset, indexOfDataset) => ({
6828
6857
  ...dataset,
6829
- data: Object.values(labelMap).map((dataOfLabel) => dataOfLabel[indexOfDataset]),
6858
+ data: Array.from(labelSet).map((label) => labelMap[label][indexOfDataset]),
6830
6859
  })),
6831
6860
  };
6832
6861
  }
@@ -7543,7 +7572,7 @@ function getBestTimeUnitForScale(labels, format) {
7543
7572
  return undefined;
7544
7573
  }
7545
7574
  const labelsTimestamps = labelDates.map((date) => date.getTime());
7546
- const period = Math.max(...labelsTimestamps) - Math.min(...labelsTimestamps);
7575
+ const period = largeMax(labelsTimestamps) - largeMin(labelsTimestamps);
7547
7576
  const minUnit = getFormatMinDisplayUnit(format);
7548
7577
  if (UNIT_LENGTH.second >= UNIT_LENGTH[minUnit] && Milliseconds.inSeconds(period) < 180) {
7549
7578
  return "second";
@@ -7983,7 +8012,7 @@ function getPieConfiguration(chart, labels, dataSetFormat) {
7983
8012
  }
7984
8013
  function getPieColors(colors, dataSetsValues) {
7985
8014
  const pieColors = [];
7986
- const maxLength = Math.max(...dataSetsValues.map((ds) => ds.data.length));
8015
+ const maxLength = largeMax(dataSetsValues.map((ds) => ds.data.length));
7987
8016
  for (let i = 0; i <= maxLength; i++) {
7988
8017
  pieColors.push(colors.next());
7989
8018
  }
@@ -8946,8 +8975,8 @@ const DELETE_CONTENT_ROWS_NAME = (env) => {
8946
8975
  let last;
8947
8976
  const activesRows = env.model.getters.getActiveRows();
8948
8977
  if (activesRows.size !== 0) {
8949
- first = Math.min(...activesRows);
8950
- last = Math.max(...activesRows);
8978
+ first = largeMin([...activesRows]);
8979
+ last = largeMax([...activesRows]);
8951
8980
  }
8952
8981
  else {
8953
8982
  const zone = env.model.getters.getSelectedZones()[0];
@@ -8975,8 +9004,8 @@ const DELETE_CONTENT_COLUMNS_NAME = (env) => {
8975
9004
  let last;
8976
9005
  const activeCols = env.model.getters.getActiveCols();
8977
9006
  if (activeCols.size !== 0) {
8978
- first = Math.min(...activeCols);
8979
- last = Math.max(...activeCols);
9007
+ first = largeMin([...activeCols]);
9008
+ last = largeMax([...activeCols]);
8980
9009
  }
8981
9010
  else {
8982
9011
  const zone = env.model.getters.getSelectedZones()[0];
@@ -9004,8 +9033,8 @@ const REMOVE_ROWS_NAME = (env) => {
9004
9033
  let last;
9005
9034
  const activesRows = env.model.getters.getActiveRows();
9006
9035
  if (activesRows.size !== 0) {
9007
- first = Math.min(...activesRows);
9008
- last = Math.max(...activesRows);
9036
+ first = largeMin([...activesRows]);
9037
+ last = largeMax([...activesRows]);
9009
9038
  }
9010
9039
  else {
9011
9040
  const zone = env.model.getters.getSelectedZones()[0];
@@ -9046,8 +9075,8 @@ const REMOVE_COLUMNS_NAME = (env) => {
9046
9075
  let last;
9047
9076
  const activeCols = env.model.getters.getActiveCols();
9048
9077
  if (activeCols.size !== 0) {
9049
- first = Math.min(...activeCols);
9050
- last = Math.max(...activeCols);
9078
+ first = largeMin([...activeCols]);
9079
+ last = largeMax([...activeCols]);
9051
9080
  }
9052
9081
  else {
9053
9082
  const zone = env.model.getters.getSelectedZones()[0];
@@ -9130,7 +9159,7 @@ const INSERT_ROWS_BEFORE_ACTION = (env) => {
9130
9159
  let row;
9131
9160
  let quantity;
9132
9161
  if (activeRows.size) {
9133
- row = Math.min(...activeRows);
9162
+ row = largeMin([...activeRows]);
9134
9163
  quantity = activeRows.size;
9135
9164
  }
9136
9165
  else {
@@ -9162,7 +9191,7 @@ const INSERT_ROWS_AFTER_ACTION = (env) => {
9162
9191
  let row;
9163
9192
  let quantity;
9164
9193
  if (activeRows.size) {
9165
- row = Math.max(...activeRows);
9194
+ row = largeMax([...activeRows]);
9166
9195
  quantity = activeRows.size;
9167
9196
  }
9168
9197
  else {
@@ -9207,7 +9236,7 @@ const INSERT_COLUMNS_BEFORE_ACTION = (env) => {
9207
9236
  let column;
9208
9237
  let quantity;
9209
9238
  if (activeCols.size) {
9210
- column = Math.min(...activeCols);
9239
+ column = largeMin([...activeCols]);
9211
9240
  quantity = activeCols.size;
9212
9241
  }
9213
9242
  else {
@@ -9241,7 +9270,7 @@ const INSERT_COLUMNS_AFTER_ACTION = (env) => {
9241
9270
  let column;
9242
9271
  let quantity;
9243
9272
  if (activeCols.size) {
9244
- column = Math.max(...activeCols);
9273
+ column = largeMax([...activeCols]);
9245
9274
  quantity = activeCols.size;
9246
9275
  }
9247
9276
  else {
@@ -9446,9 +9475,12 @@ const INSERT_LINK_NAME = (env) => {
9446
9475
  // Filters action
9447
9476
  //------------------------------------------------------------------------------
9448
9477
  const FILTERS_CREATE_FILTER_TABLE = (env) => {
9478
+ const zones = env.model.getters.getSelectedZones();
9479
+ if (zones.length === 1 && getZoneArea(zones[0]) === 1) {
9480
+ env.model.selection.selectTableAroundSelection();
9481
+ }
9449
9482
  const sheetId = env.model.getters.getActiveSheetId();
9450
- const selection = env.model.getters.getSelection().zones;
9451
- interactiveAddFilter(env, sheetId, selection);
9483
+ interactiveAddFilter(env, sheetId, env.model.getters.getSelectedZones());
9452
9484
  };
9453
9485
  const FILTERS_REMOVE_FILTER_TABLE = (env) => {
9454
9486
  const sheetId = env.model.getters.getActiveSheetId();
@@ -21312,6 +21344,11 @@ class Composer extends owl.Component {
21312
21344
  onBlur() {
21313
21345
  this.isKeyStillDown = false;
21314
21346
  }
21347
+ onContextMenu(ev) {
21348
+ if (this.env.model.getters.getEditionMode() === "inactive") {
21349
+ this.props.onInputContextMenu?.(ev);
21350
+ }
21351
+ }
21315
21352
  // ---------------------------------------------------------------------------
21316
21353
  // Private
21317
21354
  // ---------------------------------------------------------------------------
@@ -21533,6 +21570,7 @@ Composer.props = {
21533
21570
  onComposerCellFocused: { type: Function, optional: true },
21534
21571
  onComposerContentFocused: Function,
21535
21572
  isDefaultFocus: { type: Boolean, optional: true },
21573
+ onInputContextMenu: { type: Function, optional: true },
21536
21574
  };
21537
21575
 
21538
21576
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
@@ -21609,6 +21647,7 @@ class GridComposer extends owl.Component {
21609
21647
  isDefaultFocus: true,
21610
21648
  onComposerContentFocused: this.props.onComposerContentFocused,
21611
21649
  onComposerCellFocused: this.props.onComposerCellFocused,
21650
+ onInputContextMenu: this.props.onInputContextMenu,
21612
21651
  };
21613
21652
  }
21614
21653
  get containerStyle() {
@@ -21697,6 +21736,7 @@ GridComposer.props = {
21697
21736
  onComposerContentFocused: Function,
21698
21737
  gridDims: Object,
21699
21738
  onComposerCellFocused: Function,
21739
+ onInputContextMenu: Function,
21700
21740
  };
21701
21741
 
21702
21742
  const CSS$1 = css /* scss */ `
@@ -24032,8 +24072,8 @@ class Grid extends owl.Component {
24032
24072
  else if (this.env.model.getters.getActiveRows().has(row)) {
24033
24073
  type = "ROW";
24034
24074
  }
24035
- const { x, y, width, height } = this.env.model.getters.getVisibleRect(lastZone);
24036
- this.toggleContextMenu(type, x + width, y + height);
24075
+ const { x, y, width } = this.env.model.getters.getVisibleRect(lastZone);
24076
+ this.toggleContextMenu(type, this.canvasPosition.x + x + width, this.canvasPosition.y + y);
24037
24077
  }
24038
24078
  onCellRightClicked(col, row, { x, y }) {
24039
24079
  const zones = this.env.model.getters.getSelectedZones();
@@ -26360,29 +26400,12 @@ function convertWidthFromExcel(width) {
26360
26400
  return width;
26361
26401
  return Math.round((width / WIDTH_FACTOR) * 100) / 100;
26362
26402
  }
26363
- function convertBorderDescr(descr) {
26364
- if (!descr) {
26365
- return undefined;
26366
- }
26367
- return {
26368
- style: descr.style,
26369
- color: { rgb: descr.color },
26370
- };
26371
- }
26372
26403
  function extractStyle(cell, data) {
26373
26404
  let style = {};
26374
26405
  if (cell.style) {
26375
26406
  style = data.styles[cell.style];
26376
26407
  }
26377
26408
  const format = extractFormat(cell, data);
26378
- const exportedBorder = {};
26379
- if (cell.border) {
26380
- const border = data.borders[cell.border];
26381
- exportedBorder.left = convertBorderDescr(border.left);
26382
- exportedBorder.right = convertBorderDescr(border.right);
26383
- exportedBorder.bottom = convertBorderDescr(border.bottom);
26384
- exportedBorder.top = convertBorderDescr(border.top);
26385
- }
26386
26409
  const styles = {
26387
26410
  font: {
26388
26411
  size: style?.fontSize || DEFAULT_FONT_SIZE,
@@ -26396,7 +26419,7 @@ function extractStyle(cell, data) {
26396
26419
  }
26397
26420
  : { reservedAttribute: "none" },
26398
26421
  numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
26399
- border: exportedBorder || {},
26422
+ border: cell.border || 0,
26400
26423
  alignment: {
26401
26424
  horizontal: style.align,
26402
26425
  vertical: style.verticalAlign
@@ -26428,15 +26451,12 @@ function extractFormat(cell, data) {
26428
26451
  return undefined;
26429
26452
  }
26430
26453
  function normalizeStyle(construct, styles) {
26431
- const { id: fontId } = pushElement(styles["font"], construct.fonts);
26432
- const { id: fillId } = pushElement(styles["fill"], construct.fills);
26433
- const { id: borderId } = pushElement(styles["border"], construct.borders);
26434
26454
  // Normalize this
26435
26455
  const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
26436
26456
  const style = {
26437
- fontId,
26438
- fillId,
26439
- borderId,
26457
+ fontId: pushElement(styles.font, construct.fonts),
26458
+ fillId: pushElement(styles.fill, construct.fills),
26459
+ borderId: styles.border,
26440
26460
  numFmtId,
26441
26461
  alignment: {
26442
26462
  vertical: styles.alignment.vertical,
@@ -26444,8 +26464,7 @@ function normalizeStyle(construct, styles) {
26444
26464
  wrapText: styles.alignment.wrapText,
26445
26465
  },
26446
26466
  };
26447
- const { id } = pushElement(style, construct.styles);
26448
- return id;
26467
+ return pushElement(style, construct.styles);
26449
26468
  }
26450
26469
  function convertFormat(format, numFmtStructure) {
26451
26470
  if (!format) {
@@ -26453,8 +26472,7 @@ function convertFormat(format, numFmtStructure) {
26453
26472
  }
26454
26473
  let formatId = XLSX_FORMAT_MAP[format.format];
26455
26474
  if (!formatId) {
26456
- const { id } = pushElement(format, numFmtStructure);
26457
- formatId = id + FIRST_NUMFMT_ID;
26475
+ formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
26458
26476
  }
26459
26477
  return formatId;
26460
26478
  }
@@ -26479,20 +26497,15 @@ function addRelsToFile(relsFiles, path, rel) {
26479
26497
  return id;
26480
26498
  }
26481
26499
  function pushElement(property, propertyList) {
26482
- for (let [key, value] of Object.entries(propertyList)) {
26483
- if (JSON.stringify(value) === JSON.stringify(property)) {
26484
- return { id: parseInt(key, 10), list: propertyList };
26500
+ let len = propertyList.length;
26501
+ const operator = typeof property === "object" ? deepEquals : (a, b) => a === b;
26502
+ for (let i = 0; i < len; i++) {
26503
+ if (operator(property, propertyList[i])) {
26504
+ return i;
26485
26505
  }
26486
26506
  }
26487
- let elemId = propertyList.findIndex((elem) => JSON.stringify(elem) === JSON.stringify(property));
26488
- if (elemId === -1) {
26489
- propertyList.push(property);
26490
- elemId = propertyList.length - 1;
26491
- }
26492
- return {
26493
- id: elemId,
26494
- list: propertyList,
26495
- };
26507
+ propertyList[propertyList.length] = property;
26508
+ return propertyList.length - 1;
26496
26509
  }
26497
26510
  const chartIds = [];
26498
26511
  /**
@@ -26929,7 +26942,7 @@ function convertHyperlink(link, cellValue, warningManager) {
26929
26942
  function getSheetDims(sheet) {
26930
26943
  const dims = [0, 0];
26931
26944
  for (let row of sheet.rows) {
26932
- dims[0] = Math.max(dims[0], ...row.cells.map((cell) => toCartesian(cell.xc).col));
26945
+ dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
26933
26946
  dims[1] = Math.max(dims[1], row.index);
26934
26947
  }
26935
26948
  dims[0] = Math.max(dims[0], EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
@@ -27198,7 +27211,25 @@ function parseXML(xmlString, mimeType = "text/xml") {
27198
27211
  }
27199
27212
  return document;
27200
27213
  }
27201
- function getDefaultXLSXStructure() {
27214
+ function convertBorderDescr(descr) {
27215
+ if (!descr) {
27216
+ return undefined;
27217
+ }
27218
+ return {
27219
+ style: descr.style,
27220
+ color: { rgb: descr.color },
27221
+ };
27222
+ }
27223
+ function getDefaultXLSXStructure(data) {
27224
+ const xlsxBorders = Object.values(data.borders).map((border) => {
27225
+ return {
27226
+ left: convertBorderDescr(border.left),
27227
+ right: convertBorderDescr(border.right),
27228
+ bottom: convertBorderDescr(border.bottom),
27229
+ top: convertBorderDescr(border.top),
27230
+ };
27231
+ });
27232
+ const borders = [{}, ...xlsxBorders];
27202
27233
  return {
27203
27234
  relsFiles: [],
27204
27235
  sharedStrings: [],
@@ -27221,7 +27252,7 @@ function getDefaultXLSXStructure() {
27221
27252
  },
27222
27253
  ],
27223
27254
  fills: [{ reservedAttribute: "none" }, { reservedAttribute: "gray125" }],
27224
- borders: [{}],
27255
+ borders,
27225
27256
  numFmts: [],
27226
27257
  dxfs: [],
27227
27258
  };
@@ -31172,7 +31203,17 @@ class FiltersPlugin extends CorePlugin {
31172
31203
  }
31173
31204
  }
31174
31205
  exportForExcel(data) {
31175
- this.export(data);
31206
+ for (const sheet of data.sheets) {
31207
+ for (const filterTable of this.getFilterTables(sheet.id)) {
31208
+ if (zoneToDimension(filterTable.zone).numberOfRows === 1) {
31209
+ continue;
31210
+ }
31211
+ sheet.filterTables.push({
31212
+ range: zoneToXc(filterTable.zone),
31213
+ filters: [],
31214
+ });
31215
+ }
31216
+ }
31176
31217
  }
31177
31218
  }
31178
31219
 
@@ -31216,7 +31257,7 @@ class HeaderSizePlugin extends CorePlugin {
31216
31257
  for (let headerIndex of [...cmd.elements].sort((a, b) => b - a)) {
31217
31258
  sizes.splice(headerIndex, 1);
31218
31259
  }
31219
- const min = Math.min(...cmd.elements);
31260
+ const min = largeMin(cmd.elements);
31220
31261
  sizes = sizes.map((size, row) => {
31221
31262
  if (cmd.dimension === "ROW" && row >= min) {
31222
31263
  // invalidate sizes
@@ -31443,7 +31484,7 @@ class HeaderVisibilityPlugin extends CorePlugin {
31443
31484
  if (hiddenElements.size >= elements) {
31444
31485
  return 67 /* CommandResult.TooManyHiddenElements */;
31445
31486
  }
31446
- else if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
31487
+ else if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
31447
31488
  return 87 /* CommandResult.InvalidHeaderIndex */;
31448
31489
  }
31449
31490
  else {
@@ -32216,8 +32257,8 @@ class RangeAdapter {
32216
32257
  let newRange = range;
32217
32258
  let changeType = "NONE";
32218
32259
  for (let group of groups) {
32219
- const min = Math.min(...group);
32220
- const max = Math.max(...group);
32260
+ const min = largeMin(group);
32261
+ const max = largeMax(group);
32221
32262
  if (range.zone[start] <= min && min <= range.zone[end]) {
32222
32263
  const toRemove = Math.min(range.zone[end], max) - min + 1;
32223
32264
  changeType = "RESIZE";
@@ -32648,7 +32689,7 @@ class SheetPlugin extends CorePlugin {
32648
32689
  const elements = cmd.dimension === "COL"
32649
32690
  ? this.getNumberCols(cmd.sheetId)
32650
32691
  : this.getNumberRows(cmd.sheetId);
32651
- if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
32692
+ if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
32652
32693
  return 87 /* CommandResult.InvalidHeaderIndex */;
32653
32694
  }
32654
32695
  else if (this.checkElementsIncludeAllNonFrozenHeaders(cmd.sheetId, cmd.dimension, cmd.elements)) {
@@ -34150,13 +34191,13 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
34150
34191
  .map((cell) => cell.value);
34151
34192
  switch (threshold.type) {
34152
34193
  case "value":
34153
- const result = functionName === "max" ? Math.max(...rangeValues) : Math.min(...rangeValues);
34194
+ const result = functionName === "max" ? largeMax(rangeValues) : largeMin(rangeValues);
34154
34195
  return result;
34155
34196
  case "number":
34156
34197
  return Number(threshold.value);
34157
34198
  case "percentage":
34158
- const min = Math.min(...rangeValues);
34159
- const max = Math.max(...rangeValues);
34199
+ const min = largeMin(rangeValues);
34200
+ const max = largeMax(rangeValues);
34160
34201
  const delta = max - min;
34161
34202
  return min + (delta * Number(threshold.value)) / 100;
34162
34203
  case "percentile":
@@ -35040,12 +35081,13 @@ class SheetViewPlugin extends UIPlugin {
35040
35081
  case "AlterZone":
35041
35082
  break;
35042
35083
  case "ZonesSelected":
35084
+ const sheetId = this.getters.getActiveSheetId();
35043
35085
  let { col, row } = findCellInNewZone(event.previousAnchor.zone, event.anchor.zone);
35044
35086
  if (event.mode === "updateAnchor") {
35045
35087
  const oldZone = event.previousAnchor.zone;
35046
35088
  const newZone = event.anchor.zone;
35047
35089
  // altering a zone should not move the viewport in a dimension that wasn't changed
35048
- const { top, bottom, left, right } = this.getters.getActiveMainViewport();
35090
+ const { top, bottom, left, right } = this.getMainInternalViewport(sheetId);
35049
35091
  if (oldZone.left === newZone.left && oldZone.right === newZone.right) {
35050
35092
  col = left > col || col > right ? left : col;
35051
35093
  }
@@ -35053,10 +35095,9 @@ class SheetViewPlugin extends UIPlugin {
35053
35095
  row = top > row || row > bottom ? top : row;
35054
35096
  }
35055
35097
  }
35056
- const sheetId = this.getters.getActiveSheetId();
35057
35098
  col = Math.min(col, this.getters.getNumberCols(sheetId) - 1);
35058
35099
  row = Math.min(row, this.getters.getNumberRows(sheetId) - 1);
35059
- this.refreshViewport(this.getters.getActiveSheetId(), { col, row });
35100
+ this.refreshViewport(sheetId, { col, row });
35060
35101
  break;
35061
35102
  }
35062
35103
  }
@@ -35080,16 +35121,16 @@ class SheetViewPlugin extends UIPlugin {
35080
35121
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
35081
35122
  break;
35082
35123
  case "SHIFT_VIEWPORT_DOWN":
35083
- const { top } = this.getActiveMainViewport();
35084
35124
  const sheetId = this.getters.getActiveSheetId();
35085
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).start + this.sheetViewHeight);
35086
- this.shiftVertically(shiftedOffsetY);
35125
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
35126
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
35127
+ this.shiftVertically(topRowDims.start + viewportHeight - offsetCorrectionY);
35087
35128
  break;
35088
35129
  case "SHIFT_VIEWPORT_UP": {
35089
- const { top } = this.getActiveMainViewport();
35090
35130
  const sheetId = this.getters.getActiveSheetId();
35091
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).end - this.sheetViewHeight);
35092
- this.shiftVertically(shiftedOffsetY);
35131
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
35132
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
35133
+ this.shiftVertically(topRowDims.end - offsetCorrectionY - viewportHeight);
35093
35134
  break;
35094
35135
  }
35095
35136
  case "REMOVE_COLUMNS_ROWS":
@@ -35451,17 +35492,6 @@ class SheetViewPlugin extends UIPlugin {
35451
35492
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
35452
35493
  Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
35453
35494
  }
35454
- /**
35455
- * Clip the vertical offset within the allowed range.
35456
- * Not above the sheet, nor below the sheet.
35457
- */
35458
- clipOffsetY(offsetY) {
35459
- const { height } = this.getMainViewportRect();
35460
- const maxOffset = height - this.sheetViewHeight;
35461
- offsetY = Math.min(offsetY, maxOffset);
35462
- offsetY = Math.max(offsetY, 0);
35463
- return offsetY;
35464
- }
35465
35495
  getViewportOffset(sheetId) {
35466
35496
  return {
35467
35497
  x: this.viewports[sheetId]?.bottomRight.offsetScrollbarX || 0,
@@ -35517,12 +35547,15 @@ class SheetViewPlugin extends UIPlugin {
35517
35547
  * viewport top.
35518
35548
  */
35519
35549
  shiftVertically(offset) {
35520
- const { top } = this.getActiveMainViewport();
35550
+ const sheetId = this.getters.getActiveSheetId();
35551
+ const { top } = this.getMainInternalViewport(sheetId);
35521
35552
  const { scrollX } = this.getActiveSheetScrollInfo();
35522
35553
  this.setSheetViewOffset(scrollX, offset);
35523
35554
  const { anchor } = this.getters.getSelection();
35524
- const deltaRow = this.getActiveMainViewport().top - top;
35525
- this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
35555
+ if (anchor.cell.row >= this.getters.getPaneDivisions(sheetId).ySplit) {
35556
+ const deltaRow = this.getMainInternalViewport(sheetId).top - top;
35557
+ this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
35558
+ }
35526
35559
  }
35527
35560
  getVisibleFigures() {
35528
35561
  const sheetId = this.getters.getActiveSheetId();
@@ -36106,13 +36139,13 @@ class AutomaticSumPlugin extends UIPlugin {
36106
36139
  const cells = this.getters.getEvaluatedCellsInZone(sheet.id, zone);
36107
36140
  const cellPositions = range(end, -1, -1);
36108
36141
  const invalidCells = cellPositions.filter((position) => cells[position] && !cells[position].isAutoSummable);
36109
- const maxValidPosition = Math.max(...invalidCells);
36142
+ const maxValidPosition = largeMax(invalidCells);
36110
36143
  const numberSequences = groupConsecutive(cellPositions.filter((position) => this.isNumber(cells[position])));
36111
36144
  const firstSequence = numberSequences[0] || [];
36112
- if (Math.max(...firstSequence) < maxValidPosition) {
36145
+ if (largeMax(firstSequence) < maxValidPosition) {
36113
36146
  return Infinity;
36114
36147
  }
36115
- return Math.min(...firstSequence);
36148
+ return largeMin(firstSequence);
36116
36149
  }
36117
36150
  shouldFindData(sheetId, zone) {
36118
36151
  return this.getters.isEmpty(sheetId, zone) || this.getters.isSingleCellOrMerge(sheetId, zone);
@@ -37697,7 +37730,7 @@ class RendererPlugin extends UIPlugin {
37697
37730
  * column of the current viewport
37698
37731
  */
37699
37732
  getColDimensionsInViewport(sheetId, col) {
37700
- const left = Math.min(...this.getters.getSheetViewVisibleCols());
37733
+ const left = largeMin(this.getters.getSheetViewVisibleCols());
37701
37734
  const start = this.getters.getColRowOffsetInViewport("COL", left, col);
37702
37735
  const size = this.getters.getColSize(sheetId, col);
37703
37736
  const isColHidden = this.getters.isColHidden(sheetId, col);
@@ -37712,7 +37745,7 @@ class RendererPlugin extends UIPlugin {
37712
37745
  * of the current viewport
37713
37746
  */
37714
37747
  getRowDimensionsInViewport(sheetId, row) {
37715
- const top = Math.min(...this.getters.getSheetViewVisibleRows());
37748
+ const top = largeMin(this.getters.getSheetViewVisibleRows());
37716
37749
  const start = this.getters.getColRowOffsetInViewport("ROW", top, row);
37717
37750
  const size = this.getters.getRowSize(sheetId, row);
37718
37751
  const isRowHidden = this.getters.isRowHidden(sheetId, row);
@@ -39240,7 +39273,7 @@ class SheetUIPlugin extends UIPlugin {
39240
39273
  getColMaxWidth(sheetId, index) {
39241
39274
  const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
39242
39275
  const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
39243
- return Math.max(0, ...sizes);
39276
+ return Math.max(0, largeMax(sizes));
39244
39277
  }
39245
39278
  splitWordToSpecificWidth(ctx, word, width, style) {
39246
39279
  const wordWidth = computeTextWidth(ctx, word, style);
@@ -42503,12 +42536,14 @@ class BottomBarSheet extends owl.Component {
42503
42536
  this.editionState = "initializing";
42504
42537
  }
42505
42538
  stopEdition() {
42506
- if (!this.state.isEditing)
42539
+ const input = this.sheetNameRef.el;
42540
+ if (!this.state.isEditing || !input)
42507
42541
  return;
42508
42542
  this.state.isEditing = false;
42509
42543
  this.editionState = "initializing";
42510
- this.sheetNameRef.el?.blur();
42544
+ input.blur();
42511
42545
  const inputValue = this.getInputContent() || "";
42546
+ input.innerText = inputValue;
42512
42547
  interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
42513
42548
  }
42514
42549
  cancelEdition() {
@@ -42969,7 +43004,7 @@ class BottomBar extends owl.Component {
42969
43004
  this.sheetListRef.el.scrollTo({ top: 0, left: scroll, behavior: "smooth" });
42970
43005
  }
42971
43006
  onSheetMouseDown(sheetId, event) {
42972
- if (event.button !== 0)
43007
+ if (event.button !== 0 || this.env.model.getters.isReadonly())
42973
43008
  return;
42974
43009
  this.closeMenu();
42975
43010
  const mouseX = event.clientX;
@@ -43070,7 +43105,6 @@ css /* scss */ `
43070
43105
  cursor: pointer;
43071
43106
  }
43072
43107
  `;
43073
- let tKey = 1;
43074
43108
  class SpreadsheetDashboard extends owl.Component {
43075
43109
  static template = "o-spreadsheet-SpreadsheetDashboard";
43076
43110
  static components = {
@@ -43148,13 +43182,9 @@ class SpreadsheetDashboard extends owl.Component {
43148
43182
  coordinates: rect,
43149
43183
  position: { col, row },
43150
43184
  action,
43151
- // we can't rely on position only because a row or a column could
43152
- // be inserted at any time.
43153
- tKey: `${tKey}-${col}-${row}`,
43154
43185
  });
43155
43186
  }
43156
43187
  }
43157
- tKey++;
43158
43188
  return cells;
43159
43189
  }
43160
43190
  getClickableAction(position) {
@@ -46143,7 +46173,7 @@ function addLineChart(chart) {
46143
46173
  }
46144
46174
  function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
46145
46175
  const colors = new ChartColors();
46146
- const maxLength = Math.max(...chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
46176
+ const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
46147
46177
  const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
46148
46178
  const dataSetsNodes = [];
46149
46179
  for (const [dsIndex, dataset] of Object.entries(chart.dataSets).reverse()) {
@@ -46292,8 +46322,7 @@ function addContent(content, sharedStrings, forceString = false) {
46292
46322
  attrs.push(["t", "b"]);
46293
46323
  }
46294
46324
  else if (forceString || !isNumber(value)) {
46295
- const { id } = pushElement(content, sharedStrings);
46296
- value = id.toString();
46325
+ value = pushElement(content, sharedStrings);
46297
46326
  attrs.push(["t", "s"]);
46298
46327
  }
46299
46328
  return { attrs, node: escapeXml /*xml*/ `<v>${value}</v>` };
@@ -46418,8 +46447,7 @@ function addCellIsRule(cf, rule, dxfs) {
46418
46447
  if (rule.style.fillColor) {
46419
46448
  dxf.fill = { fgColor: { rgb: rule.style.fillColor } };
46420
46449
  }
46421
- const { id } = pushElement(dxf, dxfs);
46422
- ruleAttributes.push(["dxfId", id]);
46450
+ ruleAttributes.push(["dxfId", pushElement(dxf, dxfs)]);
46423
46451
  return escapeXml /*xml*/ `
46424
46452
  <conditionalFormatting sqref="${cf.ranges.join(" ")}">
46425
46453
  <cfRule ${formatAttributes(ruleAttributes)}>
@@ -47223,7 +47251,7 @@ function addSheetViews(sheet) {
47223
47251
  */
47224
47252
  function getXLSX(data) {
47225
47253
  const files = [];
47226
- const construct = getDefaultXLSXStructure();
47254
+ const construct = getDefaultXLSXStructure(data);
47227
47255
  files.push(createWorkbook(data, construct));
47228
47256
  files.push(...createWorksheets(data, construct));
47229
47257
  files.push(createStylesSheet(construct));
@@ -48064,6 +48092,6 @@ exports.setTranslationMethod = setTranslationMethod;
48064
48092
  exports.tokenize = tokenize;
48065
48093
 
48066
48094
 
48067
- __info__.version = '16.3.30';
48068
- __info__.date = '2024-03-25T09:36:48.685Z';
48069
- __info__.hash = '0d2ee33';
48095
+ __info__.version = '16.3.33';
48096
+ __info__.date = '2024-04-18T16:36:40.811Z';
48097
+ __info__.hash = '89f04ea';