@odoo/o-spreadsheet 17.0.27 → 17.0.29

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.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 17.0.27
6
- * @date 2024-07-02T09:01:48.383Z
7
- * @hash c1c2d01
5
+ * @version 17.0.29
6
+ * @date 2024-07-08T05:40:27.608Z
7
+ * @hash 2d467e3
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -657,7 +657,7 @@ function getAddHeaderStartIndex(position, base) {
657
657
  /**
658
658
  * Compares two objects.
659
659
  */
660
- function deepEquals(o1, o2, ignoreFunctions) {
660
+ function deepEquals(o1, o2) {
661
661
  if (o1 === o2)
662
662
  return true;
663
663
  if ((o1 && !o2) || (o2 && !o1))
@@ -673,17 +673,13 @@ function deepEquals(o1, o2, ignoreFunctions) {
673
673
  }
674
674
  }
675
675
  for (const key in o1) {
676
- const typeOfO1Key = typeof o1[key];
677
- if (typeOfO1Key !== typeof o2[key])
676
+ if (typeof o1[key] !== typeof o2[key])
678
677
  return false;
679
- if (typeOfO1Key === "object") {
680
- if (!deepEquals(o1[key], o2[key], ignoreFunctions))
678
+ if (typeof o1[key] === "object") {
679
+ if (!deepEquals(o1[key], o2[key]))
681
680
  return false;
682
681
  }
683
682
  else {
684
- if (ignoreFunctions && typeOfO1Key === "function") {
685
- continue;
686
- }
687
683
  if (o1[key] !== o2[key])
688
684
  return false;
689
685
  }
@@ -754,11 +750,9 @@ class JetSet extends Set {
754
750
  return this;
755
751
  }
756
752
  deleteMany(iterable) {
757
- let wasDeleted = false;
758
753
  for (const element of iterable) {
759
- wasDeleted ||= super.delete(element);
754
+ super.delete(element);
760
755
  }
761
- return wasDeleted;
762
756
  }
763
757
  }
764
758
  /**
@@ -1815,7 +1809,7 @@ const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSepa
1815
1809
  });
1816
1810
  const getNumberRegex = memoize(function getNumberRegex(locale) {
1817
1811
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
1818
- const thousandsSeparator = escapeRegExp(locale.thousandsSeparator);
1812
+ const thousandsSeparator = escapeRegExp(locale.thousandsSeparator || "");
1819
1813
  const pIntegerAndDecimals = `(\\d+(${thousandsSeparator}\\d{3,})*(${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
1820
1814
  const pOnlyDecimals = `(${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
1821
1815
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -1842,7 +1836,7 @@ function isNumber(value, locale) {
1842
1836
  return getNumberRegex(locale).test(value.trim());
1843
1837
  }
1844
1838
  const getInvaluableSymbolsRegexp = memoize(function getInvaluableSymbolsRegexp(locale) {
1845
- return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator)}]`, "g");
1839
+ return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator || "")}]`, "g");
1846
1840
  });
1847
1841
  /**
1848
1842
  * Convert a string into a number. It assumes that the string actually represents
@@ -2544,6 +2538,9 @@ function getPredicate(descr, isQuery, locale) {
2544
2538
  return result;
2545
2539
  }
2546
2540
  function operandToRegExp(operand) {
2541
+ if (operand === "*") {
2542
+ return /.+/;
2543
+ }
2547
2544
  let exp = "";
2548
2545
  let predecessor = "";
2549
2546
  for (let char of operand) {
@@ -2567,9 +2564,9 @@ function operandToRegExp(operand) {
2567
2564
  }
2568
2565
  return new RegExp("^" + exp + "$", "i");
2569
2566
  }
2570
- function evaluatePredicate(value, criterion) {
2567
+ function evaluatePredicate(value = "", criterion) {
2571
2568
  const { operator, operand } = criterion;
2572
- if (value === undefined || operand === undefined || value === null || operand === null) {
2569
+ if (operand === undefined || value === null || operand === null) {
2573
2570
  return false;
2574
2571
  }
2575
2572
  if (typeof operand === "number" && operator === "=") {
@@ -4782,7 +4779,6 @@ class ChartJsComponent extends Component {
4782
4779
  static template = "o-spreadsheet-ChartJsComponent";
4783
4780
  canvas = useRef("graphContainer");
4784
4781
  chart;
4785
- currentRuntime;
4786
4782
  get background() {
4787
4783
  return this.chartRuntime.background;
4788
4784
  }
@@ -4799,17 +4795,10 @@ class ChartJsComponent extends Component {
4799
4795
  setup() {
4800
4796
  onMounted(() => {
4801
4797
  const runtime = this.chartRuntime;
4802
- this.currentRuntime = runtime;
4803
4798
  // Note: chartJS modify the runtime in place, so it's important to give it a copy
4804
4799
  this.createChart(deepCopy(runtime.chartJsConfig));
4805
4800
  });
4806
- useEffect(() => {
4807
- const runtime = this.chartRuntime;
4808
- if (!deepEquals(runtime, this.currentRuntime, "ignoreFunctions")) {
4809
- this.currentRuntime = runtime;
4810
- this.updateChartJs(deepCopy(runtime));
4811
- }
4812
- });
4801
+ useEffect(() => this.updateChartJs(deepCopy(this.chartRuntime)), () => [this.chartRuntime]);
4813
4802
  }
4814
4803
  createChart(chartData) {
4815
4804
  const canvas = this.canvas.el;
@@ -7677,19 +7666,22 @@ class TokenizingChars {
7677
7666
  }
7678
7667
 
7679
7668
  function isValidLocale(locale) {
7680
- if (!(locale &&
7681
- typeof locale === "object" &&
7682
- typeof locale.name === "string" &&
7683
- typeof locale.code === "string" &&
7684
- typeof locale.thousandsSeparator === "string" &&
7685
- typeof locale.decimalSeparator === "string" &&
7686
- typeof locale.dateFormat === "string" &&
7687
- typeof locale.timeFormat === "string" &&
7688
- typeof locale.formulaArgSeparator === "string")) {
7669
+ if (!locale ||
7670
+ typeof locale !== "object" ||
7671
+ !(!locale.thousandsSeparator || typeof locale.thousandsSeparator === "string")) {
7689
7672
  return false;
7690
7673
  }
7691
- if (!Object.values(locale).every((v) => v)) {
7692
- return false;
7674
+ for (const property of [
7675
+ "code",
7676
+ "name",
7677
+ "decimalSeparator",
7678
+ "dateFormat",
7679
+ "timeFormat",
7680
+ "formulaArgSeparator",
7681
+ ]) {
7682
+ if (!locale[property] || typeof locale[property] !== "string") {
7683
+ return false;
7684
+ }
7693
7685
  }
7694
7686
  if (locale.formulaArgSeparator === locale.decimalSeparator) {
7695
7687
  return false;
@@ -7787,7 +7779,10 @@ function canonicalizeNumberLiteral(content, locale) {
7787
7779
  if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
7788
7780
  return content;
7789
7781
  }
7790
- return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
7782
+ if (locale.thousandsSeparator) {
7783
+ content = content.replaceAll(locale.thousandsSeparator, "");
7784
+ }
7785
+ return content.replace(locale.decimalSeparator, ".");
7791
7786
  }
7792
7787
  /**
7793
7788
  * Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
@@ -9465,15 +9460,6 @@ function createLineChartRuntime(chart, getters) {
9465
9460
  }
9466
9461
  const colors = new ChartColors();
9467
9462
  for (let [index, { label, data }] of dataSetsValues.entries()) {
9468
- if (["linear", "time"].includes(axisType)) {
9469
- // Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
9470
- data = data.map((y, index) => ({ x: labels[index] || undefined, y }));
9471
- }
9472
- const color = colors.next();
9473
- let backgroundRGBA = colorToRGBA(color);
9474
- if (chart.stacked) {
9475
- backgroundRGBA.a = LINE_FILL_TRANSPARENCY;
9476
- }
9477
9463
  if (chart.cumulative) {
9478
9464
  let accumulator = 0;
9479
9465
  data = data.map((value) => {
@@ -9484,6 +9470,15 @@ function createLineChartRuntime(chart, getters) {
9484
9470
  return value;
9485
9471
  });
9486
9472
  }
9473
+ if (["linear", "time"].includes(axisType)) {
9474
+ // Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
9475
+ data = data.map((y, index) => ({ x: labels[index] || undefined, y }));
9476
+ }
9477
+ const color = colors.next();
9478
+ let backgroundRGBA = colorToRGBA(color);
9479
+ if (chart.stacked) {
9480
+ backgroundRGBA.a = LINE_FILL_TRANSPARENCY;
9481
+ }
9487
9482
  const backgroundColor = rgbaToHex(backgroundRGBA);
9488
9483
  const dataset = {
9489
9484
  label,
@@ -24281,7 +24276,13 @@ class SettingsPanel extends Component {
24281
24276
  }
24282
24277
  async loadLocales() {
24283
24278
  this.loadedLocales = (await this.env.loadLocales())
24284
- .filter(isValidLocale)
24279
+ .filter((locale) => {
24280
+ const isValid = isValidLocale(locale);
24281
+ if (!isValid) {
24282
+ console.warn(`Invalid locale: ${locale["code"]} ${locale}`);
24283
+ }
24284
+ return isValid;
24285
+ })
24285
24286
  .sort((a, b) => a.name.localeCompare(b.name));
24286
24287
  }
24287
24288
  get numberFormatPreview() {
@@ -30064,6 +30065,7 @@ class Grid extends Component {
30064
30065
  return;
30065
30066
  }
30066
30067
  if (clipboardData.types.indexOf(ClipboardMIMEType.PlainText) > -1) {
30068
+ ev.preventDefault();
30067
30069
  const content = clipboardData.getData(ClipboardMIMEType.PlainText);
30068
30070
  const target = this.env.model.getters.getSelectedZones();
30069
30071
  const clipboardString = this.env.model.getters.getClipboardTextContent();
@@ -30326,6 +30328,8 @@ const NON_RETROCOMPATIBLE_FUNCTIONS = [
30326
30328
  "BITOR",
30327
30329
  "BITRSHIFT",
30328
30330
  "BITXOR",
30331
+ "BYCOL",
30332
+ "BYROW",
30329
30333
  "CEILING.MATH",
30330
30334
  "CEILING.PRECISE",
30331
30335
  "CHISQ.DIST",
@@ -30333,6 +30337,8 @@ const NON_RETROCOMPATIBLE_FUNCTIONS = [
30333
30337
  "CHISQ.INV",
30334
30338
  "CHISQ.INV.RT",
30335
30339
  "CHISQ.TEST",
30340
+ "CHOOSECOLS",
30341
+ "CHOOSEROWS",
30336
30342
  "COMBINA",
30337
30343
  "CONCAT",
30338
30344
  "CONFIDENCE.NORM",
@@ -30345,14 +30351,17 @@ const NON_RETROCOMPATIBLE_FUNCTIONS = [
30345
30351
  "CSCH",
30346
30352
  "DAYS",
30347
30353
  "DECIMAL",
30354
+ "DROP",
30348
30355
  "ERF.PRECISE",
30349
30356
  "ERFC.PRECISE",
30357
+ "EXPAND",
30350
30358
  "EXPON.DIST",
30351
30359
  "F.DIST",
30352
30360
  "F.DIST.RT",
30353
30361
  "F.INV",
30354
30362
  "F.INV.RT",
30355
30363
  "F.TEST",
30364
+ "FIELDVALUE",
30356
30365
  "FILTERXML",
30357
30366
  "FLOOR.MATH",
30358
30367
  "FLOOR.PRECISE",
@@ -30367,6 +30376,7 @@ const NON_RETROCOMPATIBLE_FUNCTIONS = [
30367
30376
  "GAMMA.INV",
30368
30377
  "GAMMALN.PRECISE",
30369
30378
  "GAUSS",
30379
+ "HSTACK",
30370
30380
  "HYPGEOM.DIST",
30371
30381
  "IFNA",
30372
30382
  "IFS",
@@ -30379,9 +30389,14 @@ const NON_RETROCOMPATIBLE_FUNCTIONS = [
30379
30389
  "IMSINH",
30380
30390
  "IMTAN",
30381
30391
  "ISFORMULA",
30392
+ "ISOMITTED",
30382
30393
  "ISOWEEKNUM",
30394
+ "LAMBDA",
30395
+ "LET",
30383
30396
  "LOGNORM.DIST",
30384
30397
  "LOGNORM.INV",
30398
+ "MAKEARRAY",
30399
+ "MAP",
30385
30400
  "MAXIFS",
30386
30401
  "MINIFS",
30387
30402
  "MODE.MULT",
@@ -30401,17 +30416,26 @@ const NON_RETROCOMPATIBLE_FUNCTIONS = [
30401
30416
  "PERMUTATIONA",
30402
30417
  "PHI",
30403
30418
  "POISSON.DIST",
30419
+ "PQSOURCE",
30420
+ "PYTHON_STR",
30421
+ "PYTHON_TYPE",
30422
+ "PYTHON_TYPENAME",
30404
30423
  "QUARTILE.EXC",
30405
30424
  "QUARTILE.INC",
30406
30425
  "QUERYSTRING",
30426
+ "RANDARRAY",
30407
30427
  "RANK.AVG",
30408
30428
  "RANK.EQ",
30429
+ "REDUCE",
30409
30430
  "RRI",
30431
+ "SCAN",
30410
30432
  "SEC",
30411
30433
  "SECH",
30434
+ "SEQUENCE",
30412
30435
  "SHEET",
30413
30436
  "SHEETS",
30414
30437
  "SKEW.P",
30438
+ "SORTBY",
30415
30439
  "STDEV.P",
30416
30440
  "STDEV.S",
30417
30441
  "SWITCH",
@@ -30421,13 +30445,24 @@ const NON_RETROCOMPATIBLE_FUNCTIONS = [
30421
30445
  "T.INV",
30422
30446
  "T.INV.2T",
30423
30447
  "T.TEST",
30448
+ "TAKE",
30449
+ "TEXTAFTER",
30450
+ "TEXTBEFORE",
30424
30451
  "TEXTJOIN",
30452
+ "TEXTSPLIT",
30453
+ "TOCOL",
30454
+ "TOROW",
30425
30455
  "UNICHAR",
30426
30456
  "UNICODE",
30457
+ "UNIQUE",
30427
30458
  "VAR.P",
30428
30459
  "VAR.S",
30460
+ "VSTACK",
30429
30461
  "WEBSERVICE",
30430
30462
  "WEIBULL.DIST",
30463
+ "WRAPCOLS",
30464
+ "WRAPROWS",
30465
+ "XLOOKUP",
30431
30466
  "XOR",
30432
30467
  "Z.TEST",
30433
30468
  ];
@@ -34606,6 +34641,21 @@ class BordersPlugin extends CorePlugin {
34606
34641
  return [];
34607
34642
  return Object.keys(sheetBorders).map((index) => parseInt(index, 10));
34608
34643
  }
34644
+ /**
34645
+ * Get all the rows which contains at least a border
34646
+ */
34647
+ getRowsWithBorders(sheetId) {
34648
+ const sheetBorders = this.borders[sheetId]?.filter(isDefined$1);
34649
+ if (!sheetBorders)
34650
+ return [];
34651
+ const rowsWithBorders = new Set();
34652
+ for (const rowBorders of sheetBorders) {
34653
+ for (const rowBorder in rowBorders) {
34654
+ rowsWithBorders.add(parseInt(rowBorder, 10));
34655
+ }
34656
+ }
34657
+ return Array.from(rowsWithBorders);
34658
+ }
34609
34659
  /**
34610
34660
  * Get the range of all the rows in the sheet
34611
34661
  */
@@ -34655,7 +34705,7 @@ class BordersPlugin extends CorePlugin {
34655
34705
  destructive: false,
34656
34706
  });
34657
34707
  }
34658
- this.getRowsRange(sheetId)
34708
+ this.getRowsWithBorders(sheetId)
34659
34709
  .filter((row) => row >= start)
34660
34710
  .sort((a, b) => (delta < 0 ? a - b : b - a)) // start by the end when moving up
34661
34711
  .forEach((row) => {
@@ -35119,7 +35169,7 @@ function parseExpression(tokens, parent_priority = 0) {
35119
35169
  * Parse an expression (as a string) into an AST.
35120
35170
  */
35121
35171
  function parse(str) {
35122
- return parseTokens(tokenize(str));
35172
+ return parseTokens(rangeTokenize(str));
35123
35173
  }
35124
35174
  function parseTokens(tokens) {
35125
35175
  tokens = tokens.filter((x) => x.type !== "SPACE");
@@ -41637,6 +41687,7 @@ class Evaluator {
41637
41687
  }
41638
41688
  finally {
41639
41689
  this.cellsBeingComputed.delete(cellId);
41690
+ this.nextPositionsToUpdate.delete(positionId);
41640
41691
  }
41641
41692
  }
41642
41693
  computeAndSave(position) {
@@ -41678,11 +41729,36 @@ class Evaluator {
41678
41729
  forEachSpreadPositionInMatrix(nbColumns, nbRows,
41679
41730
  // thanks to the isMatrix check above, we know that formulaReturn is MatrixFunctionReturn
41680
41731
  this.spreadValues(formulaPosition, formulaReturn));
41732
+ this.invalidatePositionsDependingOnSpread(formulaPosition, nbColumns, nbRows);
41681
41733
  return createEvaluatedCell(formulaReturn[0][0].value, {
41682
41734
  format: cellData.format || formulaReturn[0][0]?.format,
41683
41735
  locale: this.getters.getLocale(),
41684
41736
  });
41685
41737
  }
41738
+ invalidatePositionsDependingOnSpread(arrayFormulaPosition, nbColumns, nbRows) {
41739
+ // the result matrix is split in 2 zones to exclude the array formula position
41740
+ const top = arrayFormulaPosition.row;
41741
+ const left = arrayFormulaPosition.col;
41742
+ const bottom = top + nbRows - 1;
41743
+ const leftColumnZone = {
41744
+ top: top + 1,
41745
+ bottom,
41746
+ left,
41747
+ right: left,
41748
+ };
41749
+ const rightPartZone = {
41750
+ top,
41751
+ bottom,
41752
+ left: left + 1,
41753
+ right: left + nbColumns - 1,
41754
+ };
41755
+ const sheetId = arrayFormulaPosition.sheetId;
41756
+ const invalidatedPositions = this.formulaDependencies().getCellsDependingOn([
41757
+ { sheetId, zone: rightPartZone },
41758
+ { sheetId, zone: leftColumnZone },
41759
+ ]);
41760
+ this.nextPositionsToUpdate.addMany(invalidatedPositions);
41761
+ }
41686
41762
  assertSheetHasEnoughSpaceToSpreadFormulaResult({ sheetId, col, row }, matrixResult) {
41687
41763
  const numberOfCols = this.getters.getNumberCols(sheetId);
41688
41764
  const numberOfRows = this.getters.getNumberRows(sheetId);
@@ -41731,9 +41807,6 @@ class Evaluator {
41731
41807
  });
41732
41808
  const positionId = this.encoder.encode(position);
41733
41809
  this.setEvaluatedCell(positionId, evaluatedCell);
41734
- // check if formula dependencies present in the spread zone
41735
- // if so, they need to be recomputed
41736
- this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
41737
41810
  };
41738
41811
  }
41739
41812
  invalidateSpreading(positionId) {
@@ -57468,6 +57541,6 @@ const constants = {
57468
57541
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
57469
57542
 
57470
57543
 
57471
- __info__.version = "17.0.27";
57472
- __info__.date = "2024-07-02T09:01:48.383Z";
57473
- __info__.hash = "c1c2d01";
57544
+ __info__.version = "17.0.29";
57545
+ __info__.date = "2024-07-08T05:40:27.608Z";
57546
+ __info__.hash = "2d467e3";