@odoo/o-spreadsheet 17.2.8 → 17.2.9

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.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.2.8
7
- * @date 2024-05-24T11:29:49.320Z
8
- * @hash bfbcaa0
6
+ * @version 17.2.9
7
+ * @date 2024-06-03T14:56:21.684Z
8
+ * @hash 086af6d
9
9
  */
10
10
 
11
11
  'use strict';
@@ -2660,7 +2660,7 @@ function evaluatePredicate(value, criterion) {
2660
2660
  return false;
2661
2661
  }
2662
2662
  if (typeof operand === "number" && operator === "=") {
2663
- return toString(value) === toString(operand);
2663
+ return value.toString() === operand.toString();
2664
2664
  }
2665
2665
  if (operator === "<>" || operator === "=") {
2666
2666
  let result;
@@ -2720,14 +2720,13 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2720
2720
  if (countArg % 2 === 1) {
2721
2721
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2722
2722
  }
2723
- const dimRow = args[0].length;
2724
- const dimCol = args[0][0].length;
2723
+ const firstArg = toMatrix(args[0]);
2724
+ const dimRow = firstArg.length;
2725
+ const dimCol = firstArg[0].length;
2725
2726
  let predicates = [];
2726
2727
  for (let i = 0; i < countArg - 1; i += 2) {
2727
- const criteriaRange = args[i];
2728
- if (!isMatrix(criteriaRange) ||
2729
- criteriaRange.length !== dimRow ||
2730
- criteriaRange[0].length !== dimCol) {
2728
+ const criteriaRange = toMatrix(args[i]);
2729
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2731
2730
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2732
2731
  }
2733
2732
  const description = toString(args[i + 1]);
@@ -2741,7 +2740,7 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2741
2740
  for (let j = 0; j < dimCol; j++) {
2742
2741
  let validatedPredicates = true;
2743
2742
  for (let k = 0; k < countArg - 1; k += 2) {
2744
- const criteriaValue = args[k][i][j].value;
2743
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2745
2744
  const criterion = predicates[k / 2];
2746
2745
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2747
2746
  if (!validatedPredicates) {
@@ -4458,8 +4457,11 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
4458
4457
  /**
4459
4458
  * Create a range from a xc. If the xc is empty, this function returns undefined.
4460
4459
  */
4461
- function createRange(getters, sheetId, range) {
4462
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
4460
+ function createValidRange(getters, sheetId, xc) {
4461
+ if (!xc)
4462
+ return;
4463
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
4464
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
4463
4465
  }
4464
4466
  /**
4465
4467
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -9646,8 +9648,8 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
9646
9648
  type = "scorecard";
9647
9649
  constructor(definition, sheetId, getters) {
9648
9650
  super(definition, sheetId, getters);
9649
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
9650
- this.baseline = createRange(getters, sheetId, definition.baseline);
9651
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
9652
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
9651
9653
  this.baselineMode = definition.baselineMode;
9652
9654
  this.baselineDescr = definition.baselineDescr;
9653
9655
  this.background = definition.background;
@@ -10217,6 +10219,9 @@ function makeArg(str, description) {
10217
10219
  if (types.some((t) => t.startsWith("RANGE"))) {
10218
10220
  result.acceptMatrix = true;
10219
10221
  }
10222
+ if (types.every((t) => t.startsWith("RANGE"))) {
10223
+ result.acceptMatrixOnly = true;
10224
+ }
10220
10225
  return result;
10221
10226
  }
10222
10227
  /**
@@ -10498,11 +10503,16 @@ const CHOOSECOLS = {
10498
10503
  compute: function (array, ...columns) {
10499
10504
  const _array = toMatrix(array);
10500
10505
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
10501
- 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()));
10506
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
10507
+ 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(",")));
10502
10508
  const result = Array(_columns.length);
10503
10509
  for (let col = 0; col < _columns.length; col++) {
10504
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
10505
- result[col] = _array[colIndex];
10510
+ if (_columns[col] > 0) {
10511
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
10512
+ }
10513
+ else {
10514
+ result[col] = _array[_array.length + _columns[col]];
10515
+ }
10506
10516
  }
10507
10517
  return result;
10508
10518
  },
@@ -10523,8 +10533,14 @@ const CHOOSEROWS = {
10523
10533
  const _array = toMatrix(array);
10524
10534
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
10525
10535
  const _nbColumns = _array.length;
10526
- 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()));
10527
- return generateMatrix(_nbColumns, _rows.length, (col, row) => _array[col][_rows[row] - 1]); // -1 because rows arguments are 1-indexed
10536
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
10537
+ 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(",")));
10538
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
10539
+ if (_rows[row] > 0) {
10540
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
10541
+ }
10542
+ return _array[col][_array[col].length + _rows[row]];
10543
+ });
10528
10544
  },
10529
10545
  isExported: true,
10530
10546
  };
@@ -11432,7 +11448,7 @@ const COUNTUNIQUEIFS = {
11432
11448
  compute: function (range, ...args) {
11433
11449
  let uniqueValues = new Set();
11434
11450
  visitMatchingRanges(args, (i, j) => {
11435
- const data = range[i][j];
11451
+ const data = range[i]?.[j];
11436
11452
  if (isDefined(data)) {
11437
11453
  uniqueValues.add(data.value);
11438
11454
  }
@@ -12062,7 +12078,7 @@ const SUMIF = {
12062
12078
  }
12063
12079
  let sum = 0;
12064
12080
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
12065
- const value = sumRange[i][j].value;
12081
+ const value = sumRange[i]?.[j]?.value;
12066
12082
  if (typeof value === "number") {
12067
12083
  sum += value;
12068
12084
  }
@@ -12087,7 +12103,7 @@ const SUMIFS = {
12087
12103
  compute: function (sumRange, ...criters) {
12088
12104
  let sum = 0;
12089
12105
  visitMatchingRanges(criters, (i, j) => {
12090
- const value = sumRange[i][j].value;
12106
+ const value = sumRange[i]?.[j]?.value;
12091
12107
  if (typeof value === "number") {
12092
12108
  sum += value;
12093
12109
  }
@@ -12634,7 +12650,7 @@ const AVERAGEIF = {
12634
12650
  let count = 0;
12635
12651
  let sum = 0;
12636
12652
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
12637
- const value = _averageRange[i][j].value;
12653
+ const value = _averageRange[i]?.[j]?.value;
12638
12654
  if (typeof value === "number") {
12639
12655
  count += 1;
12640
12656
  sum += value;
@@ -12663,7 +12679,7 @@ const AVERAGEIFS = {
12663
12679
  let count = 0;
12664
12680
  let sum = 0;
12665
12681
  visitMatchingRanges(args, (i, j) => {
12666
- const value = _averageRange[i][j].value;
12682
+ const value = _averageRange[i]?.[j]?.value;
12667
12683
  if (typeof value === "number") {
12668
12684
  count += 1;
12669
12685
  sum += value;
@@ -12968,7 +12984,7 @@ const MAXIFS = {
12968
12984
  compute: function (range, ...args) {
12969
12985
  let result = -Infinity;
12970
12986
  visitMatchingRanges(args, (i, j) => {
12971
- const value = range[i][j].value;
12987
+ const value = range[i]?.[j]?.value;
12972
12988
  if (typeof value === "number") {
12973
12989
  result = result < value ? value : result;
12974
12990
  }
@@ -13051,7 +13067,7 @@ const MINIFS = {
13051
13067
  compute: function (range, ...args) {
13052
13068
  let result = Infinity;
13053
13069
  visitMatchingRanges(args, (i, j) => {
13054
- const value = range[i][j].value;
13070
+ const value = range[i]?.[j]?.value;
13055
13071
  if (typeof value === "number") {
13056
13072
  result = result > value ? value : result;
13057
13073
  }
@@ -18803,6 +18819,9 @@ function addInputHandling(descr) {
18803
18819
  }
18804
18820
  args[i] = arg[0][0];
18805
18821
  }
18822
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
18823
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
18824
+ }
18806
18825
  }
18807
18826
  return descr.compute.apply(this, args);
18808
18827
  }
@@ -19805,7 +19824,7 @@ class BarChart extends AbstractChart {
19805
19824
  constructor(definition, sheetId, getters) {
19806
19825
  super(definition, sheetId, getters);
19807
19826
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
19808
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
19827
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
19809
19828
  this.background = definition.background;
19810
19829
  this.verticalAxisPosition = definition.verticalAxisPosition;
19811
19830
  this.legendPosition = definition.legendPosition;
@@ -20049,7 +20068,7 @@ class GaugeChart extends AbstractChart {
20049
20068
  type = "gauge";
20050
20069
  constructor(definition, sheetId, getters) {
20051
20070
  super(definition, sheetId, getters);
20052
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
20071
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
20053
20072
  this.sectionRule = definition.sectionRule;
20054
20073
  this.background = definition.background;
20055
20074
  }
@@ -20570,7 +20589,7 @@ class LineChart extends AbstractChart {
20570
20589
  constructor(definition, sheetId, getters) {
20571
20590
  super(definition, sheetId, getters);
20572
20591
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
20573
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
20592
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
20574
20593
  this.background = definition.background;
20575
20594
  this.verticalAxisPosition = definition.verticalAxisPosition;
20576
20595
  this.legendPosition = definition.legendPosition;
@@ -20685,7 +20704,7 @@ class PieChart extends AbstractChart {
20685
20704
  constructor(definition, sheetId, getters) {
20686
20705
  super(definition, sheetId, getters);
20687
20706
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
20688
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
20707
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
20689
20708
  this.background = definition.background;
20690
20709
  this.legendPosition = definition.legendPosition;
20691
20710
  this.aggregated = definition.aggregated;
@@ -20887,7 +20906,7 @@ class ScatterChart extends AbstractChart {
20887
20906
  constructor(definition, sheetId, getters) {
20888
20907
  super(definition, sheetId, getters);
20889
20908
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
20890
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
20909
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
20891
20910
  this.background = definition.background;
20892
20911
  this.verticalAxisPosition = definition.verticalAxisPosition;
20893
20912
  this.legendPosition = definition.legendPosition;
@@ -20973,13 +20992,6 @@ function createScatterChartRuntime(chart, getters) {
20973
20992
  // have less options than the line chart (it only works with linear labels)
20974
20993
  chartJsConfig.type = "line";
20975
20994
  const configOptions = chartJsConfig.options;
20976
- configOptions.elements = {
20977
- point: {
20978
- radius: 3,
20979
- hoverRadius: 3,
20980
- hitRadius: 8,
20981
- },
20982
- };
20983
20995
  const locale = getters.getLocale();
20984
20996
  configOptions.plugins.tooltip.callbacks.title = () => "";
20985
20997
  configOptions.plugins.tooltip.callbacks.label = (tooltipItem) => {
@@ -26813,7 +26825,7 @@ class LineBarPieConfigPanel extends owl.Component {
26813
26825
  }
26814
26826
  const getters = this.env.model.getters;
26815
26827
  const sheetId = getters.getActiveSheetId();
26816
- const labelRange = createRange(getters, sheetId, this.labelRange);
26828
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
26817
26829
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
26818
26830
  if (dataSets.length) {
26819
26831
  return dataSets[0].dataRange.zone.top + 1;
@@ -26842,15 +26854,23 @@ class BarConfigPanel extends LineBarPieConfigPanel {
26842
26854
  }
26843
26855
  }
26844
26856
 
26857
+ /**
26858
+ * Start listening to pointer events and apply the given callbacks.
26859
+ *
26860
+ * @returns A function to remove the listeners.
26861
+ */
26845
26862
  function startDnd(onMouseMove, onMouseUp, onMouseDown = () => { }) {
26846
- const _onMouseUp = (ev) => {
26847
- onMouseUp(ev);
26863
+ const removeListeners = () => {
26848
26864
  window.removeEventListener("pointerdown", onMouseDown);
26849
26865
  window.removeEventListener("pointerup", _onMouseUp);
26850
26866
  window.removeEventListener("dragstart", _onDragStart);
26851
26867
  window.removeEventListener("pointermove", onMouseMove);
26852
26868
  window.removeEventListener("wheel", onMouseMove);
26853
26869
  };
26870
+ const _onMouseUp = (ev) => {
26871
+ onMouseUp(ev);
26872
+ removeListeners();
26873
+ };
26854
26874
  function _onDragStart(ev) {
26855
26875
  ev.preventDefault();
26856
26876
  }
@@ -26862,6 +26882,7 @@ function startDnd(onMouseMove, onMouseUp, onMouseDown = () => { }) {
26862
26882
  // preventDefault() is not allowed in passive event handler.
26863
26883
  // https://chromestatus.com/feature/6662647093133312
26864
26884
  window.addEventListener("wheel", onMouseMove, { passive: false });
26885
+ return removeListeners;
26865
26886
  }
26866
26887
  /**
26867
26888
  * Function to be used during a pointerdown event, this function allows to
@@ -28056,6 +28077,7 @@ function useDragAndDropListItems() {
28056
28077
  state.itemsStyle = {};
28057
28078
  document.body.style.cursor = previousCursor;
28058
28079
  args.onCancel?.();
28080
+ cleanUp();
28059
28081
  };
28060
28082
  const onDragEnd = (itemId, indexAtEnd) => {
28061
28083
  state.draggedItemId = undefined;
@@ -28076,7 +28098,8 @@ function useDragAndDropListItems() {
28076
28098
  onDragEnd,
28077
28099
  onCancel: state.cancel,
28078
28100
  });
28079
- startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
28101
+ const stopListening = startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
28102
+ cleanupFns.push(stopListening);
28080
28103
  const onScroll = dndHelper.onScroll.bind(dndHelper);
28081
28104
  args.containerEl.addEventListener("scroll", onScroll);
28082
28105
  cleanupFns.push(() => args.containerEl.removeEventListener("scroll", onScroll));
@@ -28153,7 +28176,7 @@ class DOMDndHelper {
28153
28176
  this.moveDraggedItemToPosition(this.currentMousePosition + this.scrollOffset);
28154
28177
  }
28155
28178
  onMouseMove(ev) {
28156
- if (ev.button !== -1) {
28179
+ if (ev.button > 1) {
28157
28180
  this.onCancel();
28158
28181
  return;
28159
28182
  }
@@ -31323,14 +31346,14 @@ class FigureComponent extends owl.Component {
31323
31346
  }
31324
31347
  onKeyDown(ev) {
31325
31348
  const figure = this.props.figure;
31326
- switch (ev.key) {
31349
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
31350
+ switch (keyDownShortcut) {
31327
31351
  case "Delete":
31328
31352
  this.env.model.dispatch("DELETE_FIGURE", {
31329
31353
  sheetId: this.env.model.getters.getActiveSheetId(),
31330
31354
  id: figure.id,
31331
31355
  });
31332
31356
  this.props.onFigureDeleted();
31333
- ev.stopPropagation();
31334
31357
  ev.preventDefault();
31335
31358
  ev.stopPropagation();
31336
31359
  break;
@@ -31351,7 +31374,22 @@ class FigureComponent extends owl.Component {
31351
31374
  x: figure.x + delta[0],
31352
31375
  y: figure.y + delta[1],
31353
31376
  });
31377
+ ev.preventDefault();
31378
+ ev.stopPropagation();
31379
+ break;
31380
+ case "Ctrl+A":
31381
+ // Maybe in the future we will implement a way to select all figures
31382
+ ev.preventDefault();
31354
31383
  ev.stopPropagation();
31384
+ break;
31385
+ case "Ctrl+Y":
31386
+ case "Ctrl+Z":
31387
+ if (keyDownShortcut === "Ctrl+Y") {
31388
+ this.env.model.dispatch("REQUEST_REDO");
31389
+ }
31390
+ else if (keyDownShortcut === "Ctrl+Z") {
31391
+ this.env.model.dispatch("REQUEST_UNDO");
31392
+ }
31355
31393
  ev.preventDefault();
31356
31394
  ev.stopPropagation();
31357
31395
  break;
@@ -41139,12 +41177,6 @@ function compileTokens(tokens) {
41139
41177
  // detect when an argument need to be evaluated as a meta argument
41140
41178
  const isMeta = argTypes.includes("META");
41141
41179
  const hasRange = argTypes.some((t) => isRangeType(t));
41142
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
41143
- if (isRangeOnly) {
41144
- if (!isRangeInput(currentArg)) {
41145
- 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()));
41146
- }
41147
- }
41148
41180
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange, {
41149
41181
  functionName,
41150
41182
  paramIndex: i + 1,
@@ -41315,16 +41347,6 @@ function assertEnoughArgs(ast) {
41315
41347
  function isRangeType(type) {
41316
41348
  return type.startsWith("RANGE");
41317
41349
  }
41318
- function isRangeInput(arg) {
41319
- if (arg.type === "REFERENCE") {
41320
- return true;
41321
- }
41322
- if (arg.type === "FUNCALL") {
41323
- const fnDef = functions$1[arg.value.toUpperCase()];
41324
- return fnDef && isRangeType(fnDef.returns[0]);
41325
- }
41326
- return false;
41327
- }
41328
41350
 
41329
41351
  const functions = functionRegistry.content;
41330
41352
  function isExportableToExcel(tokens) {
@@ -44062,6 +44084,9 @@ class RangeAdapter {
44062
44084
  if (range.invalidXc) {
44063
44085
  return range.invalidXc;
44064
44086
  }
44087
+ if (!this.getters.tryGetSheet(range.sheetId)) {
44088
+ return CellErrorType.InvalidReference;
44089
+ }
44065
44090
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
44066
44091
  return CellErrorType.InvalidReference;
44067
44092
  }
@@ -47446,7 +47471,6 @@ class PositionSet {
47446
47471
  *
47447
47472
  */
47448
47473
  class SpreadingRelation {
47449
- createEmptyPositionSet;
47450
47474
  /**
47451
47475
  * Internal structure:
47452
47476
  * For something like
@@ -47477,9 +47501,6 @@ class SpreadingRelation {
47477
47501
  */
47478
47502
  resultsToArrayFormulas = new PositionMap();
47479
47503
  arrayFormulasToResults = new PositionMap();
47480
- constructor(createEmptyPositionSet) {
47481
- this.createEmptyPositionSet = createEmptyPositionSet;
47482
- }
47483
47504
  getFormulaPositionsSpreadingOn(resultPosition) {
47484
47505
  return this.resultsToArrayFormulas.get(resultPosition) || EMPTY_ARRAY;
47485
47506
  }
@@ -47498,13 +47519,13 @@ class SpreadingRelation {
47498
47519
  */
47499
47520
  addRelation({ arrayFormulaPosition, resultPosition, }) {
47500
47521
  if (!this.resultsToArrayFormulas.has(resultPosition)) {
47501
- this.resultsToArrayFormulas.set(resultPosition, this.createEmptyPositionSet());
47522
+ this.resultsToArrayFormulas.set(resultPosition, []);
47502
47523
  }
47503
- this.resultsToArrayFormulas.get(resultPosition)?.add(arrayFormulaPosition);
47524
+ this.resultsToArrayFormulas.get(resultPosition)?.push(arrayFormulaPosition);
47504
47525
  if (!this.arrayFormulasToResults.has(arrayFormulaPosition)) {
47505
- this.arrayFormulasToResults.set(arrayFormulaPosition, this.createEmptyPositionSet());
47526
+ this.arrayFormulasToResults.set(arrayFormulaPosition, []);
47506
47527
  }
47507
- this.arrayFormulasToResults.get(arrayFormulaPosition)?.add(resultPosition);
47528
+ this.arrayFormulasToResults.get(arrayFormulaPosition)?.push(resultPosition);
47508
47529
  }
47509
47530
  hasArrayFormulaResult(position) {
47510
47531
  return this.resultsToArrayFormulas.has(position);
@@ -47525,7 +47546,7 @@ class Evaluator {
47525
47546
  evaluatedCells = new PositionMap();
47526
47547
  formulaDependencies = lazy(new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this)));
47527
47548
  blockedArrayFormulas = new PositionSet({});
47528
- spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
47549
+ spreadingRelations = new SpreadingRelation();
47529
47550
  constructor(context, getters) {
47530
47551
  this.context = context;
47531
47552
  this.getters = getters;
@@ -47602,7 +47623,7 @@ class Evaluator {
47602
47623
  }
47603
47624
  buildDependencyGraph() {
47604
47625
  this.blockedArrayFormulas = this.createEmptyPositionSet();
47605
- this.spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
47626
+ this.spreadingRelations = new SpreadingRelation();
47606
47627
  this.formulaDependencies = lazy(() => {
47607
47628
  const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position)
47608
47629
  .filter((range) => !range.invalidSheetName && !range.invalidXc)
@@ -48091,16 +48112,22 @@ class EvaluationPlugin extends UIPlugin {
48091
48112
  let newContent = undefined;
48092
48113
  let newFormat = undefined;
48093
48114
  let isExported = true;
48115
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
48094
48116
  const formulaCell = this.getCorrespondingFormulaCell(position);
48095
48117
  if (formulaCell) {
48096
48118
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
48097
48119
  isFormula = isExported;
48098
48120
  if (!isExported) {
48099
- newContent = (value ?? "").toString();
48100
- newFormat = evaluatedCell.format;
48121
+ // If the cell contains a non-exported formula and that is evaluates to
48122
+ // nothing* ,we don't export it.
48123
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
48124
+ // the empty string.
48125
+ if (value !== "") {
48126
+ newContent = (value ?? "").toString();
48127
+ newFormat = evaluatedCell.format;
48128
+ }
48101
48129
  }
48102
48130
  }
48103
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
48104
48131
  const exportedCellData = exportedSheetData.cells[xc] || {};
48105
48132
  const format = newFormat
48106
48133
  ? getItemId(newFormat, data.formats)
@@ -52090,7 +52117,7 @@ class ClipboardPlugin extends UIPlugin {
52090
52117
  paintFormatStatus = "inactive";
52091
52118
  originSheetId;
52092
52119
  copiedData;
52093
- _isCutOperation;
52120
+ _isCutOperation = false;
52094
52121
  // ---------------------------------------------------------------------------
52095
52122
  // Command Handling
52096
52123
  // ---------------------------------------------------------------------------
@@ -52102,14 +52129,17 @@ class ClipboardPlugin extends UIPlugin {
52102
52129
  case "PASTE_FROM_OS_CLIPBOARD": {
52103
52130
  const copiedData = this.convertOSClipboardData(cmd.text);
52104
52131
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52105
- return this.isPasteAllowed(cmd.target, copiedData, { pasteOption });
52132
+ return this.isPasteAllowed(cmd.target, copiedData, { pasteOption, isCutOperation: false });
52106
52133
  }
52107
52134
  case "PASTE": {
52108
52135
  if (!this.copiedData) {
52109
52136
  return "EmptyClipboard" /* CommandResult.EmptyClipboard */;
52110
52137
  }
52111
52138
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52112
- return this.isPasteAllowed(cmd.target, this.copiedData, { pasteOption });
52139
+ return this.isPasteAllowed(cmd.target, this.copiedData, {
52140
+ pasteOption: pasteOption,
52141
+ isCutOperation: this._isCutOperation,
52142
+ });
52113
52143
  }
52114
52144
  case "COPY_PASTE_CELLS_ABOVE": {
52115
52145
  const zones = this.getters.getSelectedZones();
@@ -52127,13 +52157,13 @@ class ClipboardPlugin extends UIPlugin {
52127
52157
  }
52128
52158
  case "INSERT_CELL": {
52129
52159
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
52130
- const copiedData = this.copy("CUT", cut);
52131
- return this.isPasteAllowed(paste, copiedData, {});
52160
+ const copiedData = this.copy(cut);
52161
+ return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
52132
52162
  }
52133
52163
  case "DELETE_CELL": {
52134
52164
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
52135
- const copiedData = this.copy("CUT", cut);
52136
- return this.isPasteAllowed(paste, copiedData, {});
52165
+ const copiedData = this.copy(cut);
52166
+ return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
52137
52167
  }
52138
52168
  case "ACTIVATE_PAINT_FORMAT": {
52139
52169
  if (this.paintFormatStatus !== "inactive") {
@@ -52151,23 +52181,27 @@ class ClipboardPlugin extends UIPlugin {
52151
52181
  const zones = this.getters.getSelectedZones();
52152
52182
  this.status = "visible";
52153
52183
  this.originSheetId = this.getters.getActiveSheetId();
52154
- this.copiedData = this.copy(cmd.type, zones);
52184
+ this.copiedData = this.copy(zones);
52185
+ this._isCutOperation = cmd.type === "CUT";
52155
52186
  break;
52156
52187
  case "PASTE_FROM_OS_CLIPBOARD": {
52188
+ this._isCutOperation = false;
52157
52189
  this.copiedData = this.convertOSClipboardData(cmd.text);
52158
52190
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52159
- this.paste(cmd.target, {
52191
+ this.paste(cmd.target, this.copiedData, {
52160
52192
  pasteOption,
52161
52193
  selectTarget: true,
52194
+ isCutOperation: false,
52162
52195
  });
52163
52196
  this.status = "invisible";
52164
52197
  break;
52165
52198
  }
52166
52199
  case "PASTE": {
52167
52200
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52168
- this.paste(cmd.target, {
52201
+ this.paste(cmd.target, this.copiedData, {
52169
52202
  pasteOption,
52170
52203
  selectTarget: true,
52204
+ isCutOperation: this._isCutOperation,
52171
52205
  });
52172
52206
  if (this.paintFormatStatus === "oneOff") {
52173
52207
  this.paintFormatStatus = "inactive";
@@ -52188,9 +52222,9 @@ class ClipboardPlugin extends UIPlugin {
52188
52222
  top: multipleRowsInSelection ? zone.top : zone.top - 1,
52189
52223
  };
52190
52224
  this.originSheetId = this.getters.getActiveSheetId();
52191
- this.copiedData = this.copy("COPY", [copyTarget]);
52192
- this.paste([zone], {
52193
- pasteOption: undefined,
52225
+ const copiedData = this.copy([copyTarget]);
52226
+ this.paste([zone], copiedData, {
52227
+ isCutOperation: false,
52194
52228
  selectTarget: true,
52195
52229
  });
52196
52230
  }
@@ -52205,9 +52239,9 @@ class ClipboardPlugin extends UIPlugin {
52205
52239
  left: multipleColsInSelection ? zone.left : zone.left - 1,
52206
52240
  };
52207
52241
  this.originSheetId = this.getters.getActiveSheetId();
52208
- this.copiedData = this.copy("COPY", [copyTarget]);
52209
- this.paste([zone], {
52210
- pasteOption: undefined,
52242
+ const copiedData = this.copy([copyTarget]);
52243
+ this.paste([zone], copiedData, {
52244
+ isCutOperation: false,
52211
52245
  selectTarget: true,
52212
52246
  });
52213
52247
  }
@@ -52223,14 +52257,14 @@ class ClipboardPlugin extends UIPlugin {
52223
52257
  }
52224
52258
  break;
52225
52259
  }
52226
- this.copiedData = this.copy("CUT", cut);
52227
- this.paste(paste, {});
52260
+ const copiedData = this.copy(cut);
52261
+ this.paste(paste, copiedData, { isCutOperation: true });
52228
52262
  break;
52229
52263
  }
52230
52264
  case "INSERT_CELL": {
52231
52265
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
52232
- this.copiedData = this.copy("CUT", cut);
52233
- this.paste(paste, {});
52266
+ const copiedData = this.copy(cut);
52267
+ this.paste(paste, copiedData, { isCutOperation: true });
52234
52268
  break;
52235
52269
  }
52236
52270
  case "ADD_COLUMNS_ROWS": {
@@ -52262,7 +52296,8 @@ class ClipboardPlugin extends UIPlugin {
52262
52296
  break;
52263
52297
  }
52264
52298
  case "REPEAT_PASTE": {
52265
- this.paste(cmd.target, {
52299
+ this.paste(cmd.target, this.copiedData, {
52300
+ isCutOperation: false,
52266
52301
  pasteOption: cmd.pasteOption,
52267
52302
  selectTarget: true,
52268
52303
  });
@@ -52270,7 +52305,7 @@ class ClipboardPlugin extends UIPlugin {
52270
52305
  }
52271
52306
  case "ACTIVATE_PAINT_FORMAT": {
52272
52307
  const zones = this.getters.getSelectedZones();
52273
- this.copiedData = this.copy("COPY", zones);
52308
+ this.copiedData = this.copy(zones);
52274
52309
  this.status = "visible";
52275
52310
  if (cmd.persistent) {
52276
52311
  this.paintFormatStatus = "persistent";
@@ -52301,7 +52336,6 @@ class ClipboardPlugin extends UIPlugin {
52301
52336
  }
52302
52337
  }
52303
52338
  convertOSClipboardData(clipboardData) {
52304
- this._isCutOperation = false;
52305
52339
  const handlers = clipboardHandlersRegistries.figureHandlers
52306
52340
  .getAll()
52307
52341
  .map((handler) => new handler(this.getters, this.dispatch));
@@ -52339,7 +52373,6 @@ class ClipboardPlugin extends UIPlugin {
52339
52373
  for (const handler of this.selectClipboardHandlers(copiedData)) {
52340
52374
  const result = handler.isPasteAllowed(this.getters.getActiveSheetId(), target, copiedData, {
52341
52375
  ...options,
52342
- isCutOperation: this.isCutOperation(),
52343
52376
  });
52344
52377
  if (result !== "Success" /* CommandResult.Success */) {
52345
52378
  return result;
@@ -52362,9 +52395,8 @@ class ClipboardPlugin extends UIPlugin {
52362
52395
  }
52363
52396
  return false;
52364
52397
  }
52365
- copy(operation, zones) {
52398
+ copy(zones) {
52366
52399
  let copiedData = {};
52367
- this._isCutOperation = operation === "CUT";
52368
52400
  const clipboardData = this.getClipboardData(zones);
52369
52401
  for (const handler of this.selectClipboardHandlers(clipboardData)) {
52370
52402
  const data = handler.copy(clipboardData);
@@ -52372,8 +52404,8 @@ class ClipboardPlugin extends UIPlugin {
52372
52404
  }
52373
52405
  return copiedData;
52374
52406
  }
52375
- paste(zones, options) {
52376
- if (!this.copiedData) {
52407
+ paste(zones, copiedData, options) {
52408
+ if (!copiedData) {
52377
52409
  return;
52378
52410
  }
52379
52411
  let zone = undefined;
@@ -52381,12 +52413,9 @@ class ClipboardPlugin extends UIPlugin {
52381
52413
  let target = {
52382
52414
  zones,
52383
52415
  };
52384
- const handlers = this.selectClipboardHandlers(this.copiedData);
52416
+ const handlers = this.selectClipboardHandlers(copiedData);
52385
52417
  for (const handler of handlers) {
52386
- const currentTarget = handler.getPasteTarget(zones, this.copiedData, {
52387
- ...options,
52388
- isCutOperation: this.isCutOperation(),
52389
- });
52418
+ const currentTarget = handler.getPasteTarget(zones, copiedData, options);
52390
52419
  if (currentTarget.figureId) {
52391
52420
  target.figureId = currentTarget.figureId;
52392
52421
  }
@@ -52402,7 +52431,7 @@ class ClipboardPlugin extends UIPlugin {
52402
52431
  if (zone !== undefined) {
52403
52432
  this.addMissingDimensions(this.getters.getActiveSheetId(), zone.right - zone.left + 1, zone.bottom - zone.top + 1, zone.left, zone.top);
52404
52433
  }
52405
- handlers.forEach((handler) => handler.paste(target, this.copiedData, { ...options, isCutOperation: this.isCutOperation() }));
52434
+ handlers.forEach((handler) => handler.paste(target, copiedData, options));
52406
52435
  if (!options?.selectTarget) {
52407
52436
  return;
52408
52437
  }
@@ -54872,6 +54901,7 @@ class BottomBarSheet extends owl.Component {
54872
54901
  sheetDivRef = owl.useRef("sheetDiv");
54873
54902
  sheetNameRef = owl.useRef("sheetNameSpan");
54874
54903
  editionState = "initializing";
54904
+ DOMFocusableElementStore;
54875
54905
  setup() {
54876
54906
  owl.onMounted(() => {
54877
54907
  if (this.isSheetActive) {
@@ -54884,6 +54914,7 @@ class BottomBarSheet extends owl.Component {
54884
54914
  this.focusInputAndSelectContent();
54885
54915
  }
54886
54916
  });
54917
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
54887
54918
  }
54888
54919
  focusInputAndSelectContent() {
54889
54920
  if (!this.state.isEditing || !this.sheetNameRef.el)
@@ -54925,9 +54956,11 @@ class BottomBarSheet extends owl.Component {
54925
54956
  if (ev.key === "Enter") {
54926
54957
  ev.preventDefault();
54927
54958
  this.stopEdition();
54959
+ this.DOMFocusableElementStore.focus();
54928
54960
  }
54929
54961
  if (ev.key === "Escape") {
54930
54962
  this.cancelEdition();
54963
+ this.DOMFocusableElementStore.focus();
54931
54964
  }
54932
54965
  }
54933
54966
  onClickSheetName(ev) {
@@ -59650,7 +59683,11 @@ function addRows(construct, data, sheet) {
59650
59683
  let cellNode = escapeXml ``;
59651
59684
  // Either formula or static value inside the cell
59652
59685
  if (cell.isFormula) {
59653
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
59686
+ const res = addFormula(cell);
59687
+ if (!res) {
59688
+ continue;
59689
+ }
59690
+ ({ attrs: additionalAttrs, node: cellNode } = res);
59654
59691
  }
59655
59692
  else if (cell.content && isMarkdownLink(cell.content)) {
59656
59693
  const { label } = parseMarkdownLink(cell.content);
@@ -60730,6 +60767,6 @@ exports.tokenColors = tokenColors;
60730
60767
  exports.tokenize = tokenize;
60731
60768
 
60732
60769
 
60733
- __info__.version = "17.2.8";
60734
- __info__.date = "2024-05-24T11:29:49.320Z";
60735
- __info__.hash = "bfbcaa0";
60770
+ __info__.version = "17.2.9";
60771
+ __info__.date = "2024-06-03T14:56:21.684Z";
60772
+ __info__.hash = "086af6d";