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