@odoo/o-spreadsheet 17.3.7 → 17.3.9

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.3.7
7
- * @date 2024-07-02T10:38:52.530Z
8
- * @hash c570df3
6
+ * @version 17.3.9
7
+ * @date 2024-07-11T06:37:05.603Z
8
+ * @hash 2346a16
9
9
  */
10
10
 
11
11
  (function (exports, owl) {
@@ -592,7 +592,7 @@
592
592
  /**
593
593
  * Compares two objects.
594
594
  */
595
- function deepEquals(o1, o2, ignoreFunctions) {
595
+ function deepEquals(o1, o2) {
596
596
  if (o1 === o2)
597
597
  return true;
598
598
  if ((o1 && !o2) || (o2 && !o1))
@@ -608,17 +608,13 @@
608
608
  }
609
609
  }
610
610
  for (const key in o1) {
611
- const typeOfO1Key = typeof o1[key];
612
- if (typeOfO1Key !== typeof o2[key])
611
+ if (typeof o1[key] !== typeof o2[key])
613
612
  return false;
614
- if (typeOfO1Key === "object") {
615
- if (!deepEquals(o1[key], o2[key], ignoreFunctions))
613
+ if (typeof o1[key] === "object") {
614
+ if (!deepEquals(o1[key], o2[key]))
616
615
  return false;
617
616
  }
618
617
  else {
619
- if (ignoreFunctions && typeOfO1Key === "function") {
620
- continue;
621
- }
622
618
  if (o1[key] !== o2[key])
623
619
  return false;
624
620
  }
@@ -1831,7 +1827,7 @@
1831
1827
  });
1832
1828
  const getNumberRegex = memoize(function getNumberRegex(locale) {
1833
1829
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
1834
- const thousandsSeparator = escapeRegExp(locale.thousandsSeparator);
1830
+ const thousandsSeparator = escapeRegExp(locale.thousandsSeparator || "");
1835
1831
  const pIntegerAndDecimals = `(\\d+(${thousandsSeparator}\\d{3,})*(${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
1836
1832
  const pOnlyDecimals = `(${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
1837
1833
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -1858,7 +1854,7 @@
1858
1854
  return getNumberRegex(locale).test(value.trim());
1859
1855
  }
1860
1856
  const getInvaluableSymbolsRegexp = memoize(function getInvaluableSymbolsRegexp(locale) {
1861
- return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator)}]`, "g");
1857
+ return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator || "")}]`, "g");
1862
1858
  });
1863
1859
  /**
1864
1860
  * Convert a string into a number. It assumes that the string actually represents
@@ -2765,6 +2761,9 @@
2765
2761
  * If the character is a special regular expression character, it is escaped with "\\".
2766
2762
  */
2767
2763
  const wildcardToRegExp = memoize(function wildcardToRegExp(operand) {
2764
+ if (operand === "*") {
2765
+ return /.+/;
2766
+ }
2768
2767
  let exp = "";
2769
2768
  let predecessor = "";
2770
2769
  for (let char of operand) {
@@ -2788,9 +2787,9 @@
2788
2787
  }
2789
2788
  return new RegExp("^" + exp + "$", "i");
2790
2789
  });
2791
- function evaluatePredicate(value, criterion) {
2790
+ function evaluatePredicate(value = "", criterion) {
2792
2791
  const { operator, operand } = criterion;
2793
- if (value === undefined || operand === undefined || value === null || operand === null) {
2792
+ if (operand === undefined || value === null || operand === null) {
2794
2793
  return false;
2795
2794
  }
2796
2795
  if (typeof operand === "number" && operator === "=") {
@@ -5895,19 +5894,22 @@
5895
5894
  }
5896
5895
 
5897
5896
  function isValidLocale(locale) {
5898
- if (!(locale &&
5899
- typeof locale === "object" &&
5900
- typeof locale.name === "string" &&
5901
- typeof locale.code === "string" &&
5902
- typeof locale.thousandsSeparator === "string" &&
5903
- typeof locale.decimalSeparator === "string" &&
5904
- typeof locale.dateFormat === "string" &&
5905
- typeof locale.timeFormat === "string" &&
5906
- typeof locale.formulaArgSeparator === "string")) {
5897
+ if (!locale ||
5898
+ typeof locale !== "object" ||
5899
+ !(!locale.thousandsSeparator || typeof locale.thousandsSeparator === "string")) {
5907
5900
  return false;
5908
5901
  }
5909
- if (!Object.values(locale).every((v) => v)) {
5910
- return false;
5902
+ for (const property of [
5903
+ "code",
5904
+ "name",
5905
+ "decimalSeparator",
5906
+ "dateFormat",
5907
+ "timeFormat",
5908
+ "formulaArgSeparator",
5909
+ ]) {
5910
+ if (!locale[property] || typeof locale[property] !== "string") {
5911
+ return false;
5912
+ }
5911
5913
  }
5912
5914
  if (locale.formulaArgSeparator === locale.decimalSeparator) {
5913
5915
  return false;
@@ -6005,7 +6007,10 @@
6005
6007
  if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
6006
6008
  return content;
6007
6009
  }
6008
- return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
6010
+ if (locale.thousandsSeparator) {
6011
+ content = content.replaceAll(locale.thousandsSeparator, "");
6012
+ }
6013
+ return content.replace(locale.decimalSeparator, ".");
6009
6014
  }
6010
6015
  /**
6011
6016
  * Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
@@ -6994,6 +6999,146 @@
6994
6999
  return undefined;
6995
7000
  }
6996
7001
 
7002
+ var State;
7003
+ (function (State) {
7004
+ /**
7005
+ * Initial state.
7006
+ * Expecting any reference for the left part of a range
7007
+ * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
7008
+ */
7009
+ State[State["LeftRef"] = 0] = "LeftRef";
7010
+ /**
7011
+ * Expecting any reference for the right part of a range
7012
+ * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
7013
+ */
7014
+ State[State["RightRef"] = 1] = "RightRef";
7015
+ /**
7016
+ * Expecting the separator without any constraint on the right part
7017
+ */
7018
+ State[State["Separator"] = 2] = "Separator";
7019
+ /**
7020
+ * Expecting the separator for a full column range
7021
+ */
7022
+ State[State["FullColumnSeparator"] = 3] = "FullColumnSeparator";
7023
+ /**
7024
+ * Expecting the separator for a full row range
7025
+ */
7026
+ State[State["FullRowSeparator"] = 4] = "FullRowSeparator";
7027
+ /**
7028
+ * Expecting the right part of a full column range
7029
+ * e.g. "1", "A1"
7030
+ */
7031
+ State[State["RightColumnRef"] = 5] = "RightColumnRef";
7032
+ /**
7033
+ * Expecting the right part of a full row range
7034
+ * e.g. "A", "A1"
7035
+ */
7036
+ State[State["RightRowRef"] = 6] = "RightRowRef";
7037
+ /**
7038
+ * Final state. A range has been matched
7039
+ */
7040
+ State[State["Found"] = 7] = "Found";
7041
+ })(State || (State = {}));
7042
+ const goTo = (state, guard = () => true) => [
7043
+ {
7044
+ goTo: state,
7045
+ guard,
7046
+ },
7047
+ ];
7048
+ const goToMulti = (state, guard = () => true) => ({
7049
+ goTo: state,
7050
+ guard,
7051
+ });
7052
+ const machine = {
7053
+ [State.LeftRef]: {
7054
+ REFERENCE: goTo(State.Separator),
7055
+ NUMBER: goTo(State.FullRowSeparator),
7056
+ SYMBOL: [
7057
+ goToMulti(State.FullColumnSeparator, (token) => isColReference(token.value)),
7058
+ goToMulti(State.FullRowSeparator, (token) => isRowReference(token.value)),
7059
+ ],
7060
+ },
7061
+ [State.FullColumnSeparator]: {
7062
+ SPACE: goTo(State.FullColumnSeparator),
7063
+ OPERATOR: goTo(State.RightColumnRef, (token) => token.value === ":"),
7064
+ },
7065
+ [State.FullRowSeparator]: {
7066
+ SPACE: goTo(State.FullRowSeparator),
7067
+ OPERATOR: goTo(State.RightRowRef, (token) => token.value === ":"),
7068
+ },
7069
+ [State.Separator]: {
7070
+ SPACE: goTo(State.Separator),
7071
+ OPERATOR: goTo(State.RightRef, (token) => token.value === ":"),
7072
+ },
7073
+ [State.RightRef]: {
7074
+ SPACE: goTo(State.RightRef),
7075
+ NUMBER: goTo(State.Found),
7076
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7077
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
7078
+ },
7079
+ [State.RightColumnRef]: {
7080
+ SPACE: goTo(State.RightColumnRef),
7081
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
7082
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7083
+ },
7084
+ [State.RightRowRef]: {
7085
+ SPACE: goTo(State.RightRowRef),
7086
+ NUMBER: goTo(State.Found),
7087
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7088
+ SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
7089
+ },
7090
+ [State.Found]: {},
7091
+ };
7092
+ /**
7093
+ * Check if the list of tokens starts with a sequence of tokens representing
7094
+ * a range.
7095
+ * If a range is found, the sequence is removed from the list and is returned
7096
+ * as a single token.
7097
+ */
7098
+ function matchReference(tokens) {
7099
+ let head = 0;
7100
+ let transitions = machine[State.LeftRef];
7101
+ let matchedTokens = "";
7102
+ while (transitions !== undefined) {
7103
+ const token = tokens[head++];
7104
+ if (!token) {
7105
+ return null;
7106
+ }
7107
+ const transition = transitions[token.type]?.find((transition) => transition.guard(token));
7108
+ const nextState = transition ? transition.goTo : undefined;
7109
+ switch (nextState) {
7110
+ case undefined:
7111
+ return null;
7112
+ case State.Found:
7113
+ matchedTokens += token.value;
7114
+ tokens.splice(0, head);
7115
+ return {
7116
+ type: "REFERENCE",
7117
+ value: matchedTokens,
7118
+ };
7119
+ default:
7120
+ transitions = machine[nextState];
7121
+ matchedTokens += token.value;
7122
+ break;
7123
+ }
7124
+ }
7125
+ return null;
7126
+ }
7127
+ /**
7128
+ * Take the result of the tokenizer and transform it to be usable in the
7129
+ * manipulations of range
7130
+ *
7131
+ * @param formula
7132
+ */
7133
+ function rangeTokenize(formula, locale = DEFAULT_LOCALE) {
7134
+ const tokens = tokenize(formula, locale);
7135
+ const result = [];
7136
+ while (tokens.length) {
7137
+ result.push(matchReference(tokens) || tokens.shift());
7138
+ }
7139
+ return result;
7140
+ }
7141
+
6997
7142
  const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
6998
7143
  const UNARY_OPERATORS_PREFIX = ["-", "+"];
6999
7144
  const UNARY_OPERATORS_POSTFIX = ["%"];
@@ -7142,7 +7287,7 @@
7142
7287
  * Parse an expression (as a string) into an AST.
7143
7288
  */
7144
7289
  function parse(str) {
7145
- return parseTokens(tokenize(str));
7290
+ return parseTokens(rangeTokenize(str));
7146
7291
  }
7147
7292
  function parseTokens(tokens) {
7148
7293
  tokens = tokens.filter((x) => x.type !== "SPACE");
@@ -7278,146 +7423,6 @@
7278
7423
  return needParenthesis ? `(${astToFormula(rightOperation)})` : astToFormula(rightOperation);
7279
7424
  }
7280
7425
 
7281
- var State;
7282
- (function (State) {
7283
- /**
7284
- * Initial state.
7285
- * Expecting any reference for the left part of a range
7286
- * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
7287
- */
7288
- State[State["LeftRef"] = 0] = "LeftRef";
7289
- /**
7290
- * Expecting any reference for the right part of a range
7291
- * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
7292
- */
7293
- State[State["RightRef"] = 1] = "RightRef";
7294
- /**
7295
- * Expecting the separator without any constraint on the right part
7296
- */
7297
- State[State["Separator"] = 2] = "Separator";
7298
- /**
7299
- * Expecting the separator for a full column range
7300
- */
7301
- State[State["FullColumnSeparator"] = 3] = "FullColumnSeparator";
7302
- /**
7303
- * Expecting the separator for a full row range
7304
- */
7305
- State[State["FullRowSeparator"] = 4] = "FullRowSeparator";
7306
- /**
7307
- * Expecting the right part of a full column range
7308
- * e.g. "1", "A1"
7309
- */
7310
- State[State["RightColumnRef"] = 5] = "RightColumnRef";
7311
- /**
7312
- * Expecting the right part of a full row range
7313
- * e.g. "A", "A1"
7314
- */
7315
- State[State["RightRowRef"] = 6] = "RightRowRef";
7316
- /**
7317
- * Final state. A range has been matched
7318
- */
7319
- State[State["Found"] = 7] = "Found";
7320
- })(State || (State = {}));
7321
- const goTo = (state, guard = () => true) => [
7322
- {
7323
- goTo: state,
7324
- guard,
7325
- },
7326
- ];
7327
- const goToMulti = (state, guard = () => true) => ({
7328
- goTo: state,
7329
- guard,
7330
- });
7331
- const machine = {
7332
- [State.LeftRef]: {
7333
- REFERENCE: goTo(State.Separator),
7334
- NUMBER: goTo(State.FullRowSeparator),
7335
- SYMBOL: [
7336
- goToMulti(State.FullColumnSeparator, (token) => isColReference(token.value)),
7337
- goToMulti(State.FullRowSeparator, (token) => isRowReference(token.value)),
7338
- ],
7339
- },
7340
- [State.FullColumnSeparator]: {
7341
- SPACE: goTo(State.FullColumnSeparator),
7342
- OPERATOR: goTo(State.RightColumnRef, (token) => token.value === ":"),
7343
- },
7344
- [State.FullRowSeparator]: {
7345
- SPACE: goTo(State.FullRowSeparator),
7346
- OPERATOR: goTo(State.RightRowRef, (token) => token.value === ":"),
7347
- },
7348
- [State.Separator]: {
7349
- SPACE: goTo(State.Separator),
7350
- OPERATOR: goTo(State.RightRef, (token) => token.value === ":"),
7351
- },
7352
- [State.RightRef]: {
7353
- SPACE: goTo(State.RightRef),
7354
- NUMBER: goTo(State.Found),
7355
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7356
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
7357
- },
7358
- [State.RightColumnRef]: {
7359
- SPACE: goTo(State.RightColumnRef),
7360
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
7361
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7362
- },
7363
- [State.RightRowRef]: {
7364
- SPACE: goTo(State.RightRowRef),
7365
- NUMBER: goTo(State.Found),
7366
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7367
- SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
7368
- },
7369
- [State.Found]: {},
7370
- };
7371
- /**
7372
- * Check if the list of tokens starts with a sequence of tokens representing
7373
- * a range.
7374
- * If a range is found, the sequence is removed from the list and is returned
7375
- * as a single token.
7376
- */
7377
- function matchReference(tokens) {
7378
- let head = 0;
7379
- let transitions = machine[State.LeftRef];
7380
- let matchedTokens = "";
7381
- while (transitions !== undefined) {
7382
- const token = tokens[head++];
7383
- if (!token) {
7384
- return null;
7385
- }
7386
- const transition = transitions[token.type]?.find((transition) => transition.guard(token));
7387
- const nextState = transition ? transition.goTo : undefined;
7388
- switch (nextState) {
7389
- case undefined:
7390
- return null;
7391
- case State.Found:
7392
- matchedTokens += token.value;
7393
- tokens.splice(0, head);
7394
- return {
7395
- type: "REFERENCE",
7396
- value: matchedTokens,
7397
- };
7398
- default:
7399
- transitions = machine[nextState];
7400
- matchedTokens += token.value;
7401
- break;
7402
- }
7403
- }
7404
- return null;
7405
- }
7406
- /**
7407
- * Take the result of the tokenizer and transform it to be usable in the
7408
- * manipulations of range
7409
- *
7410
- * @param formula
7411
- */
7412
- function rangeTokenize(formula, locale = DEFAULT_LOCALE) {
7413
- const tokens = tokenize(formula, locale);
7414
- const result = [];
7415
- while (tokens.length) {
7416
- result.push(matchReference(tokens) || tokens.shift());
7417
- }
7418
- return result;
7419
- }
7420
-
7421
7426
  /**
7422
7427
  * Add the following information on tokens:
7423
7428
  * - length
@@ -9835,7 +9840,6 @@ stores.inject(MyMetaStore, storeInstance);
9835
9840
  };
9836
9841
  canvas = owl.useRef("graphContainer");
9837
9842
  chart;
9838
- currentRuntime;
9839
9843
  get background() {
9840
9844
  return this.chartRuntime.background;
9841
9845
  }
@@ -9852,18 +9856,11 @@ stores.inject(MyMetaStore, storeInstance);
9852
9856
  setup() {
9853
9857
  owl.onMounted(() => {
9854
9858
  const runtime = this.chartRuntime;
9855
- this.currentRuntime = runtime;
9856
9859
  // Note: chartJS modify the runtime in place, so it's important to give it a copy
9857
9860
  this.createChart(deepCopy(runtime.chartJsConfig));
9858
9861
  });
9859
9862
  owl.onWillUnmount(() => this.chart?.destroy());
9860
- owl.useEffect(() => {
9861
- const runtime = this.chartRuntime;
9862
- if (!deepEquals(runtime, this.currentRuntime, "ignoreFunctions")) {
9863
- this.currentRuntime = runtime;
9864
- this.updateChartJs(deepCopy(runtime));
9865
- }
9866
- });
9863
+ owl.useEffect(() => this.updateChartJs(deepCopy(this.chartRuntime)), () => [this.chartRuntime]);
9867
9864
  }
9868
9865
  createChart(chartData) {
9869
9866
  const canvas = this.canvas.el;
@@ -22697,7 +22694,7 @@ stores.inject(MyMetaStore, storeInstance);
22697
22694
  /**
22698
22695
  * Get a default chart js configuration
22699
22696
  */
22700
- function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, truncateLabels }) {
22697
+ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, truncateLabels = true }) {
22701
22698
  const chartTitle = chart.title.text ? chart.title : { ...chart.title, content: "" };
22702
22699
  const options = {
22703
22700
  // https://www.chartjs.org/docs/latest/general/responsive.html
@@ -23926,10 +23923,6 @@ stores.inject(MyMetaStore, storeInstance);
23926
23923
  const colors = new ColorGenerator();
23927
23924
  const definition = chart.getDefinition();
23928
23925
  for (let [index, { label, data }] of dataSetsValues.entries()) {
23929
- if (["linear", "time"].includes(axisType)) {
23930
- // Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
23931
- data = data.map((y, index) => ({ x: labels[index] || undefined, y }));
23932
- }
23933
23926
  const color = colors.next();
23934
23927
  let backgroundRGBA = colorToRGBA(color);
23935
23928
  if (stacked) {
@@ -23945,6 +23938,10 @@ stores.inject(MyMetaStore, storeInstance);
23945
23938
  return value;
23946
23939
  });
23947
23940
  }
23941
+ if (["linear", "time"].includes(axisType)) {
23942
+ // Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
23943
+ data = data.map((y, index) => ({ x: labels[index] || undefined, y }));
23944
+ }
23948
23945
  const backgroundColor = rgbaToHex(backgroundRGBA);
23949
23946
  const dataset = {
23950
23947
  label,
@@ -36262,7 +36259,13 @@ stores.inject(MyMetaStore, storeInstance);
36262
36259
  }
36263
36260
  async loadLocales() {
36264
36261
  this.loadedLocales = (await this.env.loadLocales())
36265
- .filter(isValidLocale)
36262
+ .filter((locale) => {
36263
+ const isValid = isValidLocale(locale);
36264
+ if (!isValid) {
36265
+ console.warn(`Invalid locale: ${locale["code"]} ${locale}`);
36266
+ }
36267
+ return isValid;
36268
+ })
36266
36269
  .sort((a, b) => a.name.localeCompare(b.name));
36267
36270
  }
36268
36271
  get numberFormatPreview() {
@@ -41414,6 +41417,7 @@ stores.inject(MyMetaStore, storeInstance);
41414
41417
  return;
41415
41418
  }
41416
41419
  if (clipboardData.types.indexOf(ClipboardMIMEType.PlainText) > -1) {
41420
+ ev.preventDefault();
41417
41421
  const content = clipboardData.getData(ClipboardMIMEType.PlainText);
41418
41422
  const target = this.env.model.getters.getSelectedZones();
41419
41423
  const clipboardString = this.env.model.getters.getClipboardTextContent();
@@ -45125,7 +45129,7 @@ stores.inject(MyMetaStore, storeInstance);
45125
45129
  return relsFile;
45126
45130
  }
45127
45131
 
45128
- const EXCEL_IMPORT_VERSION = 16;
45132
+ const EXCEL_IMPORT_VERSION = 17;
45129
45133
  class XlsxReader {
45130
45134
  warningManager;
45131
45135
  xmls;
@@ -45257,7 +45261,7 @@ stores.inject(MyMetaStore, storeInstance);
45257
45261
  * a breaking change is made in the way the state is handled, and an upgrade
45258
45262
  * function should be defined
45259
45263
  */
45260
- const CURRENT_VERSION = 16;
45264
+ const CURRENT_VERSION = 17;
45261
45265
  const INITIAL_SHEET_ID = "Sheet1";
45262
45266
  /**
45263
45267
  * This function tries to load anything that could look like a valid
@@ -46204,6 +46208,21 @@ stores.inject(MyMetaStore, storeInstance);
46204
46208
  return [];
46205
46209
  return Object.keys(sheetBorders).map((index) => parseInt(index, 10));
46206
46210
  }
46211
+ /**
46212
+ * Get all the rows which contains at least a border
46213
+ */
46214
+ getRowsWithBorders(sheetId) {
46215
+ const sheetBorders = this.borders[sheetId]?.filter(isDefined);
46216
+ if (!sheetBorders)
46217
+ return [];
46218
+ const rowsWithBorders = new Set();
46219
+ for (const rowBorders of sheetBorders) {
46220
+ for (const rowBorder in rowBorders) {
46221
+ rowsWithBorders.add(parseInt(rowBorder, 10));
46222
+ }
46223
+ }
46224
+ return Array.from(rowsWithBorders);
46225
+ }
46207
46226
  /**
46208
46227
  * Get the range of all the rows in the sheet
46209
46228
  */
@@ -46253,7 +46272,7 @@ stores.inject(MyMetaStore, storeInstance);
46253
46272
  destructive: false,
46254
46273
  });
46255
46274
  }
