@odoo/o-spreadsheet 17.2.8 → 17.2.10

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.10
7
+ * @date 2024-06-10T09:38:54.354Z
8
+ * @hash 14317ee
9
9
  */
10
10
 
11
11
  (function (exports, owl) {
@@ -294,7 +294,10 @@
294
294
  * Check if the object is a plain old javascript object.
295
295
  */
296
296
  function isPlainObject(obj) {
297
- return typeof obj === "object" && obj?.constructor === Object;
297
+ return (typeof obj === "object" &&
298
+ obj !== null &&
299
+ // obj.constructor can be undefined when there's no prototype (`Object.create(null, {})`)
300
+ (obj?.constructor === Object || obj?.constructor === undefined));
298
301
  }
299
302
  /**
300
303
  * Sanitize the name of a sheet, by eventually removing quotes
@@ -2659,7 +2662,7 @@
2659
2662
  return false;
2660
2663
  }
2661
2664
  if (typeof operand === "number" && operator === "=") {
2662
- return toString(value) === toString(operand);
2665
+ return value.toString() === operand.toString();
2663
2666
  }
2664
2667
  if (operator === "<>" || operator === "=") {
2665
2668
  let result;
@@ -2719,14 +2722,13 @@
2719
2722
  if (countArg % 2 === 1) {
2720
2723
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2721
2724
  }
2722
- const dimRow = args[0].length;
2723
- const dimCol = args[0][0].length;
2725
+ const firstArg = toMatrix(args[0]);
2726
+ const dimRow = firstArg.length;
2727
+ const dimCol = firstArg[0].length;
2724
2728
  let predicates = [];
2725
2729
  for (let i = 0; i < countArg - 1; i += 2) {
2726
- const criteriaRange = args[i];
2727
- if (!isMatrix(criteriaRange) ||
2728
- criteriaRange.length !== dimRow ||
2729
- criteriaRange[0].length !== dimCol) {
2730
+ const criteriaRange = toMatrix(args[i]);
2731
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2730
2732
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2731
2733
  }
2732
2734
  const description = toString(args[i + 1]);
@@ -2740,7 +2742,7 @@
2740
2742
  for (let j = 0; j < dimCol; j++) {
2741
2743
  let validatedPredicates = true;
2742
2744
  for (let k = 0; k < countArg - 1; k += 2) {
2743
- const criteriaValue = args[k][i][j].value;
2745
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2744
2746
  const criterion = predicates[k / 2];
2745
2747
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2746
2748
  if (!validatedPredicates) {
@@ -4457,8 +4459,11 @@
4457
4459
  /**
4458
4460
  * Create a range from a xc. If the xc is empty, this function returns undefined.
4459
4461
  */
4460
- function createRange(getters, sheetId, range) {
4461
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
4462
+ function createValidRange(getters, sheetId, xc) {
4463
+ if (!xc)
4464
+ return;
4465
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
4466
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
4462
4467
  }
4463
4468
  /**
4464
4469
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -9645,8 +9650,8 @@ stores.inject(MyMetaStore, storeInstance);
9645
9650
  type = "scorecard";
9646
9651
  constructor(definition, sheetId, getters) {
9647
9652
  super(definition, sheetId, getters);
9648
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
9649
- this.baseline = createRange(getters, sheetId, definition.baseline);
9653
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
9654
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
9650
9655
  this.baselineMode = definition.baselineMode;
9651
9656
  this.baselineDescr = definition.baselineDescr;
9652
9657
  this.background = definition.background;
@@ -10216,6 +10221,9 @@ stores.inject(MyMetaStore, storeInstance);
10216
10221
  if (types.some((t) => t.startsWith("RANGE"))) {
10217
10222
  result.acceptMatrix = true;
10218
10223
  }
10224
+ if (types.every((t) => t.startsWith("RANGE"))) {
10225
+ result.acceptMatrixOnly = true;
10226
+ }
10219
10227
  return result;
10220
10228
  }
10221
10229
  /**
@@ -10497,11 +10505,16 @@ stores.inject(MyMetaStore, storeInstance);
10497
10505
  compute: function (array, ...columns) {
10498
10506
  const _array = toMatrix(array);
10499
10507
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
10500
- 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()));
10508
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
10509
+ 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(",")));
10501
10510
  const result = Array(_columns.length);
10502
10511
  for (let col = 0; col < _columns.length; col++) {
10503
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
10504
- result[col] = _array[colIndex];
10512
+ if (_columns[col] > 0) {
10513
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
10514
+ }
10515
+ else {
10516
+ result[col] = _array[_array.length + _columns[col]];
10517
+ }
10505
10518
  }
10506
10519
  return result;
10507
10520
  },
@@ -10522,8 +10535,14 @@ stores.inject(MyMetaStore, storeInstance);
10522
10535
  const _array = toMatrix(array);
10523
10536
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
10524
10537
  const _nbColumns = _array.length;
10525
- 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()));
10526
- return generateMatrix(_nbColumns, _rows.length, (col, row) => _array[col][_rows[row] - 1]); // -1 because rows arguments are 1-indexed
10538
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
10539
+ 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(",")));
10540
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
10541
+ if (_rows[row] > 0) {
10542
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
10543
+ }
10544
+ return _array[col][_array[col].length + _rows[row]];
10545
+ });
10527
10546
  },
10528
10547
  isExported: true,
10529
10548
  };
@@ -11431,7 +11450,7 @@ stores.inject(MyMetaStore, storeInstance);
11431
11450
  compute: function (range, ...args) {
11432
11451
  let uniqueValues = new Set();
11433
11452
  visitMatchingRanges(args, (i, j) => {
11434
- const data = range[i][j];
11453
+ const data = range[i]?.[j];
11435
11454
  if (isDefined(data)) {
11436
11455
  uniqueValues.add(data.value);
11437
11456
  }
@@ -12061,7 +12080,7 @@ stores.inject(MyMetaStore, storeInstance);
12061
12080
  }
12062
12081
  let sum = 0;
12063
12082
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
12064
- const value = sumRange[i][j].value;
12083
+ const value = sumRange[i]?.[j]?.value;
12065
12084
  if (typeof value === "number") {
12066
12085
  sum += value;
12067
12086
  }
@@ -12086,7 +12105,7 @@ stores.inject(MyMetaStore, storeInstance);
12086
12105
  compute: function (sumRange, ...criters) {
12087
12106
  let sum = 0;
12088
12107
  visitMatchingRanges(criters, (i, j) => {
12089
- const value = sumRange[i][j].value;
12108
+ const value = sumRange[i]?.[j]?.value;
12090
12109
  if (typeof value === "number") {
12091
12110
  sum += value;
12092
12111
  }
@@ -12633,7 +12652,7 @@ stores.inject(MyMetaStore, storeInstance);
12633
12652
  let count = 0;
12634
12653
  let sum = 0;
12635
12654
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
12636
- const value = _averageRange[i][j].value;
12655
+ const value = _averageRange[i]?.[j]?.value;
12637
12656
  if (typeof value === "number") {
12638
12657
  count += 1;
12639
12658
  sum += value;
@@ -12662,7 +12681,7 @@ stores.inject(MyMetaStore, storeInstance);
12662
12681
  let count = 0;
12663
12682
  let sum = 0;
12664
12683
  visitMatchingRanges(args, (i, j) => {
12665
- const value = _averageRange[i][j].value;
12684
+ const value = _averageRange[i]?.[j]?.value;
12666
12685
  if (typeof value === "number") {
12667
12686
  count += 1;
12668
12687
  sum += value;
@@ -12967,7 +12986,7 @@ stores.inject(MyMetaStore, storeInstance);
12967
12986
  compute: function (range, ...args) {
12968
12987
  let result = -Infinity;
12969
12988
  visitMatchingRanges(args, (i, j) => {
12970
- const value = range[i][j].value;
12989
+ const value = range[i]?.[j]?.value;
12971
12990
  if (typeof value === "number") {
12972
12991
  result = result < value ? value : result;
12973
12992
  }
@@ -13050,7 +13069,7 @@ stores.inject(MyMetaStore, storeInstance);
13050
13069
  compute: function (range, ...args) {
13051
13070
  let result = Infinity;
13052
13071
  visitMatchingRanges(args, (i, j) => {
13053
- const value = range[i][j].value;
13072
+ const value = range[i]?.[j]?.value;
13054
13073
  if (typeof value === "number") {
13055
13074
  result = result > value ? value : result;
13056
13075
  }
@@ -18802,6 +18821,9 @@ stores.inject(MyMetaStore, storeInstance);
18802
18821
  }
18803
18822
  args[i] = arg[0][0];
18804
18823
  }
18824
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
18825
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
18826
+ }
18805
18827
  }
18806
18828
  return descr.compute.apply(this, args);
18807
18829
  }
@@ -19754,7 +19776,7 @@ stores.inject(MyMetaStore, storeInstance);
19754
19776
  if ("chartJsConfig" in runtime) {
19755
19777
  runtime.chartJsConfig.plugins = [backgroundColorChartJSPlugin];
19756
19778
  // @ts-ignore
19757
- const chart = new window.Chart(canvas, runtime.chartJsConfig);
19779
+ const chart = new window.Chart(canvas, deepCopy(runtime.chartJsConfig));
19758
19780
  const imgContent = chart.toBase64Image();
19759
19781
  chart.destroy();
19760
19782
  div.remove();
@@ -19804,7 +19826,7 @@ stores.inject(MyMetaStore, storeInstance);
19804
19826
  constructor(definition, sheetId, getters) {
19805
19827
  super(definition, sheetId, getters);
19806
19828
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
19807
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
19829
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
19808
19830
  this.background = definition.background;
19809
19831
  this.verticalAxisPosition = definition.verticalAxisPosition;
19810
19832
  this.legendPosition = definition.legendPosition;
@@ -20048,7 +20070,7 @@ stores.inject(MyMetaStore, storeInstance);
20048
20070
  type = "gauge";
20049
20071
  constructor(definition, sheetId, getters) {
20050
20072
  super(definition, sheetId, getters);
20051
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
20073
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
20052
20074
  this.sectionRule = definition.sectionRule;
20053
20075
  this.background = definition.background;
20054
20076
  }
@@ -20569,7 +20591,7 @@ stores.inject(MyMetaStore, storeInstance);
20569
20591
  constructor(definition, sheetId, getters) {
20570
20592
  super(definition, sheetId, getters);
20571
20593
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
20572
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
20594
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
20573
20595
  this.background = definition.background;
20574
20596
  this.verticalAxisPosition = definition.verticalAxisPosition;
20575
20597
  this.legendPosition = definition.legendPosition;
@@ -20684,7 +20706,7 @@ stores.inject(MyMetaStore, storeInstance);
20684
20706
  constructor(definition, sheetId, getters) {
20685
20707
  super(definition, sheetId, getters);
20686
20708
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
20687
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
20709
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
20688
20710
  this.background = definition.background;
20689
20711
  this.legendPosition = definition.legendPosition;
20690
20712
  this.aggregated = definition.aggregated;
@@ -20886,7 +20908,7 @@ stores.inject(MyMetaStore, storeInstance);
20886
20908
  constructor(definition, sheetId, getters) {
20887
20909
  super(definition, sheetId, getters);
20888
20910
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
20889
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
20911
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
20890
20912
  this.background = definition.background;
20891
20913
  this.verticalAxisPosition = definition.verticalAxisPosition;
20892
20914
  this.legendPosition = definition.legendPosition;
@@ -20972,13 +20994,6 @@ stores.inject(MyMetaStore, storeInstance);
20972
20994
  // have less options than the line chart (it only works with linear labels)
20973
20995
  chartJsConfig.type = "line";
20974
20996
  const configOptions = chartJsConfig.options;
20975
- configOptions.elements = {
20976
- point: {
20977
- radius: 3,
20978
- hoverRadius: 3,
20979
- hitRadius: 8,
20980
- },
20981
- };
20982
20997
  const locale = getters.getLocale();
20983
20998
  configOptions.plugins.tooltip.callbacks.title = () => "";
20984
20999
  configOptions.plugins.tooltip.callbacks.label = (tooltipItem) => {
@@ -21707,8 +21722,7 @@ stores.inject(MyMetaStore, storeInstance);
21707
21722
  */
21708
21723
  function useSpreadsheetRect() {
21709
21724
  const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
21710
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
21711
- updatePosition();
21725
+ let spreadsheetElement = null;
21712
21726
  function updatePosition() {
21713
21727
  if (!spreadsheetElement) {
21714
21728
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -26812,7 +26826,7 @@ stores.inject(MyMetaStore, storeInstance);
26812
26826
  }
26813
26827
  const getters = this.env.model.getters;
26814
26828
  const sheetId = getters.getActiveSheetId();
26815
- const labelRange = createRange(getters, sheetId, this.labelRange);
26829
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
26816
26830
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
26817
26831
  if (dataSets.length) {
26818
26832
  return dataSets[0].dataRange.zone.top + 1;
@@ -26841,15 +26855,23 @@ stores.inject(MyMetaStore, storeInstance);
26841
26855
  }
26842
26856
  }
26843
26857
 
26858
+ /**
26859
+ * Start listening to pointer events and apply the given callbacks.
26860
+ *
26861
+ * @returns A function to remove the listeners.
26862
+ */
26844
26863
  function startDnd(onMouseMove, onMouseUp, onMouseDown = () => { }) {
26845
- const _onMouseUp = (ev) => {
26846
- onMouseUp(ev);
26864
+ const removeListeners = () => {
26847
26865
  window.removeEventListener("pointerdown", onMouseDown);
26848
26866
  window.removeEventListener("pointerup", _onMouseUp);
26849
26867
  window.removeEventListener("dragstart", _onDragStart);
26850
26868
  window.removeEventListener("pointermove", onMouseMove);
26851
26869
  window.removeEventListener("wheel", onMouseMove);
26852
26870
  };
26871
+ const _onMouseUp = (ev) => {
26872
+ onMouseUp(ev);
26873
+ removeListeners();
26874
+ };
26853
26875
  function _onDragStart(ev) {
26854
26876
  ev.preventDefault();
26855
26877
  }
@@ -26861,6 +26883,7 @@ stores.inject(MyMetaStore, storeInstance);
26861
26883
  // preventDefault() is not allowed in passive event handler.
26862
26884
  // https://chromestatus.com/feature/6662647093133312
26863
26885
  window.addEventListener("wheel", onMouseMove, { passive: false });
26886
+ return removeListeners;
26864
26887
  }
26865
26888
  /**
26866
26889
  * Function to be used during a pointerdown event, this function allows to
@@ -28055,6 +28078,7 @@ stores.inject(MyMetaStore, storeInstance);
28055
28078
  state.itemsStyle = {};
28056
28079
  document.body.style.cursor = previousCursor;
28057
28080
  args.onCancel?.();
28081
+ cleanUp();
28058
28082
  };
28059
28083
  const onDragEnd = (itemId, indexAtEnd) => {
28060
28084
  state.draggedItemId = undefined;
@@ -28075,7 +28099,8 @@ stores.inject(MyMetaStore, storeInstance);
28075
28099
  onDragEnd,
28076
28100
  onCancel: state.cancel,
28077
28101
  });
28078
- startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
28102
+ const stopListening = startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
28103
+ cleanupFns.push(stopListening);
28079
28104
  const onScroll = dndHelper.onScroll.bind(dndHelper);
28080
28105
  args.containerEl.addEventListener("scroll", onScroll);
28081
28106
  cleanupFns.push(() => args.containerEl.removeEventListener("scroll", onScroll));
@@ -28152,7 +28177,7 @@ stores.inject(MyMetaStore, storeInstance);
28152
28177
  this.moveDraggedItemToPosition(this.currentMousePosition + this.scrollOffset);
28153
28178
  }
28154
28179
  onMouseMove(ev) {
28155
- if (ev.button !== -1) {
28180
+ if (ev.button > 1) {
28156
28181
  this.onCancel();
28157
28182
  return;
28158
28183
  }
@@ -31322,14 +31347,14 @@ stores.inject(MyMetaStore, storeInstance);
31322
31347
  }
31323
31348
  onKeyDown(ev) {
31324
31349
  const figure = this.props.figure;
31325
- switch (ev.key) {
31350
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
31351
+ switch (keyDownShortcut) {
31326
31352
  case "Delete":
31327
31353
  this.env.model.dispatch("DELETE_FIGURE", {
31328
31354
  sheetId: this.env.model.getters.getActiveSheetId(),
31329
31355
  id: figure.id,
31330
31356
  });
31331
31357
  this.props.onFigureDeleted();
31332
- ev.stopPropagation();
31333
31358
  ev.preventDefault();
31334
31359
  ev.stopPropagation();
31335
31360
  break;
@@ -31350,7 +31375,22 @@ stores.inject(MyMetaStore, storeInstance);
31350
31375
  x: figure.x + delta[0],
31351
31376
  y: figure.y + delta[1],
31352
31377
  });
31378
+ ev.preventDefault();
31353
31379
  ev.stopPropagation();
31380
+ break;
31381
+ case "Ctrl+A":
31382
+ // Maybe in the future we will implement a way to select all figures
31383
+ ev.preventDefault();
31384
+ ev.stopPropagation();
31385
+ break;
31386
+ case "Ctrl+Y":
31387
+ case "Ctrl+Z":
31388
+ if (keyDownShortcut === "Ctrl+Y") {
31389
+ this.env.model.dispatch("REQUEST_REDO");
31390
+ }
31391
+ else if (keyDownShortcut === "Ctrl+Z") {
31392
+ this.env.model.dispatch("REQUEST_UNDO");
31393
+ }
31354
31394
  ev.preventDefault();
31355
31395
  ev.stopPropagation();
31356
31396
  break;
@@ -32393,8 +32433,15 @@ stores.inject(MyMetaStore, storeInstance);
32393
32433
  }
32394
32434
  onPaste(ev) {
32395
32435
  if (this.composerStore.editionMode !== "inactive") {
32436
+ // let the browser clipboard work
32396
32437
  ev.stopPropagation();
32397
32438
  }
32439
+ else {
32440
+ // the user meant to paste in the sheet, not open the composer with the pasted content
32441
+ // While we're not editing, we still have the focus and should therefore prevent
32442
+ // the native "paste" to occur.
32443
+ ev.preventDefault();
32444
+ }
32398
32445
  }
32399
32446
  /*
32400
32447
  * Triggered automatically by the content-editable between the keydown and key up
@@ -32403,9 +32450,6 @@ stores.inject(MyMetaStore, storeInstance);
32403
32450
  if (!this.shouldProcessInputEvents) {
32404
32451
  return;
32405
32452
  }
32406
- if (ev.inputType === "insertFromPaste" && this.composerStore.editionMode === "inactive") {
32407
- return;
32408
- }
32409
32453
  ev.stopPropagation();
32410
32454
  let content;
32411
32455
  if (this.composerStore.editionMode === "inactive") {
@@ -32772,10 +32816,7 @@ stores.inject(MyMetaStore, storeInstance);
32772
32816
  }
32773
32817
  get containerStyle() {
32774
32818
  if (this.composerStore.editionMode === "inactive") {
32775
- return `
32776
- position: absolute;
32777
- z-index: -1000;
32778
- `;
32819
+ return `z-index: -1000;`;
32779
32820
  }
32780
32821
  const isFormula = this.composerStore.currentContent.startsWith("=");
32781
32822
  const cell = this.env.model.getters.getActiveCell();
@@ -41138,12 +41179,6 @@ stores.inject(MyMetaStore, storeInstance);
41138
41179
  // detect when an argument need to be evaluated as a meta argument
41139
41180
  const isMeta = argTypes.includes("META");
41140
41181
  const hasRange = argTypes.some((t) => isRangeType(t));
41141
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
41142
- if (isRangeOnly) {
41143
- if (!isRangeInput(currentArg)) {
41144
- 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()));
41145
- }
41146
- }
41147
41182
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange, {
41148
41183
  functionName,
41149
41184
  paramIndex: i + 1,
@@ -41314,16 +41349,6 @@ stores.inject(MyMetaStore, storeInstance);
41314
41349
  function isRangeType(type) {
41315
41350
  return type.startsWith("RANGE");
41316
41351
  }
41317
- function isRangeInput(arg) {
41318
- if (arg.type === "REFERENCE") {
41319
- return true;
41320
- }
41321
- if (arg.type === "FUNCALL") {
41322
- const fnDef = functions$1[arg.value.toUpperCase()];
41323
- return fnDef && isRangeType(fnDef.returns[0]);
41324
- }
41325
- return false;
41326
- }
41327
41352
 
41328
41353
  const functions = functionRegistry.content;
41329
41354
  function isExportableToExcel(tokens) {
@@ -44061,6 +44086,9 @@ stores.inject(MyMetaStore, storeInstance);
44061
44086
  if (range.invalidXc) {
44062
44087
  return range.invalidXc;
44063
44088
  }
44089
+ if (!this.getters.tryGetSheet(range.sheetId)) {
44090
+ return CellErrorType.InvalidReference;
44091
+ }
44064
44092
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
44065
44093
  return CellErrorType.InvalidReference;
44066
44094
  }
@@ -47445,7 +47473,6 @@ stores.inject(MyMetaStore, storeInstance);
47445
47473
  *
47446
47474
  */
47447
47475
  class SpreadingRelation {
47448
- createEmptyPositionSet;
47449
47476
  /**
47450
47477
  * Internal structure:
47451
47478
  * For something like
@@ -47476,9 +47503,6 @@ stores.inject(MyMetaStore, storeInstance);
47476
47503
  */
47477
47504
  resultsToArrayFormulas = new PositionMap();
47478
47505
  arrayFormulasToResults = new PositionMap();
47479
- constructor(createEmptyPositionSet) {
47480
- this.createEmptyPositionSet = createEmptyPositionSet;
47481
- }
47482
47506
  getFormulaPositionsSpreadingOn(resultPosition) {
47483
47507
  return this.resultsToArrayFormulas.get(resultPosition) || EMPTY_ARRAY;
47484
47508
  }
@@ -47497,13 +47521,13 @@ stores.inject(MyMetaStore, storeInstance);
47497
47521
  */
47498
47522
  addRelation({ arrayFormulaPosition, resultPosition, }) {
47499
47523
  if (!this.resultsToArrayFormulas.has(resultPosition)) {
47500
- this.resultsToArrayFormulas.set(resultPosition, this.createEmptyPositionSet());
47524
+ this.resultsToArrayFormulas.set(resultPosition, []);
47501
47525
  }
47502
- this.resultsToArrayFormulas.get(resultPosition)?.add(arrayFormulaPosition);
47526
+ this.resultsToArrayFormulas.get(resultPosition)?.push(arrayFormulaPosition);
47503
47527
  if (!this.arrayFormulasToResults.has(arrayFormulaPosition)) {
47504
- this.arrayFormulasToResults.set(arrayFormulaPosition, this.createEmptyPositionSet());
47528
+ this.arrayFormulasToResults.set(arrayFormulaPosition, []);
47505
47529
  }
47506
- this.arrayFormulasToResults.get(arrayFormulaPosition)?.add(resultPosition);
47530
+ this.arrayFormulasToResults.get(arrayFormulaPosition)?.push(resultPosition);
47507
47531
  }
47508
47532
  hasArrayFormulaResult(position) {
47509
47533
  return this.resultsToArrayFormulas.has(position);
@@ -47524,7 +47548,7 @@ stores.inject(MyMetaStore, storeInstance);
47524
47548
  evaluatedCells = new PositionMap();
47525
47549
  formulaDependencies = lazy(new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this)));
47526
47550
  blockedArrayFormulas = new PositionSet({});
47527
- spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
47551
+ spreadingRelations = new SpreadingRelation();
47528
47552
  constructor(context, getters) {
47529
47553
  this.context = context;
47530
47554
  this.getters = getters;
@@ -47601,7 +47625,7 @@ stores.inject(MyMetaStore, storeInstance);
47601
47625
  }
47602
47626
  buildDependencyGraph() {
47603
47627
  this.blockedArrayFormulas = this.createEmptyPositionSet();
47604
- this.spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
47628
+ this.spreadingRelations = new SpreadingRelation();
47605
47629
  this.formulaDependencies = lazy(() => {
47606
47630
  const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position)
47607
47631
  .filter((range) => !range.invalidSheetName && !range.invalidXc)
@@ -48090,16 +48114,22 @@ stores.inject(MyMetaStore, storeInstance);
48090
48114
  let newContent = undefined;
48091
48115
  let newFormat = undefined;
48092
48116
  let isExported = true;
48117
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
48093
48118
  const formulaCell = this.getCorrespondingFormulaCell(position);
48094
48119
  if (formulaCell) {
48095
48120
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
48096
48121
  isFormula = isExported;
48097
48122
  if (!isExported) {
48098
- newContent = (value ?? "").toString();
48099
- newFormat = evaluatedCell.format;
48123
+ // If the cell contains a non-exported formula and that is evaluates to
48124
+ // nothing* ,we don't export it.
48125
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
48126
+ // the empty string.
48127
+ if (value !== "") {
48128
+ newContent = (value ?? "").toString();
48129
+ newFormat = evaluatedCell.format;
48130
+ }
48100
48131
  }
48101
48132
  }
48102
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
48103
48133
  const exportedCellData = exportedSheetData.cells[xc] || {};
48104
48134
  const format = newFormat
48105
48135
  ? getItemId(newFormat, data.formats)
@@ -52089,7 +52119,7 @@ stores.inject(MyMetaStore, storeInstance);
52089
52119
  paintFormatStatus = "inactive";
52090
52120
  originSheetId;
52091
52121
  copiedData;
52092
- _isCutOperation;
52122
+ _isCutOperation = false;
52093
52123
  // ---------------------------------------------------------------------------
52094
52124
  // Command Handling
52095
52125
  // ---------------------------------------------------------------------------
@@ -52101,14 +52131,17 @@ stores.inject(MyMetaStore, storeInstance);
52101
52131
  case "PASTE_FROM_OS_CLIPBOARD": {
52102
52132
  const copiedData = this.convertOSClipboardData(cmd.text);
52103
52133
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52104
- return this.isPasteAllowed(cmd.target, copiedData, { pasteOption });
52134
+ return this.isPasteAllowed(cmd.target, copiedData, { pasteOption, isCutOperation: false });
52105
52135
  }
52106
52136
  case "PASTE": {
52107
52137
  if (!this.copiedData) {
52108
52138
  return "EmptyClipboard" /* CommandResult.EmptyClipboard */;
52109
52139
  }
52110
52140
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52111
- return this.isPasteAllowed(cmd.target, this.copiedData, { pasteOption });
52141
+ return this.isPasteAllowed(cmd.target, this.copiedData, {
52142
+ pasteOption: pasteOption,
52143
+ isCutOperation: this._isCutOperation,
52144
+ });
52112
52145
  }
52113
52146
  case "COPY_PASTE_CELLS_ABOVE": {
52114
52147
  const zones = this.getters.getSelectedZones();
@@ -52126,13 +52159,13 @@ stores.inject(MyMetaStore, storeInstance);
52126
52159
  }
52127
52160
  case "INSERT_CELL": {
52128
52161
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
52129
- const copiedData = this.copy("CUT", cut);
52130
- return this.isPasteAllowed(paste, copiedData, {});
52162
+ const copiedData = this.copy(cut);
52163
+ return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
52131
52164
  }
52132
52165
  case "DELETE_CELL": {
52133
52166
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
52134
- const copiedData = this.copy("CUT", cut);
52135
- return this.isPasteAllowed(paste, copiedData, {});
52167
+ const copiedData = this.copy(cut);
52168
+ return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
52136
52169
  }
52137
52170
  case "ACTIVATE_PAINT_FORMAT": {
52138
52171
  if (this.paintFormatStatus !== "inactive") {
@@ -52150,23 +52183,27 @@ stores.inject(MyMetaStore, storeInstance);
52150
52183
  const zones = this.getters.getSelectedZones();
52151
52184
  this.status = "visible";
52152
52185
  this.originSheetId = this.getters.getActiveSheetId();
52153
- this.copiedData = this.copy(cmd.type, zones);
52186
+ this.copiedData = this.copy(zones);
52187
+ this._isCutOperation = cmd.type === "CUT";
52154
52188
  break;
52155
52189
  case "PASTE_FROM_OS_CLIPBOARD": {
52190
+ this._isCutOperation = false;
52156
52191
  this.copiedData = this.convertOSClipboardData(cmd.text);
52157
52192
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52158
- this.paste(cmd.target, {
52193
+ this.paste(cmd.target, this.copiedData, {
52159
52194
  pasteOption,
52160
52195
  selectTarget: true,
52196
+ isCutOperation: false,
52161
52197
  });
52162
52198
  this.status = "invisible";
52163
52199
  break;
52164
52200
  }
52165
52201
  case "PASTE": {
52166
52202
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52167
- this.paste(cmd.target, {
52203
+ this.paste(cmd.target, this.copiedData, {
52168
52204
  pasteOption,
52169
52205
  selectTarget: true,
52206
+ isCutOperation: this._isCutOperation,
52170
52207
  });
52171
52208
  if (this.paintFormatStatus === "oneOff") {
52172
52209
  this.paintFormatStatus = "inactive";
@@ -52187,9 +52224,9 @@ stores.inject(MyMetaStore, storeInstance);
52187
52224
  top: multipleRowsInSelection ? zone.top : zone.top - 1,
52188
52225
  };
52189
52226
  this.originSheetId = this.getters.getActiveSheetId();
52190
- this.copiedData = this.copy("COPY", [copyTarget]);
52191
- this.paste([zone], {
52192
- pasteOption: undefined,
52227
+ const copiedData = this.copy([copyTarget]);
52228
+ this.paste([zone], copiedData, {
52229
+ isCutOperation: false,
52193
52230
  selectTarget: true,
52194
52231
  });
52195
52232
  }
@@ -52204,9 +52241,9 @@ stores.inject(MyMetaStore, storeInstance);
52204
52241
  left: multipleColsInSelection ? zone.left : zone.left - 1,
52205
52242
  };
52206
52243
  this.originSheetId = this.getters.getActiveSheetId();
52207
- this.copiedData = this.copy("COPY", [copyTarget]);
52208
- this.paste([zone], {
52209
- pasteOption: undefined,
52244
+ const copiedData = this.copy([copyTarget]);
52245
+ this.paste([zone], copiedData, {
52246
+ isCutOperation: false,
52210
52247
  selectTarget: true,
52211
52248
  });
52212
52249
  }
@@ -52222,14 +52259,14 @@ stores.inject(MyMetaStore, storeInstance);
52222
52259
  }
52223
52260
  break;
52224
52261
  }
52225
- this.copiedData = this.copy("CUT", cut);
52226
- this.paste(paste, {});
52262
+ const copiedData = this.copy(cut);
52263
+ this.paste(paste, copiedData, { isCutOperation: true });
52227
52264
  break;
52228
52265
  }
52229
52266
  case "INSERT_CELL": {
52230
52267
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
52231
- this.copiedData = this.copy("CUT", cut);
52232
- this.paste(paste, {});
52268
+ const copiedData = this.copy(cut);
52269
+ this.paste(paste, copiedData, { isCutOperation: true });
52233
52270
  break;
52234
52271
  }
52235
52272
  case "ADD_COLUMNS_ROWS": {
@@ -52261,7 +52298,8 @@ stores.inject(MyMetaStore, storeInstance);
52261
52298
  break;
52262
52299
  }
52263
52300
  case "REPEAT_PASTE": {
52264
- this.paste(cmd.target, {
52301
+ this.paste(cmd.target, this.copiedData, {
52302
+ isCutOperation: false,
52265
52303
  pasteOption: cmd.pasteOption,
52266
52304
  selectTarget: true,
52267
52305
  });
@@ -52269,7 +52307,7 @@ stores.inject(MyMetaStore, storeInstance);
52269
52307
  }
52270
52308
  case "ACTIVATE_PAINT_FORMAT": {
52271
52309
  const zones = this.getters.getSelectedZones();
52272
- this.copiedData = this.copy("COPY", zones);
52310
+ this.copiedData = this.copy(zones);
52273
52311
  this.status = "visible";
52274
52312
  if (cmd.persistent) {
52275
52313
  this.paintFormatStatus = "persistent";
@@ -52300,7 +52338,6 @@ stores.inject(MyMetaStore, storeInstance);
52300
52338
  }
52301
52339
  }
52302
52340
  convertOSClipboardData(clipboardData) {
52303
- this._isCutOperation = false;
52304
52341
  const handlers = clipboardHandlersRegistries.figureHandlers
52305
52342
  .getAll()
52306
52343
  .map((handler) => new handler(this.getters, this.dispatch));
@@ -52338,7 +52375,6 @@ stores.inject(MyMetaStore, storeInstance);
52338
52375
  for (const handler of this.selectClipboardHandlers(copiedData)) {
52339
52376
  const result = handler.isPasteAllowed(this.getters.getActiveSheetId(), target, copiedData, {
52340
52377
  ...options,
52341
- isCutOperation: this.isCutOperation(),
52342
52378
  });
52343
52379
  if (result !== "Success" /* CommandResult.Success */) {
52344
52380
  return result;
@@ -52361,9 +52397,8 @@ stores.inject(MyMetaStore, storeInstance);
52361
52397
  }
52362
52398
  return false;
52363
52399
  }
52364
- copy(operation, zones) {
52400
+ copy(zones) {
52365
52401
  let copiedData = {};
52366
- this._isCutOperation = operation === "CUT";
52367
52402
  const clipboardData = this.getClipboardData(zones);
52368
52403
  for (const handler of this.selectClipboardHandlers(clipboardData)) {
52369
52404
  const data = handler.copy(clipboardData);
@@ -52371,8 +52406,8 @@ stores.inject(MyMetaStore, storeInstance);
52371
52406
  }
52372
52407
  return copiedData;
52373
52408
  }
52374
- paste(zones, options) {
52375
- if (!this.copiedData) {
52409
+ paste(zones, copiedData, options) {
52410
+ if (!copiedData) {
52376
52411
  return;
52377
52412
  }
52378
52413
  let zone = undefined;
@@ -52380,12 +52415,9 @@ stores.inject(MyMetaStore, storeInstance);
52380
52415
  let target = {
52381
52416
  zones,
52382
52417
  };
52383
- const handlers = this.selectClipboardHandlers(this.copiedData);
52418
+ const handlers = this.selectClipboardHandlers(copiedData);
52384
52419
  for (const handler of handlers) {
52385
- const currentTarget = handler.getPasteTarget(zones, this.copiedData, {
52386
- ...options,
52387
- isCutOperation: this.isCutOperation(),
52388
- });
52420
+ const currentTarget = handler.getPasteTarget(zones, copiedData, options);
52389
52421
  if (currentTarget.figureId) {
52390
52422
  target.figureId = currentTarget.figureId;
52391
52423
  }
@@ -52401,7 +52433,7 @@ stores.inject(MyMetaStore, storeInstance);
52401
52433
  if (zone !== undefined) {
52402
52434
  this.addMissingDimensions(this.getters.getActiveSheetId(), zone.right - zone.left + 1, zone.bottom - zone.top + 1, zone.left, zone.top);
52403
52435
  }
52404
- handlers.forEach((handler) => handler.paste(target, this.copiedData, { ...options, isCutOperation: this.isCutOperation() }));
52436
+ handlers.forEach((handler) => handler.paste(target, copiedData, options));
52405
52437
  if (!options?.selectTarget) {
52406
52438
  return;
52407
52439
  }
@@ -54871,6 +54903,7 @@ stores.inject(MyMetaStore, storeInstance);
54871
54903
  sheetDivRef = owl.useRef("sheetDiv");
54872
54904
  sheetNameRef = owl.useRef("sheetNameSpan");
54873
54905
  editionState = "initializing";
54906
+ DOMFocusableElementStore;
54874
54907
  setup() {
54875
54908
  owl.onMounted(() => {
54876
54909
  if (this.isSheetActive) {
@@ -54883,6 +54916,7 @@ stores.inject(MyMetaStore, storeInstance);
54883
54916
  this.focusInputAndSelectContent();
54884
54917
  }
54885
54918
  });
54919
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
54886
54920
  }
54887
54921
  focusInputAndSelectContent() {
54888
54922
  if (!this.state.isEditing || !this.sheetNameRef.el)
@@ -54924,9 +54958,11 @@ stores.inject(MyMetaStore, storeInstance);
54924
54958
  if (ev.key === "Enter") {
54925
54959
  ev.preventDefault();
54926
54960
  this.stopEdition();
54961
+ this.DOMFocusableElementStore.focus();
54927
54962
  }
54928
54963
  if (ev.key === "Escape") {
54929
54964
  this.cancelEdition();
54965
+ this.DOMFocusableElementStore.focus();
54930
54966
  }
54931
54967
  }
54932
54968
  onClickSheetName(ev) {
@@ -59649,7 +59685,11 @@ stores.inject(MyMetaStore, storeInstance);
59649
59685
  let cellNode = escapeXml ``;
59650
59686
  // Either formula or static value inside the cell
59651
59687
  if (cell.isFormula) {
59652
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
59688
+ const res = addFormula(cell);
59689
+ if (!res) {
59690
+ continue;
59691
+ }
59692
+ ({ attrs: additionalAttrs, node: cellNode } = res);
59653
59693
  }
59654
59694
  else if (cell.content && isMarkdownLink(cell.content)) {
59655
59695
  const { label } = parseMarkdownLink(cell.content);
@@ -60729,9 +60769,9 @@ stores.inject(MyMetaStore, storeInstance);
60729
60769
  exports.tokenize = tokenize;
60730
60770
 
60731
60771
 
60732
- __info__.version = "17.2.8";
60733
- __info__.date = "2024-05-24T11:29:49.320Z";
60734
- __info__.hash = "bfbcaa0";
60772
+ __info__.version = "17.2.10";
60773
+ __info__.date = "2024-06-10T09:38:54.354Z";
60774
+ __info__.hash = "14317ee";
60735
60775
 
60736
60776
 
60737
60777
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);