@odoo/o-spreadsheet 18.0.20 → 18.0.21

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 18.0.20
6
- * @date 2025-03-19T08:21:32.426Z
7
- * @hash 3f48d8b
5
+ * @version 18.0.21
6
+ * @date 2025-03-26T12:49:46.872Z
7
+ * @hash c687e1c
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -1112,7 +1112,10 @@
1112
1112
  }
1113
1113
  else if (stringVals.length === 4) {
1114
1114
  const alpha = parseFloat(stringVals.pop() || "1");
1115
- alphaHex = Math.round((alpha || 1) * 255);
1115
+ if (isNaN(alpha)) {
1116
+ throw new Error("invalid alpha value");
1117
+ }
1118
+ alphaHex = Math.round(alpha * 255);
1116
1119
  }
1117
1120
  const vals = stringVals.map((val) => parseInt(val, 10));
1118
1121
  if (alphaHex !== 255) {
@@ -6836,7 +6839,7 @@
6836
6839
  */
6837
6840
  function canonicalizeNumberContent(content, locale) {
6838
6841
  return content.startsWith("=")
6839
- ? canonicalizeFormula$1(content, locale)
6842
+ ? canonicalizeFormula(content, locale)
6840
6843
  : canonicalizeNumberLiteral(content, locale);
6841
6844
  }
6842
6845
  /**
@@ -6851,7 +6854,7 @@
6851
6854
  */
6852
6855
  function canonicalizeContent(content, locale) {
6853
6856
  return content.startsWith("=")
6854
- ? canonicalizeFormula$1(content, locale)
6857
+ ? canonicalizeFormula(content, locale)
6855
6858
  : canonicalizeLiteral(content, locale);
6856
6859
  }
6857
6860
  /**
@@ -6867,15 +6870,21 @@
6867
6870
  ? localizeFormula(content, locale)
6868
6871
  : localizeLiteral(content, locale);
6869
6872
  }
6873
+ /** Change a number string to its canonical form (en_US locale) */
6874
+ function canonicalizeNumberValue(content, locale) {
6875
+ return content.startsWith("=")
6876
+ ? canonicalizeFormula(content, locale)
6877
+ : canonicalizeNumberLiteral(content, locale);
6878
+ }
6870
6879
  /** Change a formula to its canonical form (en_US locale) */
6871
- function canonicalizeFormula$1(formula, locale) {
6872
- return _localizeFormula$1(formula, locale, DEFAULT_LOCALE);
6880
+ function canonicalizeFormula(formula, locale) {
6881
+ return _localizeFormula(formula, locale, DEFAULT_LOCALE);
6873
6882
  }
6874
6883
  /** Change a formula from the canonical form to the given locale */
6875
6884
  function localizeFormula(formula, locale) {
6876
- return _localizeFormula$1(formula, DEFAULT_LOCALE, locale);
6885
+ return _localizeFormula(formula, DEFAULT_LOCALE, locale);
6877
6886
  }
6878
- function _localizeFormula$1(formula, fromLocale, toLocale) {
6887
+ function _localizeFormula(formula, fromLocale, toLocale) {
6879
6888
  if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
6880
6889
  fromLocale.decimalSeparator === toLocale.decimalSeparator) {
6881
6890
  return formula;
@@ -7031,37 +7040,6 @@
7031
7040
  return locale.dateFormat + " " + locale.timeFormat;
7032
7041
  }
7033
7042
 
7034
- /** Change a number string to its canonical form (en_US locale) */
7035
- function canonicalizeNumberValue(content, locale) {
7036
- return content.startsWith("=")
7037
- ? canonicalizeFormula(content, locale)
7038
- : canonicalizeNumberLiteral(content, locale);
7039
- }
7040
- /** Change a formula to its canonical form (en_US locale) */
7041
- function canonicalizeFormula(formula, locale) {
7042
- return _localizeFormula(formula, locale, DEFAULT_LOCALE);
7043
- }
7044
- function _localizeFormula(formula, fromLocale, toLocale) {
7045
- if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
7046
- fromLocale.decimalSeparator === toLocale.decimalSeparator) {
7047
- return formula;
7048
- }
7049
- const tokens = tokenize(formula, fromLocale);
7050
- let localizedFormula = "";
7051
- for (const token of tokens) {
7052
- if (token.type === "NUMBER") {
7053
- localizedFormula += token.value.replace(fromLocale.decimalSeparator, toLocale.decimalSeparator);
7054
- }
7055
- else if (token.type === "ARG_SEPARATOR") {
7056
- localizedFormula += toLocale.formulaArgSeparator;
7057
- }
7058
- else {
7059
- localizedFormula += token.value;
7060
- }
7061
- }
7062
- return localizedFormula;
7063
- }
7064
-
7065
7043
  function boolAnd(args) {
7066
7044
  let foundBoolean = false;
7067
7045
  let acc = true;
@@ -10072,9 +10050,9 @@ stores.inject(MyMetaStore, storeInstance);
10072
10050
  /** In XLSX color format (no #) */
10073
10051
  const AUTO_COLOR = "000000";
10074
10052
  const XLSX_ICONSET_MAP = {
10075
- arrow: "3Arrows",
10053
+ arrows: "3Arrows",
10076
10054
  smiley: "3Symbols",
10077
- dot: "3TrafficLights1",
10055
+ dots: "3TrafficLights1",
10078
10056
  };
10079
10057
  const NAMESPACE = {
10080
10058
  styleSheet: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
@@ -10746,6 +10724,7 @@ stores.inject(MyMetaStore, storeInstance);
10746
10724
  };
10747
10725
  /** Map between legend position in XLSX file and human readable position */
10748
10726
  const DRAWING_LEGEND_POSITION_CONVERSION_MAP = {
10727
+ none: "none",
10749
10728
  b: "bottom",
10750
10729
  t: "top",
10751
10730
  l: "left",
@@ -13502,7 +13481,7 @@ stores.inject(MyMetaStore, storeInstance);
13502
13481
  default: "ffffff",
13503
13482
  }).asString(),
13504
13483
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
13505
- default: "b",
13484
+ default: "none",
13506
13485
  }).asString()],