46256
- this.getRowsRange(sheetId)
46275
+ this.getRowsWithBorders(sheetId)
46257
46276
  .filter((row) => row >= start)
46258
46277
  .sort((a, b) => (delta < 0 ? a - b : b - a)) // start by the end when moving up
46259
46278
  .forEach((row) => {
@@ -52585,7 +52604,7 @@ stores.inject(MyMetaStore, storeInstance);
52585
52604
  return this.sheets[position.sheetId].getValue(position) === 1;
52586
52605
  }
52587
52606
  clear() {
52588
- const insertions = this.insertions;
52607
+ const insertions = [...this];
52589
52608
  this.insertions = [];
52590
52609
  for (const sheetId in this.sheets) {
52591
52610
  this.sheets[sheetId].clear();
@@ -52923,6 +52942,7 @@ stores.inject(MyMetaStore, storeInstance);
52923
52942
  }
52924
52943
  finally {
52925
52944
  this.cellsBeingComputed.delete(cellId);
52945
+ this.nextPositionsToUpdate.delete(position);
52926
52946
  }
52927
52947
  }
52928
52948
  computeAndSave(position) {
@@ -52949,8 +52969,33 @@ stores.inject(MyMetaStore, storeInstance);
52949
52969
  forEachSpreadPositionInMatrix(nbColumns, nbRows,
52950
52970
  // thanks to the isMatrix check above, we know that formulaReturn is MatrixFunctionReturn
52951
52971
  this.spreadValues(formulaPosition, formulaReturn));
52972
+ this.invalidatePositionsDependingOnSpread(formulaPosition, nbColumns, nbRows);
52952
52973
  return createEvaluatedCell(nullValueToZeroValue(formulaReturn[0][0]), this.getters.getLocale(), cellData);
52953
52974
  }
52975
+ invalidatePositionsDependingOnSpread(arrayFormulaPosition, nbColumns, nbRows) {
52976
+ // the result matrix is split in 2 zones to exclude the array formula position
52977
+ const top = arrayFormulaPosition.row;
52978
+ const left = arrayFormulaPosition.col;
52979
+ const bottom = top + nbRows - 1;
52980
+ const leftColumnZone = {
52981
+ top: top + 1,
52982
+ bottom,
52983
+ left,
52984
+ right: left,
52985
+ };
52986
+ const rightPartZone = {
52987
+ top,
52988
+ bottom,
52989
+ left: left + 1,
52990
+ right: left + nbColumns - 1,
52991
+ };
52992
+ const sheetId = arrayFormulaPosition.sheetId;
52993
+ const invalidatedPositions = this.formulaDependencies().getCellsDependingOn([
52994
+ { sheetId, zone: rightPartZone },
52995
+ { sheetId, zone: leftColumnZone },
52996
+ ]);
52997
+ this.nextPositionsToUpdate.addMany(invalidatedPositions);
52998
+ }
52954
52999
  assertSheetHasEnoughSpaceToSpreadFormulaResult({ sheetId, col, row }, matrixResult) {
52955
53000
  const numberOfCols = this.getters.getNumberCols(sheetId);
52956
53001
  const numberOfRows = this.getters.getNumberRows(sheetId);
@@ -53005,9 +53050,6 @@ stores.inject(MyMetaStore, storeInstance);
53005
53050
  const cell = this.getters.getCell(position);
53006
53051
  const evaluatedCell = createEvaluatedCell(nullValueToZeroValue(matrixResult[i][j]), this.getters.getLocale(), cell);
53007
53052
  this.evaluatedCells.set(position, evaluatedCell);
53008
- // check if formula dependencies present in the spread zone
53009
- // if so, they need to be recomputed
53010
- this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([position]));
53011
53053
  };
53012
53054
  }
53013
53055
  invalidateSpreading(position) {
@@ -67045,9 +67087,9 @@ stores.inject(MyMetaStore, storeInstance);
67045
67087
  exports.tokenize = tokenize;
67046
67088
 
67047
67089
 
67048
- __info__.version = "17.3.7";
67049
- __info__.date = "2024-07-02T10:38:52.530Z";
67050
- __info__.hash = "c570df3";
67090
+ __info__.version = "17.3.9";
67091
+ __info__.date = "2024-07-11T06:37:05.603Z";
67092
+ __info__.hash = "2346a16";
67051
67093
 
67052
67094
 
67053
67095
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);