@odoo/o-spreadsheet 17.0.16 → 17.0.17

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.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 17.0.16
6
- * @date 2024-03-25T09:42:01.717Z
7
- * @hash 9b128f8
5
+ * @version 17.0.17
6
+ * @date 2024-04-05T13:59:37.139Z
7
+ * @hash 33f09d7
8
8
  */
9
9
 
10
10
  'use strict';
@@ -559,7 +559,7 @@ function getItemId(item, itemsDic) {
559
559
  }
560
560
  // Generate new Id if the item didn't exist in the dictionary
561
561
  const ids = Object.keys(itemsDic);
562
- const maxId = ids.length === 0 ? 0 : Math.max(...ids.map((id) => parseInt(id, 10)));
562
+ const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
563
563
  itemsDic[maxId + 1] = item;
564
564
  return maxId + 1;
565
565
  }
@@ -776,6 +776,34 @@ function isNumberBetween(value, min, max) {
776
776
  }
777
777
  return value >= min && value <= max;
778
778
  }
779
+ /**
780
+ * Alternative to Math.max that works with large arrays.
781
+ * Typically useful for arrays bigger than 100k elements.
782
+ */
783
+ function largeMax(array) {
784
+ let len = array.length;
785
+ if (len < 100000)
786
+ return Math.max(...array);
787
+ let max = -Infinity;
788
+ while (len--) {
789
+ max = array[len] > max ? array[len] : max;
790
+ }
791
+ return max;
792
+ }
793
+ /**
794
+ * Alternative to Math.min that works with large arrays.
795
+ * Typically useful for arrays bigger than 100k elements.
796
+ */
797
+ function largeMin(array) {
798
+ let len = array.length;
799
+ if (len < 100000)
800
+ return Math.min(...array);
801
+ let min = +Infinity;
802
+ while (len--) {
803
+ min = array[len] < min ? array[len] : min;
804
+ }
805
+ return min;
806
+ }
779
807
 
780
808
  const RBA_REGEX = /rgba?\(|\s+|\)/gi;
781
809
  const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
@@ -4422,8 +4450,9 @@ function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
4422
4450
  * Get the default height of the cell given its style.
4423
4451
  */
4424
4452
  function getDefaultCellHeight(ctx, cell, colSize) {
4425
- if (!cell || !cell.content)
4453
+ if (!cell || (!cell.isFormula && !cell.content)) {
4426
4454
  return DEFAULT_CELL_HEIGHT;
4455
+ }
4427
4456
  const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
4428
4457
  const numberOfLines = cell.isFormula
4429
4458
  ? 1
@@ -8326,10 +8355,10 @@ function aggregateDataForLabels(labels, datasets) {
8326
8355
  }
8327
8356
  }
8328
8357
  return {
8329
- labels: Object.keys(labelMap),
8358
+ labels: Array.from(labelSet),
8330
8359
  dataSetsValues: datasets.map((dataset, indexOfDataset) => ({
8331
8360
  ...dataset,
8332
- data: Object.values(labelMap).map((dataOfLabel) => dataOfLabel[indexOfDataset]),
8361
+ data: Array.from(labelSet).map((label) => labelMap[label][indexOfDataset]),
8333
8362
  })),
8334
8363
  };
8335
8364
  }
@@ -8380,7 +8409,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale })
8380
8409
  const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
8381
8410
  // tooltipItem.parsed.y can be an object or a number for pie charts
8382
8411
  const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
8383
- const toolTipFormat = !format && yLabel > 1000 ? "#,##" : format;
8412
+ const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
8384
8413
  const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
8385
8414
  return xLabel ? `${xLabel}: ${yLabelStr}` : yLabelStr;
8386
8415
  },
@@ -8666,7 +8695,10 @@ function getBarConfiguration(chart, labels, localeFormat) {
8666
8695
  if (isNaN(value))
8667
8696
  return value;
8668
8697
  const { locale, format } = localeFormat;
8669
- return formatValue(value, { locale, format: !format && value > 1000 ? "#,##" : format });
8698
+ return formatValue(value, {
8699
+ locale,
8700
+ format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
8701
+ });
8670
8702
  },
