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