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