@odoo/o-spreadsheet 18.2.4 → 18.2.5

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.2.4
6
- * @date 2025-03-19T08:20:57.717Z
7
- * @hash 958936a
5
+ * @version 18.2.5
6
+ * @date 2025-03-26T12:47:44.113Z
7
+ * @hash 4675edd
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -1132,7 +1132,10 @@
1132
1132
  }
1133
1133
  else if (stringVals.length === 4) {
1134
1134
  const alpha = parseFloat(stringVals.pop() || "1");
1135
- alphaHex = Math.round((alpha || 1) * 255);
1135
+ if (isNaN(alpha)) {
1136
+ throw new Error("invalid alpha value");
1137
+ }
1138
+ alphaHex = Math.round(alpha * 255);
1136
1139
  }
1137
1140
  const vals = stringVals.map((val) => parseInt(val, 10));
1138
1141
  if (alphaHex !== 255) {
@@ -7000,7 +7003,7 @@
7000
7003
  */
7001
7004
  function canonicalizeNumberContent(content, locale) {
7002
7005
  return content.startsWith("=")
7003
- ? canonicalizeFormula$1(content, locale)
7006
+ ? canonicalizeFormula(content, locale)
7004
7007
  : canonicalizeNumberLiteral(content, locale);
7005
7008
  }
7006
7009
  /**
@@ -7015,7 +7018,7 @@
7015
7018
  */
7016
7019
  function canonicalizeContent(content, locale) {
7017
7020
  return content.startsWith("=")
7018
- ? canonicalizeFormula$1(content, locale)
7021
+ ? canonicalizeFormula(content, locale)
7019
7022
  : canonicalizeLiteral(content, locale);
7020
7023
  }
7021
7024
  /**
@@ -7031,15 +7034,21 @@
7031
7034
  ? localizeFormula(content, locale)
7032
7035
  : localizeLiteral(content, locale);
7033
7036
  }
7037
+ /** Change a number string to its canonical form (en_US locale) */
7038
+ function canonicalizeNumberValue(content, locale) {
7039
+ return content.startsWith("=")
7040
+ ? canonicalizeFormula(content, locale)
7041
+ : canonicalizeNumberLiteral(content, locale);
7042
+ }
7034
7043
  /** Change a formula to its canonical form (en_US locale) */
7035
- function canonicalizeFormula$1(formula, locale) {
7036
- return _localizeFormula$1(formula, locale, DEFAULT_LOCALE);
7044
+ function canonicalizeFormula(formula, locale) {
7045
+ return _localizeFormula(formula, locale, DEFAULT_LOCALE);
7037
7046
  }
7038
7047
  /** Change a formula from the canonical form to the given locale */
7039
7048
  function localizeFormula(formula, locale) {
7040
- return _localizeFormula$1(formula, DEFAULT_LOCALE, locale);
7049
+ return _localizeFormula(formula, DEFAULT_LOCALE, locale);
7041
7050
  }
7042
- function _localizeFormula$1(formula, fromLocale, toLocale) {
7051
+ function _localizeFormula(formula, fromLocale, toLocale) {
7043
7052
  if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
7044
7053
  fromLocale.decimalSeparator === toLocale.decimalSeparator) {
7045
7054
  return formula;
@@ -7194,37 +7203,6 @@
7194
7203
  return locale.dateFormat + " " + locale.timeFormat;
7195
7204
  }
7196
7205
 
7197
- /** Change a number string to its canonical form (en_US locale) */
7198
- function canonicalizeNumberValue(content, locale) {
7199
- return content.startsWith("=")
7200
- ? canonicalizeFormula(content, locale)
7201
- : canonicalizeNumberLiteral(content, locale);
7202
- }
7203
- /** Change a formula to its canonical form (en_US locale) */
7204
- function canonicalizeFormula(formula, locale) {
7205
- return _localizeFormula(formula, locale, DEFAULT_LOCALE);
7206
- }
7207
- function _localizeFormula(formula, fromLocale, toLocale) {
7208
- if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
7209
- fromLocale.decimalSeparator === toLocale.decimalSeparator) {
7210
- return formula;
7211
- }
7212
- const tokens = tokenize(formula, fromLocale);
7213
- let localizedFormula = "";
7214
- for (const token of tokens) {
7215
- if (token.type === "NUMBER") {
7216
- localizedFormula += token.value.replace(fromLocale.decimalSeparator, toLocale.decimalSeparator);
7217
- }
7218
- else if (token.type === "ARG_SEPARATOR") {
7219
- localizedFormula += toLocale.formulaArgSeparator;
7220
- }
7221
- else {
7222
- localizedFormula += token.value;
7223
- }
7224
- }
7225
- return localizedFormula;
7226
- }
7227
-
7228
7206
  function boolAnd(args) {
7229
7207
  let foundBoolean = false;
7230
7208
  let acc = true;
@@ -9600,6 +9578,7 @@ stores.inject(MyMetaStore, storeInstance);
9600
9578
  }
9601
9579
 
9602
9580
  const TREND_LINE_XAXIS_ID = "x1";
9581
+ const MOVING_AVERAGE_TREND_LINE_XAXIS_ID = "xMovingAverage";
9603
9582
  /**
9604
9583
  * This file contains helpers that are common to different charts (mainly
9605
9584
  * line, bar and pie charts)
@@ -9950,6 +9929,9 @@ stores.inject(MyMetaStore, storeInstance);
9950
9929
  }
9951
9930
  return label;
9952
9931
  }
9932
+ function isTrendLineAxis(axisID) {
9933
+ return axisID === TREND_LINE_XAXIS_ID || axisID === MOVING_AVERAGE_TREND_LINE_XAXIS_ID;
9934
+ }
9953
9935
 
9954
9936
  /** This is a chartJS plugin that will draw the values of each data next to the point/bar/pie slice */
9955
9937
  const chartShowValuesPlugin = {
@@ -9994,7 +9976,7 @@ stores.inject(MyMetaStore, storeInstance);
9994
9976
  const yMin = chart.chartArea.top;
9995
9977
  const textsPositions = {};
9996
9978
  for (const dataset of chart._metasets) {
9997
- if (dataset.xAxisID === TREND_LINE_XAXIS_ID || dataset.hidden) {
9979
+ if (isTrendLineAxis(dataset.axisID) || dataset.hidden) {
9998
9980
  continue;
9999
9981
  }
10000
9982
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -10037,7 +10019,7 @@ stores.inject(MyMetaStore, storeInstance);
10037
10019
  const xMin = chart.chartArea.left;
10038
10020
  const textsPositions = {};
10039
10021
  for (const dataset of chart._metasets) {
10040
- if (dataset.xAxisID === TREND_LINE_XAXIS_ID) {
10022
+ if (isTrendLineAxis(dataset.axisID)) {
10041
10023
  return; // ignore trend lines
10042
10024
  }
10043
10025
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -20545,11 +20527,26 @@ stores.inject(MyMetaStore, storeInstance);
20545
20527
  const _searchFor = toString(searchFor).toLowerCase();
20546
20528
  const _textToSearch = toString(textToSearch).toLowerCase();
20547
20529
  const _startingAt = toNumber(startingAt, this.locale);
20548
- assert(() => _textToSearch !== "", _t("The text_to_search must be non-empty."));
20549
- assert(() => _startingAt >= 1, _t("The starting_at (%s) must be greater than or equal to 1.", _startingAt.toString()));
20530
+ if (_textToSearch === "") {
20531
+ return {
20532
+ value: CellErrorType.GenericError,
20533
+ message: _t("The text_to_search must be non-empty."),
20534
+ };
20535
+ }
20536
+ if (_startingAt < 1) {
20537
+ return {
20538
+ value: CellErrorType.GenericError,
20539
+ message: _t("The starting_at (%s) must be greater than or equal to 1.", _startingAt),
20540
+ };
20541
+ }
20550
20542
  const result = _textToSearch.indexOf(_searchFor, _startingAt - 1);
20551
- assert(() => result >= 0, _t("In [[FUNCTION_NAME]] evaluation, cannot find '%s' within '%s'.", _searchFor, _textToSearch));
20552
- return result + 1;
20543
+ if (result === -1) {
20544
+ return {
20545
+ value: CellErrorType.GenericError,
20546
+ message: _t("In [[FUNCTION_NAME]] evaluation, cannot find '%s' within '%s'.", _searchFor, _textToSearch),
20547
+ };
20548
+ }
20549
+ return { value: result + 1 };
20553
20550
  },
20554
20551
  isExported: true,
20555
20552
  };
@@ -21884,11 +21881,14 @@ stores.inject(MyMetaStore, storeInstance);
21884
21881
  }
21885
21882
  }
21886
21883
  function compileTokensOrThrow(tokens) {
21887
- const { dependencies, constantValues, symbols } = formulaArguments(tokens);
21888
- const cacheKey = compilationCacheKey(tokens, dependencies, constantValues);
21884
+ const { dependencies, literalValues, symbols } = formulaArguments(tokens);
21885
+ const cacheKey = compilationCacheKey(tokens);
21889
21886
  if (!functionCache[cacheKey]) {
21890
21887
  const ast = parseTokens([...tokens]);
21891
21888
  const scope = new Scope();
21889
+ let stringCount = 0;
21890
+ let numberCount = 0;
21891
+ let dependencyCount = 0;
21892
21892
  if (ast.type === "BIN_OPERATION" && ast.value === ":") {
21893
21893
  throw new BadExpressionError(_t("Invalid formula"));
21894
21894
  }
@@ -21962,16 +21962,15 @@ stores.inject(MyMetaStore, storeInstance);
21962
21962
  case "BOOLEAN":
21963
21963
  return code.return(`{ value: ${ast.value} }`);
21964
21964
  case "NUMBER":
21965
- return code.return(`{ value: this.constantValues.numbers[${constantValues.numbers.indexOf(ast.value)}] }`);
21965
+ return code.return(`this.literalValues.numbers[${numberCount++}]`);
21966
21966
  case "STRING":
21967
- return code.return(`{ value: this.constantValues.strings[${constantValues.strings.indexOf(ast.value)}] }`);
21967
+ return code.return(`this.literalValues.strings[${stringCount++}]`);
21968
21968
  case "REFERENCE":
21969
- const referenceIndex = dependencies.indexOf(ast.value);
21970
21969
  if ((!isMeta && ast.value.includes(":")) || hasRange) {
21971
- return code.return(`range(deps[${referenceIndex}])`);
21970
+ return code.return(`range(deps[${dependencyCount++}])`);
21972
21971
  }
21973
21972
  else {
21974
- return code.return(`ref(deps[${referenceIndex}], ${isMeta ? "true" : "false"})`);
21973
+ return code.return(`ref(deps[${dependencyCount++}], ${isMeta ? "true" : "false"})`);
21975
21974
  }
21976
21975
  case "FUNCALL":
21977
21976
  const args = compileFunctionArgs(ast).map((arg) => arg.assignResultToVariable());
@@ -22003,7 +22002,7 @@ stores.inject(MyMetaStore, storeInstance);
22003
22002
  const compiledFormula = {
22004
22003
  execute: functionCache[cacheKey],
22005
22004
  dependencies,
22006
- constantValues,
22005
+ literalValues,
22007
22006
  symbols,
22008
22007
  tokens,
22009
22008
  isBadExpression: false,
@@ -22016,33 +22015,31 @@ stores.inject(MyMetaStore, storeInstance);
22016
22015
  * References, numbers and strings are replaced with placeholders because
22017
22016
  * the compiled formula does not depend on their actual value.
22018
22017
  * Both `=A1+1+"2"` and `=A2+2+"3"` are compiled to the exact same function.
22019
- *
22020
22018
  * Spaces are also ignored to compute the cache key.
22021
22019
  *
22022
- * A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|0|+|1|+SUM(|N0|,|N0|,|S0|)`
22020
+ * A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|C|+|C|+SUM(|N|,|N|,|S|)`
22023
22021
  */
22024
- function compilationCacheKey(tokens, dependencies, constantValues, symbols) {
22022
+ function compilationCacheKey(tokens) {
22025
22023
  let cacheKey = "";
22026
22024
  for (const token of tokens) {
22027
22025
  switch (token.type) {
22028
22026
  case "STRING":
22029
- const value = removeStringQuotes(token.value);
22030
- cacheKey += `|S${constantValues.strings.indexOf(value)}|`;
22027
+ cacheKey += "|S|";
22031
22028
  break;
22032
22029
  case "NUMBER":
22033
- cacheKey += `|N${constantValues.numbers.indexOf(parseNumber(token.value, DEFAULT_LOCALE))}|`;
22030
+ cacheKey += "|N|";
22034
22031
  break;
22035
22032
  case "REFERENCE":
22036
22033
  case "INVALID_REFERENCE":
22037
22034
  if (token.value.includes(":")) {
22038
- cacheKey += `R|${dependencies.indexOf(token.value)}|`;
22035
+ cacheKey += "|R|";
22039
22036
  }
22040
22037
  else {
22041
- cacheKey += `C|${dependencies.indexOf(token.value)}|`;
22038
+ cacheKey += "|C|";
22042
22039
  }
22043
22040
  break;
22044
22041
  case "SPACE":
22045
- cacheKey += "";
22042
+ // ignore spaces
22046
22043
  break;
22047
22044
  default:
22048
22045
  cacheKey += token.value;
@@ -22055,7 +22052,7 @@ stores.inject(MyMetaStore, storeInstance);
22055
22052
  * Return formula arguments which are references, strings and numbers.
22056
22053
  */
22057
22054
  function formulaArguments(tokens) {
22058
- const constantValues = {
22055
+ const literalValues = {
22059
22056
  numbers: [],
22060
22057
  strings: [],
22061
22058
  };
@@ -22069,15 +22066,11 @@ stores.inject(MyMetaStore, storeInstance);
22069
22066
  break;
22070
22067
  case "STRING":
22071
22068
  const value = removeStringQuotes(token.value);
22072
- if (!constantValues.strings.includes(value)) {
22073
- constantValues.strings.push(value);
22074
- }
22069
+ literalValues.strings.push({ value });
22075
22070
  break;
22076
22071
  case "NUMBER": {
22077
22072
  const value = parseNumber(token.value, DEFAULT_LOCALE);
22078
- if (!constantValues.numbers.includes(value)) {
22079
- constantValues.numbers.push(value);
22080
- }
22073
+ literalValues.numbers.push({ value });
22081
22074
  break;
22082
22075
  }
22083
22076
  case "SYMBOL": {
@@ -22088,7 +22081,7 @@ stores.inject(MyMetaStore, storeInstance);
22088
22081
  }
22089
22082
  return {
22090
22083
  dependencies,
22091
- constantValues,
22084
+ literalValues,
22092
22085
  symbols,
22093
22086
  };
22094
22087
  }
@@ -23009,9 +23002,9 @@ stores.inject(MyMetaStore, storeInstance);
23009
23002
  /** In XLSX color format (no #) */
23010
23003
  const AUTO_COLOR = "000000";
23011
23004
  const XLSX_ICONSET_MAP = {
23012
- arrow: "3Arrows",
23005
+ arrows: "3Arrows",
23013
23006
  smiley: "3Symbols",
23014
- dot: "3TrafficLights1",
23007
+ dots: "3TrafficLights1",
23015
23008
  };
23016
23009
  const NAMESPACE = {
23017
23010
  styleSheet: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
@@ -23542,6 +23535,7 @@ stores.inject(MyMetaStore, storeInstance);
23542
23535
  };
23543
23536
  /** Map between legend position in XLSX file and human readable position */
23544
23537
  const DRAWING_LEGEND_POSITION_CONVERSION_MAP = {
23538
+ none: "none",
23545
23539
  b: "bottom",
23546
23540
  t: "top",
23547
23541
  l: "left",
@@ -26304,7 +26298,7 @@ stores.inject(MyMetaStore, storeInstance);
26304
26298
  default: "ffffff",
26305
26299
  }).asString(),
26306
26300
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
26307
- default: "b",
26301
+ default: "none",
26308
26302
  }).asString()],
26309
26303
  stacked: barChartGrouping === "stacked",
26310
26304
  fontColor: "000000",
@@ -26338,7 +26332,7 @@ stores.inject(MyMetaStore, storeInstance);
26338
26332
  default: "ffffff",
26339
26333
  }).asString(),
26340
26334
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(chartElement, "c:legendPos", "val", {
26341
- default: "b",
26335
+ default: "none",
26342
26336
  }).asString()],
26343
26337
  stacked: barChartGrouping === "stacked",
26344
26338
  fontColor: "000000",
@@ -28950,7 +28944,8 @@ stores.inject(MyMetaStore, storeInstance);
28950
28944
  }
28951
28945
  }
28952
28946
  else if (dataSets.length === 1) {
28953
- for (let i = 0; i < getData(getters, dataSets[0]).length; i++) {
28947
+ const dataLength = getData(getters, dataSets[0]).length;
28948
+ for (let i = 0; i < dataLength; i++) {
28954
28949
  labels.formattedValues.push("");
28955
28950
  labels.values.push("");
28956
28951
  }
@@ -29133,7 +29128,7 @@ stores.inject(MyMetaStore, storeInstance);
29133
29128
  function getScatterChartDatasets(definition, args) {
29134
29129
  const dataSets = getLineChartDatasets(definition, args);
29135
29130
  for (const dataSet of dataSets) {
29136
- if (dataSet.xAxisID !== TREND_LINE_XAXIS_ID) {
29131
+ if (!isTrendLineAxis(dataSet.xAxisID)) {
29137
29132
  dataSet.showLine = false;
29138
29133
  }
29139
29134
  }
@@ -29260,7 +29255,9 @@ stores.inject(MyMetaStore, storeInstance);
29260
29255
  const borderColor = config.color || lightenColor(rgbaToHex(defaultBorderColor), 0.5);
29261
29256
  return {
29262
29257
  type: "line",
29263
- xAxisID: TREND_LINE_XAXIS_ID,
29258
+ xAxisID: config.type === "trailingMovingAverage"
29259
+ ? MOVING_AVERAGE_TREND_LINE_XAXIS_ID
29260
+ : TREND_LINE_XAXIS_ID,
29264
29261
  yAxisID: dataset.yAxisID,
29265
29262
  label: dataset.label ? _t("Trend line for %s", dataset.label) : "",
29266
29263
  data,
@@ -29335,22 +29332,19 @@ stores.inject(MyMetaStore, storeInstance);
29335
29332
  const { dataSetsValues } = args;
29336
29333
  const dataSetsLength = Math.max(0, ...dataSetsValues.map((ds) => ds?.data?.length ?? 0));
29337
29334
  const colors = getPieColors(new ColorGenerator(dataSetsLength), dataSetsValues);
29335
+ const fontColor = chartFontColor(definition.background);
29338
29336
  return {
29339
29337
  ...getLegendDisplayOptions(definition),
29340
29338
  labels: {
29341
- color: chartFontColor(definition.background),
29342
29339
  usePointStyle: true,
29343
- //@ts-ignore
29344
- generateLabels: (c) =>
29345
- //@ts-ignore
29346
- c.data.labels.map((label, index) => ({
29340
+ generateLabels: (c) => c.data.labels?.map((label, index) => ({
29347
29341
  text: truncateLabel(String(label)),
29348
29342
  strokeStyle: colors[index],
29349
29343
  fillStyle: colors[index],
29350
29344
  pointStyle: "rect",
29351
- hidden: false,
29352
29345
  lineWidth: 2,
29353
- })),
29346
+ fontColor,
29347
+ })) || [],
29354
29348
  filter: (legendItem, data) => {
29355
29349
  return "datasetIndex" in legendItem
29356
29350
  ? !data.datasets[legendItem.datasetIndex].hidden
@@ -29483,7 +29477,7 @@ stores.inject(MyMetaStore, storeInstance);
29483
29477
  color: fontColor,
29484
29478
  usePointStyle: true,
29485
29479
  generateLabels: (chart) => chart.data.datasets.map((dataset, index) => {
29486
- if (dataset["xAxisID"] === TREND_LINE_XAXIS_ID) {
29480
+ if (isTrendLineAxis(dataset["xAxisID"])) {
29487
29481
  return {
29488
29482
  text: truncateLabel(dataset.label),
29489
29483
  fontColor,
@@ -29541,6 +29535,11 @@ stores.inject(MyMetaStore, storeInstance);
29541
29535
  offset: false,
29542
29536
  display: false,
29543
29537
  };
29538
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID] = {
29539
+ ...scales.x,
29540
+ offset: false,
29541
+ display: false,
29542
+ };
29544
29543
  }
29545
29544
  return scales;
29546
29545
  }
@@ -29574,6 +29573,10 @@ stores.inject(MyMetaStore, storeInstance);
29574
29573
  ...scales.x,
29575
29574
  display: false,
29576
29575
  };
29576
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID] = {
29577
+ ...scales.x,
29578
+ display: false,
29579
+ };
29577
29580
  if (axisType === "category" || axisType === "time") {
29578
29581
  /* We add a second x axis here to draw the trend lines, with the labels length being
29579
29582
  * set so that the second axis points match the classical x axis
@@ -29582,6 +29585,8 @@ stores.inject(MyMetaStore, storeInstance);
29582
29585
  scales[TREND_LINE_XAXIS_ID]["type"] = "category";
29583
29586
  scales[TREND_LINE_XAXIS_ID]["labels"] = range(0, maxLength).map((x) => x.toString());
29584
29587
  scales[TREND_LINE_XAXIS_ID]["offset"] = false;
29588
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID]["type"] = "category";
29589
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID]["offset"] = false;
29585
29590
  }
29586
29591
  }
29587
29592
  return scales;
@@ -29900,9 +29905,7 @@ stores.inject(MyMetaStore, storeInstance);
29900
29905
  external: customTooltipHandler,
29901
29906
  callbacks: {
29902
29907
  title: function (tooltipItems) {
29903
- return tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID)
29904
- ? undefined
29905
- : "";
29908
+ return tooltipItems.some((item) => !isTrendLineAxis(item.dataset.xAxisID)) ? undefined : "";
29906
29909
  },
29907
29910
  beforeLabel: (tooltipItem) => tooltipItem.dataset?.label || tooltipItem.label,
29908
29911
  label: function (tooltipItem) {
@@ -29929,7 +29932,7 @@ stores.inject(MyMetaStore, storeInstance);
29929
29932
  if (axisType === "linear") {
29930
29933
  tooltip.callbacks.label = (tooltipItem) => {
29931
29934
  const dataSetPoint = tooltipItem.parsed.y;
29932
- let label = tooltipItem.dataset.xAxisID === TREND_LINE_XAXIS_ID
29935
+ let label = isTrendLineAxis(tooltipItem.dataset.xAxisID)
29933
29936
  ? ""
29934
29937
  : tooltipItem.parsed.x;
29935
29938
  if (typeof label === "string" && isNumber(label, locale)) {
@@ -29951,8 +29954,7 @@ stores.inject(MyMetaStore, storeInstance);
29951
29954
  }
29952
29955
  tooltip.callbacks.beforeLabel = (tooltipItem) => tooltipItem.dataset?.label || tooltipItem.label;
29953
29956
  tooltip.callbacks.title = function (tooltipItems) {
29954
- const displayTooltipTitle = axisType !== "linear" &&
29955
- tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID);
29957
+ const displayTooltipTitle = axisType !== "linear" && tooltipItems.some((item) => !isTrendLineAxis(item.dataset.xAxisID));
29956
29958
  return displayTooltipTitle ? undefined : "";
29957
29959
  };
29958
29960
  return tooltip;
@@ -34206,6 +34208,7 @@ stores.inject(MyMetaStore, storeInstance);
34206
34208
  CHART_COMMON_OPTIONS: CHART_COMMON_OPTIONS,
34207
34209
  GaugeChart: GaugeChart,
34208
34210
  LineChart: LineChart,
34211
+ MOVING_AVERAGE_TREND_LINE_XAXIS_ID: MOVING_AVERAGE_TREND_LINE_XAXIS_ID,
34209
34212
  PieChart: PieChart,
34210
34213
  ScorecardChart: ScorecardChart$1,
34211
34214
  TREND_LINE_XAXIS_ID: TREND_LINE_XAXIS_ID,
@@ -34235,6 +34238,7 @@ stores.inject(MyMetaStore, storeInstance);
34235
34238
  getDefinedAxis: getDefinedAxis,
34236
34239
  getPieColors: getPieColors,
34237
34240
  getSmartChartDefinition: getSmartChartDefinition,
34241
+ isTrendLineAxis: isTrendLineAxis,
34238
34242
  shouldRemoveFirstLabel: shouldRemoveFirstLabel,
34239
34243
  toExcelDataset: toExcelDataset,
34240
34244
  toExcelLabelRange: toExcelLabelRange,
@@ -36282,9 +36286,7 @@ stores.inject(MyMetaStore, storeInstance);
36282
36286
  }
36283
36287
  }
36284
36288
  }
36285
- // removes the index placeholders from the normalized formula
36286
- // =|N0|+|N1|+|N0| -> =|N|+|N|+|N|
36287
- const normalizedFormula = cell.compiledFormula.normalizedFormula.replace(/(|\w)(\d)(|)/g, "$1$3");
36289
+ const normalizedFormula = cell.compiledFormula.normalizedFormula;
36288
36290
  return hash(fingerprintVector) + normalizedFormula;
36289
36291
  }
36290
36292
  getLiteralFingerprint(position) {
@@ -39629,9 +39631,11 @@ stores.inject(MyMetaStore, storeInstance);
39629
39631
  if (!runtime || !("chartJsConfig" in runtime)) {
39630
39632
  return [];
39631
39633
  }
39632
- return runtime.chartJsConfig.data.datasets.map((d) => d.label);
39634
+ return runtime.chartJsConfig.data.datasets
39635
+ .filter((d) => !isTrendLineAxis(d["xAxisID"] ?? ""))
39636
+ .map((d) => d.label);
39633
39637
  }
39634
- updateSerieEditor(ev) {
39638
+ updateEditedSeries(ev) {
39635
39639
  this.state.index = ev.target.selectedIndex;
39636
39640
  }
39637
39641
  updateDataSeriesColor(color) {
@@ -39644,7 +39648,7 @@ stores.inject(MyMetaStore, storeInstance);
39644
39648
  };
39645
39649
  this.props.updateChart(this.props.figureId, { dataSets });
39646
39650
  }
39647
- getDataSerieColor() {
39651
+ getDataSeriesColor() {
39648
39652
  const dataSets = this.props.definition.dataSets;
39649
39653
  if (!dataSets?.[this.state.index])
39650
39654
  return "";
@@ -39664,7 +39668,7 @@ stores.inject(MyMetaStore, storeInstance);
39664
39668
  };
39665
39669
  this.props.updateChart(this.props.figureId, { dataSets });
39666
39670
  }
39667
- getDataSerieLabel() {
39671
+ getDataSeriesLabel() {
39668
39672
  const dataSets = this.props.definition.dataSets;
39669
39673
  return dataSets[this.state.index]?.label || this.getDataSeries()[this.state.index];
39670
39674
  }
@@ -39777,7 +39781,7 @@ stores.inject(MyMetaStore, storeInstance);
39777
39781
  }
39778
39782
  this.updateTrendLineValue(index, { window });
39779
39783
  }
39780
- getDataSerieColor(index) {
39784
+ getDataSeriesColor(index) {
39781
39785
  const dataSets = this.props.definition.dataSets;
39782
39786
  if (!dataSets?.[index])
39783
39787
  return "";
@@ -39788,7 +39792,7 @@ stores.inject(MyMetaStore, storeInstance);
39788
39792
  }
39789
39793
  getTrendLineColor(index) {
39790
39794
  return (this.getTrendLineConfiguration(index)?.color ??
39791
- setColorAlpha(this.getDataSerieColor(index), 0.5));
39795
+ setColorAlpha(this.getDataSeriesColor(index), 0.5));
39792
39796
  }
39793
39797
  updateTrendLineColor(index, color) {
39794
39798
  this.updateTrendLineValue(index, { color });
@@ -70768,7 +70772,9 @@ stores.inject(MyMetaStore, storeInstance);
70768
70772
  border: 1px solid;
70769
70773
  font-family: ${DEFAULT_FONT};
70770
70774
 
70771
- .o-composer:empty:not(:focus):not(.active)::before {
70775
+ /* In readonly we always show the fx icon if the composer is empty, not matter the focus */
70776
+ .o-composer:empty:not(:focus):not(.active)::before,
70777
+ &.o-topbar-composer-readonly .o-composer:empty::before {
70772
70778
  content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
70773
70779
  position: relative;
70774
70780
  top: 20%;
@@ -74094,10 +74100,14 @@ stores.inject(MyMetaStore, storeInstance);
74094
74100
  continue;
74095
74101
  }
74096
74102
  const cfValueObjectNodes = cfValueObject.map((attrs) => escapeXml /*xml*/ `<cfvo ${formatAttributes(attrs)} />`);
74103
+ const iconSetAttrs = [["iconSet", getIconSet(rule.icons)]];
74104
+ if (isIconSetReversed(rule.icons)) {
74105
+ iconSetAttrs.push(["reverse", "1"]);
74106
+ }
74097
74107
  conditionalFormats.push(escapeXml /*xml*/ `
74098
74108
  <conditionalFormatting sqref="${range}">
74099
74109
  <cfRule ${formatAttributes(ruleAttributes)}>
74100
- <iconSet iconSet="${getIconSet(rule.icons)}">
74110
+ <iconSet ${formatAttributes(iconSetAttrs)}>
74101
74111
  ${joinXmlNodes(cfValueObjectNodes)}
74102
74112
  </iconSet>
74103
74113
  </cfRule>
@@ -74115,9 +74125,21 @@ stores.inject(MyMetaStore, storeInstance);
74115
74125
  ["stopIfTrue", cf.stopIfTrue ? 1 : 0],
74116
74126
  ];
74117
74127
  }
74128
+ function isIconSetReversed(iconSet) {
74129
+ const defaultIconSet = ICON_SETS[detectIconsType(iconSet)];
74130
+ return iconSet.upper === defaultIconSet.bad && iconSet.lower === defaultIconSet.good;
74131
+ }
74118
74132
  function getIconSet(iconSet) {
74119
- return XLSX_ICONSET_MAP[Object.keys(XLSX_ICONSET_MAP).find((key) => iconSet.upper.toLowerCase().startsWith(key)) ||
74120
- "dots"];
74133
+ return XLSX_ICONSET_MAP[detectIconsType(iconSet)];
74134
+ }
74135
+ /**
74136
+ * Partial detection based on "upper" point only.
74137
+ * We support any arbitrary icon in the set, while excel doesn't allow
74138
+ * mixing icons from different types.
74139
+ */
74140
+ function detectIconsType(iconSet) {
74141
+ const type = Object.keys(ICON_SETS).find((type) => Object.values(ICON_SETS[type]).includes(iconSet.upper)) || "dots";
74142
+ return type;
74121
74143
  }
74122
74144
  function thresholdAttributes(threshold, position) {
74123
74145
  const type = getExcelThresholdType(threshold.type, position);
@@ -76067,9 +76089,9 @@ stores.inject(MyMetaStore, storeInstance);
76067
76089
  exports.tokenize = tokenize;
76068
76090
 
76069
76091
 
76070
- __info__.version = "18.2.4";
76071
- __info__.date = "2025-03-19T08:20:57.717Z";
76072
- __info__.hash = "958936a";
76092
+ __info__.version = "18.2.5";
76093
+ __info__.date = "2025-03-26T12:47:44.113Z";
76094
+ __info__.hash = "4675edd";
76073
76095
 
76074
76096
 
76075
76097
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);