13507
13486
  stacked: barChartGrouping === "stacked",
13508
13487
  fontColor: "000000",
@@ -13536,7 +13515,7 @@ stores.inject(MyMetaStore, storeInstance);
13536
13515
  default: "ffffff",
13537
13516
  }).asString(),
13538
13517
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(chartElement, "c:legendPos", "val", {
13539
- default: "b",
13518
+ default: "none",
13540
13519
  }).asString()],
13541
13520
  stacked: barChartGrouping === "stacked",
13542
13521
  fontColor: "000000",
@@ -16728,7 +16707,8 @@ stores.inject(MyMetaStore, storeInstance);
16728
16707
  }
16729
16708
  }
16730
16709
  else if (dataSets.length === 1) {
16731
- for (let i = 0; i < getData(getters, dataSets[0]).length; i++) {
16710
+ const dataLength = getData(getters, dataSets[0]).length;
16711
+ for (let i = 0; i < dataLength; i++) {
16732
16712
  labels.formattedValues.push("");
16733
16713
  labels.values.push("");
16734
16714
  }
@@ -25974,11 +25954,26 @@ stores.inject(MyMetaStore, storeInstance);
25974
25954
  const _searchFor = toString(searchFor).toLowerCase();
25975
25955
  const _textToSearch = toString(textToSearch).toLowerCase();
25976
25956
  const _startingAt = toNumber(startingAt, this.locale);
25977
- assert(() => _textToSearch !== "", _t("The text_to_search must be non-empty."));
25978
- assert(() => _startingAt >= 1, _t("The starting_at (%s) must be greater than or equal to 1.", _startingAt.toString()));
25957
+ if (_textToSearch === "") {
25958
+ return {
25959
+ value: CellErrorType.GenericError,
25960
+ message: _t("The text_to_search must be non-empty."),
25961
+ };
25962
+ }
25963
+ if (_startingAt < 1) {
25964
+ return {
25965
+ value: CellErrorType.GenericError,
25966
+ message: _t("The starting_at (%s) must be greater than or equal to 1.", _startingAt),
25967
+ };
25968
+ }
25979
25969
  const result = _textToSearch.indexOf(_searchFor, _startingAt - 1);
25980
- assert(() => result >= 0, _t("In [[FUNCTION_NAME]] evaluation, cannot find '%s' within '%s'.", _searchFor, _textToSearch));
25981
- return result + 1;
25970
+ if (result === -1) {
25971
+ return {
25972
+ value: CellErrorType.GenericError,
25973
+ message: _t("In [[FUNCTION_NAME]] evaluation, cannot find '%s' within '%s'.", _searchFor, _textToSearch),
25974
+ };
25975
+ }
25976
+ return { value: result + 1 };
25982
25977
  },
25983
25978
  isExported: true,
25984
25979
  };
@@ -27828,11 +27823,14 @@ stores.inject(MyMetaStore, storeInstance);
27828
27823
  }
27829
27824
  }
