@odoo/o-spreadsheet 17.1.16 → 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.16
6
- * @date 2024-05-24T11:27:23.083Z
7
- * @hash 3a41c3a
5
+ * @version 17.1.17
6
+ * @date 2024-06-03T14:54:06.711Z
7
+ * @hash 7dedb2f
8
8
  */
9
9
 
10
10
  'use strict';
@@ -2607,7 +2607,7 @@ function evaluatePredicate(value, criterion) {
2607
2607
  return false;
2608
2608
  }
2609
2609
  if (typeof operand === "number" && operator === "=") {
2610
- return toString(value) === toString(operand);
2610
+ return value.toString() === operand.toString();
2611
2611
  }
2612
2612
  if (operator === "<>" || operator === "=") {
2613
2613
  let result;
@@ -2667,14 +2667,13 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2667
2667
  if (countArg % 2 === 1) {
2668
2668
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2669
2669
  }
2670
- const dimRow = args[0].length;
2671
- const dimCol = args[0][0].length;
2670
+ const firstArg = toMatrix(args[0]);
2671
+ const dimRow = firstArg.length;
2672
+ const dimCol = firstArg[0].length;
2672
2673
  let predicates = [];
2673
2674
  for (let i = 0; i < countArg - 1; i += 2) {
2674
- const criteriaRange = args[i];
2675
- if (!isMatrix(criteriaRange) ||
2676
- criteriaRange.length !== dimRow ||
2677
- criteriaRange[0].length !== dimCol) {
2675
+ const criteriaRange = toMatrix(args[i]);
2676
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2678
2677
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2679
2678
  }
2680
2679
  const description = toString(args[i + 1]);
@@ -2684,7 +2683,7 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2684
2683
  for (let j = 0; j < dimCol; j++) {
2685
2684
  let validatedPredicates = true;
2686
2685
  for (let k = 0; k < countArg - 1; k += 2) {
2687
- const criteriaValue = args[k][i][j].value;
2686
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2688
2687
  const criterion = predicates[k / 2];
2689
2688
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2690
2689
  if (!validatedPredicates) {
@@ -4372,8 +4371,11 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
4372
4371
  /**
4373
4372
  * Create a range from a xc. If the xc is empty, this function returns undefined.
4374
4373
  */
4375
- function createRange(getters, sheetId, range) {
4376
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
4374
+ function createValidRange(getters, sheetId, xc) {
4375
+ if (!xc)
4376
+ return;
4377
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
4378
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
4377
4379
  }
4378
4380
  /**
4379
4381
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5304,8 +5306,8 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
5304
5306
  type = "scorecard";
5305
5307
  constructor(definition, sheetId, getters) {
5306
5308
  super(definition, sheetId, getters);
5307
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
5308
- this.baseline = createRange(getters, sheetId, definition.baseline);
5309
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
5310
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
5309
5311
  this.baselineMode = definition.baselineMode;
5310
5312
  this.baselineDescr = definition.baselineDescr;
5311
5313
  this.background = definition.background;
@@ -8648,7 +8650,7 @@ class BarChart extends AbstractChart {
8648
8650
  constructor(definition, sheetId, getters) {
8649
8651
  super(definition, sheetId, getters);
8650
8652
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
8651
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
8653
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
8652
8654
  this.background = definition.background;
8653
8655
  this.verticalAxisPosition = definition.verticalAxisPosition;
8654
8656
  this.legendPosition = definition.legendPosition;
@@ -8891,7 +8893,7 @@ class GaugeChart extends AbstractChart {
8891
8893
  type = "gauge";
8892
8894
  constructor(definition, sheetId, getters) {
8893
8895
  super(definition, sheetId, getters);
8894
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
8896
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
8895
8897
  this.sectionRule = definition.sectionRule;
8896
8898
  this.background = definition.background;
8897
8899
  }
@@ -9225,7 +9227,7 @@ class LineChart extends AbstractChart {
9225
9227
  constructor(definition, sheetId, getters) {
9226
9228
  super(definition, sheetId, getters);
9227
9229
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9228
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
9230
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
9229
9231
  this.background = definition.background;
9230
9232
  this.verticalAxisPosition = definition.verticalAxisPosition;
9231
9233
  this.legendPosition = definition.legendPosition;
@@ -9545,7 +9547,7 @@ class PieChart extends AbstractChart {
9545
9547
  constructor(definition, sheetId, getters) {
9546
9548
  super(definition, sheetId, getters);
9547
9549
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9548
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
9550
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
9549
9551
  this.background = definition.background;
9550
9552
  this.legendPosition = definition.legendPosition;
9551
9553
  this.aggregated = definition.aggregated;
@@ -11189,6 +11191,9 @@ function makeArg(str, description) {
11189
11191
  if (types.some((t) => t.startsWith("RANGE"))) {
11190
11192
  result.acceptMatrix = true;
11191
11193
  }
11194
+ if (types.every((t) => t.startsWith("RANGE"))) {
11195
+ result.acceptMatrixOnly = true;
11196
+ }
11192
11197
  return result;
11193
11198
  }
11194
11199
  /**
@@ -11470,11 +11475,16 @@ const CHOOSECOLS = {
11470
11475
  compute: function (array, ...columns) {
11471
11476
  const _array = toMatrix(array);
11472
11477
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
11473
- 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()));
11478
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
11479
+ 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(",")));
11474
11480
  const result = Array(_columns.length);
11475
11481
  for (let col = 0; col < _columns.length; col++) {
11476
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
11477
- result[col] = _array[colIndex];
11482
+ if (_columns[col] > 0) {
11483
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
11484
+ }
11485
+ else {
11486
+ result[col] = _array[_array.length + _columns[col]];
11487
+ }
11478
11488
  }
11479
11489
  return result;
11480
11490
  },
@@ -11495,8 +11505,14 @@ const CHOOSEROWS = {
11495
11505
  const _array = toMatrix(array);
11496
11506
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
11497
11507
  const _nbColumns = _array.length;
11498
- 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()));
11499
- return generateMatrix(_nbColumns, _rows.length, (col, row) => _array[col][_rows[row] - 1]); // -1 because rows arguments are 1-indexed
11508
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
11509
+ 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(",")));
11510
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
11511
+ if (_rows[row] > 0) {
11512
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
11513
+ }
11514
+ return _array[col][_array[col].length + _rows[row]];
11515
+ });
11500
11516
  },
11501
11517
  isExported: true,
11502
11518
  };
@@ -12404,7 +12420,7 @@ const COUNTUNIQUEIFS = {
12404
12420
  compute: function (range, ...args) {
12405
12421
  let uniqueValues = new Set();
12406
12422
  visitMatchingRanges(args, (i, j) => {
12407
- const data = range[i][j];
12423
+ const data = range[i]?.[j];
12408
12424
  if (isDefined(data)) {
12409
12425
  uniqueValues.add(data.value);
12410
12426
  }
@@ -13034,7 +13050,7 @@ const SUMIF = {
13034
13050
  }
13035
13051
  let sum = 0;
13036
13052
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
13037
- const value = sumRange[i][j].value;
13053
+ const value = sumRange[i]?.[j]?.value;
13038
13054
  if (typeof value === "number") {
13039
13055
  sum += value;
13040
13056
  }
@@ -13059,7 +13075,7 @@ const SUMIFS = {
13059
13075
  compute: function (sumRange, ...criters) {
13060
13076
  let sum = 0;
13061
13077
  visitMatchingRanges(criters, (i, j) => {
13062
- const value = sumRange[i][j].value;
13078
+ const value = sumRange[i]?.[j]?.value;
13063
13079
  if (typeof value === "number") {
13064
13080
  sum += value;
13065
13081
  }
@@ -13606,7 +13622,7 @@ const AVERAGEIF = {
13606
13622
  let count = 0;
13607
13623
  let sum = 0;
13608
13624
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
13609
- const value = _averageRange[i][j].value;
13625
+ const value = _averageRange[i]?.[j]?.value;
13610
13626
  if (typeof value === "number") {
13611
13627
  count += 1;
13612
13628
  sum += value;
@@ -13635,7 +13651,7 @@ const AVERAGEIFS = {
13635
13651
  let count = 0;
13636
13652
  let sum = 0;
13637
13653
  visitMatchingRanges(args, (i, j) => {
13638
- const value = _averageRange[i][j].value;
13654
+ const value = _averageRange[i]?.[j]?.value;
13639
13655
  if (typeof value === "number") {
13640
13656
  count += 1;
13641
13657
  sum += value;
@@ -13940,7 +13956,7 @@ const MAXIFS = {
13940
13956
  compute: function (range, ...args) {
13941
13957
  let result = -Infinity;
13942
13958
  visitMatchingRanges(args, (i, j) => {
13943
- const value = range[i][j].value;
13959
+ const value = range[i]?.[j]?.value;
13944
13960
  if (typeof value === "number") {
13945
13961
  result = result < value ? value : result;
13946
13962
  }
@@ -14023,7 +14039,7 @@ const MINIFS = {
14023
14039
  compute: function (range, ...args) {
14024
14040
  let result = Infinity;
14025
14041
  visitMatchingRanges(args, (i, j) => {
14026
- const value = range[i][j].value;
14042
+ const value = range[i]?.[j]?.value;
14027
14043
  if (typeof value === "number") {
14028
14044
  result = result > value ? value : result;
14029
14045
  }
@@ -19800,6 +19816,9 @@ function addInputHandling(descr) {
19800
19816
  }
19801
19817
  args[i] = arg[0][0];
19802
19818
  }
19819
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
19820
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
19821
+ }
19803
19822
  }
19804
19823
  return descr.compute.apply(this, args);
19805
19824
  }
@@ -22152,7 +22171,7 @@ class LineBarPieConfigPanel extends owl.Component {
22152
22171
  }
22153
22172
  const getters = this.env.model.getters;
22154
22173
  const sheetId = getters.getActiveSheetId();
22155
- const labelRange = createRange(getters, sheetId, this.labelRange);
22174
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
22156
22175
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
22157
22176
  if (dataSets.length) {
22158
22177
  return dataSets[0].dataRange.zone.top + 1;
@@ -26275,14 +26294,14 @@ class FigureComponent extends owl.Component {
26275
26294
  }
26276
26295
  onKeyDown(ev) {
26277
26296
  const figure = this.props.figure;
26278
- switch (ev.key) {
26297
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
26298
+ switch (keyDownShortcut) {
26279
26299
  case "Delete":
26280
26300
  this.env.model.dispatch("DELETE_FIGURE", {
26281
26301
  sheetId: this.env.model.getters.getActiveSheetId(),
26282
26302
  id: figure.id,
26283
26303
  });
26284
26304
  this.props.onFigureDeleted();
26285
- ev.stopPropagation();
26286
26305
  ev.preventDefault();
26287
26306
  ev.stopPropagation();
26288
26307
  break;
@@ -26303,7 +26322,22 @@ class FigureComponent extends owl.Component {
26303
26322
  x: figure.x + delta[0],
26304
26323
  y: figure.y + delta[1],
26305
26324
  });
26325
+ ev.preventDefault();
26326
+ ev.stopPropagation();
26327
+ break;
26328
+ case "Ctrl+A":
26329
+ // Maybe in the future we will implement a way to select all figures
26330
+ ev.preventDefault();
26306
26331
  ev.stopPropagation();
26332
+ break;
26333
+ case "Ctrl+Y":
26334
+ case "Ctrl+Z":
26335
+ if (keyDownShortcut === "Ctrl+Y") {
26336
+ this.env.model.dispatch("REQUEST_REDO");
26337
+ }
26338
+ else if (keyDownShortcut === "Ctrl+Z") {
26339
+ this.env.model.dispatch("REQUEST_UNDO");
26340
+ }
26307
26341
  ev.preventDefault();
26308
26342
  ev.stopPropagation();
26309
26343
  break;
@@ -35764,12 +35798,6 @@ function compileTokens(tokens) {
35764
35798
  // detect when an argument need to be evaluated as a meta argument
35765
35799
  const isMeta = argTypes.includes("META");
35766
35800
  const hasRange = argTypes.some((t) => isRangeType(t));
35767
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
35768
- if (isRangeOnly) {
35769
- if (!isRangeInput(currentArg)) {
35770
- 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()));
35771
- }
35772
- }
35773
35801
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange, {
35774
35802
  functionName,
35775
35803
  paramIndex: i + 1,
@@ -35940,16 +35968,6 @@ function assertEnoughArgs(ast) {
35940
35968
  function isRangeType(type) {
35941
35969
  return type.startsWith("RANGE");
35942
35970
  }
35943
- function isRangeInput(arg) {
35944
- if (arg.type === "REFERENCE") {
35945
- return true;
35946
- }
35947
- if (arg.type === "FUNCALL") {
35948
- const fnDef = functions$1[arg.value.toUpperCase()];
35949
- return fnDef && isRangeType(fnDef.returns[0]);
35950
- }
35951
- return false;
35952
- }
35953
35971
 
35954
35972
  /**
35955
35973
  * Add the following information on tokens:
@@ -39062,6 +39080,9 @@ class RangeAdapter {
39062
39080
  if (range.invalidXc) {
39063
39081
  return range.invalidXc;
39064
39082
  }
39083
+ if (!this.getters.tryGetSheet(range.sheetId)) {
39084
+ return CellErrorType.InvalidReference;
39085
+ }
39065
39086
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
39066
39087
  return CellErrorType.InvalidReference;
39067
39088
  }
@@ -42509,16 +42530,22 @@ class EvaluationPlugin extends UIPlugin {
42509
42530
  let newContent = undefined;
42510
42531
  let newFormat = undefined;
42511
42532
  let isExported = true;
42533
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42512
42534
  const formulaCell = this.getCorrespondingFormulaCell(position);
42513
42535
  if (formulaCell) {
42514
42536
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
42515
42537
  isFormula = isExported;
42516
42538
  if (!isExported) {
42517
- newContent = value.toString();
42518
- newFormat = evaluatedCell.format;
42539
+ // If the cell contains a non-exported formula and that is evaluates to
42540
+ // nothing* ,we don't export it.
42541
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
42542
+ // the empty string.
42543
+ if (value !== "") {
42544
+ newContent = value.toString();
42545
+ newFormat = evaluatedCell.format;
42546
+ }
42519
42547
  }
42520
42548
  }
42521
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42522
42549
  const exportedCellData = exportedSheetData.cells[xc] || {};
42523
42550
  const format = newFormat
42524
42551
  ? getItemId(newFormat, data.formats)
@@ -52015,9 +52042,11 @@ class BottomBarSheet extends owl.Component {
52015
52042
  if (ev.key === "Enter") {
52016
52043
  ev.preventDefault();
52017
52044
  this.stopEdition();
52045
+ this.env.focusableElement.focus();
52018
52046
  }
52019
52047
  if (ev.key === "Escape") {
52020
52048
  this.cancelEdition();
52049
+ this.env.focusableElement.focus();
52021
52050
  }
52022
52051
  }
52023
52052
  onClickSheetName(ev) {
@@ -56712,7 +56741,11 @@ function addRows(construct, data, sheet) {
56712
56741
  let cellNode = escapeXml ``;
56713
56742
  // Either formula or static value inside the cell
56714
56743
  if (cell.isFormula) {
56715
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
56744
+ const res = addFormula(cell);
56745
+ if (!res) {
56746
+ continue;
56747
+ }
56748
+ ({ attrs: additionalAttrs, node: cellNode } = res);
56716
56749
  }
56717
56750
  else if (cell.content && isMarkdownLink(cell.content)) {
56718
56751
  const { label } = parseMarkdownLink(cell.content);
@@ -57742,6 +57775,6 @@ exports.setTranslationMethod = setTranslationMethod;
57742
57775
  exports.tokenize = tokenize;
57743
57776
 
57744
57777
 
57745
- __info__.version = "17.1.16";
57746
- __info__.date = "2024-05-24T11:27:23.083Z";
57747
- __info__.hash = "3a41c3a";
57778
+ __info__.version = "17.1.17";
57779
+ __info__.date = "2024-06-03T14:54:06.711Z";
57780
+ __info__.hash = "7dedb2f";
@@ -5200,6 +5200,7 @@ type Getters = {
5200
5200
  type ArgType = "ANY" | "BOOLEAN" | "NUMBER" | "STRING" | "DATE" | "RANGE" | "RANGE<BOOLEAN>" | "RANGE<NUMBER>" | "RANGE<DATE>" | "RANGE<STRING>" | "RANGE<ANY>" | "META";
5201
5201
  interface ArgDefinition {
5202
5202
  acceptMatrix?: boolean;
5203
+ acceptMatrixOnly?: boolean;
5203
5204
  repeating?: boolean;
5204
5205
  optional?: boolean;
5205
5206
  description: string;