@odoo/o-spreadsheet 18.1.12 → 18.1.13
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.
- package/dist/o-spreadsheet.cjs.js +132 -110
- package/dist/o-spreadsheet.d.ts +7 -5
- package/dist/o-spreadsheet.esm.js +132 -110
- package/dist/o-spreadsheet.iife.js +132 -110
- package/dist/o-spreadsheet.iife.min.js +370 -368
- package/dist/o_spreadsheet.xml +9 -6
- package/package.json +1 -1
|
@@ -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.1.
|
|
6
|
-
* @date 2025-03-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.1.13
|
|
6
|
+
* @date 2025-03-26T12:48:31.680Z
|
|
7
|
+
* @hash 45ec54c
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -1122,7 +1122,10 @@ function rgbaStringToHex(color) {
|
|
|
1122
1122
|
}
|
|
1123
1123
|
else if (stringVals.length === 4) {
|
|
1124
1124
|
const alpha = parseFloat(stringVals.pop() || "1");
|
|
1125
|
-
|
|
1125
|
+
if (isNaN(alpha)) {
|
|
1126
|
+
throw new Error("invalid alpha value");
|
|
1127
|
+
}
|
|
1128
|
+
alphaHex = Math.round(alpha * 255);
|
|
1126
1129
|
}
|
|
1127
1130
|
const vals = stringVals.map((val) => parseInt(val, 10));
|
|
1128
1131
|
if (alphaHex !== 255) {
|
|
@@ -6992,7 +6995,7 @@ function isValidLocale(locale) {
|
|
|
6992
6995
|
*/
|
|
6993
6996
|
function canonicalizeNumberContent(content, locale) {
|
|
6994
6997
|
return content.startsWith("=")
|
|
6995
|
-
? canonicalizeFormula
|
|
6998
|
+
? canonicalizeFormula(content, locale)
|
|
6996
6999
|
: canonicalizeNumberLiteral(content, locale);
|
|
6997
7000
|
}
|
|
6998
7001
|
/**
|
|
@@ -7007,7 +7010,7 @@ function canonicalizeNumberContent(content, locale) {
|
|
|
7007
7010
|
*/
|
|
7008
7011
|
function canonicalizeContent(content, locale) {
|
|
7009
7012
|
return content.startsWith("=")
|
|
7010
|
-
? canonicalizeFormula
|
|
7013
|
+
? canonicalizeFormula(content, locale)
|
|
7011
7014
|
: canonicalizeLiteral(content, locale);
|
|
7012
7015
|
}
|
|
7013
7016
|
/**
|
|
@@ -7023,15 +7026,21 @@ function localizeContent(content, locale) {
|
|
|
7023
7026
|
? localizeFormula(content, locale)
|
|
7024
7027
|
: localizeLiteral(content, locale);
|
|
7025
7028
|
}
|
|
7029
|
+
/** Change a number string to its canonical form (en_US locale) */
|
|
7030
|
+
function canonicalizeNumberValue(content, locale) {
|
|
7031
|
+
return content.startsWith("=")
|
|
7032
|
+
? canonicalizeFormula(content, locale)
|
|
7033
|
+
: canonicalizeNumberLiteral(content, locale);
|
|
7034
|
+
}
|
|
7026
7035
|
/** Change a formula to its canonical form (en_US locale) */
|
|
7027
|
-
function canonicalizeFormula
|
|
7028
|
-
return _localizeFormula
|
|
7036
|
+
function canonicalizeFormula(formula, locale) {
|
|
7037
|
+
return _localizeFormula(formula, locale, DEFAULT_LOCALE);
|
|
7029
7038
|
}
|
|
7030
7039
|
/** Change a formula from the canonical form to the given locale */
|
|
7031
7040
|
function localizeFormula(formula, locale) {
|
|
7032
|
-
return _localizeFormula
|
|
7041
|
+
return _localizeFormula(formula, DEFAULT_LOCALE, locale);
|
|
7033
7042
|
}
|
|
7034
|
-
function _localizeFormula
|
|
7043
|
+
function _localizeFormula(formula, fromLocale, toLocale) {
|
|
7035
7044
|
if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
|
|
7036
7045
|
fromLocale.decimalSeparator === toLocale.decimalSeparator) {
|
|
7037
7046
|
return formula;
|
|
@@ -7186,37 +7195,6 @@ function getDateTimeFormat(locale) {
|
|
|
7186
7195
|
return locale.dateFormat + " " + locale.timeFormat;
|
|
7187
7196
|
}
|
|
7188
7197
|
|
|
7189
|
-
/** Change a number string to its canonical form (en_US locale) */
|
|
7190
|
-
function canonicalizeNumberValue(content, locale) {
|
|
7191
|
-
return content.startsWith("=")
|
|
7192
|
-
? canonicalizeFormula(content, locale)
|
|
7193
|
-
: canonicalizeNumberLiteral(content, locale);
|
|
7194
|
-
}
|
|
7195
|
-
/** Change a formula to its canonical form (en_US locale) */
|
|
7196
|
-
function canonicalizeFormula(formula, locale) {
|
|
7197
|
-
return _localizeFormula(formula, locale, DEFAULT_LOCALE);
|
|
7198
|
-
}
|
|
7199
|
-
function _localizeFormula(formula, fromLocale, toLocale) {
|
|
7200
|
-
if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
|
|
7201
|
-
fromLocale.decimalSeparator === toLocale.decimalSeparator) {
|
|
7202
|
-
return formula;
|
|
7203
|
-
}
|
|
7204
|
-
const tokens = tokenize(formula, fromLocale);
|
|
7205
|
-
let localizedFormula = "";
|
|
7206
|
-
for (const token of tokens) {
|
|
7207
|
-
if (token.type === "NUMBER") {
|
|
7208
|
-
localizedFormula += token.value.replace(fromLocale.decimalSeparator, toLocale.decimalSeparator);
|
|
7209
|
-
}
|
|
7210
|
-
else if (token.type === "ARG_SEPARATOR") {
|
|
7211
|
-
localizedFormula += toLocale.formulaArgSeparator;
|
|
7212
|
-
}
|
|
7213
|
-
else {
|
|
7214
|
-
localizedFormula += token.value;
|
|
7215
|
-
}
|
|
7216
|
-
}
|
|
7217
|
-
return localizedFormula;
|
|
7218
|
-
}
|
|
7219
|
-
|
|
7220
7198
|
function boolAnd(args) {
|
|
7221
7199
|
let foundBoolean = false;
|
|
7222
7200
|
let acc = true;
|
|
@@ -9591,6 +9569,7 @@ class ComposerFocusStore extends SpreadsheetStore {
|
|
|
9591
9569
|
}
|
|
9592
9570
|
|
|
9593
9571
|
const TREND_LINE_XAXIS_ID = "x1";
|
|
9572
|
+
const MOVING_AVERAGE_TREND_LINE_XAXIS_ID = "xMovingAverage";
|
|
9594
9573
|
/**
|
|
9595
9574
|
* This file contains helpers that are common to different charts (mainly
|
|
9596
9575
|
* line, bar and pie charts)
|
|
@@ -9931,6 +9910,9 @@ function getPieColors(colors, dataSetsValues) {
|
|
|
9931
9910
|
}
|
|
9932
9911
|
return pieColors;
|
|
9933
9912
|
}
|
|
9913
|
+
function isTrendLineAxis(axisID) {
|
|
9914
|
+
return axisID === TREND_LINE_XAXIS_ID || axisID === MOVING_AVERAGE_TREND_LINE_XAXIS_ID;
|
|
9915
|
+
}
|
|
9934
9916
|
|
|
9935
9917
|
/** This is a chartJS plugin that will draw the values of each data next to the point/bar/pie slice */
|
|
9936
9918
|
const chartShowValuesPlugin = {
|
|
@@ -9975,7 +9957,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
9975
9957
|
const yMin = chart.chartArea.top;
|
|
9976
9958
|
const textsPositions = {};
|
|
9977
9959
|
for (const dataset of chart._metasets) {
|
|
9978
|
-
if (dataset.
|
|
9960
|
+
if (isTrendLineAxis(dataset.axisID) || dataset.hidden) {
|
|
9979
9961
|
continue;
|
|
9980
9962
|
}
|
|
9981
9963
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
@@ -10018,7 +10000,7 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
10018
10000
|
const xMin = chart.chartArea.left;
|
|
10019
10001
|
const textsPositions = {};
|
|
10020
10002
|
for (const dataset of chart._metasets) {
|
|
10021
|
-
if (dataset.
|
|
10003
|
+
if (isTrendLineAxis(dataset.axisID)) {
|
|
10022
10004
|
return; // ignore trend lines
|
|
10023
10005
|
}
|
|
10024
10006
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
@@ -20382,11 +20364,26 @@ const SEARCH = {
|
|
|
20382
20364
|
const _searchFor = toString(searchFor).toLowerCase();
|
|
20383
20365
|
const _textToSearch = toString(textToSearch).toLowerCase();
|
|
20384
20366
|
const _startingAt = toNumber(startingAt, this.locale);
|
|
20385
|
-
|
|
20386
|
-
|
|
20367
|
+
if (_textToSearch === "") {
|
|
20368
|
+
return {
|
|
20369
|
+
value: CellErrorType.GenericError,
|
|
20370
|
+
message: _t("The text_to_search must be non-empty."),
|
|
20371
|
+
};
|
|
20372
|
+
}
|
|
20373
|
+
if (_startingAt < 1) {
|
|
20374
|
+
return {
|
|
20375
|
+
value: CellErrorType.GenericError,
|
|
20376
|
+
message: _t("The starting_at (%s) must be greater than or equal to 1.", _startingAt),
|
|
20377
|
+
};
|
|
20378
|
+
}
|
|
20387
20379
|
const result = _textToSearch.indexOf(_searchFor, _startingAt - 1);
|
|
20388
|
-
|
|
20389
|
-
|
|
20380
|
+
if (result === -1) {
|
|
20381
|
+
return {
|
|
20382
|
+
value: CellErrorType.GenericError,
|
|
20383
|
+
message: _t("In [[FUNCTION_NAME]] evaluation, cannot find '%s' within '%s'.", _searchFor, _textToSearch),
|
|
20384
|
+
};
|
|
20385
|
+
}
|
|
20386
|
+
return { value: result + 1 };
|
|
20390
20387
|
},
|
|
20391
20388
|
isExported: true,
|
|
20392
20389
|
};
|
|
@@ -21721,11 +21718,14 @@ function compileTokens(tokens) {
|
|
|
21721
21718
|
}
|
|
21722
21719
|
}
|
|
21723
21720
|
function compileTokensOrThrow(tokens) {
|
|
21724
|
-
const { dependencies,
|
|
21725
|
-
const cacheKey = compilationCacheKey(tokens
|
|
21721
|
+
const { dependencies, literalValues, symbols } = formulaArguments(tokens);
|
|
21722
|
+
const cacheKey = compilationCacheKey(tokens);
|
|
21726
21723
|
if (!functionCache[cacheKey]) {
|
|
21727
21724
|
const ast = parseTokens([...tokens]);
|
|
21728
21725
|
const scope = new Scope();
|
|
21726
|
+
let stringCount = 0;
|
|
21727
|
+
let numberCount = 0;
|
|
21728
|
+
let dependencyCount = 0;
|
|
21729
21729
|
if (ast.type === "BIN_OPERATION" && ast.value === ":") {
|
|
21730
21730
|
throw new BadExpressionError(_t("Invalid formula"));
|
|
21731
21731
|
}
|
|
@@ -21799,16 +21799,15 @@ function compileTokensOrThrow(tokens) {
|
|
|
21799
21799
|
case "BOOLEAN":
|
|
21800
21800
|
return code.return(`{ value: ${ast.value} }`);
|
|
21801
21801
|
case "NUMBER":
|
|
21802
|
-
return code.return(`
|
|
21802
|
+
return code.return(`this.literalValues.numbers[${numberCount++}]`);
|
|
21803
21803
|
case "STRING":
|
|
21804
|
-
return code.return(`
|
|
21804
|
+
return code.return(`this.literalValues.strings[${stringCount++}]`);
|
|
21805
21805
|
case "REFERENCE":
|
|
21806
|
-
const referenceIndex = dependencies.indexOf(ast.value);
|
|
21807
21806
|
if ((!isMeta && ast.value.includes(":")) || hasRange) {
|
|
21808
|
-
return code.return(`range(deps[${
|
|
21807
|
+
return code.return(`range(deps[${dependencyCount++}])`);
|
|
21809
21808
|
}
|
|
21810
21809
|
else {
|
|
21811
|
-
return code.return(`ref(deps[${
|
|
21810
|
+
return code.return(`ref(deps[${dependencyCount++}], ${isMeta ? "true" : "false"})`);
|
|
21812
21811
|
}
|
|
21813
21812
|
case "FUNCALL":
|
|
21814
21813
|
const args = compileFunctionArgs(ast).map((arg) => arg.assignResultToVariable());
|
|
@@ -21840,7 +21839,7 @@ function compileTokensOrThrow(tokens) {
|
|
|
21840
21839
|
const compiledFormula = {
|
|
21841
21840
|
execute: functionCache[cacheKey],
|
|
21842
21841
|
dependencies,
|
|
21843
|
-
|
|
21842
|
+
literalValues,
|
|
21844
21843
|
symbols,
|
|
21845
21844
|
tokens,
|
|
21846
21845
|
isBadExpression: false,
|
|
@@ -21853,33 +21852,31 @@ function compileTokensOrThrow(tokens) {
|
|
|
21853
21852
|
* References, numbers and strings are replaced with placeholders because
|
|
21854
21853
|
* the compiled formula does not depend on their actual value.
|
|
21855
21854
|
* Both `=A1+1+"2"` and `=A2+2+"3"` are compiled to the exact same function.
|
|
21856
|
-
*
|
|
21857
21855
|
* Spaces are also ignored to compute the cache key.
|
|
21858
21856
|
*
|
|
21859
|
-
* A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|
|
|
21857
|
+
* A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|C|+|C|+SUM(|N|,|N|,|S|)`
|
|
21860
21858
|
*/
|
|
21861
|
-
function compilationCacheKey(tokens
|
|
21859
|
+
function compilationCacheKey(tokens) {
|
|
21862
21860
|
let cacheKey = "";
|
|
21863
21861
|
for (const token of tokens) {
|
|
21864
21862
|
switch (token.type) {
|
|
21865
21863
|
case "STRING":
|
|
21866
|
-
|
|
21867
|
-
cacheKey += `|S${constantValues.strings.indexOf(value)}|`;
|
|
21864
|
+
cacheKey += "|S|";
|
|
21868
21865
|
break;
|
|
21869
21866
|
case "NUMBER":
|
|
21870
|
-
cacheKey +=
|
|
21867
|
+
cacheKey += "|N|";
|
|
21871
21868
|
break;
|
|
21872
21869
|
case "REFERENCE":
|
|
21873
21870
|
case "INVALID_REFERENCE":
|
|
21874
21871
|
if (token.value.includes(":")) {
|
|
21875
|
-
cacheKey +=
|
|
21872
|
+
cacheKey += "|R|";
|
|
21876
21873
|
}
|
|
21877
21874
|
else {
|
|
21878
|
-
cacheKey +=
|
|
21875
|
+
cacheKey += "|C|";
|
|
21879
21876
|
}
|
|
21880
21877
|
break;
|
|
21881
21878
|
case "SPACE":
|
|
21882
|
-
|
|
21879
|
+
// ignore spaces
|
|
21883
21880
|
break;
|
|
21884
21881
|
default:
|
|
21885
21882
|
cacheKey += token.value;
|
|
@@ -21892,7 +21889,7 @@ function compilationCacheKey(tokens, dependencies, constantValues, symbols) {
|
|
|
21892
21889
|
* Return formula arguments which are references, strings and numbers.
|
|
21893
21890
|
*/
|
|
21894
21891
|
function formulaArguments(tokens) {
|
|
21895
|
-
const
|
|
21892
|
+
const literalValues = {
|
|
21896
21893
|
numbers: [],
|
|
21897
21894
|
strings: [],
|
|
21898
21895
|
};
|
|
@@ -21906,15 +21903,11 @@ function formulaArguments(tokens) {
|
|
|
21906
21903
|
break;
|
|
21907
21904
|
case "STRING":
|
|
21908
21905
|
const value = removeStringQuotes(token.value);
|
|
21909
|
-
|
|
21910
|
-
constantValues.strings.push(value);
|
|
21911
|
-
}
|
|
21906
|
+
literalValues.strings.push({ value });
|
|
21912
21907
|
break;
|
|
21913
21908
|
case "NUMBER": {
|
|
21914
21909
|
const value = parseNumber(token.value, DEFAULT_LOCALE);
|
|
21915
|
-
|
|
21916
|
-
constantValues.numbers.push(value);
|
|
21917
|
-
}
|
|
21910
|
+
literalValues.numbers.push({ value });
|
|
21918
21911
|
break;
|
|
21919
21912
|
}
|
|
21920
21913
|
case "SYMBOL": {
|
|
@@ -21925,7 +21918,7 @@ function formulaArguments(tokens) {
|
|
|
21925
21918
|
}
|
|
21926
21919
|
return {
|
|
21927
21920
|
dependencies,
|
|
21928
|
-
|
|
21921
|
+
literalValues,
|
|
21929
21922
|
symbols,
|
|
21930
21923
|
};
|
|
21931
21924
|
}
|
|
@@ -22846,9 +22839,9 @@ const XLSX_CHART_TYPES = [
|
|
|
22846
22839
|
/** In XLSX color format (no #) */
|
|
22847
22840
|
const AUTO_COLOR = "000000";
|
|
22848
22841
|
const XLSX_ICONSET_MAP = {
|
|
22849
|
-
|
|
22842
|
+
arrows: "3Arrows",
|
|
22850
22843
|
smiley: "3Symbols",
|
|
22851
|
-
|
|
22844
|
+
dots: "3TrafficLights1",
|
|
22852
22845
|
};
|
|
22853
22846
|
const NAMESPACE = {
|
|
22854
22847
|
styleSheet: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
|
|
@@ -23519,6 +23512,7 @@ const ICON_SET_CONVERSION_MAP = {
|
|
|
23519
23512
|
};
|
|
23520
23513
|
/** Map between legend position in XLSX file and human readable position */
|
|
23521
23514
|
const DRAWING_LEGEND_POSITION_CONVERSION_MAP = {
|
|
23515
|
+
none: "none",
|
|
23522
23516
|
b: "bottom",
|
|
23523
23517
|
t: "top",
|
|
23524
23518
|
l: "left",
|
|
@@ -26281,7 +26275,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
26281
26275
|
default: "ffffff",
|
|
26282
26276
|
}).asString(),
|
|
26283
26277
|
legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
|
|
26284
|
-
default: "
|
|
26278
|
+
default: "none",
|
|
26285
26279
|
}).asString()],
|
|
26286
26280
|
stacked: barChartGrouping === "stacked",
|
|
26287
26281
|
fontColor: "000000",
|
|
@@ -26315,7 +26309,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
26315
26309
|
default: "ffffff",
|
|
26316
26310
|
}).asString(),
|
|
26317
26311
|
legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(chartElement, "c:legendPos", "val", {
|
|
26318
|
-
default: "
|
|
26312
|
+
default: "none",
|
|
26319
26313
|
}).asString()],
|
|
26320
26314
|
stacked: barChartGrouping === "stacked",
|
|
26321
26315
|
fontColor: "000000",
|
|
@@ -28927,7 +28921,8 @@ function getChartLabelValues(getters, dataSets, labelRange) {
|
|
|
28927
28921
|
}
|
|
28928
28922
|
}
|
|
28929
28923
|
else if (dataSets.length === 1) {
|
|
28930
|
-
|
|
28924
|
+
const dataLength = getData(getters, dataSets[0]).length;
|
|
28925
|
+
for (let i = 0; i < dataLength; i++) {
|
|
28931
28926
|
labels.formattedValues.push("");
|
|
28932
28927
|
labels.values.push("");
|
|
28933
28928
|
}
|
|
@@ -29110,7 +29105,7 @@ function getLineChartDatasets(definition, args) {
|
|
|
29110
29105
|
function getScatterChartDatasets(definition, args) {
|
|
29111
29106
|
const dataSets = getLineChartDatasets(definition, args);
|
|
29112
29107
|
for (const dataSet of dataSets) {
|
|
29113
|
-
if (dataSet.xAxisID
|
|
29108
|
+
if (!isTrendLineAxis(dataSet.xAxisID)) {
|
|
29114
29109
|
dataSet.showLine = false;
|
|
29115
29110
|
}
|
|
29116
29111
|
}
|
|
@@ -29237,7 +29232,9 @@ function getTrendingLineDataSet(dataset, config, data) {
|
|
|
29237
29232
|
const borderColor = config.color || lightenColor(rgbaToHex(defaultBorderColor), 0.5);
|
|
29238
29233
|
return {
|
|
29239
29234
|
type: "line",
|
|
29240
|
-
xAxisID:
|
|
29235
|
+
xAxisID: config.type === "trailingMovingAverage"
|
|
29236
|
+
? MOVING_AVERAGE_TREND_LINE_XAXIS_ID
|
|
29237
|
+
: TREND_LINE_XAXIS_ID,
|
|
29241
29238
|
yAxisID: dataset.yAxisID,
|
|
29242
29239
|
label: dataset.label ? _t("Trend line for %s", dataset.label) : "",
|
|
29243
29240
|
data,
|
|
@@ -29312,22 +29309,19 @@ function getPieChartLegend(definition, args) {
|
|
|
29312
29309
|
const { dataSetsValues } = args;
|
|
29313
29310
|
const dataSetsLength = Math.max(0, ...dataSetsValues.map((ds) => ds?.data?.length ?? 0));
|
|
29314
29311
|
const colors = getPieColors(new ColorGenerator(dataSetsLength), dataSetsValues);
|
|
29312
|
+
const fontColor = chartFontColor(definition.background);
|
|
29315
29313
|
return {
|
|
29316
29314
|
...getLegendDisplayOptions(definition),
|
|
29317
29315
|
labels: {
|
|
29318
|
-
color: chartFontColor(definition.background),
|
|
29319
29316
|
usePointStyle: true,
|
|
29320
|
-
|
|
29321
|
-
|
|
29322
|
-
//@ts-ignore
|
|
29323
|
-
c.data.labels.map((label, index) => ({
|
|
29324
|
-
text: label,
|
|
29317
|
+
generateLabels: (c) => c.data.labels?.map((label, index) => ({
|
|
29318
|
+
text: String(label),
|
|
29325
29319
|
strokeStyle: colors[index],
|
|
29326
29320
|
fillStyle: colors[index],
|
|
29327
29321
|
pointStyle: "rect",
|
|
29328
|
-
hidden: false,
|
|
29329
29322
|
lineWidth: 2,
|
|
29330
|
-
|
|
29323
|
+
fontColor,
|
|
29324
|
+
})) || [],
|
|
29331
29325
|
filter: (legendItem, data) => {
|
|
29332
29326
|
return "datasetIndex" in legendItem
|
|
29333
29327
|
? !data.datasets[legendItem.datasetIndex].hidden
|
|
@@ -29460,7 +29454,7 @@ function getCustomLegendLabels(fontColor, legendLabelConfig) {
|
|
|
29460
29454
|
color: fontColor,
|
|
29461
29455
|
usePointStyle: true,
|
|
29462
29456
|
generateLabels: (chart) => chart.data.datasets.map((dataset, index) => {
|
|
29463
|
-
if (dataset["xAxisID"]
|
|
29457
|
+
if (isTrendLineAxis(dataset["xAxisID"])) {
|
|
29464
29458
|
return {
|
|
29465
29459
|
text: dataset.label ?? "",
|
|
29466
29460
|
fontColor,
|
|
@@ -29518,6 +29512,11 @@ function getBarChartScales(definition, args) {
|
|
|
29518
29512
|
offset: false,
|
|
29519
29513
|
display: false,
|
|
29520
29514
|
};
|
|
29515
|
+
scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID] = {
|
|
29516
|
+
...scales.x,
|
|
29517
|
+
offset: false,
|
|
29518
|
+
display: false,
|
|
29519
|
+
};
|
|
29521
29520
|
}
|
|
29522
29521
|
return scales;
|
|
29523
29522
|
}
|
|
@@ -29551,6 +29550,10 @@ function getLineChartScales(definition, args) {
|
|
|
29551
29550
|
...scales.x,
|
|
29552
29551
|
display: false,
|
|
29553
29552
|
};
|
|
29553
|
+
scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID] = {
|
|
29554
|
+
...scales.x,
|
|
29555
|
+
display: false,
|
|
29556
|
+
};
|
|
29554
29557
|
if (axisType === "category" || axisType === "time") {
|
|
29555
29558
|
/* We add a second x axis here to draw the trend lines, with the labels length being
|
|
29556
29559
|
* set so that the second axis points match the classical x axis
|
|
@@ -29559,6 +29562,8 @@ function getLineChartScales(definition, args) {
|
|
|
29559
29562
|
scales[TREND_LINE_XAXIS_ID]["type"] = "category";
|
|
29560
29563
|
scales[TREND_LINE_XAXIS_ID]["labels"] = range(0, maxLength).map((x) => x.toString());
|
|
29561
29564
|
scales[TREND_LINE_XAXIS_ID]["offset"] = false;
|
|
29565
|
+
scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID]["type"] = "category";
|
|
29566
|
+
scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID]["offset"] = false;
|
|
29562
29567
|
}
|
|
29563
29568
|
}
|
|
29564
29569
|
return scales;
|
|
@@ -29804,9 +29809,7 @@ function getBarChartTooltip(definition, args) {
|
|
|
29804
29809
|
return {
|
|
29805
29810
|
callbacks: {
|
|
29806
29811
|
title: function (tooltipItems) {
|
|
29807
|
-
return tooltipItems.some((item) => item.dataset.xAxisID
|
|
29808
|
-
? undefined
|
|
29809
|
-
: "";
|
|
29812
|
+
return tooltipItems.some((item) => !isTrendLineAxis(item.dataset.xAxisID)) ? undefined : "";
|
|
29810
29813
|
},
|
|
29811
29814
|
label: function (tooltipItem) {
|
|
29812
29815
|
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
@@ -29829,7 +29832,7 @@ function getLineChartTooltip(definition, args) {
|
|
|
29829
29832
|
if (axisType === "linear") {
|
|
29830
29833
|
tooltip.callbacks.label = (tooltipItem) => {
|
|
29831
29834
|
const dataSetPoint = tooltipItem.parsed.y;
|
|
29832
|
-
let label = tooltipItem.dataset.xAxisID
|
|
29835
|
+
let label = isTrendLineAxis(tooltipItem.dataset.xAxisID)
|
|
29833
29836
|
? ""
|
|
29834
29837
|
: tooltipItem.parsed.x;
|
|
29835
29838
|
if (typeof label === "string" && isNumber(label, locale)) {
|
|
@@ -29854,8 +29857,7 @@ function getLineChartTooltip(definition, args) {
|
|
|
29854
29857
|
};
|
|
29855
29858
|
}
|
|
29856
29859
|
tooltip.callbacks.title = function (tooltipItems) {
|
|
29857
|
-
const displayTooltipTitle = axisType !== "linear" &&
|
|
29858
|
-
tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID);
|
|
29860
|
+
const displayTooltipTitle = axisType !== "linear" && tooltipItems.some((item) => !isTrendLineAxis(item.dataset.xAxisID));
|
|
29859
29861
|
return displayTooltipTitle ? undefined : "";
|
|
29860
29862
|
};
|
|
29861
29863
|
return tooltip;
|
|
@@ -34012,6 +34014,7 @@ var CHART_HELPERS = /*#__PURE__*/Object.freeze({
|
|
|
34012
34014
|
CHART_COMMON_OPTIONS: CHART_COMMON_OPTIONS,
|
|
34013
34015
|
GaugeChart: GaugeChart,
|
|
34014
34016
|
LineChart: LineChart,
|
|
34017
|
+
MOVING_AVERAGE_TREND_LINE_XAXIS_ID: MOVING_AVERAGE_TREND_LINE_XAXIS_ID,
|
|
34015
34018
|
PieChart: PieChart,
|
|
34016
34019
|
ScorecardChart: ScorecardChart$1,
|
|
34017
34020
|
TREND_LINE_XAXIS_ID: TREND_LINE_XAXIS_ID,
|
|
@@ -34041,6 +34044,7 @@ var CHART_HELPERS = /*#__PURE__*/Object.freeze({
|
|
|
34041
34044
|
getDefinedAxis: getDefinedAxis,
|
|
34042
34045
|
getPieColors: getPieColors,
|
|
34043
34046
|
getSmartChartDefinition: getSmartChartDefinition,
|
|
34047
|
+
isTrendLineAxis: isTrendLineAxis,
|
|
34044
34048
|
shouldRemoveFirstLabel: shouldRemoveFirstLabel,
|
|
34045
34049
|
toExcelDataset: toExcelDataset,
|
|
34046
34050
|
toExcelLabelRange: toExcelLabelRange,
|
|
@@ -36088,9 +36092,7 @@ class FormulaFingerprintStore extends SpreadsheetStore {
|
|
|
36088
36092
|
}
|
|
36089
36093
|
}
|
|
36090
36094
|
}
|
|
36091
|
-
|
|
36092
|
-
// =|N0|+|N1|+|N0| -> =|N|+|N|+|N|
|
|
36093
|
-
const normalizedFormula = cell.compiledFormula.normalizedFormula.replace(/(|\w)(\d)(|)/g, "$1$3");
|
|
36095
|
+
const normalizedFormula = cell.compiledFormula.normalizedFormula;
|
|
36094
36096
|
return hash(fingerprintVector) + normalizedFormula;
|
|
36095
36097
|
}
|
|
36096
36098
|
getLiteralFingerprint(position) {
|
|
@@ -39081,9 +39083,11 @@ class SeriesDesignEditor extends owl.Component {
|
|
|
39081
39083
|
if (!runtime || !("chartJsConfig" in runtime)) {
|
|
39082
39084
|
return [];
|
|
39083
39085
|
}
|
|
39084
|
-
return runtime.chartJsConfig.data.datasets
|
|
39086
|
+
return runtime.chartJsConfig.data.datasets
|
|
39087
|
+
.filter((d) => !isTrendLineAxis(d["xAxisID"] ?? ""))
|
|
39088
|
+
.map((d) => d.label);
|
|
39085
39089
|
}
|
|
39086
|
-
|
|
39090
|
+
updateEditedSeries(ev) {
|
|
39087
39091
|
this.state.index = ev.target.selectedIndex;
|
|
39088
39092
|
}
|
|
39089
39093
|
updateDataSeriesColor(color) {
|
|
@@ -39096,7 +39100,7 @@ class SeriesDesignEditor extends owl.Component {
|
|
|
39096
39100
|
};
|
|
39097
39101
|
this.props.updateChart(this.props.figureId, { dataSets });
|
|
39098
39102
|
}
|
|
39099
|
-
|
|
39103
|
+
getDataSeriesColor() {
|
|
39100
39104
|
const dataSets = this.props.definition.dataSets;
|
|
39101
39105
|
if (!dataSets?.[this.state.index])
|
|
39102
39106
|
return "";
|
|
@@ -39116,7 +39120,7 @@ class SeriesDesignEditor extends owl.Component {
|
|
|
39116
39120
|
};
|
|
39117
39121
|
this.props.updateChart(this.props.figureId, { dataSets });
|
|
39118
39122
|
}
|
|
39119
|
-
|
|
39123
|
+
getDataSeriesLabel() {
|
|
39120
39124
|
const dataSets = this.props.definition.dataSets;
|
|
39121
39125
|
return dataSets[this.state.index]?.label || this.getDataSeries()[this.state.index];
|
|
39122
39126
|
}
|
|
@@ -39229,7 +39233,7 @@ class SeriesWithAxisDesignEditor extends owl.Component {
|
|
|
39229
39233
|
}
|
|
39230
39234
|
this.updateTrendLineValue(index, { window });
|
|
39231
39235
|
}
|
|
39232
|
-
|
|
39236
|
+
getDataSeriesColor(index) {
|
|
39233
39237
|
const dataSets = this.props.definition.dataSets;
|
|
39234
39238
|
if (!dataSets?.[index])
|
|
39235
39239
|
return "";
|
|
@@ -39240,7 +39244,7 @@ class SeriesWithAxisDesignEditor extends owl.Component {
|
|
|
39240
39244
|
}
|
|
39241
39245
|
getTrendLineColor(index) {
|
|
39242
39246
|
return (this.getTrendLineConfiguration(index)?.color ??
|
|
39243
|
-
setColorAlpha(this.
|
|
39247
|
+
setColorAlpha(this.getDataSeriesColor(index), 0.5));
|
|
39244
39248
|
}
|
|
39245
39249
|
updateTrendLineColor(index, color) {
|
|
39246
39250
|
this.updateTrendLineValue(index, { color });
|
|
@@ -70323,7 +70327,9 @@ css /* scss */ `
|
|
|
70323
70327
|
border: 1px solid;
|
|
70324
70328
|
font-family: ${DEFAULT_FONT};
|
|
70325
70329
|
|
|
70326
|
-
|
|
70330
|
+
/* In readonly we always show the fx icon if the composer is empty, not matter the focus */
|
|
70331
|
+
.o-composer:empty:not(:focus):not(.active)::before,
|
|
70332
|
+
&.o-topbar-composer-readonly .o-composer:empty::before {
|
|
70327
70333
|
content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
|
|
70328
70334
|
position: relative;
|
|
70329
70335
|
top: 20%;
|
|
@@ -73664,10 +73670,14 @@ function addIconSetRule(cf, rule) {
|
|
|
73664
73670
|
continue;
|
|
73665
73671
|
}
|
|
73666
73672
|
const cfValueObjectNodes = cfValueObject.map((attrs) => escapeXml /*xml*/ `<cfvo ${formatAttributes(attrs)} />`);
|
|
73673
|
+
const iconSetAttrs = [["iconSet", getIconSet(rule.icons)]];
|
|
73674
|
+
if (isIconSetReversed(rule.icons)) {
|
|
73675
|
+
iconSetAttrs.push(["reverse", "1"]);
|
|
73676
|
+
}
|
|
73667
73677
|
conditionalFormats.push(escapeXml /*xml*/ `
|
|
73668
73678
|
<conditionalFormatting sqref="${range}">
|
|
73669
73679
|
<cfRule ${formatAttributes(ruleAttributes)}>
|
|
73670
|
-
<iconSet
|
|
73680
|
+
<iconSet ${formatAttributes(iconSetAttrs)}>
|
|
73671
73681
|
${joinXmlNodes(cfValueObjectNodes)}
|
|
73672
73682
|
</iconSet>
|
|
73673
73683
|
</cfRule>
|
|
@@ -73685,9 +73695,21 @@ function commonCfAttributes(cf) {
|
|
|
73685
73695
|
["stopIfTrue", cf.stopIfTrue ? 1 : 0],
|
|
73686
73696
|
];
|
|
73687
73697
|
}
|
|
73698
|
+
function isIconSetReversed(iconSet) {
|
|
73699
|
+
const defaultIconSet = ICON_SETS[detectIconsType(iconSet)];
|
|
73700
|
+
return iconSet.upper === defaultIconSet.bad && iconSet.lower === defaultIconSet.good;
|
|
73701
|
+
}
|
|
73688
73702
|
function getIconSet(iconSet) {
|
|
73689
|
-
return XLSX_ICONSET_MAP[
|
|
73690
|
-
|
|
73703
|
+
return XLSX_ICONSET_MAP[detectIconsType(iconSet)];
|
|
73704
|
+
}
|
|
73705
|
+
/**
|
|
73706
|
+
* Partial detection based on "upper" point only.
|
|
73707
|
+
* We support any arbitrary icon in the set, while excel doesn't allow
|
|
73708
|
+
* mixing icons from different types.
|
|
73709
|
+
*/
|
|
73710
|
+
function detectIconsType(iconSet) {
|
|
73711
|
+
const type = Object.keys(ICON_SETS).find((type) => Object.values(ICON_SETS[type]).includes(iconSet.upper)) || "dots";
|
|
73712
|
+
return type;
|
|
73691
73713
|
}
|
|
73692
73714
|
function thresholdAttributes(threshold, position) {
|
|
73693
73715
|
const type = getExcelThresholdType(threshold.type, position);
|
|
@@ -75604,6 +75626,6 @@ exports.tokenColors = tokenColors;
|
|
|
75604
75626
|
exports.tokenize = tokenize;
|
|
75605
75627
|
|
|
75606
75628
|
|
|
75607
|
-
__info__.version = "18.1.
|
|
75608
|
-
__info__.date = "2025-03-
|
|
75609
|
-
__info__.hash = "
|
|
75629
|
+
__info__.version = "18.1.13";
|
|
75630
|
+
__info__.date = "2025-03-26T12:48:31.680Z";
|
|
75631
|
+
__info__.hash = "45ec54c";
|
package/dist/o-spreadsheet.d.ts
CHANGED
|
@@ -7704,11 +7704,11 @@ declare class SeriesDesignEditor extends Component<Props$X, SpreadsheetChildEnv>
|
|
|
7704
7704
|
index: number;
|
|
7705
7705
|
};
|
|
7706
7706
|
getDataSeries(): (string | undefined)[];
|
|
7707
|
-
|
|
7707
|
+
updateEditedSeries(ev: Event): void;
|
|
7708
7708
|
updateDataSeriesColor(color: string): void;
|
|
7709
|
-
|
|
7710
|
-
updateDataSeriesLabel(ev:
|
|
7711
|
-
|
|
7709
|
+
getDataSeriesColor(): "" | Color;
|
|
7710
|
+
updateDataSeriesLabel(ev: Event): void;
|
|
7711
|
+
getDataSeriesLabel(): string | undefined;
|
|
7712
7712
|
}
|
|
7713
7713
|
|
|
7714
7714
|
interface Props$W {
|
|
@@ -7752,7 +7752,7 @@ declare class SeriesWithAxisDesignEditor extends Component<Props$W, SpreadsheetC
|
|
|
7752
7752
|
getMaxPolynomialDegree(index: any): number;
|
|
7753
7753
|
get defaultWindowSize(): number;
|
|
7754
7754
|
onChangeMovingAverageWindow(index: number, ev: InputEvent): void;
|
|
7755
|
-
|
|
7755
|
+
getDataSeriesColor(index: number): "" | Color;
|
|
7756
7756
|
getTrendLineColor(index: number): string;
|
|
7757
7757
|
updateTrendLineColor(index: number, color: Color): void;
|
|
7758
7758
|
updateTrendLineValue(index: number, config: any): void;
|
|
@@ -13160,7 +13160,9 @@ declare const chartHelpers: {
|
|
|
13160
13160
|
formatChartDatasetValue(axisFormats: ChartAxisFormats, locale: Locale): (value: any, axisId: string | undefined) => any;
|
|
13161
13161
|
formatTickValue(localeFormat: LocaleFormat): (value: any) => any;
|
|
13162
13162
|
getPieColors(colors: ColorGenerator, dataSetsValues: DatasetValues[]): Color[];
|
|
13163
|
+
isTrendLineAxis(axisID: string): boolean;
|
|
13163
13164
|
TREND_LINE_XAXIS_ID: "x1";
|
|
13165
|
+
MOVING_AVERAGE_TREND_LINE_XAXIS_ID: "xMovingAverage";
|
|
13164
13166
|
CHART_AXIS_CHOICES: {
|
|
13165
13167
|
value: string;
|
|
13166
13168
|
label: string;
|