@odoo/o-spreadsheet 17.2.14 → 17.2.15

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.15
7
+ * @date 2024-07-08T05:41:55.356Z
8
+ * @hash acfb3e7
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';
@@ -1750,7 +1750,7 @@ const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSepa
1750
1750
  });
1751
1751
  const getNumberRegex = memoize(function getNumberRegex(locale) {
1752
1752
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
1753
- const thousandsSeparator = escapeRegExp(locale.thousandsSeparator);
1753
+ const thousandsSeparator = escapeRegExp(locale.thousandsSeparator || "");
1754
1754
  const pIntegerAndDecimals = `(\\d+(${thousandsSeparator}\\d{3,})*(${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
1755
1755
  const pOnlyDecimals = `(${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
1756
1756
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -1777,7 +1777,7 @@ function isNumber(value, locale) {
1777
1777
  return getNumberRegex(locale).test(value.trim());
1778
1778
  }
1779
1779
  const getInvaluableSymbolsRegexp = memoize(function getInvaluableSymbolsRegexp(locale) {
1780
- return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator)}]`, "g");
1780
+ return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator || "")}]`, "g");
1781
1781
  });
1782
1782
  /**
1783
1783
  * Convert a string into a number. It assumes that the string actually represents
@@ -5357,19 +5357,22 @@ class TokenizingChars {
5357
5357
  }
5358
5358
 
5359
5359
  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")) {
5360
+ if (!locale ||
5361
+ typeof locale !== "object" ||
5362
+ !(!locale.thousandsSeparator || typeof locale.thousandsSeparator === "string")) {
5369
5363
  return false;
5370
5364
  }
5371
- if (!Object.values(locale).every((v) => v)) {
5372
- return false;
5365
+ for (const property of [
5366
+ "code",
5367
+ "name",
5368
+ "decimalSeparator",
5369
+ "dateFormat",
5370
+ "timeFormat",
5371
+ "formulaArgSeparator",
5372
+ ]) {
5373
+ if (!locale[property] || typeof locale[property] !== "string") {
5374
+ return false;
5375
+ }
5373
5376
  }
5374
5377
  if (locale.formulaArgSeparator === locale.decimalSeparator) {
5375
5378
  return false;
@@ -5467,7 +5470,10 @@ function canonicalizeNumberLiteral(content, locale) {
5467
5470
  if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
5468
5471
  return content;
5469
5472
  }
5470
- return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
5473
+ if (locale.thousandsSeparator) {
5474
+ content = content.replaceAll(locale.thousandsSeparator, "");
5475
+ }
5476
+ return content.replace(locale.decimalSeparator, ".");
5471
5477
  }
5472
5478
  /**
5473
5479
  * Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
@@ -6451,6 +6457,146 @@ function transformRangeData(range, executed) {
6451
6457
  return undefined;
6452
6458
  }
6453
6459
 
6460
+ var State;
6461
+ (function (State) {
6462
+ /**
6463
+ * Initial state.
6464
+ * Expecting any reference for the left part of a range
6465
+ * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
6466
+ */
6467
+ State[State["LeftRef"] = 0] = "LeftRef";
6468
+ /**
6469
+ * Expecting any reference for the right part of a range
6470
+ * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
6471
+ */
6472
+ State[State["RightRef"] = 1] = "RightRef";
6473
+ /**
6474
+ * Expecting the separator without any constraint on the right part
6475
+ */
6476
+ State[State["Separator"] = 2] = "Separator";
6477
+ /**
6478
+ * Expecting the separator for a full column range
6479
+ */
6480
+ State[State["FullColumnSeparator"] = 3] = "FullColumnSeparator";
6481
+ /**
6482
+ * Expecting the separator for a full row range
6483
+ */
6484
+ State[State["FullRowSeparator"] = 4] = "FullRowSeparator";
6485
+ /**
6486
+ * Expecting the right part of a full column range
6487
+ * e.g. "1", "A1"
6488
+ */
6489
+ State[State["RightColumnRef"] = 5] = "RightColumnRef";
6490
+ /**
6491
+ * Expecting the right part of a full row range
6492
+ * e.g. "A", "A1"
6493
+ */
6494
+ State[State["RightRowRef"] = 6] = "RightRowRef";
6495
+ /**
6496
+ * Final state. A range has been matched
6497
+ */
6498
+ State[State["Found"] = 7] = "Found";
6499
+ })(State || (State = {}));
6500
+ const goTo = (state, guard = () => true) => [
6501
+ {
6502
+ goTo: state,
6503
+ guard,
6504
+ },
6505
+ ];
6506
+ const goToMulti = (state, guard = () => true) => ({
6507
+ goTo: state,
6508
+ guard,
6509
+ });
6510
+ const machine = {
6511
+ [State.LeftRef]: {
6512
+ REFERENCE: goTo(State.Separator),
6513
+ NUMBER: goTo(State.FullRowSeparator),
6514
+ SYMBOL: [
6515
+ goToMulti(State.FullColumnSeparator, (token) => isColReference(token.value)),
6516
+ goToMulti(State.FullRowSeparator, (token) => isRowReference(token.value)),
6517
+ ],
6518
+ },
6519
+ [State.FullColumnSeparator]: {
6520
+ SPACE: goTo(State.FullColumnSeparator),
6521
+ OPERATOR: goTo(State.RightColumnRef, (token) => token.value === ":"),
6522
+ },
6523
+ [State.FullRowSeparator]: {
6524
+ SPACE: goTo(State.FullRowSeparator),
6525
+ OPERATOR: goTo(State.RightRowRef, (token) => token.value === ":"),
6526
+ },
6527
+ [State.Separator]: {
6528
+ SPACE: goTo(State.Separator),
6529
+ OPERATOR: goTo(State.RightRef, (token) => token.value === ":"),
6530
+ },
6531
+ [State.RightRef]: {
6532
+ SPACE: goTo(State.RightRef),
6533
+ NUMBER: goTo(State.Found),
6534
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
6535
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
6536
+ },
6537
+ [State.RightColumnRef]: {
6538
+ SPACE: goTo(State.RightColumnRef),
6539
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
6540
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
6541
+ },
6542
+ [State.RightRowRef]: {
6543
+ SPACE: goTo(State.RightRowRef),
6544
+ NUMBER: goTo(State.Found),
6545
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
6546
+ SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
6547
+ },
6548
+ [State.Found]: {},
6549
+ };
6550
+ /**
6551
+ * Check if the list of tokens starts with a sequence of tokens representing
6552
+ * a range.
6553
+ * If a range is found, the sequence is removed from the list and is returned
6554
+ * as a single token.
6555
+ */
6556
+ function matchReference(tokens) {
6557
+ let head = 0;
6558
+ let transitions = machine[State.LeftRef];
6559
+ let matchedTokens = "";
6560
+ while (transitions !== undefined) {
6561
+ const token = tokens[head++];
6562
+ if (!token) {
6563
+ return null;
6564
+ }
6565
+ const transition = transitions[token.type]?.find((transition) => transition.guard(token));
6566
+ const nextState = transition ? transition.goTo : undefined;
6567
+ switch (nextState) {
6568
+ case undefined:
6569
+ return null;
6570
+ case State.Found:
6571
+ matchedTokens += token.value;
6572
+ tokens.splice(0, head);
6573
+ return {
6574
+ type: "REFERENCE",
6575
+ value: matchedTokens,
6576
+ };
6577
+ default:
6578
+ transitions = machine[nextState];
6579
+ matchedTokens += token.value;
6580
+ break;
6581
+ }
6582
+ }
6583
+ return null;
6584
+ }
6585
+ /**
6586
+ * Take the result of the tokenizer and transform it to be usable in the
6587
+ * manipulations of range
6588
+ *
6589
+ * @param formula
6590
+ */
6591
+ function rangeTokenize(formula, locale = DEFAULT_LOCALE) {
6592
+ const tokens = tokenize(formula, locale);
6593
+ const result = [];
6594
+ while (tokens.length) {
6595
+ result.push(matchReference(tokens) || tokens.shift());
6596
+ }
6597
+ return result;
6598
+ }
6599
+
6454
6600
  const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
