@odoo/o-spreadsheet 17.1.15 → 17.1.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.1.15
6
- * @date 2024-05-15T09:22:23.258Z
7
- * @hash fc959fe
5
+ * @version 17.1.17
6
+ * @date 2024-06-03T14:54:06.711Z
7
+ * @hash 7dedb2f
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -566,8 +566,9 @@
566
566
  return false;
567
567
  }
568
568
  else {
569
- if (ignoreFunctions && typeOfO1Key === "function")
570
- return true;
569
+ if (ignoreFunctions && typeOfO1Key === "function") {
570
+ continue;
571
+ }
571
572
  if (o1[key] !== o2[key])
572
573
  return false;
573
574
  }
@@ -1801,7 +1802,7 @@
1801
1802
  }
1802
1803
  valueOf() {
1803
1804
  const str = super.valueOf();
1804
- return _loaded() ? sprintf(_translate(str), ...this.values) : str;
1805
+ return _loaded() ? sprintf(_translate(str), ...this.values) : sprintf(str, ...this.values);
1805
1806
  }
1806
1807
  toString() {
1807
1808
  return this.valueOf();
@@ -2605,7 +2606,7 @@
2605
2606
  return false;
2606
2607
  }
2607
2608
  if (typeof operand === "number" && operator === "=") {
2608
- return toString(value) === toString(operand);
2609
+ return value.toString() === operand.toString();
2609
2610
  }
