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