6455
6601
  const UNARY_OPERATORS_PREFIX = ["-", "+"];
6456
6602
  const UNARY_OPERATORS_POSTFIX = ["%"];
@@ -6599,7 +6745,7 @@ function parseExpression(tokens, parent_priority = 0) {
6599
6745
  * Parse an expression (as a string) into an AST.
6600
6746
  */
6601
6747
  function parse(str) {
6602
- return parseTokens(tokenize(str));
6748
+ return parseTokens(rangeTokenize(str));
6603
6749
  }
6604
6750
  function parseTokens(tokens) {
6605
6751
  tokens = tokens.filter((x) => x.type !== "SPACE");
@@ -6735,146 +6881,6 @@ function rightOperandToFormula(operationAST) {
6735
6881
  return needParenthesis ? `(${astToFormula(rightOperation)})` : astToFormula(rightOperation);
6736
6882
  }
6737
6883
 
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
6884
  /**
6879
6885
  * Add the following information on tokens:
6880
6886
  * - length
@@ -20546,10 +20552,6 @@ function createLineOrScatterChartRuntime(chart, getters) {
20546
20552
  const cumulative = "cumulative" in chart ? chart.cumulative : false;
20547
20553
  const colors = new ChartColors();
20548
20554
  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
20555
  const color = colors.next();
20554
20556
  let backgroundRGBA = colorToRGBA(color);
20555
20557
  if (stacked) {
@@ -20565,6 +20567,10 @@ function createLineOrScatterChartRuntime(chart, getters) {
20565
20567
  return value;
20566
20568
  });
20567
20569
  }
20570
+ if (["linear", "time"].includes(axisType)) {
20571
+ // Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
20572
+ data = data.map((y, index) => ({ x: labels[index] || undefined, y }));
20573
+ }
20568
20574
  const backgroundColor = rgbaToHex(backgroundRGBA);
20569
20575
  const dataset = {
20570
20576
  label,
@@ -30422,7 +30428,13 @@ class SettingsPanel extends Component {
30422
30428
  }
30423
30429
  async loadLocales() {
30424
30430
  this.loadedLocales = (await this.env.loadLocales())
30425
- .filter(isValidLocale)
30431
+ .filter((locale) => {
30432
+ const isValid = isValidLocale(locale);
30433
+ if (!isValid) {
30434
+ console.warn(`Invalid locale: ${locale["code"]} ${locale}`);
30435
+ }
30436
+ return isValid;
30437
+ })
30426
30438
  .sort((a, b) => a.name.localeCompare(b.name));
30427
30439
  }
30428
30440
  get numberFormatPreview() {
@@ -36230,6 +36242,7 @@ class Grid extends Component {
36230
36242
  return;
36231
36243
  }
36232
36244
  if (clipboardData.types.indexOf(ClipboardMIMEType.PlainText) > -1) {
36245
+ ev.preventDefault();
36233
36246
  const content = clipboardData.getData(ClipboardMIMEType.PlainText);
36234
36247
  const target = this.env.model.getters.getSelectedZones();
36235
36248
  const clipboardString = this.env.model.getters.getClipboardTextContent();
@@ -40806,6 +40819,21 @@ class BordersPlugin extends CorePlugin {
40806
40819
  return [];
40807
40820
  return Object.keys(sheetBorders).map((index) => parseInt(index, 10));
40808
40821
  }
40822
+ /**
40823
+ * Get all the rows which contains at least a border
40824
+ */
40825
+ getRowsWithBorders(sheetId) {
40826
+ const sheetBorders = this.borders[sheetId]?.filter(isDefined$1);
40827
+ if (!sheetBorders)
40828
+ return [];
40829
+ const rowsWithBorders = new Set();
40830
+ for (const rowBorders of sheetBorders) {
40831
+ for (const rowBorder in rowBorders) {
40832
+ rowsWithBorders.add(parseInt(rowBorder, 10));
40833
+ }
40834
+ }
40835
+ return Array.from(rowsWithBorders);
40836
+ }
40809
40837
  /**
40810
40838
  * Get the range of all the rows in the sheet
40811
40839
  */
@@ -40855,7 +40883,7 @@ class BordersPlugin extends CorePlugin {
40855
40883
  destructive: false,
40856
40884
  });
40857
40885
  }
40858
- this.getRowsRange(sheetId)
40886
+ this.getRowsWithBorders(sheetId)
40859
40887
  .filter((row) => row >= start)
40860
40888
  .sort((a, b) => (delta < 0 ? a - b : b - a)) // start by the end when moving up
40861
40889
  .forEach((row) => {
@@ -60798,6 +60826,6 @@ const constants = {
60798
60826
  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
60827
 
60800
60828
 
60801
- __info__.version = "17.2.14";
60802
- __info__.date = "2024-07-02T10:35:53.850Z";
60803
- __info__.hash = "fb0d979";
60829
+ __info__.version = "17.2.15";
60830
+ __info__.date = "2024-07-08T05:41:55.356Z";
60831
+ __info__.hash = "acfb3e7";