@odoo/o-spreadsheet 18.5.0-alpha.3 → 18.5.0-alpha.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 +291 -120
- package/dist/o-spreadsheet.d.ts +313 -159
- package/dist/o-spreadsheet.esm.js +291 -120
- package/dist/o-spreadsheet.iife.js +291 -120
- package/dist/o-spreadsheet.iife.min.js +419 -450
- package/dist/o_spreadsheet.xml +18 -14
- 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.5.0-alpha.
|
|
6
|
-
* @date 2025-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.5.0-alpha.5
|
|
6
|
+
* @date 2025-08-04T06:53:29.412Z
|
|
7
|
+
* @hash 71c9a36
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -1058,16 +1058,21 @@ const colors = [
|
|
|
1058
1058
|
"#001f3f",
|
|
1059
1059
|
];
|
|
1060
1060
|
/*
|
|
1061
|
-
* transform a color number (R * 256^2 + G * 256 + B) into classic
|
|
1061
|
+
* transform a color number (R * 256^2 + G * 256 + B) into classic hex (+alpha) value
|
|
1062
1062
|
* */
|
|
1063
|
-
function
|
|
1064
|
-
|
|
1063
|
+
function colorNumberToHex(color, alpha = 1) {
|
|
1064
|
+
const alphaHex = alpha !== 1
|
|
1065
|
+
? Math.round(alpha * 255)
|
|
1066
|
+
.toString(16)
|
|
1067
|
+
.padStart(2, "0")
|
|
1068
|
+
: "";
|
|
1069
|
+
return toHex(color.toString(16).padStart(6, "0")) + alphaHex;
|
|
1065
1070
|
}
|
|
1066
1071
|
function colorToNumber(color) {
|
|
1067
1072
|
if (typeof color === "number") {
|
|
1068
1073
|
return color;
|
|
1069
1074
|
}
|
|
1070
|
-
return Number.parseInt(toHex(color).slice(1), 16);
|
|
1075
|
+
return Number.parseInt(toHex(color).slice(1, 7), 16);
|
|
1071
1076
|
}
|
|
1072
1077
|
/**
|
|
1073
1078
|
* Converts any CSS color value to a standardized hex6 value.
|
|
@@ -1326,6 +1331,12 @@ function hslaToHex(hsla) {
|
|
|
1326
1331
|
function hexToHSLA(hex) {
|
|
1327
1332
|
return rgbaToHSLA(colorToRGBA(hex));
|
|
1328
1333
|
}
|
|
1334
|
+
function colorOrNumberToRGBA(color) {
|
|
1335
|
+
if (typeof color === "number") {
|
|
1336
|
+
return colorToRGBA(colorNumberToHex(color));
|
|
1337
|
+
}
|
|
1338
|
+
return colorToRGBA(color);
|
|
1339
|
+
}
|
|
1329
1340
|
/**
|
|
1330
1341
|
* Will compare two color strings
|
|
1331
1342
|
* A tolerance can be provided to account for small differences that could
|
|
@@ -1607,6 +1618,8 @@ function getColorScale(colorScalePoints) {
|
|
|
1607
1618
|
const sortedColorScalePoints = [...colorScalePoints.sort((a, b) => a.value - b.value)];
|
|
1608
1619
|
const thresholds = [];
|
|
1609
1620
|
for (let i = 1; i < sortedColorScalePoints.length; i++) {
|
|
1621
|
+
const minColorAlpha = colorOrNumberToRGBA(sortedColorScalePoints[i - 1].color).a;
|
|
1622
|
+
const maxColorAlpha = colorOrNumberToRGBA(sortedColorScalePoints[i].color).a;
|
|
1610
1623
|
const minColor = colorToNumber(sortedColorScalePoints[i - 1].color);
|
|
1611
1624
|
const maxColor = colorToNumber(sortedColorScalePoints[i].color);
|
|
1612
1625
|
thresholds.push({
|
|
@@ -1614,19 +1627,21 @@ function getColorScale(colorScalePoints) {
|
|
|
1614
1627
|
max: sortedColorScalePoints[i].value,
|
|
1615
1628
|
minColor,
|
|
1616
1629
|
maxColor,
|
|
1630
|
+
minColorAlpha: minColorAlpha,
|
|
1631
|
+
maxColorAlpha: maxColorAlpha,
|
|
1617
1632
|
colorDiff: computeColorDiffUnits(sortedColorScalePoints[i - 1].value, sortedColorScalePoints[i].value, minColor, maxColor),
|
|
1618
1633
|
});
|
|
1619
1634
|
}
|
|
1620
1635
|
return (value) => {
|
|
1621
1636
|
if (value < thresholds[0].min) {
|
|
1622
|
-
return
|
|
1637
|
+
return colorNumberToHex(thresholds[0].minColor, thresholds[0].minColorAlpha);
|
|
1623
1638
|
}
|
|
1624
1639
|
for (const threshold of thresholds) {
|
|
1625
1640
|
if (value >= threshold.min && value <= threshold.max) {
|
|
1626
|
-
return
|
|
1641
|
+
return colorNumberToHex(colorCell(value, threshold.min, threshold.minColor, threshold.colorDiff), threshold.maxColorAlpha);
|
|
1627
1642
|
}
|
|
1628
1643
|
}
|
|
1629
|
-
return
|
|
1644
|
+
return colorNumberToHex(thresholds[thresholds.length - 1].maxColor, thresholds[thresholds.length - 1].maxColorAlpha);
|
|
1630
1645
|
};
|
|
1631
1646
|
}
|
|
1632
1647
|
function computeColorDiffUnits(minValue, maxValue, minColor, maxColor) {
|
|
@@ -8640,12 +8655,12 @@ const AGGREGATOR_NAMES = {
|
|
|
8640
8655
|
avg: _t("Average"),
|
|
8641
8656
|
sum: _t("Sum"),
|
|
8642
8657
|
};
|
|
8643
|
-
const
|
|
8658
|
+
const DEFAULT_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
|
|
8644
8659
|
const AGGREGATORS_BY_FIELD_TYPE = {
|
|
8645
|
-
integer:
|
|
8646
|
-
char:
|
|
8660
|
+
integer: DEFAULT_AGGREGATORS,
|
|
8661
|
+
char: DEFAULT_AGGREGATORS,
|
|
8662
|
+
datetime: DEFAULT_AGGREGATORS,
|
|
8647
8663
|
boolean: ["count_distinct", "count", "bool_and", "bool_or"],
|
|
8648
|
-
datetime: ["max", "min", "count_distinct", "count"],
|
|
8649
8664
|
};
|
|
8650
8665
|
const AGGREGATORS = {};
|
|
8651
8666
|
for (const type in AGGREGATORS_BY_FIELD_TYPE) {
|
|
@@ -20478,6 +20493,54 @@ const PROPER = {
|
|
|
20478
20493
|
},
|
|
20479
20494
|
isExported: true,
|
|
20480
20495
|
};
|
|
20496
|
+
const REGEXEXTRACT_DEFAULT_MODE = 0;
|
|
20497
|
+
const REGEXEXTRACT_DEFAULT_CASE_SENSITIVITY = 0;
|
|
20498
|
+
// -----------------------------------------------------------------------------
|
|
20499
|
+
// REGEXEXTRACT
|
|
20500
|
+
// -----------------------------------------------------------------------------
|
|
20501
|
+
const REGEXEXTRACT = {
|
|
20502
|
+
description: _t("Extract text from a string based on the supplied regular expression."),
|
|
20503
|
+
args: [
|
|
20504
|
+
arg("text (string)", _t("The string on which you want to extract text.")),
|
|
20505
|
+
arg("pattern (string)", _t("The regular expression pattern to match against the text.")),
|
|
20506
|
+
arg(`return_mode (number, default=${REGEXEXTRACT_DEFAULT_MODE})`, _t("0 = first match, 1 = all matches as an array, 2 = capturing groups from the first match as an array.")),
|
|
20507
|
+
arg(`case_sensitivity (number, default=${REGEXEXTRACT_DEFAULT_CASE_SENSITIVITY})`, _t("0 = case-sensitive, 1 = case-insensitive.")),
|
|
20508
|
+
],
|
|
20509
|
+
compute: function (text, pattern, return_mode = { value: REGEXEXTRACT_DEFAULT_MODE }, newText = { value: REGEXEXTRACT_DEFAULT_CASE_SENSITIVITY }) {
|
|
20510
|
+
const _text = toString(text);
|
|
20511
|
+
const _pattern = toString(pattern);
|
|
20512
|
+
const _returnMode = toNumber(return_mode, this.locale);
|
|
20513
|
+
const _caseSensitivity = toNumber(newText, this.locale);
|
|
20514
|
+
if (_text === "" || _pattern === "") {
|
|
20515
|
+
return { value: "" };
|
|
20516
|
+
}
|
|
20517
|
+
if (_returnMode < 0 || _returnMode > 2) {
|
|
20518
|
+
return new EvaluationError(_t("The return_mode (%s) must be 0, 1 or 2.", _returnMode));
|
|
20519
|
+
}
|
|
20520
|
+
if (_caseSensitivity !== 0 && _caseSensitivity !== 1) {
|
|
20521
|
+
return new EvaluationError(_t("The case_sensitivity (%s) must be 0 or 1.", _caseSensitivity));
|
|
20522
|
+
}
|
|
20523
|
+
const flags = _caseSensitivity === 1 ? "gi" : "g";
|
|
20524
|
+
const regex = new RegExp(_pattern, flags);
|
|
20525
|
+
const matches = [..._text.matchAll(regex)];
|
|
20526
|
+
if (matches.length === 0) {
|
|
20527
|
+
return { value: CellErrorType.NotAvailable, message: _t("No matches found.") };
|
|
20528
|
+
}
|
|
20529
|
+
if (_returnMode === 0) {
|
|
20530
|
+
return matches[0][0];
|
|
20531
|
+
}
|
|
20532
|
+
else if (_returnMode === 1) {
|
|
20533
|
+
return matches.map((match) => [match[0]]);
|
|
20534
|
+
}
|
|
20535
|
+
else {
|
|
20536
|
+
if (matches[0].length < 2) {
|
|
20537
|
+
return new EvaluationError(_t("No capturing groups found."));
|
|
20538
|
+
}
|
|
20539
|
+
return matches[0].slice(1).map((s) => [s]);
|
|
20540
|
+
}
|
|
20541
|
+
},
|
|
20542
|
+
isExported: true,
|
|
20543
|
+
};
|
|
20481
20544
|
// -----------------------------------------------------------------------------
|
|
20482
20545
|
// REPLACE
|
|
20483
20546
|
// -----------------------------------------------------------------------------
|
|
@@ -20754,6 +20817,105 @@ const VALUE = {
|
|
|
20754
20817
|
},
|
|
20755
20818
|
isExported: true,
|
|
20756
20819
|
};
|
|
20820
|
+
// -----------------------------------------------------------------------------
|
|
20821
|
+
// TEXTAFTER
|
|
20822
|
+
// -----------------------------------------------------------------------------
|
|
20823
|
+
const TEXT_FN_DEFAULT_INSTANCE = 1;
|
|
20824
|
+
const TEXT_FN_DEFAULT_MATCH_MODE = 0;
|
|
20825
|
+
const TEXT_FN_DEFAULT_MATCH_END = 0;
|
|
20826
|
+
const TEXTAFTER = {
|
|
20827
|
+
description: _t("Returns text that occurs after a given substring or delimiter."),
|
|
20828
|
+
args: [
|
|
20829
|
+
arg("text (string)", _t("The source text.")),
|
|
20830
|
+
arg("delimiter (string)", _t("The substring after which text will be returned.")),
|
|
20831
|
+
arg(`instance_num (number, default=${TEXT_FN_DEFAULT_INSTANCE})`, _t("The desired instance of the delimiter after which we extract the text. A negative number searches from the end.")),
|
|
20832
|
+
arg(`match_mode (number, default=${TEXT_FN_DEFAULT_MATCH_MODE})`, _t("0 = case-sensitive, 1 = case-insensitive.")),
|
|
20833
|
+
arg(`match_end (number, default=${TEXT_FN_DEFAULT_MATCH_END}))`, _t("Whether to treat the end of text as a delimiter.")),
|
|
20834
|
+
arg(`if_not_found (string, default="${CellErrorType.NotAvailable}")`, _t("Value to return if the delimiter is not found.")),
|
|
20835
|
+
],
|
|
20836
|
+
compute: function (text, delimiter, matchIndex = { value: TEXT_FN_DEFAULT_INSTANCE }, matchMode = { value: TEXT_FN_DEFAULT_MATCH_MODE }, matchEnd = { value: TEXT_FN_DEFAULT_MATCH_END }, ifNotFound = new NotAvailableError()) {
|
|
20837
|
+
const _text = toString(text);
|
|
20838
|
+
const _matchIndex = toNumber(matchIndex, this.locale);
|
|
20839
|
+
const _matchMode = toNumber(matchMode, this.locale);
|
|
20840
|
+
const _matchEnd = toNumber(matchEnd, this.locale);
|
|
20841
|
+
if (_matchIndex === 0) {
|
|
20842
|
+
return new EvaluationError(_t("The instance_num (%s) must not be zero.", _matchIndex));
|
|
20843
|
+
}
|
|
20844
|
+
if (_matchMode !== 0 && _matchMode !== 1) {
|
|
20845
|
+
return new EvaluationError(_t("match_mode should have a value of 0 or 1."));
|
|
20846
|
+
}
|
|
20847
|
+
if (_matchEnd !== 0 && _matchEnd !== 1) {
|
|
20848
|
+
return new EvaluationError(_t("match_end should have a value of 0 or 1."));
|
|
20849
|
+
}
|
|
20850
|
+
const _delimiter = toString(delimiter);
|
|
20851
|
+
if (_delimiter === "") {
|
|
20852
|
+
return Math.sign(_matchIndex) > 0 ? { value: _text } : { value: "" };
|
|
20853
|
+
}
|
|
20854
|
+
const flags = _matchMode === 1 ? "gi" : "g";
|
|
20855
|
+
const pattern = escapeRegExp(_delimiter);
|
|
20856
|
+
const regexp = new RegExp(pattern, flags);
|
|
20857
|
+
let matchIndices = [..._text.matchAll(regexp)].map((match) => match.index + pattern.length);
|
|
20858
|
+
if (_matchIndex < 0) {
|
|
20859
|
+
matchIndices = matchIndices.reverse();
|
|
20860
|
+
}
|
|
20861
|
+
// If _matchEnd, we act like the text is appended by the delimiter (or prepended if negative index)
|
|
20862
|
+
if (_matchEnd && Math.abs(_matchIndex) === matchIndices.length + 1) {
|
|
20863
|
+
return Math.sign(_matchIndex) > 0 ? { value: "" } : { value: _text };
|
|
20864
|
+
}
|
|
20865
|
+
const targetIndex = matchIndices[Math.abs(_matchIndex) - 1];
|
|
20866
|
+
return targetIndex === undefined ? ifNotFound : { value: _text.substring(targetIndex) };
|
|
20867
|
+
},
|
|
20868
|
+
isExported: true,
|
|
20869
|
+
};
|
|
20870
|
+
// -----------------------------------------------------------------------------
|
|
20871
|
+
// TEXTBEFORE
|
|
20872
|
+
// -----------------------------------------------------------------------------
|
|
20873
|
+
const TEXTBEFORE = {
|
|
20874
|
+
description: _t("Returns text that occurs before a given substring or delimiter."),
|
|
20875
|
+
args: [
|
|
20876
|
+
arg("text (string)", _t("The source text.")),
|
|
20877
|
+
arg("delimiter (string)", _t("The substring after which text will be returned.")),
|
|
20878
|
+
arg(`instance_num (number, default=${TEXT_FN_DEFAULT_INSTANCE})`, _t("The desired instance of the delimiter before which we extract the text. A negative number searches from the end.")),
|
|
20879
|
+
arg(`match_mode (number, default=${TEXT_FN_DEFAULT_MATCH_MODE})`, _t("0 = case-sensitive, 1 = case-insensitive.")),
|
|
20880
|
+
arg(`match_end (number, default=${TEXT_FN_DEFAULT_MATCH_END}))`, _t("Whether to match a delimiter against the end of the text.")),
|
|
20881
|
+
arg(`if_not_found (string, default="${CellErrorType.NotAvailable}")`, _t("Value to return if the delimiter is not found.")),
|
|
20882
|
+
],
|
|
20883
|
+
compute: function (text, delimiter, matchIndex = { value: TEXT_FN_DEFAULT_INSTANCE }, matchMode = { value: TEXT_FN_DEFAULT_MATCH_MODE }, matchEnd = { value: TEXT_FN_DEFAULT_MATCH_END }, ifNotFound = new NotAvailableError()) {
|
|
20884
|
+
const _text = toString(text);
|
|
20885
|
+
const _matchIndex = toNumber(matchIndex, this.locale);
|
|
20886
|
+
const _matchMode = toNumber(matchMode, this.locale);
|
|
20887
|
+
const _matchEnd = toNumber(matchEnd, this.locale);
|
|
20888
|
+
if (_matchIndex === 0) {
|
|
20889
|
+
return new EvaluationError(_t("The instance_num (%s) must not be zero.", _matchIndex));
|
|
20890
|
+
}
|
|
20891
|
+
if (_matchMode !== 0 && _matchMode !== 1) {
|
|
20892
|
+
return new EvaluationError(_t("match_mode should have a value of 0 or 1."));
|
|
20893
|
+
}
|
|
20894
|
+
if (_matchEnd !== 0 && _matchEnd !== 1) {
|
|
20895
|
+
return new EvaluationError(_t("match_end should have a value of 0 or 1."));
|
|
20896
|
+
}
|
|
20897
|
+
const _delimiter = toString(delimiter);
|
|
20898
|
+
if (_delimiter === "") {
|
|
20899
|
+
return Math.sign(_matchIndex) > 0 ? { value: "" } : { value: _text };
|
|
20900
|
+
}
|
|
20901
|
+
const flags = _matchMode === 1 ? "gi" : "g";
|
|
20902
|
+
const pattern = escapeRegExp(_delimiter);
|
|
20903
|
+
const regexp = new RegExp(pattern, flags);
|
|
20904
|
+
let matchIndices = [..._text.matchAll(regexp)].map((match) => match.index + pattern.length);
|
|
20905
|
+
if (_matchIndex < 0) {
|
|
20906
|
+
matchIndices = matchIndices.reverse();
|
|
20907
|
+
}
|
|
20908
|
+
// If _matchEnd, we act like the text is appended by the delimiter (or prepended if negative index)
|
|
20909
|
+
if (_matchEnd && Math.abs(_matchIndex) === matchIndices.length + 1) {
|
|
20910
|
+
return Math.sign(_matchIndex) > 0 ? { value: _text } : { value: "" };
|
|
20911
|
+
}
|
|
20912
|
+
const targetIndex = matchIndices[Math.abs(_matchIndex) - 1];
|
|
20913
|
+
return targetIndex === undefined
|
|
20914
|
+
? ifNotFound
|
|
20915
|
+
: { value: _text.substring(0, targetIndex - _delimiter.length) };
|
|
20916
|
+
},
|
|
20917
|
+
isExported: true,
|
|
20918
|
+
};
|
|
20757
20919
|
|
|
20758
20920
|
var text = /*#__PURE__*/Object.freeze({
|
|
20759
20921
|
__proto__: null,
|
|
@@ -20768,12 +20930,15 @@ var text = /*#__PURE__*/Object.freeze({
|
|
|
20768
20930
|
LOWER: LOWER,
|
|
20769
20931
|
MID: MID,
|
|
20770
20932
|
PROPER: PROPER,
|
|
20933
|
+
REGEXEXTRACT: REGEXEXTRACT,
|
|
20771
20934
|
REPLACE: REPLACE,
|
|
20772
20935
|
RIGHT: RIGHT,
|
|
20773
20936
|
SEARCH: SEARCH,
|
|
20774
20937
|
SPLIT: SPLIT,
|
|
20775
20938
|
SUBSTITUTE: SUBSTITUTE,
|
|
20776
20939
|
TEXT: TEXT,
|
|
20940
|
+
TEXTAFTER: TEXTAFTER,
|
|
20941
|
+
TEXTBEFORE: TEXTBEFORE,
|
|
20777
20942
|
TEXTJOIN: TEXTJOIN,
|
|
20778
20943
|
TEXTSPLIT: TEXTSPLIT,
|
|
20779
20944
|
TRIM: TRIM,
|
|
@@ -22777,6 +22942,7 @@ class ChartJsComponent extends owl.Component {
|
|
|
22777
22942
|
this.animationStore = useStore(ChartAnimationStore);
|
|
22778
22943
|
}
|
|
22779
22944
|
owl.onMounted(() => {
|
|
22945
|
+
registerChartJSExtensions();
|
|
22780
22946
|
const runtime = this.chartRuntime;
|
|
22781
22947
|
this.currentRuntime = runtime;
|
|
22782
22948
|
// Note: chartJS modify the runtime in place, so it's important to give it a copy
|
|
@@ -30517,28 +30683,17 @@ class MenuPopover extends owl.Component {
|
|
|
30517
30683
|
}
|
|
30518
30684
|
}
|
|
30519
30685
|
|
|
30520
|
-
class
|
|
30521
|
-
|
|
30522
|
-
|
|
30523
|
-
static props = { figureUI: Object };
|
|
30686
|
+
class ChartDashboardMenuStore extends SpreadsheetStore {
|
|
30687
|
+
chartId;
|
|
30688
|
+
mutators = ["reset"];
|
|
30524
30689
|
originalChartDefinition;
|
|
30525
|
-
|
|
30526
|
-
|
|
30527
|
-
|
|
30528
|
-
|
|
30529
|
-
this.fullScreenFigureStore = useStore(FullScreenChartStore);
|
|
30530
|
-
this.originalChartDefinition = this.env.model.getters.getChartDefinition(this.props.figureUI.id);
|
|
30531
|
-
owl.onWillUpdateProps(({ figureUI }) => {
|
|
30532
|
-
if (figureUI.id !== this.props.figureUI.id) {
|
|
30533
|
-
this.originalChartDefinition = this.env.model.getters.getChartDefinition(figureUI.id);
|
|
30534
|
-
}
|
|
30535
|
-
});
|
|
30536
|
-
}
|
|
30537
|
-
getMenuItems() {
|
|
30538
|
-
return [this.fullScreenMenuItem, ...this.changeChartTypeMenuItems].filter(isDefined);
|
|
30690
|
+
constructor(get, chartId) {
|
|
30691
|
+
super(get);
|
|
30692
|
+
this.chartId = chartId;
|
|
30693
|
+
this.originalChartDefinition = this.getters.getChartDefinition(this.chartId);
|
|
30539
30694
|
}
|
|
30540
30695
|
get changeChartTypeMenuItems() {
|
|
30541
|
-
const definition = this.
|
|
30696
|
+
const definition = this.getters.getChartDefinition(this.chartId);
|
|
30542
30697
|
if (!["line", "bar", "pie"].includes(definition.type)) {
|
|
30543
30698
|
return [];
|
|
30544
30699
|
}
|
|
@@ -30547,27 +30702,19 @@ class ChartDashboardMenu extends owl.Component {
|
|
|
30547
30702
|
return {
|
|
30548
30703
|
id: item.chartType,
|
|
30549
30704
|
label: item.displayName,
|
|
30550
|
-
onClick: () => this.
|
|
30551
|
-
isSelected: item.chartType === this.
|
|
30705
|
+
onClick: () => this.updateType(item.chartType),
|
|
30706
|
+
isSelected: item.chartType === this.getters.getChartDefinition(this.chartId).type,
|
|
30552
30707
|
iconClass: this.getIconClasses(item.chartType),
|
|
30553
30708
|
};
|
|
30554
30709
|
});
|
|
30555
30710
|
}
|
|
30556
|
-
|
|
30557
|
-
|
|
30558
|
-
|
|
30559
|
-
}
|
|
30560
|
-
if (type.includes("line")) {
|
|
30561
|
-
return "fa fa-line-chart";
|
|
30562
|
-
}
|
|
30563
|
-
if (type.includes("pie")) {
|
|
30564
|
-
return "fa fa-pie-chart";
|
|
30565
|
-
}
|
|
30566
|
-
return "";
|
|
30711
|
+
reset(chartId) {
|
|
30712
|
+
this.chartId = chartId;
|
|
30713
|
+
this.originalChartDefinition = this.getters.getChartDefinition(chartId);
|
|
30567
30714
|
}
|
|
30568
|
-
|
|
30569
|
-
const figureId = this.
|
|
30570
|
-
const currentDefinition = this.
|
|
30715
|
+
updateType(type) {
|
|
30716
|
+
const figureId = this.chartId;
|
|
30717
|
+
const currentDefinition = this.getters.getChartDefinition(figureId);
|
|
30571
30718
|
if (currentDefinition.type === type) {
|
|
30572
30719
|
return;
|
|
30573
30720
|
}
|
|
@@ -30578,7 +30725,7 @@ class ChartDashboardMenu extends owl.Component {
|
|
|
30578
30725
|
else {
|
|
30579
30726
|
const newChartInfo = chartSubtypeRegistry.get(type);
|
|
30580
30727
|
const ChartClass = chartRegistry.get(newChartInfo.chartType);
|
|
30581
|
-
const chartCreationContext = this.
|
|
30728
|
+
const chartCreationContext = this.getters.getContextCreationChart(figureId);
|
|
30582
30729
|
if (!chartCreationContext)
|
|
30583
30730
|
return;
|
|
30584
30731
|
definition = {
|
|
@@ -30586,14 +30733,45 @@ class ChartDashboardMenu extends owl.Component {
|
|
|
30586
30733
|
...newChartInfo.subtypeDefinition,
|
|
30587
30734
|
};
|
|
30588
30735
|
}
|
|
30589
|
-
this.
|
|
30736
|
+
this.model.dispatch("UPDATE_CHART", {
|
|
30590
30737
|
definition,
|
|
30591
30738
|
figureId,
|
|
30592
|
-
sheetId: this.
|
|
30739
|
+
sheetId: this.getters.getActiveSheetId(),
|
|
30593
30740
|
});
|
|
30594
30741
|
}
|
|
30595
|
-
|
|
30596
|
-
|
|
30742
|
+
getIconClasses(type) {
|
|
30743
|
+
if (type.includes("bar")) {
|
|
30744
|
+
return "fa fa-bar-chart";
|
|
30745
|
+
}
|
|
30746
|
+
if (type.includes("line")) {
|
|
30747
|
+
return "fa fa-line-chart";
|
|
30748
|
+
}
|
|
30749
|
+
if (type.includes("pie")) {
|
|
30750
|
+
return "fa fa-pie-chart";
|
|
30751
|
+
}
|
|
30752
|
+
return "";
|
|
30753
|
+
}
|
|
30754
|
+
}
|
|
30755
|
+
|
|
30756
|
+
class ChartDashboardMenu extends owl.Component {
|
|
30757
|
+
static template = "o-spreadsheet-ChartDashboardMenu";
|
|
30758
|
+
static components = { MenuPopover };
|
|
30759
|
+
static props = { figureUI: Object };
|
|
30760
|
+
fullScreenFigureStore;
|
|
30761
|
+
store;
|
|
30762
|
+
menuState = owl.useState({ isOpen: false, anchorRect: null, menuItems: [] });
|
|
30763
|
+
setup() {
|
|
30764
|
+
super.setup();
|
|
30765
|
+
this.store = useLocalStore(ChartDashboardMenuStore, this.props.figureUI.id);
|
|
30766
|
+
this.fullScreenFigureStore = useStore(FullScreenChartStore);
|
|
30767
|
+
owl.onWillUpdateProps(({ figureUI }) => {
|
|
30768
|
+
if (figureUI.id !== this.props.figureUI.id) {
|
|
30769
|
+
this.store.reset(figureUI.id);
|
|
30770
|
+
}
|
|
30771
|
+
});
|
|
30772
|
+
}
|
|
30773
|
+
getMenuItems() {
|
|
30774
|
+
return [this.fullScreenMenuItem, ...this.store.changeChartTypeMenuItems].filter(isDefined);
|
|
30597
30775
|
}
|
|
30598
30776
|
get backgroundColor() {
|
|
30599
30777
|
const color = this.env.model.getters.getChartDefinition(this.props.figureUI.id).background;
|
|
@@ -31735,7 +31913,7 @@ criterionEvaluatorRegistry.add("isValueInRange", {
|
|
|
31735
31913
|
}
|
|
31736
31914
|
const criterionValues = getters.getDataValidationRangeValues(sheetId, criterion);
|
|
31737
31915
|
return criterionValues
|
|
31738
|
-
.map((value) => value.toLowerCase())
|
|
31916
|
+
.map((value) => value.value.toLowerCase())
|
|
31739
31917
|
.includes(value.toString().toLowerCase());
|
|
31740
31918
|
},
|
|
31741
31919
|
getErrorString: (criterion) => _t("The value must be a value in the range %s", String(criterion.values[0])),
|
|
@@ -32167,40 +32345,6 @@ function compareContentToSpanElement(content, node) {
|
|
|
32167
32345
|
return sameColor && sameClass && sameContent;
|
|
32168
32346
|
}
|
|
32169
32347
|
|
|
32170
|
-
// -----------------------------------------------------------------------------
|
|
32171
|
-
// Formula Assistant component
|
|
32172
|
-
// -----------------------------------------------------------------------------
|
|
32173
|
-
css /* scss */ `
|
|
32174
|
-
.o-formula-assistant {
|
|
32175
|
-
background: #ffffff;
|
|
32176
|
-
.o-formula-assistant-head {
|
|
32177
|
-
background-color: #f2f2f2;
|
|
32178
|
-
padding: 10px;
|
|
32179
|
-
}
|
|
32180
|
-
.collapsed {
|
|
32181
|
-
transform: rotate(180deg);
|
|
32182
|
-
}
|
|
32183
|
-
.o-formula-assistant-core {
|
|
32184
|
-
border-bottom: 1px solid gray;
|
|
32185
|
-
}
|
|
32186
|
-
.o-formula-assistant-arg-description {
|
|
32187
|
-
font-size: 85%;
|
|
32188
|
-
}
|
|
32189
|
-
.o-formula-assistant-focus {
|
|
32190
|
-
div:first-child,
|
|
32191
|
-
span {
|
|
32192
|
-
color: ${COMPOSER_ASSISTANT_COLOR};
|
|
32193
|
-
text-shadow: 0px 0px 1px ${COMPOSER_ASSISTANT_COLOR};
|
|
32194
|
-
}
|
|
32195
|
-
div:last-child {
|
|
32196
|
-
color: black;
|
|
32197
|
-
}
|
|
32198
|
-
}
|
|
32199
|
-
.o-formula-assistant-gray {
|
|
32200
|
-
color: gray;
|
|
32201
|
-
}
|
|
32202
|
-
}
|
|
32203
|
-
`;
|
|
32204
32348
|
class FunctionDescriptionProvider extends owl.Component {
|
|
32205
32349
|
static template = "o-spreadsheet-FunctionDescriptionProvider";
|
|
32206
32350
|
static props = {
|
|
@@ -51913,16 +52057,16 @@ class ConditionalFormatPreview extends owl.Component {
|
|
|
51913
52057
|
return cssPropertiesToCss(cellStyleToCss(rule.style));
|
|
51914
52058
|
}
|
|
51915
52059
|
else if (rule.type === "ColorScaleRule") {
|
|
51916
|
-
const minColor =
|
|
51917
|
-
const midColor = rule.midpoint ?
|
|
51918
|
-
const maxColor =
|
|
52060
|
+
const minColor = colorNumberToHex(rule.minimum.color);
|
|
52061
|
+
const midColor = rule.midpoint ? colorNumberToHex(rule.midpoint.color) : null;
|
|
52062
|
+
const maxColor = colorNumberToHex(rule.maximum.color);
|
|
51919
52063
|
const baseString = "background-image: linear-gradient(to right, ";
|
|
51920
52064
|
return midColor
|
|
51921
52065
|
? baseString + minColor + ", " + midColor + ", " + maxColor + ")"
|
|
51922
52066
|
: baseString + minColor + ", " + maxColor + ")";
|
|
51923
52067
|
}
|
|
51924
52068
|
else if (rule.type === "DataBarRule") {
|
|
51925
|
-
const color =
|
|
52069
|
+
const color = colorNumberToHex(rule.color);
|
|
51926
52070
|
return `background-image: linear-gradient(to right, ${color} 50%, white 50%)`;
|
|
51927
52071
|
}
|
|
51928
52072
|
return "";
|
|
@@ -52112,7 +52256,8 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
52112
52256
|
static props = {
|
|
52113
52257
|
editedCf: Object,
|
|
52114
52258
|
onCancel: Function,
|
|
52115
|
-
|
|
52259
|
+
onExit: Function,
|
|
52260
|
+
isNewCf: Boolean,
|
|
52116
52261
|
};
|
|
52117
52262
|
static components = {
|
|
52118
52263
|
SelectionInput,
|
|
@@ -52129,7 +52274,7 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
52129
52274
|
icons = ICONS;
|
|
52130
52275
|
iconSets = ICON_SETS;
|
|
52131
52276
|
getTextDecoration = getTextDecoration;
|
|
52132
|
-
|
|
52277
|
+
colorNumberToHex = colorNumberToHex;
|
|
52133
52278
|
state;
|
|
52134
52279
|
setup() {
|
|
52135
52280
|
this.state = owl.useState({
|
|
@@ -52137,6 +52282,7 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
52137
52282
|
currentCFType: this.props.editedCf.rule.type,
|
|
52138
52283
|
ranges: this.props.editedCf.ranges,
|
|
52139
52284
|
rules: this.getDefaultRules(),
|
|
52285
|
+
hasEditedCf: this.props.isNewCf,
|
|
52140
52286
|
});
|
|
52141
52287
|
switch (this.props.editedCf.rule.type) {
|
|
52142
52288
|
case "CellIsRule":
|
|
@@ -52188,6 +52334,9 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
52188
52334
|
ranges: ranges.map((xc) => this.env.model.getters.getRangeDataFromXc(sheetId, xc)),
|
|
52189
52335
|
sheetId,
|
|
52190
52336
|
});
|
|
52337
|
+
if (result.isSuccessful) {
|
|
52338
|
+
this.state.hasEditedCf = true;
|
|
52339
|
+
}
|
|
52191
52340
|
const reasons = result.reasons.filter((r) => r !== "NoChanges" /* CommandResult.NoChanges */);
|
|
52192
52341
|
if (!newCf.suppressErrors) {
|
|
52193
52342
|
this.state.errors = reasons;
|
|
@@ -52209,7 +52358,15 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
52209
52358
|
onSave() {
|
|
52210
52359
|
const result = this.updateConditionalFormat({});
|
|
52211
52360
|
if (result.length === 0) {
|
|
52212
|
-
this.props.
|
|
52361
|
+
this.props.onExit();
|
|
52362
|
+
}
|
|
52363
|
+
}
|
|
52364
|
+
onCancel() {
|
|
52365
|
+
if (this.state.hasEditedCf) {
|
|
52366
|
+
this.props.onCancel();
|
|
52367
|
+
}
|
|
52368
|
+
else {
|
|
52369
|
+
this.props.onExit();
|
|
52213
52370
|
}
|
|
52214
52371
|
}
|
|
52215
52372
|
getDefaultRules() {
|
|
@@ -52368,9 +52525,9 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
52368
52525
|
}
|
|
52369
52526
|
getPreviewGradient() {
|
|
52370
52527
|
const rule = this.state.rules.colorScale;
|
|
52371
|
-
const minColor =
|
|
52372
|
-
const midColor =
|
|
52373
|
-
const maxColor =
|
|
52528
|
+
const minColor = colorNumberToHex(rule.minimum.color);
|
|
52529
|
+
const midColor = colorNumberToHex(rule.midpoint?.color || DEFAULT_COLOR_SCALE_MIDPOINT_COLOR);
|
|
52530
|
+
const maxColor = colorNumberToHex(rule.maximum.color);
|
|
52374
52531
|
const baseString = "background-image: linear-gradient(to right, ";
|
|
52375
52532
|
return rule.midpoint === undefined
|
|
52376
52533
|
? baseString + minColor + ", " + maxColor + ")"
|
|
@@ -52378,8 +52535,8 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
52378
52535
|
}
|
|
52379
52536
|
getThresholdColor(threshold) {
|
|
52380
52537
|
return threshold
|
|
52381
|
-
?
|
|
52382
|
-
:
|
|
52538
|
+
? colorNumberToHex(threshold.color)
|
|
52539
|
+
: colorNumberToHex(DEFAULT_COLOR_SCALE_MIDPOINT_COLOR);
|
|
52383
52540
|
}
|
|
52384
52541
|
onMidpointChange(ev) {
|
|
52385
52542
|
const type = ev.target.value;
|
|
@@ -66603,9 +66760,9 @@ class CustomColorsPlugin extends CoreViewPlugin {
|
|
|
66603
66760
|
formatColors.push(rule.style.fillColor);
|
|
66604
66761
|
}
|
|
66605
66762
|
else if (rule.type === "ColorScaleRule") {
|
|
66606
|
-
formatColors.push(
|
|
66607
|
-
formatColors.push(rule.midpoint ?
|
|
66608
|
-
formatColors.push(
|
|
66763
|
+
formatColors.push(colorNumberToHex(rule.minimum.color));
|
|
66764
|
+
formatColors.push(rule.midpoint ? colorNumberToHex(rule.midpoint.color) : undefined);
|
|
66765
|
+
formatColors.push(colorNumberToHex(rule.maximum.color));
|
|
66609
66766
|
}
|
|
66610
66767
|
}
|
|
66611
66768
|
return formatColors.filter(isDefined);
|
|
@@ -66976,7 +67133,7 @@ class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
|
|
|
66976
67133
|
if (!computedDataBars[col])
|
|
66977
67134
|
computedDataBars[col] = [];
|
|
66978
67135
|
computedDataBars[col][row] = {
|
|
66979
|
-
color:
|
|
67136
|
+
color: colorNumberToHex(color),
|
|
66980
67137
|
percentage: (cell.value * 100) / max,
|
|
66981
67138
|
};
|
|
66982
67139
|
}
|
|
@@ -67105,8 +67262,16 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
67105
67262
|
}
|
|
67106
67263
|
getDataValidationRangeValues(sheetId, criterion) {
|
|
67107
67264
|
const range = this.getters.getRangeFromSheetXC(sheetId, String(criterion.values[0]));
|
|
67108
|
-
const
|
|
67109
|
-
|
|
67265
|
+
const values = [];
|
|
67266
|
+
const labelsSet = new Set();
|
|
67267
|
+
for (const p of positions(range.zone)) {
|
|
67268
|
+
const cell = this.getters.getEvaluatedCell({ ...p, sheetId: range.sheetId });
|
|
67269
|
+
if (cell.formattedValue && !labelsSet.has(cell.formattedValue)) {
|
|
67270
|
+
labelsSet.add(cell.formattedValue);
|
|
67271
|
+
values.push({ label: cell.formattedValue, value: cell.value?.toString() || "" });
|
|
67272
|
+
}
|
|
67273
|
+
}
|
|
67274
|
+
return values;
|
|
67110
67275
|
}
|
|
67111
67276
|
isCellValidCheckbox(cellPosition) {
|
|
67112
67277
|
if (!this.getters.isMainCellPosition(cellPosition)) {
|
|
@@ -75728,25 +75893,30 @@ autoCompleteProviders.add("dataValidation", {
|
|
|
75728
75893
|
}
|
|
75729
75894
|
const sheetId = this.composer.currentEditedCell.sheetId;
|
|
75730
75895
|
const values = rule.criterion.type === "isValueInRange"
|
|
75731
|
-
?
|
|
75732
|
-
: rule.criterion.values;
|
|
75896
|
+
? this.getters.getDataValidationRangeValues(sheetId, rule.criterion)
|
|
75897
|
+
: rule.criterion.values.map((value) => ({ label: value, value }));
|
|
75733
75898
|
const isChip = rule.criterion.displayStyle === "chip";
|
|
75734
75899
|
if (!isChip) {
|
|
75735
|
-
return values.map((value) => ({
|
|
75900
|
+
return values.map((value) => ({
|
|
75901
|
+
text: value.value,
|
|
75902
|
+
fuzzySearchKey: value.label,
|
|
75903
|
+
htmlContent: [{ value: value.label }],
|
|
75904
|
+
}));
|
|
75736
75905
|
}
|
|
75737
75906
|
const colors = rule.criterion.colors;
|
|
75738
75907
|
return values.map((value) => {
|
|
75739
|
-
const color = colors?.[value];
|
|
75908
|
+
const color = colors?.[value.value];
|
|
75740
75909
|
return {
|
|
75741
|
-
text: value,
|
|
75910
|
+
text: value.value,
|
|
75742
75911
|
htmlContent: [
|
|
75743
75912
|
{
|
|
75744
|
-
value,
|
|
75913
|
+
value: value.label,
|
|
75745
75914
|
color: color ? chipTextColor(color) : undefined,
|
|
75746
75915
|
backgroundColor: color || GRAY_200,
|
|
75747
75916
|
classes: ["badge rounded-pill fs-6 fw-normal w-100 mt-1 text-start"],
|
|
75748
75917
|
},
|
|
75749
75918
|
],
|
|
75919
|
+
fuzzySearchKey: value.label,
|
|
75750
75920
|
};
|
|
75751
75921
|
});
|
|
75752
75922
|
},
|
|
@@ -79987,7 +80157,6 @@ css /* scss */ `
|
|
|
79987
80157
|
}
|
|
79988
80158
|
}
|
|
79989
80159
|
|
|
79990
|
-
.o-spreadsheet-topbar-wrapper,
|
|
79991
80160
|
.o-spreadsheet-bottombar-wrapper {
|
|
79992
80161
|
z-index: ${ComponentsImportance.ScrollBar + 1};
|
|
79993
80162
|
}
|
|
@@ -80102,7 +80271,6 @@ class Spreadsheet extends owl.Component {
|
|
|
80102
80271
|
this.checkViewportSize();
|
|
80103
80272
|
stores.on("store-updated", this, render);
|
|
80104
80273
|
resizeObserver.observe(this.spreadsheetRef.el);
|
|
80105
|
-
registerChartJSExtensions();
|
|
80106
80274
|
});
|
|
80107
80275
|
owl.onWillUnmount(() => {
|
|
80108
80276
|
this.unbindModelEvents();
|
|
@@ -82748,7 +82916,7 @@ function addDataBarRule(cf, rule) {
|
|
|
82748
82916
|
<dataBar>
|
|
82749
82917
|
<cfvo type="min" val="0"/>
|
|
82750
82918
|
<cfvo type="max" val="100"/>
|
|
82751
|
-
<color rgb="${toXlsxHexColor(
|
|
82919
|
+
<color rgb="${toXlsxHexColor(colorNumberToHex(rule.color))}"/>
|
|
82752
82920
|
</dataBar>
|
|
82753
82921
|
</cfRule>
|
|
82754
82922
|
</conditionalFormatting>
|
|
@@ -82776,7 +82944,7 @@ function addColorScaleRule(cf, rule) {
|
|
|
82776
82944
|
continue;
|
|
82777
82945
|
}
|
|
82778
82946
|
cfValueObject.push(thresholdAttributes(threshold, position));
|
|
82779
|
-
colors.push([["rgb", toXlsxHexColor(
|
|
82947
|
+
colors.push([["rgb", toXlsxHexColor(colorNumberToHex(threshold.color))]]);
|
|
82780
82948
|
}
|
|
82781
82949
|
if (!canExport) {
|
|
82782
82950
|
console.warn("Conditional formats with formula rules are not supported at the moment. The rule is therefore skipped.");
|
|
@@ -84720,6 +84888,8 @@ const components = {
|
|
|
84720
84888
|
WaterfallChartDesignPanel,
|
|
84721
84889
|
ComboChartDesignPanel,
|
|
84722
84890
|
FunnelChartDesignPanel,
|
|
84891
|
+
SunburstChartDesignPanel,
|
|
84892
|
+
TreeMapChartDesignPanel,
|
|
84723
84893
|
ChartTypePicker,
|
|
84724
84894
|
FigureComponent,
|
|
84725
84895
|
MenuPopover,
|
|
@@ -84749,6 +84919,7 @@ const hooks = {
|
|
|
84749
84919
|
};
|
|
84750
84920
|
const stores = {
|
|
84751
84921
|
useStoreProvider,
|
|
84922
|
+
ChartDashboardMenuStore,
|
|
84752
84923
|
DependencyContainer,
|
|
84753
84924
|
CellPopoverStore,
|
|
84754
84925
|
ComposerFocusStore,
|
|
@@ -84835,6 +85006,6 @@ exports.tokenColors = tokenColors;
|
|
|
84835
85006
|
exports.tokenize = tokenize;
|
|
84836
85007
|
|
|
84837
85008
|
|
|
84838
|
-
__info__.version = "18.5.0-alpha.
|
|
84839
|
-
__info__.date = "2025-
|
|
84840
|
-
__info__.hash = "
|
|
85009
|
+
__info__.version = "18.5.0-alpha.5";
|
|
85010
|
+
__info__.date = "2025-08-04T06:53:29.412Z";
|
|
85011
|
+
__info__.hash = "71c9a36";
|