2610
2611
  if (operator === "<>" || operator === "=") {
2611
2612
  let result;
@@ -2665,14 +2666,13 @@
2665
2666
  if (countArg % 2 === 1) {
2666
2667
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2667
2668
  }
2668
- const dimRow = args[0].length;
2669
- const dimCol = args[0][0].length;
2669
+ const firstArg = toMatrix(args[0]);
2670
+ const dimRow = firstArg.length;
2671
+ const dimCol = firstArg[0].length;
2670
2672
  let predicates = [];
2671
2673
  for (let i = 0; i < countArg - 1; i += 2) {
2672
- const criteriaRange = args[i];
2673
- if (!isMatrix(criteriaRange) ||
2674
- criteriaRange.length !== dimRow ||
2675
- criteriaRange[0].length !== dimCol) {
2674
+ const criteriaRange = toMatrix(args[i]);
2675
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2676
2676
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2677
2677
  }
2678
2678
  const description = toString(args[i + 1]);
@@ -2682,7 +2682,7 @@
2682
2682
  for (let j = 0; j < dimCol; j++) {
2683
2683
  let validatedPredicates = true;
2684
2684
  for (let k = 0; k < countArg - 1; k += 2) {
2685
- const criteriaValue = args[k][i][j].value;
2685
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2686
2686
  const criterion = predicates[k / 2];
2687
2687
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2688
2688
  if (!validatedPredicates) {
@@ -4370,8 +4370,11 @@
4370
4370
  /**
4371
4371
  * Create a range from a xc. If the xc is empty, this function returns undefined.
4372
4372
  */
4373
- function createRange(getters, sheetId, range) {
4374
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
4373
+ function createValidRange(getters, sheetId, xc) {
4374
+ if (!xc)
4375
+ return;
4376
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
4377
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
4375
4378
  }
4376
4379
  /**
4377
4380
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5302,8 +5305,8 @@
5302
5305
  type = "scorecard";
5303
5306
  constructor(definition, sheetId, getters) {
5304
5307
  super(definition, sheetId, getters);
5305
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
5306
- this.baseline = createRange(getters, sheetId, definition.baseline);
5308
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
5309
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
5307
5310
  this.baselineMode = definition.baselineMode;
5308
5311
  this.baselineDescr = definition.baselineDescr;
5309
5312
  this.background = definition.background;
@@ -8646,7 +8649,7 @@
8646
8649
  constructor(definition, sheetId, getters) {
8647
8650
  super(definition, sheetId, getters);
8648
8651
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
8649
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
8652
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
8650
8653
  this.background = definition.background;
8651
8654
  this.verticalAxisPosition = definition.verticalAxisPosition;
8652
8655
  this.legendPosition = definition.legendPosition;
@@ -8889,7 +8892,7 @@
8889
8892
  type = "gauge";
8890
8893
  constructor(definition, sheetId, getters) {
8891
8894
  super(definition, sheetId, getters);
8892
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
8895
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
8893
8896
  this.sectionRule = definition.sectionRule;
8894
8897
  this.background = definition.background;
8895
8898
  }
@@ -9223,7 +9226,7 @@
9223
9226
  constructor(definition, sheetId, getters) {
9224
9227
  super(definition, sheetId, getters);
9225
9228
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9226
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
9229
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
9227
9230
  this.background = definition.background;
9228
9231
  this.verticalAxisPosition = definition.verticalAxisPosition;
9229
9232
  this.legendPosition = definition.legendPosition;
@@ -9543,7 +9546,7 @@
9543
9546
  constructor(definition, sheetId, getters) {
9544
9547
  super(definition, sheetId, getters);
9545
9548
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9546
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
9549
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
9547
9550
  this.background = definition.background;
9548
9551
  this.legendPosition = definition.legendPosition;
9549
9552
  this.aggregated = definition.aggregated;
@@ -11187,6 +11190,9 @@
11187
11190
  if (types.some((t) => t.startsWith("RANGE"))) {
11188
11191
  result.acceptMatrix = true;
11189
11192
  }
11193
+ if (types.every((t) => t.startsWith("RANGE"))) {
11194
+ result.acceptMatrixOnly = true;
11195
+ }
11190
11196
  return result;
11191
11197
  }
11192
11198
  /**
@@ -11468,11 +11474,16 @@
11468
11474
  compute: function (array, ...columns) {
11469
11475
  const _array = toMatrix(array);
11470
11476
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
11471
- assert(() => _columns.every((col) => col > 0 && col <= _array.length), _t("The columns arguments must be between 1 and %s (got %s).", _array.length.toString(), (_columns.find((col) => col <= 0 || col > _array.length) || 0).toString()));
11477
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
11478
+ assert(() => argOutOfRange.length === 0, _t("The columns arguments must be between -%s and %s (got %s), excluding 0.", _array.length.toString(), _array.length.toString(), argOutOfRange.join(",")));
11472
11479
  const result = Array(_columns.length);
11473
11480
  for (let col = 0; col < _columns.length; col++) {
11474
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
11475
- result[col] = _array[colIndex];
11481
+ if (_columns[col] > 0) {
11482
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
11483
+ }
11484
+ else {
11485
+ result[col] = _array[_array.length + _columns[col]];
11486
+ }
11476
11487
  }
11477
11488
  return result;
11478
11489
  },
@@ -11493,8 +11504,14 @@
11493
11504
  const _array = toMatrix(array);
11494
11505
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
11495
11506
  const _nbColumns = _array.length;
11496
- assert(() => _rows.every((row) => row > 0 && row <= _array[0].length), _t("The rows arguments must be between 1 and %s (got %s).", _array[0].length.toString(), (_rows.find((row) => row <= 0 || row > _array[0].length) || 0).toString()));
11497
- return generateMatrix(_nbColumns, _rows.length, (col, row) => _array[col][_rows[row] - 1]); // -1 because rows arguments are 1-indexed
11507
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
11508
+ assert(() => argOutOfRange.length === 0, _t("The rows arguments must be between -%s and %s (got %s), excluding 0.", _array[0].length.toString(), _array[0].length.toString(), argOutOfRange.join(",")));
11509
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
11510
+ if (_rows[row] > 0) {
11511
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
11512
+ }
11513
+ return _array[col][_array[col].length + _rows[row]];
11514
+ });
11498
11515
  },
11499
11516
  isExported: true,
11500
11517
  };
@@ -12402,7 +12419,7 @@
12402
12419
  compute: function (range, ...args) {
12403
12420
  let uniqueValues = new Set();
12404
12421
  visitMatchingRanges(args, (i, j) => {
12405
- const data = range[i][j];
12422
+ const data = range[i]?.[j];
12406
12423
  if (isDefined(data)) {
12407
12424
  uniqueValues.add(data.value);
12408
12425
  }
@@ -13032,7 +13049,7 @@
13032
13049
  }
13033
13050
  let sum = 0;
13034
13051
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
13035
- const value = sumRange[i][j].value;
13052
+ const value = sumRange[i]?.[j]?.value;
13036
13053
  if (typeof value === "number") {
13037
13054
  sum += value;
13038
13055
  }
@@ -13057,7 +13074,7 @@
13057
13074
  compute: function (sumRange, ...criters) {
13058
13075
  let sum = 0;
13059
13076
  visitMatchingRanges(criters, (i, j) => {
13060
- const value = sumRange[i][j].value;
13077
+ const value = sumRange[i]?.[j]?.value;
13061
13078
  if (typeof value === "number") {
13062
13079
  sum += value;
13063
13080
  }
@@ -13604,7 +13621,7 @@
13604
13621
  let count = 0;
13605
13622
  let sum = 0;
13606
13623
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
13607
- const value = _averageRange[i][j].value;
13624
+ const value = _averageRange[i]?.[j]?.value;
13608
13625
  if (typeof value === "number") {
13609
13626
  count += 1;
13610
13627
  sum += value;
@@ -13633,7 +13650,7 @@
13633
13650
  let count = 0;
13634
13651
  let sum = 0;
13635
13652
  visitMatchingRanges(args, (i, j) => {
13636
- const value = _averageRange[i][j].value;
13653
+ const value = _averageRange[i]?.[j]?.value;
13637
13654
  if (typeof value === "number") {
13638
13655
  count += 1;
13639
13656
  sum += value;
@@ -13938,7 +13955,7 @@
13938
13955
  compute: function (range, ...args) {
13939
13956
  let result = -Infinity;
13940
13957
  visitMatchingRanges(args, (i, j) => {
13941
- const value = range[i][j].value;
13958
+ const value = range[i]?.[j]?.value;
13942
13959
  if (typeof value === "number") {
13943
13960
  result = result < value ? value : result;
13944
13961
  }
@@ -14021,7 +14038,7 @@
14021
14038
  compute: function (range, ...args) {
14022
14039
  let result = Infinity;
14023
14040
  visitMatchingRanges(args, (i, j) => {
14024
- const value = range[i][j].value;
14041
+ const value = range[i]?.[j]?.value;
14025
14042
  if (typeof value === "number") {
14026
14043
  result = result > value ? value : result;
14027
14044
  }
@@ -19798,6 +19815,9 @@
19798
19815
  }
19799
19816
  args[i] = arg[0][0];
19800
19817
  }
19818
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
19819
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
19820
+ }
19801
19821
  }
19802
19822
  return descr.compute.apply(this, args);
19803
19823
  }
@@ -22150,7 +22170,7 @@
22150
22170
  }
22151
22171
  const getters = this.env.model.getters;
22152
22172
  const sheetId = getters.getActiveSheetId();
22153
- const labelRange = createRange(getters, sheetId, this.labelRange);
22173
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
22154
22174
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
22155
22175
  if (dataSets.length) {
22156
22176
  return dataSets[0].dataRange.zone.top + 1;
@@ -26273,14 +26293,14 @@
26273
26293
  }
26274
26294
  onKeyDown(ev) {
26275
26295
  const figure = this.props.figure;
26276
- switch (ev.key) {
26296
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
26297
+ switch (keyDownShortcut) {
26277
26298
  case "Delete":
26278
26299
  this.env.model.dispatch("DELETE_FIGURE", {
26279
26300
  sheetId: this.env.model.getters.getActiveSheetId(),
26280
26301
  id: figure.id,
26281
26302
  });
26282
26303
  this.props.onFigureDeleted();
26283
- ev.stopPropagation();
26284
26304
  ev.preventDefault();
26285
26305
  ev.stopPropagation();
26286
26306
  break;
@@ -26301,7 +26321,22 @@
26301
26321
  x: figure.x + delta[0],
26302
26322
  y: figure.y + delta[1],
26303
26323
  });
26324
+ ev.preventDefault();
26304
26325
  ev.stopPropagation();
26326
+ break;
26327
+ case "Ctrl+A":
26328
+ // Maybe in the future we will implement a way to select all figures
26329
+ ev.preventDefault();
26330
+ ev.stopPropagation();
26331
+ break;
26332
+ case "Ctrl+Y":
26333
+ case "Ctrl+Z":
26334
+ if (keyDownShortcut === "Ctrl+Y") {
26335
+ this.env.model.dispatch("REQUEST_REDO");
26336
+ }
26337
+ else if (keyDownShortcut === "Ctrl+Z") {
26338
+ this.env.model.dispatch("REQUEST_UNDO");
26339
+ }
26305
26340
  ev.preventDefault();
26306
26341
  ev.stopPropagation();
26307
26342
  break;
@@ -27176,7 +27211,7 @@
27176
27211
  "Ctrl+Enter": this.processNewLineEvent,
27177
27212
  Escape: this.processEscapeKey,
27178
27213
  F2: () => console.warn("Not implemented"),
27179
- F4: this.processF4Key,
27214
+ F4: (ev) => this.processF4Key(ev),
27180
27215
  Tab: (ev) => this.processTabKey(ev, "right"),
27181
27216
  "Shift+Tab": (ev) => this.processTabKey(ev, "left"),
27182
27217
  };
@@ -27290,9 +27325,10 @@
27290
27325
  processEscapeKey() {
27291
27326
  this.env.model.dispatch("CANCEL_EDITION");
27292
27327
  }
27293
- processF4Key() {
27328
+ processF4Key(ev) {
27294
27329
  this.env.model.dispatch("CYCLE_EDITION_REFERENCES");
27295
27330
  this.processContent();
27331
+ ev.stopPropagation();
27296
27332
  }
27297
27333
  processNumpadDecimal(ev) {
27298
27334
  ev.stopPropagation();
@@ -35761,12 +35797,6 @@
35761
35797
  // detect when an argument need to be evaluated as a meta argument
35762
35798
  const isMeta = argTypes.includes("META");
35763
35799
  const hasRange = argTypes.some((t) => isRangeType(t));
35764
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
35765
- if (isRangeOnly) {
35766
- if (!isRangeInput(currentArg)) {
35767
- throw new BadExpressionError(_t("Function %s expects the parameter %s to be reference to a cell or range, not a %s.", functionName, (i + 1).toString(), currentArg.type.toLowerCase()));
35768
- }
35769
- }
35770
35800
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange, {
35771
35801
  functionName,
35772
35802
  paramIndex: i + 1,
@@ -35937,16 +35967,6 @@
35937
35967
  function isRangeType(type) {
35938
35968
  return type.startsWith("RANGE");
35939
35969
  }
35940
- function isRangeInput(arg) {
35941
- if (arg.type === "REFERENCE") {
35942
- return true;
35943
- }
35944
- if (arg.type === "FUNCALL") {
35945
- const fnDef = functions$1[arg.value.toUpperCase()];
35946
- return fnDef && isRangeType(fnDef.returns[0]);
35947
- }
35948
- return false;
35949
- }
35950
35970
 
35951
35971
  /**
35952
35972
  * Add the following information on tokens:
@@ -38453,7 +38473,12 @@
38453
38473
  * if they have at least a common cell
38454
38474
  */
38455
38475
  doesIntersectMerge(sheetId, zone) {
38456
- return positions(zone).some(({ col, row }) => this.getMerge({ sheetId, col, row }) !== undefined);
38476
+ for (const merge of this.getMerges(sheetId)) {
38477
+ if (overlap(zone, merge)) {
38478
+ return true;
38479
+ }
38480
+ }
38481
+ return false;
38457
38482
  }
38458
38483
  /**
38459
38484
  * Returns true if two columns have at least one merge in common
@@ -39054,6 +39079,9 @@
39054
39079
  if (range.invalidXc) {
39055
39080
  return range.invalidXc;
39056
39081
  }
39082
+ if (!this.getters.tryGetSheet(range.sheetId)) {
39083
+ return CellErrorType.InvalidReference;
39084
+ }
39057
39085
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
39058
39086
  return CellErrorType.InvalidReference;
39059
39087
  }
@@ -42501,16 +42529,22 @@
42501
42529
  let newContent = undefined;
42502
42530
  let newFormat = undefined;
42503
42531
  let isExported = true;
42532
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42504
42533
  const formulaCell = this.getCorrespondingFormulaCell(position);
42505
42534
  if (formulaCell) {
42506
42535
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
42507
42536
  isFormula = isExported;
42508
42537
  if (!isExported) {
42509
- newContent = value.toString();
42510
- newFormat = evaluatedCell.format;
42538
+ // If the cell contains a non-exported formula and that is evaluates to
42539
+ // nothing* ,we don't export it.
42540
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
42541
+ // the empty string.
42542
+ if (value !== "") {
42543
+ newContent = value.toString();
42544
+ newFormat = evaluatedCell.format;
42545
+ }
42511
42546
  }
42512
42547
  }
42513
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42514
42548
  const exportedCellData = exportedSheetData.cells[xc] || {};
42515
42549
  const format = newFormat
42516
42550
  ? getItemId(newFormat, data.formats)
@@ -48812,7 +48846,7 @@
48812
48846
  case "ADD_COLUMNS_ROWS": {
48813
48847
  this.status = "invisible";
48814
48848
  // If we add a col/row inside or before the cut area, we invalidate the clipboard
48815
- if (this.state?.operation !== "CUT") {
48849
+ if (this.state?.operation !== "CUT" || cmd.sheetId !== this.state?.sheetId) {
48816
48850
  return;
48817
48851
  }
48818
48852
  const isClipboardDirty = this.state.isColRowDirtyingClipboard(cmd.position === "before" ? cmd.base : cmd.base + 1, cmd.dimension);
@@ -48824,7 +48858,7 @@
48824
48858
  case "REMOVE_COLUMNS_ROWS": {
48825
48859
  this.status = "invisible";
48826
48860
  // If we remove a col/row inside or before the cut area, we invalidate the clipboard
48827
- if (this.state?.operation !== "CUT") {
48861
+ if (this.state?.operation !== "CUT" || cmd.sheetId !== this.state?.sheetId) {
48828
48862
  return;
48829
48863
  }
48830
48864
  for (let el of cmd.elements) {
@@ -52007,9 +52041,11 @@
52007
52041
  if (ev.key === "Enter") {
52008
52042
  ev.preventDefault();
52009
52043
  this.stopEdition();
52044
+ this.env.focusableElement.focus();
52010
52045
  }
52011
52046
  if (ev.key === "Escape") {
52012
52047
  this.cancelEdition();
52048
+ this.env.focusableElement.focus();
52013
52049
  }
52014
52050
  }
52015
52051
  onClickSheetName(ev) {
@@ -53895,6 +53931,10 @@
53895
53931
  }, () => [this.env.model.getters.getActiveSheetId()]);
53896
53932
  owl.useExternalListener(window, "resize", () => this.render(true));
53897
53933
  owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
53934
+ // For some reason, the wheel event is not properly registered inside templates
53935
+ // in Chromium-based browsers based on chromium 125
53936
+ // This hack ensures the event declared in the template is properly registered/working
53937
+ owl.useExternalListener(document.body, "wheel", () => { });
53898
53938
  this.bindModelEvents();
53899
53939
  owl.onWillUpdateProps((nextProps) => {
53900
53940
  if (nextProps.model !== this.props.model) {
@@ -56700,7 +56740,11 @@
56700
56740
  let cellNode = escapeXml ``;
56701
56741
  // Either formula or static value inside the cell
56702
56742
  if (cell.isFormula) {
56703
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
56743
+ const res = addFormula(cell);
56744
+ if (!res) {
56745
+ continue;
56746
+ }
56747
+ ({ attrs: additionalAttrs, node: cellNode } = res);
56704
56748
  }
56705
56749
  else if (cell.content && isMarkdownLink(cell.content)) {
56706
56750
  const { label } = parseMarkdownLink(cell.content);
@@ -57730,9 +57774,9 @@
57730
57774
  exports.tokenize = tokenize;
57731
57775
 
57732
57776
 
57733
- __info__.version = "17.1.15";
57734
- __info__.date = "2024-05-15T09:22:23.258Z";
57735
- __info__.hash = "fc959fe";
57777
+ __info__.version = "17.1.17";
57778
+ __info__.date = "2024-06-03T14:54:06.711Z";
57779
+ __info__.hash = "7dedb2f";
57736
57780
 
57737
57781
 
57738
57782
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);