8671
8703
  },
8672
8704
  },
@@ -9080,7 +9112,7 @@ function getBestTimeUnitForScale(labels, format, locale) {
9080
9112
  return undefined;
9081
9113
  }
9082
9114
  const labelsTimestamps = labelDates.map((date) => date.getTime());
9083
- const period = Math.max(...labelsTimestamps) - Math.min(...labelsTimestamps);
9115
+ const period = largeMax(labelsTimestamps) - largeMin(labelsTimestamps);
9084
9116
  const minUnit = getFormatMinDisplayUnit(format);
9085
9117
  if (UNIT_LENGTH.second >= UNIT_LENGTH[minUnit] && Milliseconds.inSeconds(period) < 180) {
9086
9118
  return "second";
@@ -9317,7 +9349,10 @@ function getLineConfiguration(chart, labels, localeFormat) {
9317
9349
  if (isNaN(value))
9318
9350
  return value;
9319
9351
  const { locale, format } = localeFormat;
9320
- return formatValue(value, { locale, format: !format && value > 1000 ? "#,##" : format });
9352
+ return formatValue(value, {
9353
+ locale,
9354
+ format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
9355
+ });
9321
9356
  },
9322
9357
  },
9323
9358
  },
@@ -9544,7 +9579,7 @@ function getPieConfiguration(chart, labels, localeFormat) {
9544
9579
  const percentage = calculatePercentage(data, dataIndex);
9545
9580
  const xLabel = tooltipItem.label || tooltipItem.dataset.label;
9546
9581
  const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
9547
- const toolTipFormat = !format && yLabel > 1000 ? "#,##" : format;
9582
+ const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
9548
9583
  const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
9549
9584
  return xLabel ? `${xLabel}: ${yLabelStr} (${percentage}%)` : `${yLabelStr} (${percentage}%)`;
9550
9585
  };
@@ -9552,7 +9587,7 @@ function getPieConfiguration(chart, labels, localeFormat) {
9552
9587
  }
