@odoo/o-spreadsheet 17.1.25 → 17.1.27

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.1.25
6
- * @date 2024-07-24T10:26:01.576Z
7
- * @hash 0edff47
5
+ * @version 17.1.27
6
+ * @date 2024-08-09T12:20:52.051Z
7
+ * @hash c626332
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -480,7 +480,7 @@
480
480
  let timeout;
481
481
  return function () {
482
482
  const context = this;
483
- const args = arguments;
483
+ const args = Array.from(arguments);
484
484
  function later() {
485
485
  timeout = null;
486
486
  if (!immediate) {
@@ -683,7 +683,7 @@
683
683
  */
684
684
  function largeMax(array) {
685
685
  let len = array.length;
686
- if (len < 100000)
686
+ if (len < 100_000)
687
687
  return Math.max(...array);
688
688
  let max = -Infinity;
689
689
  while (len--) {
@@ -697,7 +697,7 @@
697
697
  */
698
698
  function largeMin(array) {
699
699
  let len = array.length;
700
- if (len < 100000)
700
+ if (len < 100_000)
701
701
  return Math.min(...array);
702
702
  let min = +Infinity;
703
703
  while (len--) {
@@ -2614,13 +2614,16 @@
2614
2614
  }
2615
2615
  return new RegExp("^" + exp + "$", "i");
2616
2616
  }
2617
- function evaluatePredicate(value = "", criterion) {
2617
+ function evaluatePredicate(value = "", criterion, locale) {
2618
2618
  const { operator, operand } = criterion;
2619
2619
  if (operand === undefined || value === null || operand === null) {
2620
2620
  return false;
2621
2621
  }
2622
2622
  if (typeof operand === "number" && operator === "=") {
2623
- return value.toString() === operand.toString();
2623
+ if (typeof value === "string" && (isNumber(value, locale) || isDateTime(value, locale))) {
2624
+ return toNumber(value, locale) === operand;
2625
+ }
2626
+ return value === operand;
2624
2627
  }
2625
2628
  if (operator === "<>" || operator === "=") {
2626
2629
  let result;
@@ -2698,7 +2701,7 @@
2698
2701
  for (let k = 0; k < countArg - 1; k += 2) {
2699
2702
  const criteriaValue = toMatrix(args[k])[i][j].value;
2700
2703
  const criterion = predicates[k / 2];
2701
- validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2704
+ validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion, locale);
2702
2705
  if (!validatedPredicates) {
2703
2706
  break;
2704
2707
  }
@@ -5980,7 +5983,7 @@
5980
5983
  function numberCell(value, localeFormat) {
5981
5984
  return {
5982
5985
  type: CellValueType.number,
5983
- value: value || 0,
5986
+ value: value || 0, // necessary to avoid "-0" and NaN values,
5984
5987
  format: localeFormat.format,
5985
5988
  isAutoSummable: true,
5986
5989
  defaultAlign: "right",
@@ -8471,8 +8474,8 @@
8471
8474
  function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, truncateLabels = true }) {
8472
8475
  const options = {
8473
8476
  // https://www.chartjs.org/docs/latest/general/responsive.html
8474
- responsive: true,
8475
- maintainAspectRatio: false,
8477
+ responsive: true, // will resize when its container is resized
8478
+ maintainAspectRatio: false, // doesn't maintain the aspect ration (width/height =2 by default) so the user has the choice of the exact layout
8476
8479
  layout: {
8477
8480
  padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
8478
8481
  },
@@ -8518,7 +8521,7 @@
8518
8521
  labels: truncateLabels ? labels.map(truncateLabel) : labels,
8519
8522
  datasets: [],
8520
8523
  },
8521
- platform: undefined,
8524
+ platform: undefined, // This key is optional and will be set by chart.js
8522
8525
  plugins: [],
8523
8526
  };
8524
8527
  }
@@ -8782,7 +8785,7 @@
8782
8785
  },
8783
8786
  y: {
8784
8787
  position: chart.verticalAxisPosition,
8785
- beginAtZero: true,
8788
+ beginAtZero: true, // the origin of the y axis is always zero
8786
8789
  ticks: {
8787
8790
  color: fontColor,
8788
8791
  callback: (value) => {
@@ -9436,7 +9439,7 @@
9436
9439
  },
9437
9440
  y: {
9438
9441
  position: chart.verticalAxisPosition,
9439
- beginAtZero: true,
9442
+ beginAtZero: true, // the origin of the y axis is always zero
9440
9443
  ticks: {
9441
9444
  color: fontColor,
9442
9445
  callback: (value) => {
@@ -9524,7 +9527,7 @@
9524
9527
  const dataset = {
9525
9528
  label,
9526
9529
  data,
9527
- tension: 0,
9530
+ tension: 0, // 0 -> render straight lines, which is much faster
9528
9531
  borderColor: color,
9529
9532
  backgroundColor,
9530
9533
  pointBackgroundColor: color,
@@ -9635,7 +9638,7 @@
9635
9638
  ...this.getDefinition(),
9636
9639
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
9637
9640
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
9638
- verticalAxisPosition: "left",
9641
+ verticalAxisPosition: "left", //TODO ExcelChartDefinition should be adapted, but can be done later
9639
9642
  dataSets,
9640
9643
  labelRange,
9641
9644
  };
@@ -27202,7 +27205,9 @@
27202
27205
  argToFocus: 0,
27203
27206
  });
27204
27207
  compositionActive = false;
27208
+ spreadsheetRect = useSpreadsheetRect();
27205
27209
  get assistantStyle() {
27210
+ const composerRect = this.composerRef.el.getBoundingClientRect();
27206
27211
  const assistantStyle = {};
27207
27212
  assistantStyle["min-width"] = `${this.props.rect?.width || ASSISTANT_WIDTH}px`;
27208
27213
  if (this.autoCompleteState.type === "function") {
@@ -27225,6 +27230,10 @@
27225
27230
  assistantStyle.right = `0px`;
27226
27231
  }
27227
27232
  }
27233
+ if (this.props.focus === "contentFocus" &&
27234
+ composerRect.left + ASSISTANT_WIDTH > this.spreadsheetRect.width) {
27235
+ assistantStyle.right = "0px";
27236
+ }
27228
27237
  return cssPropertiesToCss(assistantStyle);
27229
27238
  }
27230
27239
  // we can't allow input events to be triggered while we remove and add back the content of the composer in processContent
@@ -30058,7 +30067,7 @@
30058
30067
  onScroll(offset) {
30059
30068
  const { scrollX } = this.env.model.getters.getActiveSheetDOMScrollInfo();
30060
30069
  this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
30061
- offsetX: scrollX,
30070
+ offsetX: scrollX, // offsetX is the same
30062
30071
  offsetY: offset,
30063
30072
  });
30064
30073
  }
@@ -30271,8 +30280,8 @@
30271
30280
  "Ctrl+Shift+L": () => this.setHorizontalAlign("left"),
30272
30281
  "Ctrl+Shift+R": () => this.setHorizontalAlign("right"),
30273
30282
  "Ctrl+Shift+V": () => PASTE_AS_VALUE_ACTION(this.env),
30274
- "Ctrl+Shift+<": () => this.clearFormatting(),
30275
- "Ctrl+<": () => this.clearFormatting(),
30283
+ "Ctrl+Shift+<": () => this.clearFormatting(), // for qwerty
30284
+ "Ctrl+<": () => this.clearFormatting(), // for azerty
30276
30285
  "Ctrl+Shift+ ": () => {
30277
30286
  this.env.model.selection.selectAll();
30278
30287
  },
@@ -31070,10 +31079,10 @@
31070
31079
  const CF_TYPE_CONVERSION_MAP = {
31071
31080
  aboveAverage: undefined,
31072
31081
  expression: undefined,
31073
- cellIs: undefined,
31074
- colorScale: undefined,
31082
+ cellIs: undefined, // exist but isn't an operator in o_spreadsheet
31083
+ colorScale: undefined, // exist but isn't an operator in o_spreadsheet
31075
31084
  dataBar: undefined,
31076
- iconSet: undefined,
31085
+ iconSet: undefined, // exist but isn't an operator in o_spreadsheet
31077
31086
  top10: undefined,
31078
31087
  uniqueValues: undefined,
31079
31088
  duplicateValues: undefined,
@@ -31308,7 +31317,7 @@
31308
31317
  61: "993366",
31309
31318
  62: "333399",
31310
31319
  63: "333333",
31311
- 64: "000000",
31320
+ 64: "000000", // system foreground
31312
31321
  65: "FFFFFF", // system background
31313
31322
  };
31314
31323
  const IMAGE_MIMETYPE_TO_EXTENSION_MAPPING = {
@@ -34978,12 +34987,13 @@
34978
34987
  this.clearBorders(cmd.sheetId, cmd.target);
34979
34988
  break;
34980
34989
  case "REMOVE_COLUMNS_ROWS":
34981
- for (let el of [...cmd.elements].sort((a, b) => b - a)) {
34990
+ const elements = [...cmd.elements].sort((a, b) => b - a);
34991
+ for (const group of groupConsecutive(elements)) {
34982
34992
  if (cmd.dimension === "COL") {
34983
- this.shiftBordersHorizontally(cmd.sheetId, el + 1, -1);
34993
+ this.shiftBordersHorizontally(cmd.sheetId, group[group.length - 1] + 1, -group.length);
34984
34994
  }
34985
34995
  else {
34986
- this.shiftBordersVertically(cmd.sheetId, el + 1, -1);
34996
+ this.shiftBordersVertically(cmd.sheetId, group[group.length - 1] + 1, -group.length);
34987
34997
  }
34988
34998
  }
34989
34999
  break;
@@ -39115,7 +39125,7 @@
39115
39125
  * @param sheetXC the string description of a range, in the form SheetName!XC:XC
39116
39126
  */
39117
39127
  getRangeFromSheetXC(defaultSheetId, sheetXC) {
39118
- if (!rangeReference.test(sheetXC)) {
39128
+ if (!rangeReference.test(sheetXC) || !this.getters.tryGetSheet(defaultSheetId)) {
39119
39129
  return new RangeImpl({
39120
39130
  sheetId: "",
39121
39131
  zone: { left: -1, top: -1, right: -1, bottom: -1 },
@@ -40015,12 +40025,7 @@
40015
40025
  });
40016
40026
  }
40017
40027
  if (colIndex > deletedColumn) {
40018
- this.dispatch("UPDATE_CELL_POSITION", {
40019
- sheetId: sheet.id,
40020
- cellId: cellId,
40021
- col: colIndex - 1,
40022
- row: rowIndex,
40023
- });
40028
+ this.setNewPosition(cellId, sheet.id, colIndex - 1, rowIndex);
40024
40029
  }
40025
40030
  }
40026
40031
  }
@@ -40030,7 +40035,7 @@
40030
40035
  * Move the cells after a column or rows insertion
40031
40036
  */
40032
40037
  moveCellsOnAddition(sheet, addedElement, quantity, dimension) {
40033
- const commands = [];
40038
+ const updates = [];
40034
40039
  for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
40035
40040
  const row = sheet.rows[rowIndex];
40036
40041
  if (dimension !== "rows" || rowIndex >= addedElement) {
@@ -40039,20 +40044,20 @@
40039
40044
  const cellId = row.cells[i];
40040
40045
  if (cellId) {
40041
40046
  if (dimension === "rows" || colIndex >= addedElement) {
40042
- commands.push({
40043
- type: "UPDATE_CELL_POSITION",
40047
+ updates.push({
40044
40048
  sheetId: sheet.id,
40045
40049
  cellId: cellId,
40046
40050
  col: colIndex + (dimension === "columns" ? quantity : 0),
40047
40051
  row: rowIndex + (dimension === "rows" ? quantity : 0),
40052
+ type: "UPDATE_CELL_POSITION",
40048
40053
  });
40049
40054
  }
40050
40055
  }
40051
40056
  }
40052
40057
  }
40053
40058
  }
40054
- for (let cmd of commands.reverse()) {
40055
- this.dispatch(cmd.type, cmd);
40059
+ for (let update of updates.reverse()) {
40060
+ this.updateCellPosition(update);
40056
40061
  }
40057
40062
  }
40058
40063
  /**
@@ -40085,12 +40090,7 @@
40085
40090
  const colIndex = Number(i);
40086
40091
  const cellId = row.cells[i];
40087
40092
  if (cellId) {
40088
- this.dispatch("UPDATE_CELL_POSITION", {
40089
- sheetId: sheet.id,
40090
- cellId: cellId,
40091
- col: colIndex,
40092
- row: rowIndex - numberRows,
40093
- });
40093
+ this.setNewPosition(cellId, sheet.id, colIndex, rowIndex - numberRows);
40094
40094
  }
40095
40095
  }
40096
40096
  }
@@ -42059,18 +42059,30 @@
42059
42059
  this.evaluate(this.getAllCells());
42060
42060
  }
42061
42061
  evaluateFormula(sheetId, formulaString) {
42062
- const compiledFormula = compile(formulaString);
42063
- const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
42064
- this.updateCompilationParameters();
42065
- const result = updateEvalContextAndExecute({ ...compiledFormula, dependencies: ranges }, this.compilationParams, sheetId);
42062
+ const result = this.evaluateFormulaResult(sheetId, formulaString);
42066
42063
  if (isMatrix(result)) {
42067
42064
  return matrixMap(result, (cell) => cell.value);
42068
42065
  }
42069
- if (result.value === null) {
42070
- return 0;
42071
- }
42072
42066
  return result.value;
42073
42067
  }
42068
+ evaluateFormulaResult(sheetId, formulaString) {
42069
+ try {
42070
+ const compiledFormula = compile(formulaString);
42071
+ const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
42072
+ this.updateCompilationParameters();
42073
+ const result = updateEvalContextAndExecute({ ...compiledFormula, dependencies: ranges }, this.compilationParams, sheetId);
42074
+ if (isMatrix(result)) {
42075
+ return result;
42076
+ }
42077
+ if (result.value === null) {
42078
+ return { value: 0, format: result.format };
42079
+ }
42080
+ return result;
42081
+ }
42082
+ catch (error) {
42083
+ return handleError(error, "");
42084
+ }
42085
+ }
42074
42086
  getAllCells() {
42075
42087
  const positionIds = new JetSet();
42076
42088
  for (const sheetId of this.getters.getSheetIds()) {
@@ -42495,6 +42507,7 @@
42495
42507
  class EvaluationPlugin extends UIPlugin {
42496
42508
  static getters = [
42497
42509
  "evaluateFormula",
42510
+ "evaluateFormulaResult",
42498
42511
  "getCorrespondingFormulaCell",
42499
42512
  "getRangeFormattedValues",
42500
42513
  "getRangeValues",
@@ -42553,12 +42566,14 @@
42553
42566
  // Getters
42554
42567
  // ---------------------------------------------------------------------------
42555
42568
  evaluateFormula(sheetId, formulaString) {
42556
- try {
42557
- return this.evaluator.evaluateFormula(sheetId, formulaString);
42558
- }
42559
- catch (error) {
42560
- return error.value || CellErrorType.GenericError;
42569
+ const result = this.evaluateFormulaResult(sheetId, formulaString);
42570
+ if (isMatrix(result)) {
42571
+ return matrixMap(result, (cell) => cell.value);
42561
42572
  }
42573
+ return result.value;
42574
+ }
42575
+ evaluateFormulaResult(sheetId, formulaString) {
42576
+ return this.evaluator.evaluateFormulaResult(sheetId, formulaString);
42562
42577
  }
42563
42578
  /**
42564
42579
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -42699,17 +42714,17 @@
42699
42714
  */
42700
42715
  function sortWithClusters(colorsToSort) {
42701
42716
  const clusters = [
42702
- { leadColor: rgba(255, 0, 0), colors: [] },
42703
- { leadColor: rgba(255, 128, 0), colors: [] },
42704
- { leadColor: rgba(128, 128, 0), colors: [] },
42705
- { leadColor: rgba(128, 255, 0), colors: [] },
42706
- { leadColor: rgba(0, 255, 0), colors: [] },
42707
- { leadColor: rgba(0, 255, 128), colors: [] },
42708
- { leadColor: rgba(0, 255, 255), colors: [] },
42709
- { leadColor: rgba(0, 127, 255), colors: [] },
42710
- { leadColor: rgba(0, 0, 255), colors: [] },
42711
- { leadColor: rgba(127, 0, 255), colors: [] },
42712
- { leadColor: rgba(128, 0, 128), colors: [] },
42717
+ { leadColor: rgba(255, 0, 0), colors: [] }, // red
42718
+ { leadColor: rgba(255, 128, 0), colors: [] }, // orange
42719
+ { leadColor: rgba(128, 128, 0), colors: [] }, // yellow
42720
+ { leadColor: rgba(128, 255, 0), colors: [] }, // chartreuse
42721
+ { leadColor: rgba(0, 255, 0), colors: [] }, // green
42722
+ { leadColor: rgba(0, 255, 128), colors: [] }, // spring green
42723
+ { leadColor: rgba(0, 255, 255), colors: [] }, // cyan
42724
+ { leadColor: rgba(0, 127, 255), colors: [] }, // azure
42725
+ { leadColor: rgba(0, 0, 255), colors: [] }, // blue
42726
+ { leadColor: rgba(127, 0, 255), colors: [] }, // violet
42727
+ { leadColor: rgba(128, 0, 128), colors: [] }, // magenta
42713
42728
  { leadColor: rgba(255, 0, 128), colors: [] }, // rose
42714
42729
  ];
42715
42730
  for (const color of colorsToSort.map(colorToRGBA)) {
@@ -46433,6 +46448,7 @@
46433
46448
  * evaluated and updated with the number type.
46434
46449
  */
46435
46450
  setDecimal(sheetId, zones, step) {
46451
+ const positionsByFormat = {};
46436
46452
  // Find the each cell with a number value and get the format
46437
46453
  for (const zone of zones) {
46438
46454
  for (const position of positions(zone)) {
@@ -46442,15 +46458,20 @@
46442
46458
  // of the format
46443
46459
  this.getters.getLocale();
46444
46460
  const newFormat = changeDecimalPlaces(numberFormat, step);
46445
- // Apply the new format on the whole zone
46446
- this.dispatch("SET_FORMATTING", {
46447
- sheetId,
46448
- target: [positionToZone(position)],
46449
- format: newFormat,
46450
- });
46461
+ positionsByFormat[newFormat] = positionsByFormat[newFormat] || [];
46462
+ positionsByFormat[newFormat].push(position);
46451
46463
  }
46452
46464
  }
46453
46465
  }
46466
+ // consolidate all positions with the same format in bigger zones
46467
+ for (const newFormat in positionsByFormat) {
46468
+ const zones = futureRecomputeZones(positionsByFormat[newFormat].map((position) => positionToZone(position)));
46469
+ this.dispatch("SET_FORMATTING", {
46470
+ sheetId,
46471
+ format: newFormat,
46472
+ target: zones,
46473
+ });
46474
+ }
46454
46475
  }
46455
46476
  /**
46456
46477
  * Take a range of cells and return the format of the first cell containing a
@@ -52496,7 +52517,7 @@
52496
52517
  .map((sheetEl) => sheetEl.getBoundingClientRect())
52497
52518
  .map((rect) => ({
52498
52519
  x: rect.x,
52499
- width: rect.width - 1,
52520
+ width: rect.width - 1, // -1 to compensate negative margin
52500
52521
  y: rect.y,
52501
52522
  height: rect.height,
52502
52523
  }));
@@ -52718,7 +52739,7 @@
52718
52739
  }
52719
52740
  return cssPropertiesToCss({
52720
52741
  top: `${groupBox.headerRect.height / 2}px`,
52721
- left: `calc(50% - 1px)`,
52742
+ left: `calc(50% - 1px)`, // -1px: we want the border to be on the center
52722
52743
  width: `30%`,
52723
52744
  height: `calc(100% - ${groupBox.headerRect.height / 2}px)`,
52724
52745
  "border-left": `1px solid ${HEADER_GROUPING_BORDER_COLOR}`,
@@ -52770,7 +52791,7 @@
52770
52791
  return "";
52771
52792
  }
52772
52793
  return cssPropertiesToCss({
52773
- top: `calc(50% - 1px)`,
52794
+ top: `calc(50% - 1px)`, // -1px: we want the border to be on the center
52774
52795
  left: `${groupBox.headerRect.width / 2}px`,
52775
52796
  width: `calc(100% - ${groupBox.headerRect.width / 2}px)`,
52776
52797
  height: `30%`,
@@ -54181,7 +54202,7 @@
54181
54202
  const gridColSize = GROUP_LAYER_WIDTH * this.rowLayers.length;
54182
54203
  const gridRowSize = GROUP_LAYER_WIDTH * this.colLayers.length;
54183
54204
  return cssPropertiesToCss({
54184
- "grid-template-columns": `${gridColSize ? gridColSize + 2 : 0}px auto`,
54205
+ "grid-template-columns": `${gridColSize ? gridColSize + 2 : 0}px auto`, // +2: margins
54185
54206
  "grid-template-rows": `${gridRowSize ? gridRowSize + 2 : 0}px auto`,
54186
54207
  });
54187
54208
  }
@@ -55626,7 +55647,7 @@
55626
55647
  }
55627
55648
 
55628
55649
  class StateObserver {
55629
- changes = [];
55650
+ changes;
55630
55651
  commands = [];
55631
55652
  /**
55632
55653
  * Record the changes which could happen in the given callback, save them in a
@@ -55658,7 +55679,7 @@
55658
55679
  if (value[key] === val) {
55659
55680
  return;
55660
55681
  }
55661
- this.changes.push({
55682
+ this.changes?.push({
55662
55683
  path: args,
55663
55684
  before: value[key],
55664
55685
  after: val,
@@ -56789,7 +56810,7 @@
56789
56810
  const colHeaderXc = toXC(tableZone.left + i, tableZone.top);
56790
56811
  const colName = sheetData.cells[colHeaderXc]?.content || `col${i}`;
56791
56812
  const colAttributes = [
56792
- ["id", i + 1],
56813
+ ["id", i + 1], // id cannot be 0
56793
56814
  ["name", colName],
56794
56815
  ];
56795
56816
  columns.push(escapeXml /*xml*/ `<tableColumn ${formatAttributes(colAttributes)}/>`);
@@ -57881,9 +57902,9 @@
57881
57902
  exports.tokenize = tokenize;
57882
57903
 
57883
57904
 
57884
- __info__.version = "17.1.25";
57885
- __info__.date = "2024-07-24T10:26:01.576Z";
57886
- __info__.hash = "0edff47";
57905
+ __info__.version = "17.1.27";
57906
+ __info__.date = "2024-08-09T12:20:52.051Z";
57907
+ __info__.hash = "c626332";
57887
57908
 
57888
57909
 
57889
57910
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);