@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
  import { Component, useRef, onMounted, onWillUnmount, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -2605,7 +2605,7 @@ function evaluatePredicate(value, criterion) {
2605
2605
  return false;
2606
2606
  }
2607
2607
  if (typeof operand === "number" && operator === "=") {
2608
- return toString(value) === toString(operand);
2608
+ return value.toString() === operand.toString();
2609
2609
  }
2610
2610
  if (operator === "<>" || operator === "=") {
2611
2611
  let result;
@@ -2665,14 +2665,13 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2665
2665
  if (countArg % 2 === 1) {
2666
2666
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2667
2667
  }
2668
- const dimRow = args[0].length;
2669
- const dimCol = args[0][0].length;
2668
+ const firstArg = toMatrix(args[0]);
2669
+ const dimRow = firstArg.length;
2670
+ const dimCol = firstArg[0].length;
2670
2671
  let predicates = [];
2671
2672
  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) {
2673
+ const criteriaRange = toMatrix(args[i]);
2674
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2676
2675
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2677
2676
  }
2678
2677
  const description = toString(args[i + 1]);
@@ -2682,7 +2681,7 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2682
2681
  for (let j = 0; j < dimCol; j++) {
2683
2682
  let validatedPredicates = true;
2684
2683
  for (let k = 0; k < countArg - 1; k += 2) {
2685
- const criteriaValue = args[k][i][j].value;
2684
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2686
2685
  const criterion = predicates[k / 2];
2687
2686
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2688
2687
  if (!validatedPredicates) {
@@ -4370,8 +4369,11 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
4370
4369
  /**
4371
4370
  * Create a range from a xc. If the xc is empty, this function returns undefined.
4372
4371
  */
4373
- function createRange(getters, sheetId, range) {
4374
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
4372
+ function createValidRange(getters, sheetId, xc) {
4373
+ if (!xc)
4374
+ return;
4375
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
4376
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
4375
4377
  }
4376
4378
  /**
4377
4379
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5302,8 +5304,8 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
5302
5304
  type = "scorecard";
5303
5305
  constructor(definition, sheetId, getters) {
5304
5306
  super(definition, sheetId, getters);
5305
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
5306
- this.baseline = createRange(getters, sheetId, definition.baseline);
5307
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
5308
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
5307
5309
  this.baselineMode = definition.baselineMode;
5308
5310
  this.baselineDescr = definition.baselineDescr;
5309
5311
  this.background = definition.background;
@@ -8646,7 +8648,7 @@ class BarChart extends AbstractChart {
8646
8648
  constructor(definition, sheetId, getters) {
8647
8649
  super(definition, sheetId, getters);
8648
8650
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
8649
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
8651
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
8650
8652
  this.background = definition.background;
8651
8653
  this.verticalAxisPosition = definition.verticalAxisPosition;
8652
8654
  this.legendPosition = definition.legendPosition;
@@ -8889,7 +8891,7 @@ class GaugeChart extends AbstractChart {
8889
8891
  type = "gauge";
8890
8892
  constructor(definition, sheetId, getters) {
8891
8893
  super(definition, sheetId, getters);
8892
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
8894
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
8893
8895
  this.sectionRule = definition.sectionRule;
8894
8896
  this.background = definition.background;
8895
8897
  }
@@ -9223,7 +9225,7 @@ class LineChart extends AbstractChart {
9223
9225
  constructor(definition, sheetId, getters) {
9224
9226
  super(definition, sheetId, getters);
9225
9227
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9226
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
9228
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
9227
9229
  this.background = definition.background;
9228
9230
  this.verticalAxisPosition = definition.verticalAxisPosition;
9229
9231
  this.legendPosition = definition.legendPosition;
@@ -9543,7 +9545,7 @@ class PieChart extends AbstractChart {
9543
9545
  constructor(definition, sheetId, getters) {
9544
9546
  super(definition, sheetId, getters);
9545
9547
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9546
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
9548
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
9547
9549
  this.background = definition.background;
9548
9550
  this.legendPosition = definition.legendPosition;
9549
9551
  this.aggregated = definition.aggregated;
@@ -11187,6 +11189,9 @@ function makeArg(str, description) {
11187
11189
  if (types.some((t) => t.startsWith("RANGE"))) {
11188
11190
  result.acceptMatrix = true;
11189
11191
  }
11192
+ if (types.every((t) => t.startsWith("RANGE"))) {
11193
+ result.acceptMatrixOnly = true;
11194
+ }
11190
11195
  return result;
11191
11196
  }
11192
11197
  /**
@@ -11468,11 +11473,16 @@ const CHOOSECOLS = {
11468
11473
  compute: function (array, ...columns) {
11469
11474
  const _array = toMatrix(array);
11470
11475
  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()));
11476
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
11477
+ 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
11478
  const result = Array(_columns.length);
11473
11479
  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];
11480
+ if (_columns[col] > 0) {
11481
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
11482
+ }
11483
+ else {
11484
+ result[col] = _array[_array.length + _columns[col]];
11485
+ }
11476
11486
  }
11477
11487
  return result;
11478
11488
  },
@@ -11493,8 +11503,14 @@ const CHOOSEROWS = {
11493
11503
  const _array = toMatrix(array);
11494
11504
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
11495
11505
  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
11506
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
11507
+ 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(",")));
11508
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
11509
+ if (_rows[row] > 0) {
11510
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
11511
+ }
11512
+ return _array[col][_array[col].length + _rows[row]];
11513
+ });
11498
11514
  },
11499
11515
  isExported: true,
11500
11516
  };
@@ -12402,7 +12418,7 @@ const COUNTUNIQUEIFS = {
12402
12418
  compute: function (range, ...args) {
12403
12419
  let uniqueValues = new Set();
12404
12420
  visitMatchingRanges(args, (i, j) => {
12405
- const data = range[i][j];
12421
+ const data = range[i]?.[j];
12406
12422
  if (isDefined(data)) {
12407
12423
  uniqueValues.add(data.value);
12408
12424
  }
@@ -13032,7 +13048,7 @@ const SUMIF = {
13032
13048
  }
13033
13049
  let sum = 0;
13034
13050
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
13035
- const value = sumRange[i][j].value;
13051
+ const value = sumRange[i]?.[j]?.value;
13036
13052
  if (typeof value === "number") {
13037
13053
  sum += value;
13038
13054
  }
@@ -13057,7 +13073,7 @@ const SUMIFS = {
13057
13073
  compute: function (sumRange, ...criters) {
13058
13074
  let sum = 0;
13059
13075
  visitMatchingRanges(criters, (i, j) => {
13060
- const value = sumRange[i][j].value;
13076
+ const value = sumRange[i]?.[j]?.value;
13061
13077
  if (typeof value === "number") {
13062
13078
  sum += value;
13063
13079
  }
@@ -13604,7 +13620,7 @@ const AVERAGEIF = {
13604
13620
  let count = 0;
13605
13621
  let sum = 0;
13606
13622
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
13607
- const value = _averageRange[i][j].value;
13623
+ const value = _averageRange[i]?.[j]?.value;
13608
13624
  if (typeof value === "number") {
13609
13625
  count += 1;
13610
13626
  sum += value;
@@ -13633,7 +13649,7 @@ const AVERAGEIFS = {
13633
13649
  let count = 0;
13634
13650
  let sum = 0;
13635
13651
  visitMatchingRanges(args, (i, j) => {
13636
- const value = _averageRange[i][j].value;
13652
+ const value = _averageRange[i]?.[j]?.value;
13637
13653
  if (typeof value === "number") {
13638
13654
  count += 1;
13639
13655
  sum += value;
@@ -13938,7 +13954,7 @@ const MAXIFS = {
13938
13954
  compute: function (range, ...args) {
13939
13955
  let result = -Infinity;
13940
13956
  visitMatchingRanges(args, (i, j) => {
13941
- const value = range[i][j].value;
13957
+ const value = range[i]?.[j]?.value;
13942
13958
  if (typeof value === "number") {
13943
13959
  result = result < value ? value : result;
13944
13960
  }
@@ -14021,7 +14037,7 @@ const MINIFS = {
14021
14037
  compute: function (range, ...args) {
14022
14038
  let result = Infinity;
14023
14039
  visitMatchingRanges(args, (i, j) => {
14024
- const value = range[i][j].value;
14040
+ const value = range[i]?.[j]?.value;
14025
14041
  if (typeof value === "number") {
14026
14042
  result = result > value ? value : result;
14027
14043
  }
@@ -19798,6 +19814,9 @@ function addInputHandling(descr) {
19798
19814
  }
19799
19815
  args[i] = arg[0][0];
19800
19816
  }
19817
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
19818
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
19819
+ }
19801
19820
  }
19802
19821
  return descr.compute.apply(this, args);
19803
19822
  }
@@ -22150,7 +22169,7 @@ class LineBarPieConfigPanel extends Component {
22150
22169
  }
22151
22170
  const getters = this.env.model.getters;
22152
22171
  const sheetId = getters.getActiveSheetId();
22153
- const labelRange = createRange(getters, sheetId, this.labelRange);
22172
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
22154
22173
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
22155
22174
  if (dataSets.length) {
22156
22175
  return dataSets[0].dataRange.zone.top + 1;
@@ -26273,14 +26292,14 @@ class FigureComponent extends Component {
26273
26292
  }
26274
26293
  onKeyDown(ev) {
26275
26294
  const figure = this.props.figure;
26276
- switch (ev.key) {
26295
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
26296
+ switch (keyDownShortcut) {
26277
26297
  case "Delete":
26278
26298
  this.env.model.dispatch("DELETE_FIGURE", {
26279
26299
  sheetId: this.env.model.getters.getActiveSheetId(),
26280
26300
  id: figure.id,
26281
26301
  });
26282
26302
  this.props.onFigureDeleted();
26283
- ev.stopPropagation();
26284
26303
  ev.preventDefault();
26285
26304
  ev.stopPropagation();
26286
26305
  break;
@@ -26301,7 +26320,22 @@ class FigureComponent extends Component {
26301
26320
  x: figure.x + delta[0],
26302
26321
  y: figure.y + delta[1],
26303
26322
  });
26323
+ ev.preventDefault();
26324
+ ev.stopPropagation();
26325
+ break;
26326
+ case "Ctrl+A":
26327
+ // Maybe in the future we will implement a way to select all figures
26328
+ ev.preventDefault();
26304
26329
  ev.stopPropagation();
26330
+ break;
26331
+ case "Ctrl+Y":
26332
+ case "Ctrl+Z":
26333
+ if (keyDownShortcut === "Ctrl+Y") {
26334
+ this.env.model.dispatch("REQUEST_REDO");
26335
+ }
26336
+ else if (keyDownShortcut === "Ctrl+Z") {
26337
+ this.env.model.dispatch("REQUEST_UNDO");
26338
+ }
26305
26339
  ev.preventDefault();
26306
26340
  ev.stopPropagation();
26307
26341
  break;
@@ -35762,12 +35796,6 @@ function compileTokens(tokens) {
35762
35796
  // detect when an argument need to be evaluated as a meta argument
35763
35797
  const isMeta = argTypes.includes("META");
35764
35798
  const hasRange = argTypes.some((t) => isRangeType(t));
35765
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
35766
- if (isRangeOnly) {
35767
- if (!isRangeInput(currentArg)) {
35768
- 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()));
35769
- }
35770
- }
35771
35799
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange, {
35772
35800
  functionName,
35773
35801
  paramIndex: i + 1,
@@ -35938,16 +35966,6 @@ function assertEnoughArgs(ast) {
35938
35966
  function isRangeType(type) {
35939
35967
  return type.startsWith("RANGE");
35940
35968
  }
35941
- function isRangeInput(arg) {
35942
- if (arg.type === "REFERENCE") {
35943
- return true;
35944
- }
35945
- if (arg.type === "FUNCALL") {
35946
- const fnDef = functions$1[arg.value.toUpperCase()];
35947
- return fnDef && isRangeType(fnDef.returns[0]);
35948
- }
35949
- return false;
35950
- }
35951
35969
 
35952
35970
  /**
35953
35971
  * Add the following information on tokens:
@@ -39060,6 +39078,9 @@ class RangeAdapter {
39060
39078
  if (range.invalidXc) {
39061
39079
  return range.invalidXc;
39062
39080
  }
39081
+ if (!this.getters.tryGetSheet(range.sheetId)) {
39082
+ return CellErrorType.InvalidReference;
39083
+ }
39063
39084
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
39064
39085
  return CellErrorType.InvalidReference;
39065
39086
  }
@@ -42507,16 +42528,22 @@ class EvaluationPlugin extends UIPlugin {
42507
42528
  let newContent = undefined;
42508
42529
  let newFormat = undefined;
42509
42530
  let isExported = true;
42531
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42510
42532
  const formulaCell = this.getCorrespondingFormulaCell(position);
42511
42533
  if (formulaCell) {
42512
42534
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
42513
42535
  isFormula = isExported;
42514
42536
  if (!isExported) {
42515
- newContent = value.toString();
42516
- newFormat = evaluatedCell.format;
42537
+ // If the cell contains a non-exported formula and that is evaluates to
42538
+ // nothing* ,we don't export it.
42539
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
42540
+ // the empty string.
42541
+ if (value !== "") {
42542
+ newContent = value.toString();
42543
+ newFormat = evaluatedCell.format;
42544
+ }
42517
42545
  }
42518
42546
  }
42519
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42520
42547
  const exportedCellData = exportedSheetData.cells[xc] || {};
42521
42548
  const format = newFormat
42522
42549
  ? getItemId(newFormat, data.formats)
@@ -52013,9 +52040,11 @@ class BottomBarSheet extends Component {
52013
52040
  if (ev.key === "Enter") {
52014
52041
  ev.preventDefault();
52015
52042
  this.stopEdition();
52043
+ this.env.focusableElement.focus();
52016
52044
  }
52017
52045
  if (ev.key === "Escape") {
52018
52046
  this.cancelEdition();
52047
+ this.env.focusableElement.focus();
52019
52048
  }
52020
52049
  }
52021
52050
  onClickSheetName(ev) {
@@ -56710,7 +56739,11 @@ function addRows(construct, data, sheet) {
56710
56739
  let cellNode = escapeXml ``;
56711
56740
  // Either formula or static value inside the cell
56712
56741
  if (cell.isFormula) {
56713
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
56742
+ const res = addFormula(cell);
56743
+ if (!res) {
56744
+ continue;
56745
+ }
56746
+ ({ attrs: additionalAttrs, node: cellNode } = res);
56714
56747
  }
56715
56748
  else if (cell.content && isMarkdownLink(cell.content)) {
56716
56749
  const { label } = parseMarkdownLink(cell.content);
@@ -57704,6 +57737,6 @@ const constants = {
57704
57737
  export { AbstractChart, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
57705
57738
 
57706
57739
 
57707
- __info__.version = "17.1.16";
57708
- __info__.date = "2024-05-24T11:27:23.083Z";
57709
- __info__.hash = "3a41c3a";
57740
+ __info__.version = "17.1.17";
57741
+ __info__.date = "2024-06-03T14:54:06.711Z";
57742
+ __info__.hash = "7dedb2f";