@odoo/o-spreadsheet 17.2.14 → 17.2.16

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.14
7
- * @date 2024-07-02T10:35:53.850Z
8
- * @hash fb0d979
6
+ * @version 17.2.16
7
+ * @date 2024-07-11T06:38:53.101Z
8
+ * @hash 9f20685
9
9
  */
10
10
 
11
11
  (function (exports, owl) {
@@ -576,7 +576,7 @@
576
576
  /**
577
577
  * Compares two objects.
578
578
  */
579
- function deepEquals(o1, o2, ignoreFunctions) {
579
+ function deepEquals(o1, o2) {
580
580
  if (o1 === o2)
581
581
  return true;
582
582
  if ((o1 && !o2) || (o2 && !o1))
@@ -592,17 +592,13 @@
592
592
  }
593
593
  }
594
594
  for (const key in o1) {
595
- const typeOfO1Key = typeof o1[key];
596
- if (typeOfO1Key !== typeof o2[key])
595
+ if (typeof o1[key] !== typeof o2[key])
597
596
  return false;
598
- if (typeOfO1Key === "object") {
599
- if (!deepEquals(o1[key], o2[key], ignoreFunctions))
597
+ if (typeof o1[key] === "object") {
598
+ if (!deepEquals(o1[key], o2[key]))
600
599
  return false;
601
600
  }
602
601
  else {
603
- if (ignoreFunctions && typeOfO1Key === "function") {
604
- continue;
605
- }
606
602
  if (o1[key] !== o2[key])
607
603
  return false;
608
604
  }
@@ -1751,7 +1747,7 @@
1751
1747
  });
1752
1748
  const getNumberRegex = memoize(function getNumberRegex(locale) {
1753
1749
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
1754
- const thousandsSeparator = escapeRegExp(locale.thousandsSeparator);
1750
+ const thousandsSeparator = escapeRegExp(locale.thousandsSeparator || "");
1755
1751
  const pIntegerAndDecimals = `(\\d+(${thousandsSeparator}\\d{3,})*(${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
1756
1752
  const pOnlyDecimals = `(${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
1757
1753
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -1778,7 +1774,7 @@
1778
1774
  return getNumberRegex(locale).test(value.trim());
1779
1775
  }
1780
1776
  const getInvaluableSymbolsRegexp = memoize(function getInvaluableSymbolsRegexp(locale) {
1781
- return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator)}]`, "g");
1777
+ return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator || "")}]`, "g");
1782
1778
  });
1783
1779
  /**
1784
1780
  * Convert a string into a number. It assumes that the string actually represents
@@ -2647,6 +2643,9 @@
2647
2643
  * If the character is a special regular expression character, it is escaped with "\\".
2648
2644
  */
2649
2645
  const wildcardToRegExp = memoize(function wildcardToRegExp(operand) {
2646
+ if (operand === "*") {
2647
+ return /.+/;
2648
+ }
2650
2649
  let exp = "";
2651
2650
  let predecessor = "";
2652
2651
  for (let char of operand) {
@@ -2670,9 +2669,9 @@
2670
2669
  }
2671
2670
  return new RegExp("^" + exp + "$", "i");
2672
2671
  });
2673
- function evaluatePredicate(value, criterion) {
2672
+ function evaluatePredicate(value = "", criterion) {
2674
2673
  const { operator, operand } = criterion;
2675
- if (value === undefined || operand === undefined || value === null || operand === null) {
2674
+ if (operand === undefined || value === null || operand === null) {
2676
2675
  return false;
2677
2676
  }
2678
2677
  if (typeof operand === "number" && operator === "=") {
@@ -5358,19 +5357,22 @@
5358
5357
  }
5359
5358
 
5360
5359
  function isValidLocale(locale) {
5361
- if (!(locale &&
5362
- typeof locale === "object" &&
5363
- typeof locale.name === "string" &&
5364
- typeof locale.code === "string" &&
5365
- typeof locale.thousandsSeparator === "string" &&
5366
- typeof locale.decimalSeparator === "string" &&
5367
- typeof locale.dateFormat === "string" &&
5368
- typeof locale.timeFormat === "string" &&
5369
- typeof locale.formulaArgSeparator === "string")) {
5360
+ if (!locale ||
5361
+ typeof locale !== "object" ||
5362
+ !(!locale.thousandsSeparator || typeof locale.thousandsSeparator === "string")) {
5370
5363
  return false;
5371
5364
  }
5372
- if (!Object.values(locale).every((v) => v)) {
5373
- return false;
5365
+ for (const property of [
5366
+ "code",
5367
+ "name",
5368
+ "decimalSeparator",
5369
+ "dateFormat",
5370
+ "timeFormat",
5371
+ "formulaArgSeparator",
5372
+ ]) {
5373
+ if (!locale[property] || typeof locale[property] !== "string") {
5374
+ return false;
5375
+ }
5374
5376
  }
5375
5377
  if (locale.formulaArgSeparator === locale.decimalSeparator) {
5376
5378
  return false;
@@ -5468,7 +5470,10 @@
5468
5470
  if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
5469
5471
  return content;
5470
5472
  }
5471
- return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
5473
+ if (locale.thousandsSeparator) {
5474
+ content = content.replaceAll(locale.thousandsSeparator, "");
5475
+ }
5476
+ return content.replace(locale.decimalSeparator, ".");
5472
5477
  }
5473
5478
  /**
5474
5479
  * Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
@@ -6452,6 +6457,146 @@
6452
6457
  return undefined;
6453
6458
  }
6454
6459
 
6460
+ var State;
6461
+ (function (State) {
6462
+ /**
6463
+ * Initial state.
6464
+ * Expecting any reference for the left part of a range
6465
+ * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
6466
+ */
6467
+ State[State["LeftRef"] = 0] = "LeftRef";
6468
+ /**
6469
+ * Expecting any reference for the right part of a range
6470
+ * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
6471
+ */
6472
+ State[State["RightRef"] = 1] = "RightRef";
6473
+ /**
6474
+ * Expecting the separator without any constraint on the right part
6475
+ */
6476
+ State[State["Separator"] = 2] = "Separator";
6477
+ /**
6478
+ * Expecting the separator for a full column range
6479
+ */
6480
+ State[State["FullColumnSeparator"] = 3] = "FullColumnSeparator";
6481
+ /**
6482
+ * Expecting the separator for a full row range
6483
+ */
6484
+ State[State["FullRowSeparator"] = 4] = "FullRowSeparator";
6485
+ /**
6486
+ * Expecting the right part of a full column range
6487
+ * e.g. "1", "A1"
6488
+ */
6489
+ State[State["RightColumnRef"] = 5] = "RightColumnRef";
6490
+ /**
6491
+ * Expecting the right part of a full row range
6492
+ * e.g. "A", "A1"
6493
+ */
6494
+ State[State["RightRowRef"] = 6] = "RightRowRef";
6495
+ /**
6496
+ * Final state. A range has been matched
6497
+ */
6498
+ State[State["Found"] = 7] = "Found";
6499
+ })(State || (State = {}));
6500
+ const goTo = (state, guard = () => true) => [
6501
+ {
6502
+ goTo: state,
6503
+ guard,
6504
+ },
6505
+ ];
6506
+ const goToMulti = (state, guard = () => true) => ({
6507
+ goTo: state,
6508
+ guard,
6509
+ });
6510
+ const machine = {
6511
+ [State.LeftRef]: {
6512
+ REFERENCE: goTo(State.Separator),
6513
+ NUMBER: goTo(State.FullRowSeparator),
6514
+ SYMBOL: [
6515
+ goToMulti(State.FullColumnSeparator, (token) => isColReference(token.value)),
6516
+ goToMulti(State.FullRowSeparator, (token) => isRowReference(token.value)),
6517
+ ],
6518
+ },
6519
+ [State.FullColumnSeparator]: {
6520
+ SPACE: goTo(State.FullColumnSeparator),
6521
+ OPERATOR: goTo(State.RightColumnRef, (token) => token.value === ":"),
6522
+ },
6523
+ [State.FullRowSeparator]: {
6524
+ SPACE: goTo(State.FullRowSeparator),
6525
+ OPERATOR: goTo(State.RightRowRef, (token) => token.value === ":"),
6526
+ },
6527
+ [State.Separator]: {
6528
+ SPACE: goTo(State.Separator),
6529
+ OPERATOR: goTo(State.RightRef, (token) => token.value === ":"),
6530
+ },
6531
+ [State.RightRef]: {
6532
+ SPACE: goTo(State.RightRef),
6533
+ NUMBER: goTo(State.Found),
6534
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
6535
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
6536
+ },
6537
+ [State.RightColumnRef]: {
6538
+ SPACE: goTo(State.RightColumnRef),
6539
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
6540
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
6541
+ },
6542
+ [State.RightRowRef]: {
6543
+ SPACE: goTo(State.RightRowRef),
6544
+ NUMBER: goTo(State.Found),
6545
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
6546
+ SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
6547
+ },
6548
+ [State.Found]: {},
6549
+ };
6550
+ /**
6551
+ * Check if the list of tokens starts with a sequence of tokens representing
6552
+ * a range.
6553
+ * If a range is found, the sequence is removed from the list and is returned
6554
+ * as a single token.
6555
+ */
6556
+ function matchReference(tokens) {
6557
+ let head = 0;
6558
+ let transitions = machine[State.LeftRef];
6559
+ let matchedTokens = "";
6560
+ while (transitions !== undefined) {
6561
+ const token = tokens[head++];
6562
+ if (!token) {
6563
+ return null;
6564
+ }
6565
+ const transition = transitions[token.type]?.find((transition) => transition.guard(token));
6566
+ const nextState = transition ? transition.goTo : undefined;
6567
+ switch (nextState) {
6568
+ case undefined:
6569
+ return null;
6570
+ case State.Found:
6571
+ matchedTokens += token.value;
6572
+ tokens.splice(0, head);
6573
+ return {
6574
+ type: "REFERENCE",
6575
+ value: matchedTokens,
6576
+ };
6577
+ default:
6578
+ transitions = machine[nextState];
6579
+ matchedTokens += token.value;
6580
+ break;
6581
+ }
6582
+ }
6583
+ return null;
6584
+ }
6585
+ /**
6586
+ * Take the result of the tokenizer and transform it to be usable in the
6587
+ * manipulations of range
6588
+ *
6589
+ * @param formula
6590
+ */
6591
+ function rangeTokenize(formula, locale = DEFAULT_LOCALE) {
6592
+ const tokens = tokenize(formula, locale);
6593
+ const result = [];
6594
+ while (tokens.length) {
6595
+ result.push(matchReference(tokens) || tokens.shift());
6596
+ }
6597
+ return result;
6598
+ }
6599
+
6455
6600
  const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
6456
6601
  const UNARY_OPERATORS_PREFIX = ["-", "+"];
6457
6602
  const UNARY_OPERATORS_POSTFIX = ["%"];
@@ -6600,7 +6745,7 @@
6600
6745
  * Parse an expression (as a string) into an AST.
6601
6746
  */
6602
6747
  function parse(str) {
6603
- return parseTokens(tokenize(str));
6748
+ return parseTokens(rangeTokenize(str));
6604
6749
  }
6605
6750
  function parseTokens(tokens) {
6606
6751
  tokens = tokens.filter((x) => x.type !== "SPACE");
@@ -6736,146 +6881,6 @@
6736
6881
  return needParenthesis ? `(${astToFormula(rightOperation)})` : astToFormula(rightOperation);
6737
6882
  }
6738
6883
 
6739
- var State;
6740
- (function (State) {
6741
- /**
6742
- * Initial state.
6743
- * Expecting any reference for the left part of a range
6744
- * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
6745
- */
6746
- State[State["LeftRef"] = 0] = "LeftRef";
6747
- /**
6748
- * Expecting any reference for the right part of a range
6749
- * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
6750
- */
6751
- State[State["RightRef"] = 1] = "RightRef";
6752
- /**
6753
- * Expecting the separator without any constraint on the right part
6754
- */
6755
- State[State["Separator"] = 2] = "Separator";
6756
- /**
6757
- * Expecting the separator for a full column range
6758
- */
6759
- State[State["FullColumnSeparator"] = 3] = "FullColumnSeparator";
6760
- /**
6761
- * Expecting the separator for a full row range
6762
- */
6763
- State[State["FullRowSeparator"] = 4] = "FullRowSeparator";
6764
- /**
6765
- * Expecting the right part of a full column range
6766
- * e.g. "1", "A1"
6767
- */
6768
- State[State["RightColumnRef"] = 5] = "RightColumnRef";
6769
- /**
6770
- * Expecting the right part of a full row range
6771
- * e.g. "A", "A1"
6772
- */
6773
- State[State["RightRowRef"] = 6] = "RightRowRef";
6774
- /**
6775
- * Final state. A range has been matched
6776
- */
6777
- State[State["Found"] = 7] = "Found";
6778
- })(State || (State = {}));
6779
- const goTo = (state, guard = () => true) => [
6780
- {
6781
- goTo: state,
6782
- guard,
6783
- },
6784
- ];
6785
- const goToMulti = (state, guard = () => true) => ({
6786
- goTo: state,
6787
- guard,
6788
- });
6789
- const machine = {
6790
- [State.LeftRef]: {
6791
- REFERENCE: goTo(State.Separator),
6792
- NUMBER: goTo(State.FullRowSeparator),
6793
- SYMBOL: [
6794
- goToMulti(State.FullColumnSeparator, (token) => isColReference(token.value)),
6795
- goToMulti(State.FullRowSeparator, (token) => isRowReference(token.value)),
6796
- ],
6797
- },
6798
- [State.FullColumnSeparator]: {
6799
- SPACE: goTo(State.FullColumnSeparator),
6800
- OPERATOR: goTo(State.RightColumnRef, (token) => token.value === ":"),
6801
- },
6802
- [State.FullRowSeparator]: {
6803
- SPACE: goTo(State.FullRowSeparator),
6804
- OPERATOR: goTo(State.RightRowRef, (token) => token.value === ":"),
6805
- },
6806
- [State.Separator]: {
6807
- SPACE: goTo(State.Separator),
6808
- OPERATOR: goTo(State.RightRef, (token) => token.value === ":"),
6809
- },
6810
- [State.RightRef]: {
6811
- SPACE: goTo(State.RightRef),
6812
- NUMBER: goTo(State.Found),
6813
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
6814
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
6815
- },
6816
- [State.RightColumnRef]: {
6817
- SPACE: goTo(State.RightColumnRef),
6818
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
6819
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
6820
- },
6821
- [State.RightRowRef]: {
6822
- SPACE: goTo(State.RightRowRef),
6823
- NUMBER: goTo(State.Found),
6824
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
6825
- SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
6826
- },
6827
- [State.Found]: {},
6828
- };
6829
- /**
6830
- * Check if the list of tokens starts with a sequence of tokens representing
6831
- * a range.
6832
- * If a range is found, the sequence is removed from the list and is returned
6833
- * as a single token.
6834
- */
6835
- function matchReference(tokens) {
6836
- let head = 0;
6837
- let transitions = machine[State.LeftRef];
6838
- let matchedTokens = "";
6839
- while (transitions !== undefined) {
6840
- const token = tokens[head++];
6841
- if (!token) {
6842
- return null;
6843
- }
6844
- const transition = transitions[token.type]?.find((transition) => transition.guard(token));
6845
- const nextState = transition ? transition.goTo : undefined;
6846
- switch (nextState) {
6847
- case undefined:
6848
- return null;
6849
- case State.Found:
6850
- matchedTokens += token.value;
6851
- tokens.splice(0, head);
6852
- return {
6853
- type: "REFERENCE",
6854
- value: matchedTokens,
6855
- };
6856
- default:
6857
- transitions = machine[nextState];
6858
- matchedTokens += token.value;
6859
- break;
6860
- }
6861
- }
6862
- return null;
6863
- }
6864
- /**
6865
- * Take the result of the tokenizer and transform it to be usable in the
6866
- * manipulations of range
6867
- *
6868
- * @param formula
6869
- */
6870
- function rangeTokenize(formula, locale = DEFAULT_LOCALE) {
6871
- const tokens = tokenize(formula, locale);
6872
- const result = [];
6873
- while (tokens.length) {
6874
- result.push(matchReference(tokens) || tokens.shift());
6875
- }
6876
- return result;
6877
- }
6878
-
6879
6884
  /**
6880
6885
  * Add the following information on tokens:
6881
6886
  * - length
@@ -9199,7 +9204,6 @@ stores.inject(MyMetaStore, storeInstance);
9199
9204
  };
9200
9205
  canvas = owl.useRef("graphContainer");
9201
9206
  chart;
9202
- currentRuntime;
9203
9207
  get background() {
9204
9208
  return this.chartRuntime.background;
9205
9209
  }
@@ -9216,18 +9220,11 @@ stores.inject(MyMetaStore, storeInstance);
9216
9220
  setup() {
9217
9221
  owl.onMounted(() => {
9218
9222
  const runtime = this.chartRuntime;
9219
- this.currentRuntime = runtime;
9220
9223
  // Note: chartJS modify the runtime in place, so it's important to give it a copy
9221
9224
  this.createChart(deepCopy(runtime.chartJsConfig));
9222
9225
  });
9223
9226
  owl.onWillUnmount(() => this.chart?.destroy());
9224
- owl.useEffect(() => {
9225
- const runtime = this.chartRuntime;
9226
- if (!deepEquals(runtime, this.currentRuntime, "ignoreFunctions")) {
9227
- this.currentRuntime = runtime;
9228
- this.updateChartJs(deepCopy(runtime));
9229
- }
9230
- });
9227
+ owl.useEffect(() => this.updateChartJs(deepCopy(this.chartRuntime)), () => [this.chartRuntime]);
9231
9228
  }
9232
9229
  createChart(chartData) {
9233
9230
  const canvas = this.canvas.el;
@@ -19629,7 +19626,7 @@ stores.inject(MyMetaStore, storeInstance);
19629
19626
  /**
19630
19627
  * Get a default chart js configuration
19631
19628
  */
19632
- function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, truncateLabels }) {
19629
+ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, truncateLabels = true }) {
19633
19630
  const options = {
19634
19631
  // https://www.chartjs.org/docs/latest/general/responsive.html
19635
19632
  responsive: true,
@@ -20547,10 +20544,6 @@ stores.inject(MyMetaStore, storeInstance);
20547
20544
  const cumulative = "cumulative" in chart ? chart.cumulative : false;
20548
20545
  const colors = new ChartColors();
20549
20546
  for (let [index, { label, data }] of dataSetsValues.entries()) {
20550
- if (["linear", "time"].includes(axisType)) {
20551
- // Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
20552
- data = data.map((y, index) => ({ x: labels[index] || undefined, y }));
20553
- }
20554
20547
  const color = colors.next();
20555
20548
  let backgroundRGBA = colorToRGBA(color);
20556
20549
  if (stacked) {
@@ -20566,6 +20559,10 @@ stores.inject(MyMetaStore, storeInstance);
20566
20559
  return value;
20567
20560
  });
20568
20561
  }
20562
+ if (["linear", "time"].includes(axisType)) {
20563
+ // Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
20564
+ data = data.map((y, index) => ({ x: labels[index] || undefined, y }));
20565
+ }
20569
20566
  const backgroundColor = rgbaToHex(backgroundRGBA);
20570
20567
  const dataset = {
20571
20568
  label,
@@ -30423,7 +30420,13 @@ stores.inject(MyMetaStore, storeInstance);
30423
30420
  }
30424
30421
  async loadLocales() {
30425
30422
  this.loadedLocales = (await this.env.loadLocales())
30426
- .filter(isValidLocale)
30423
+ .filter((locale) => {
30424
+ const isValid = isValidLocale(locale);
30425
+ if (!isValid) {
30426
+ console.warn(`Invalid locale: ${locale["code"]} ${locale}`);
30427
+ }
30428
+ return isValid;
30429
+ })
30427
30430
  .sort((a, b) => a.name.localeCompare(b.name));
30428
30431
  }
30429
30432
  get numberFormatPreview() {
@@ -36231,6 +36234,7 @@ stores.inject(MyMetaStore, storeInstance);
36231
36234
  return;
36232
36235
  }
36233
36236
  if (clipboardData.types.indexOf(ClipboardMIMEType.PlainText) > -1) {
36237
+ ev.preventDefault();
36234
36238
  const content = clipboardData.getData(ClipboardMIMEType.PlainText);
36235
36239
  const target = this.env.model.getters.getSelectedZones();
36236
36240
  const clipboardString = this.env.model.getters.getClipboardTextContent();
@@ -40807,6 +40811,21 @@ stores.inject(MyMetaStore, storeInstance);
40807
40811
  return [];
40808
40812
  return Object.keys(sheetBorders).map((index) => parseInt(index, 10));
40809
40813
  }
40814
+ /**
40815
+ * Get all the rows which contains at least a border
40816
+ */
40817
+ getRowsWithBorders(sheetId) {
40818
+ const sheetBorders = this.borders[sheetId]?.filter(isDefined$1);
40819
+ if (!sheetBorders)
40820
+ return [];
40821
+ const rowsWithBorders = new Set();
40822
+ for (const rowBorders of sheetBorders) {
40823
+ for (const rowBorder in rowBorders) {
40824
+ rowsWithBorders.add(parseInt(rowBorder, 10));
40825
+ }
40826
+ }
40827
+ return Array.from(rowsWithBorders);
40828
+ }
40810
40829
  /**
40811
40830
  * Get the range of all the rows in the sheet
40812
40831
  */
@@ -40856,7 +40875,7 @@ stores.inject(MyMetaStore, storeInstance);
40856
40875
  destructive: false,
40857
40876
  });
