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