27830
27825
  function compileTokensOrThrow(tokens) {
27831
- const { dependencies, constantValues, symbols } = formulaArguments(tokens);
27832
- const cacheKey = compilationCacheKey(tokens, dependencies, constantValues);
27826
+ const { dependencies, literalValues, symbols } = formulaArguments(tokens);
27827
+ const cacheKey = compilationCacheKey(tokens);
27833
27828
  if (!functionCache[cacheKey]) {
27834
27829
  const ast = parseTokens([...tokens]);
27835
27830
  const scope = new Scope();
27831
+ let stringCount = 0;
27832
+ let numberCount = 0;
27833
+ let dependencyCount = 0;
27836
27834
  if (ast.type === "BIN_OPERATION" && ast.value === ":") {
27837
27835
  throw new BadExpressionError(_t("Invalid formula"));
27838
27836
  }
@@ -27905,16 +27903,15 @@ stores.inject(MyMetaStore, storeInstance);
27905
27903
  case "BOOLEAN":
27906
27904
  return code.return(`{ value: ${ast.value} }`);
27907
27905
  case "NUMBER":
27908
- return code.return(`{ value: this.constantValues.numbers[${constantValues.numbers.indexOf(ast.value)}] }`);
27906
+ return code.return(`this.literalValues.numbers[${numberCount++}]`);
27909
27907
  case "STRING":
27910
- return code.return(`{ value: this.constantValues.strings[${constantValues.strings.indexOf(ast.value)}] }`);
27908
+ return code.return(`this.literalValues.strings[${stringCount++}]`);
27911
27909
  case "REFERENCE":
27912
- const referenceIndex = dependencies.indexOf(ast.value);
27913
27910
  if ((!isMeta && ast.value.includes(":")) || hasRange) {
27914
- return code.return(`range(deps[${referenceIndex}])`);
27911
+ return code.return(`range(deps[${dependencyCount++}])`);
27915
27912
  }
27916
27913
  else {
27917
- return code.return(`ref(deps[${referenceIndex}], ${isMeta ? "true" : "false"})`);
27914
+ return code.return(`ref(deps[${dependencyCount++}], ${isMeta ? "true" : "false"})`);
27918
27915
  }
27919
27916
  case "FUNCALL":
27920
27917
  const args = compileFunctionArgs(ast).map((arg) => arg.assignResultToVariable());
@@ -27946,7 +27943,7 @@ stores.inject(MyMetaStore, storeInstance);
27946
27943
  const compiledFormula = {
27947
27944
  execute: functionCache[cacheKey],
27948
27945
  dependencies,
27949
- constantValues,
27946
+ literalValues,
27950
27947
  symbols,
27951
27948
  tokens,
27952
27949
  isBadExpression: false,
@@ -27958,33 +27955,31 @@ stores.inject(MyMetaStore, storeInstance);
27958
27955
  * References, numbers and strings are replaced with placeholders because
27959
27956
  * the compiled formula does not depend on their actual value.
27960
27957
  * Both `=A1+1+"2"` and `=A2+2+"3"` are compiled to the exact same function.
27961
- *
27962
27958
  * Spaces are also ignored to compute the cache key.
27963
27959
  *
27964
- * A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|0|+|1|+SUM(|N0|,|N0|,|S0|)`
27960
+ * A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|C|+|C|+SUM(|N|,|N|,|S|)`
27965
27961
  */
27966
- function compilationCacheKey(tokens, dependencies, constantValues, symbols) {
27962
+ function compilationCacheKey(tokens) {
27967
27963
  let cacheKey = "";
27968
27964
  for (const token of tokens) {
27969
27965
  switch (token.type) {
27970
27966
  case "STRING":
27971
- const value = removeStringQuotes(token.value);
27972
- cacheKey += `|S${constantValues.strings.indexOf(value)}|`;
27967
+ cacheKey += "|S|";
27973
27968
  break;
27974
27969
  case "NUMBER":
27975
- cacheKey += `|N${constantValues.numbers.indexOf(parseNumber(token.value, DEFAULT_LOCALE))}|`;
27970
+ cacheKey += "|N|";
27976
27971
  break;
27977
27972
  case "REFERENCE":
27978
27973
  case "INVALID_REFERENCE":
27979
27974
  if (token.value.includes(":")) {
27980
- cacheKey += `R|${dependencies.indexOf(token.value)}|`;
27975
+ cacheKey += "|R|";
27981
27976
  }
27982
27977
  else {
27983
- cacheKey += `C|${dependencies.indexOf(token.value)}|`;
27978
+ cacheKey += "|C|";
27984
27979
  }
27985
27980
  break;
27986
27981
  case "SPACE":
27987
- cacheKey += "";
27982
+ // ignore spaces
27988
27983
  break;
27989
27984
  default:
27990
27985
  cacheKey += token.value;
@@ -27997,7 +27992,7 @@ stores.inject(MyMetaStore, storeInstance);
27997
27992
  * Return formula arguments which are references, strings and numbers.
27998
27993
  */
27999
27994
  function formulaArguments(tokens) {
28000
- const constantValues = {
27995
+ const literalValues = {
28001
27996
  numbers: [],
28002
27997
  strings: [],
28003
27998
  };
@@ -28011,15 +28006,11 @@ stores.inject(MyMetaStore, storeInstance);
28011
28006
  break;
28012
28007
  case "STRING":
28013
28008
  const value = removeStringQuotes(token.value);
28014
- if (!constantValues.strings.includes(value)) {
28015
- constantValues.strings.push(value);
28016
- }
28009
+ literalValues.strings.push({ value });
28017
28010
  break;
28018
28011
  case "NUMBER": {
28019
28012
  const value = parseNumber(token.value, DEFAULT_LOCALE);
28020
- if (!constantValues.numbers.includes(value)) {
28021
- constantValues.numbers.push(value);
28022
- }
28013
+ literalValues.numbers.push({ value });
28023
28014
  break;
28024
28015
  }
28025
28016
  case "SYMBOL": {
@@ -28030,7 +28021,7 @@ stores.inject(MyMetaStore, storeInstance);
28030
28021
  }
28031
28022
  return {
28032
28023
  dependencies,
28033
- constantValues,
28024
+ literalValues,
28034
28025
  symbols,
28035
28026
  };
28036
28027
  }
@@ -68298,7 +68289,9 @@ stores.inject(MyMetaStore, storeInstance);
68298
68289
  border: 1px solid;
68299
68290
  font-family: ${DEFAULT_FONT};
68300
68291
 
68301
- .o-composer:empty:not(:focus):not(.active)::before {
68292
+ /* In readonly we always show the fx icon if the composer is empty, not matter the focus */
68293
+ .o-composer:empty:not(:focus):not(.active)::before,
68294
+ &.o-topbar-composer-readonly .o-composer:empty::before {
68302
68295
  content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
68303
68296
  position: relative;
68304
68297
  top: 20%;
@@ -71659,10 +71652,14 @@ stores.inject(MyMetaStore, storeInstance);
71659
71652
  continue;
71660
71653
  }
71661
71654
  const cfValueObjectNodes = cfValueObject.map((attrs) => escapeXml /*xml*/ `<cfvo ${formatAttributes(attrs)} />`);
71655
+ const iconSetAttrs = [["iconSet", getIconSet(rule.icons)]];
71656
+ if (isIconSetReversed(rule.icons)) {
71657
+ iconSetAttrs.push(["reverse", "1"]);
71658
+ }
71662
71659
  conditionalFormats.push(escapeXml /*xml*/ `
71663
71660
  <conditionalFormatting sqref="${range}">
71664
71661
  <cfRule ${formatAttributes(ruleAttributes)}>
71665
- <iconSet iconSet="${getIconSet(rule.icons)}">
71662
+ <iconSet ${formatAttributes(iconSetAttrs)}>
71666
71663
  ${joinXmlNodes(cfValueObjectNodes)}
71667
71664
  </iconSet>
71668
71665
  </cfRule>
@@ -71680,9 +71677,21 @@ stores.inject(MyMetaStore, storeInstance);
71680
71677
  ["stopIfTrue", cf.stopIfTrue ? 1 : 0],
71681
71678
  ];
71682
71679
  }
71680
+ function isIconSetReversed(iconSet) {
71681
+ const defaultIconSet = ICON_SETS[detectIconsType(iconSet)];
71682
+ return iconSet.upper === defaultIconSet.bad && iconSet.lower === defaultIconSet.good;
71683
+ }
71683
71684
  function getIconSet(iconSet) {
71684
- return XLSX_ICONSET_MAP[Object.keys(XLSX_ICONSET_MAP).find((key) => iconSet.upper.toLowerCase().startsWith(key)) ||
71685
- "dots"];
71685
+ return XLSX_ICONSET_MAP[detectIconsType(iconSet)];
71686
+ }
71687
+ /**
71688
+ * Partial detection based on "upper" point only.
71689
+ * We support any arbitrary icon in the set, while excel doesn't allow
71690
+ * mixing icons from different types.
71691
+ */
71692
+ function detectIconsType(iconSet) {
71693
+ const type = Object.keys(ICON_SETS).find((type) => Object.values(ICON_SETS[type]).includes(iconSet.upper)) || "dots";
71694
+ return type;
71686
71695
  }
71687
71696
  function thresholdAttributes(threshold, position) {
71688
71697
  const type = getExcelThresholdType(threshold.type, position);
@@ -73606,9 +73615,9 @@ stores.inject(MyMetaStore, storeInstance);
73606
73615
  exports.tokenize = tokenize;
73607
73616
 
73608
73617
 
73609
- __info__.version = "18.0.20";
73610
- __info__.date = "2025-03-19T08:21:32.426Z";
73611
- __info__.hash = "3f48d8b";
73618
+ __info__.version = "18.0.21";
73619
+ __info__.date = "2025-03-26T12:49:46.872Z";
73620
+ __info__.hash = "c687e1c";
73612
73621
 
73613
73622
 
73614
73623
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);