40858
40877
  }
40859
- this.getRowsRange(sheetId)
40878
+ this.getRowsWithBorders(sheetId)
40860
40879
  .filter((row) => row >= start)
40861
40880
  .sort((a, b) => (delta < 0 ? a - b : b - a)) // start by the end when moving up
40862
40881
  .forEach((row) => {
@@ -47479,7 +47498,7 @@ stores.inject(MyMetaStore, storeInstance);
47479
47498
  return this.sheets[position.sheetId].getValue(position) === 1;
47480
47499
  }
47481
47500
  clear() {
47482
- const insertions = this.insertions;
47501
+ const insertions = [...this];
47483
47502
  this.insertions = [];
47484
47503
  for (const sheetId in this.sheets) {
47485
47504
  this.sheets[sheetId].clear();
@@ -47797,6 +47816,7 @@ stores.inject(MyMetaStore, storeInstance);
47797
47816
  }
47798
47817
  finally {
47799
47818
  this.cellsBeingComputed.delete(cellId);
47819
+ this.nextPositionsToUpdate.delete(position);
47800
47820
  }
47801
47821
  }
47802
47822
  computeAndSave(position) {
@@ -47821,8 +47841,33 @@ stores.inject(MyMetaStore, storeInstance);
47821
47841
  forEachSpreadPositionInMatrix(nbColumns, nbRows,
47822
47842
  // thanks to the isMatrix check above, we know that formulaReturn is MatrixFunctionReturn
47823
47843
  this.spreadValues(formulaPosition, formulaReturn));
47844
+ this.invalidatePositionsDependingOnSpread(formulaPosition, nbColumns, nbRows);
47824
47845
  return createEvaluatedCell(nullValueToZeroValue(formulaReturn[0][0]), this.getters.getLocale(), cellData);
47825
47846
  }
47847
+ invalidatePositionsDependingOnSpread(arrayFormulaPosition, nbColumns, nbRows) {
47848
+ // the result matrix is split in 2 zones to exclude the array formula position
47849
+ const top = arrayFormulaPosition.row;
47850
+ const left = arrayFormulaPosition.col;
47851
+ const bottom = top + nbRows - 1;
47852
+ const leftColumnZone = {
47853
+ top: top + 1,
47854
+ bottom,
47855
+ left,
47856
+ right: left,
47857
+ };
47858
+ const rightPartZone = {
47859
+ top,
47860
+ bottom,
47861
+ left: left + 1,
47862
+ right: left + nbColumns - 1,
47863
+ };
47864
+ const sheetId = arrayFormulaPosition.sheetId;
47865
+ const invalidatedPositions = this.formulaDependencies().getCellsDependingOn([
47866
+ { sheetId, zone: rightPartZone },
47867
+ { sheetId, zone: leftColumnZone },
47868
+ ]);
47869
+ this.nextPositionsToUpdate.addMany(invalidatedPositions);
47870
+ }
47826
47871
  assertSheetHasEnoughSpaceToSpreadFormulaResult({ sheetId, col, row }, matrixResult) {
47827
47872
  const numberOfCols = this.getters.getNumberCols(sheetId);
47828
47873
  const numberOfRows = this.getters.getNumberRows(sheetId);
@@ -47865,9 +47910,6 @@ stores.inject(MyMetaStore, storeInstance);
47865
47910
  const cell = this.getters.getCell(position);
47866
47911
  const evaluatedCell = createEvaluatedCell(nullValueToZeroValue(matrixResult[i][j]), this.getters.getLocale(), cell);
47867
47912
  this.evaluatedCells.set(position, evaluatedCell);
47868
- // check if formula dependencies present in the spread zone
47869
- // if so, they need to be recomputed
47870
- this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([position]));
47871
47913
  };
47872
47914
  }
47873
47915
  invalidateSpreading(position) {
@@ -60840,9 +60882,9 @@ stores.inject(MyMetaStore, storeInstance);
60840
60882
  exports.tokenize = tokenize;
60841
60883
 
60842
60884
 
60843
- __info__.version = "17.2.14";
60844
- __info__.date = "2024-07-02T10:35:53.850Z";
60845
- __info__.hash = "fb0d979";
60885
+ __info__.version = "17.2.16";
60886
+ __info__.date = "2024-07-11T06:38:53.101Z";
60887
+ __info__.hash = "9f20685";
60846
60888
 
60847
60889
 
60848
60890
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);