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