9553
9588
  function getPieColors(colors, dataSetsValues) {
9554
9589
  const pieColors = [];
9555
- const maxLength = Math.max(...dataSetsValues.map((ds) => ds.data.length));
9590
+ const maxLength = largeMax(dataSetsValues.map((ds) => ds.data.length));
9556
9591
  for (let i = 0; i <= maxLength; i++) {
9557
9592
  pieColors.push(colors.next());
9558
9593
  }
@@ -10454,8 +10489,8 @@ const DELETE_CONTENT_ROWS_NAME = (env) => {
10454
10489
  let last;
10455
10490
  const activesRows = env.model.getters.getActiveRows();
10456
10491
  if (activesRows.size !== 0) {
10457
- first = Math.min(...activesRows);
10458
- last = Math.max(...activesRows);
10492
+ first = largeMin([...activesRows]);
10493
+ last = largeMax([...activesRows]);
10459
10494
  }
10460
10495
  else {
10461
10496
  const zone = env.model.getters.getSelectedZones()[0];
@@ -10483,8 +10518,8 @@ const DELETE_CONTENT_COLUMNS_NAME = (env) => {
10483
10518
  let last;
10484
10519
  const activeCols = env.model.getters.getActiveCols();
10485
10520
  if (activeCols.size !== 0) {
10486
- first = Math.min(...activeCols);
10487
- last = Math.max(...activeCols);
10521
+ first = largeMin([...activeCols]);
10522
+ last = largeMax([...activeCols]);
10488
10523
  }
10489
10524
  else {
10490
10525
  const zone = env.model.getters.getSelectedZones()[0];
@@ -10512,8 +10547,8 @@ const REMOVE_ROWS_NAME = (env) => {
10512
10547
  let last;
10513
10548
  const activesRows = env.model.getters.getActiveRows();
10514
10549
  if (activesRows.size !== 0) {
10515
- first = Math.min(...activesRows);
10516
- last = Math.max(...activesRows);
10550
+ first = largeMin([...activesRows]);
10551
+ last = largeMax([...activesRows]);
10517
10552
  }
10518
10553
  else {
10519
10554
  const zone = env.model.getters.getSelectedZones()[0];
@@ -10554,8 +10589,8 @@ const REMOVE_COLUMNS_NAME = (env) => {
10554
10589
  let last;
10555
10590
  const activeCols = env.model.getters.getActiveCols();
10556
10591
  if (activeCols.size !== 0) {
10557
- first = Math.min(...activeCols);
10558
- last = Math.max(...activeCols);
10592
+ first = largeMin([...activeCols]);
10593
+ last = largeMax([...activeCols]);
10559
10594
  }
10560
10595
  else {
10561
10596
  const zone = env.model.getters.getSelectedZones()[0];
@@ -10596,7 +10631,7 @@ const INSERT_ROWS_BEFORE_ACTION = (env) => {
10596
10631
  let row;
10597
10632
  let quantity;
10598
10633
  if (activeRows.size) {
10599
- row = Math.min(...activeRows);
10634
+ row = largeMin([...activeRows]);
10600
10635
  quantity = activeRows.size;
10601
10636
  }
10602
10637
  else {
@@ -10617,7 +10652,7 @@ const INSERT_ROWS_AFTER_ACTION = (env) => {
10617
10652
  let row;
10618
10653
  let quantity;
10619
10654
  if (activeRows.size) {
10620
- row = Math.max(...activeRows);
10655
+ row = largeMax([...activeRows]);
10621
10656
  quantity = activeRows.size;
10622
10657
  }
10623
10658
  else {
@@ -10638,7 +10673,7 @@ const INSERT_COLUMNS_BEFORE_ACTION = (env) => {
10638
10673
  let column;
10639
10674
  let quantity;
10640
10675
  if (activeCols.size) {
10641
- column = Math.min(...activeCols);
10676
+ column = largeMin([...activeCols]);
10642
10677
  quantity = activeCols.size;
10643
10678
  }
10644
10679
  else {
@@ -10659,7 +10694,7 @@ const INSERT_COLUMNS_AFTER_ACTION = (env) => {
10659
10694
  let column;
10660
10695
  let quantity;
10661
10696
  if (activeCols.size) {
10662
- column = Math.max(...activeCols);
10697
+ column = largeMax([...activeCols]);
10663
10698
  quantity = activeCols.size;
10664
10699
  }
10665
10700
  else {
@@ -31856,7 +31891,7 @@ function convertHyperlink(link, cellValue, warningManager) {
31856
31891
  function getSheetDims(sheet) {
31857
31892
  const dims = [0, 0];
31858
31893
  for (let row of sheet.rows) {
31859
- dims[0] = Math.max(dims[0], ...row.cells.map((cell) => toCartesian(cell.xc).col));
31894
+ dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
31860
31895
  dims[1] = Math.max(dims[1], row.index);
31861
31896
  }
31862
31897
  dims[0] = Math.max(dims[0], EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
@@ -36746,6 +36781,9 @@ class DataValidationPlugin extends CorePlugin {
36746
36781
  if (newRule.criterion.type === "isBoolean") {
36747
36782
  this.setCenterStyleToBooleanCells(newRule);
36748
36783
  }
36784
+ else if (newRule.criterion.type === "isValueInList") {
36785
+ newRule.criterion.values = Array.from(new Set(newRule.criterion.values));
36786
+ }
36749
36787
  const adaptedRules = this.removeRangesFromRules(sheetId, newRule.ranges, rules);
36750
36788
  const ruleIndex = adaptedRules.findIndex((rule) => rule.id === newRule.id);
36751
36789
  if (ruleIndex !== -1) {
@@ -37472,7 +37510,7 @@ class HeaderVisibilityPlugin extends CorePlugin {
37472
37510
  if (hiddenElements.size >= elements) {
37473
37511
  return "TooManyHiddenElements" /* CommandResult.TooManyHiddenElements */;
37474
37512
  }
37475
- else if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
37513
+ else if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
37476
37514
  return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
37477
37515
  }
37478
37516
  else {
@@ -38287,8 +38325,8 @@ class RangeAdapter {
38287
38325
  let newRange = range;
38288
38326
  let changeType = "NONE";
38289
38327
  for (let group of groups) {
38290
- const min = Math.min(...group);
38291
- const max = Math.max(...group);
38328
+ const min = largeMin(group);
38329
+ const max = largeMax(group);
38292
38330
  if (range.zone[start] <= min && min <= range.zone[end]) {
38293
38331
  const toRemove = Math.min(range.zone[end], max) - min + 1;
38294
38332
  changeType = "RESIZE";
@@ -38711,8 +38749,8 @@ class SheetPlugin extends CorePlugin {
38711
38749
  }
38712
38750
  return "Success" /* CommandResult.Success */;
38713
38751
  case "REMOVE_COLUMNS_ROWS": {
38714
- const min = Math.min(...cmd.elements);
38715
- const max = Math.max(...cmd.elements);
38752
+ const min = largeMin(cmd.elements);
38753
+ const max = largeMax(cmd.elements);
38716
38754
  if (min < 0 || !this.doesHeaderExist(cmd.sheetId, cmd.dimension, max)) {
38717
38755
  return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
38718
38756
  }
@@ -42044,13 +42082,13 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
42044
42082
  .map((cell) => cell.value);
42045
42083
  switch (threshold.type) {
42046
42084
  case "value":
42047
- const result = functionName === "max" ? Math.max(...rangeValues) : Math.min(...rangeValues);
42085
+ const result = functionName === "max" ? largeMax(rangeValues) : largeMin(rangeValues);
42048
42086
  return result;
42049
42087
  case "number":
42050
42088
  return Number(threshold.value);
42051
42089
  case "percentage":
42052
- const min = Math.min(...rangeValues);
42053
- const max = Math.max(...rangeValues);
42090
+ const min = largeMin(rangeValues);
42091
+ const max = largeMax(rangeValues);
42054
42092
  const delta = max - min;
42055
42093
  return min + (delta * Number(threshold.value)) / 100;
42056
42094
  case "percentile":
@@ -43102,13 +43140,13 @@ class AutomaticSumPlugin extends UIPlugin {
43102
43140
  const cells = this.getters.getEvaluatedCellsInZone(sheet.id, zone);
43103
43141
  const cellPositions = range(end, -1, -1);
43104
43142
  const invalidCells = cellPositions.filter((position) => cells[position] && !cells[position].isAutoSummable);
43105
- const maxValidPosition = Math.max(...invalidCells);
43143
+ const maxValidPosition = largeMax(invalidCells);
43106
43144
  const numberSequences = groupConsecutive(cellPositions.filter((position) => this.isNumber(cells[position])));
43107
43145
  const firstSequence = numberSequences[0] || [];
43108
- if (Math.max(...firstSequence) < maxValidPosition) {
43146
+ if (largeMax(firstSequence) < maxValidPosition) {
43109
43147
  return Infinity;
43110
43148
  }
43111
- return Math.min(...firstSequence);
43149
+ return largeMin(firstSequence);
43112
43150
  }
43113
43151
  shouldFindData(sheetId, zone) {
43114
43152
  return this.getters.isEmpty(sheetId, zone) || this.getters.isSingleCellOrMerge(sheetId, zone);
@@ -45512,7 +45550,7 @@ class RendererPlugin extends UIPlugin {
45512
45550
  * column of the current viewport
45513
45551
  */
45514
45552
  getColDimensionsInViewport(sheetId, col) {
45515
- const left = Math.min(...this.getters.getSheetViewVisibleCols());
45553
+ const left = largeMin(this.getters.getSheetViewVisibleCols());
45516
45554
  const start = this.getters.getColRowOffsetInViewport("COL", left, col);
45517
45555
  const size = this.getters.getColSize(sheetId, col);
45518
45556
  const isColHidden = this.getters.isColHidden(sheetId, col);
@@ -45527,7 +45565,7 @@ class RendererPlugin extends UIPlugin {
45527
45565
  * of the current viewport
45528
45566
  */
45529
45567
  getRowDimensionsInViewport(sheetId, row) {
45530
- const top = Math.min(...this.getters.getSheetViewVisibleRows());
45568
+ const top = largeMin(this.getters.getSheetViewVisibleRows());
45531
45569
  const start = this.getters.getColRowOffsetInViewport("ROW", top, row);
45532
45570
  const size = this.getters.getRowSize(sheetId, row);
45533
45571
  const isRowHidden = this.getters.isRowHidden(sheetId, row);
@@ -46991,7 +47029,7 @@ class SheetUIPlugin extends UIPlugin {
46991
47029
  getColMaxWidth(sheetId, index) {
46992
47030
  const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
46993
47031
  const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
46994
- return Math.max(0, ...sizes);
47032
+ return Math.max(0, largeMax(sizes));
46995
47033
  }
46996
47034
  /**
46997
47035
  * Check that any "sheetId" in the command matches an existing
@@ -47756,7 +47794,7 @@ class ClipboardOsState extends ClipboardCellsAbstractState {
47756
47794
  }
47757
47795
  getPasteZone(target) {
47758
47796
  const height = this.values.length;
47759
- const width = Math.max(...this.values.map((a) => a.length));
47797
+ const width = largeMax(this.values.map((a) => a.length));
47760
47798
  const { left: activeCol, top: activeRow } = target[0];
47761
47799
  return {
47762
47800
  top: activeRow,
@@ -48793,11 +48831,11 @@ class EditionPlugin extends UIPlugin {
48793
48831
  }
48794
48832
  else {
48795
48833
  const range = this.getters.getRangeFromSheetXC(this.sheetId, rule.criterion.values[0]);
48796
- values = this.getters
48834
+ values = Array.from(new Set(this.getters
48797
48835
  .getRangeValues(range)
48798
48836
  .filter(isNotNull)
48799
48837
  .map((value) => value.toString())
48800
- .filter((val) => val !== "");
48838
+ .filter((val) => val !== "")));
48801
48839
  }
48802
48840
  const composerContent = this.getCurrentContent();
48803
48841
  if (composerContent && composerContent !== this.getInitialComposerContent()) {
@@ -51254,12 +51292,14 @@ class BottomBarSheet extends owl.Component {
51254
51292
  this.editionState = "initializing";
51255
51293
  }
51256
51294
  stopEdition() {
51257
- if (!this.state.isEditing)
51295
+ const input = this.sheetNameRef.el;
51296
+ if (!this.state.isEditing || !input)
51258
51297
  return;
51259
51298
  this.state.isEditing = false;
51260
51299
  this.editionState = "initializing";
51261
- this.sheetNameRef.el?.blur();
51300
+ input.blur();
51262
51301
  const inputValue = this.getInputContent() || "";
51302
+ input.innerText = inputValue;
51263
51303
  interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
51264
51304
  }
51265
51305
  cancelEdition() {
@@ -51553,7 +51593,7 @@ class BottomBar extends owl.Component {
51553
51593
  this.sheetListRef.el.scrollTo({ top: 0, left: scroll, behavior: "smooth" });
51554
51594
  }
51555
51595
  onSheetMouseDown(sheetId, event) {
51556
- if (event.button !== 0)
51596
+ if (event.button !== 0 || this.env.model.getters.isReadonly())
51557
51597
  return;
51558
51598
  this.closeMenu();
51559
51599
  const visibleSheets = this.getVisibleSheets();
@@ -55058,7 +55098,7 @@ function addLineChart(chart) {
55058
55098
  }
55059
55099
  function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
55060
55100
  const colors = new ChartColors();
55061
- const maxLength = Math.max(...chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
55101
+ const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
55062
55102
  const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
55063
55103
  const dataSetsNodes = [];
55064
55104
  for (const [dsIndex, dataset] of Object.entries(chart.dataSets).reverse()) {
@@ -57012,6 +57052,6 @@ exports.setTranslationMethod = setTranslationMethod;
57012
57052
  exports.tokenize = tokenize;
57013
57053
 
57014
57054
 
57015
- __info__.version = "17.0.16";
57016
- __info__.date = "2024-03-25T09:42:01.717Z";
57017
- __info__.hash = "9b128f8";
57055
+ __info__.version = "17.0.17";
57056
+ __info__.date = "2024-04-05T13:59:37.139Z";
57057
+ __info__.hash = "33f09d7";