@odoo/o-spreadsheet 18.2.0-alpha.0 → 18.2.0-alpha.1
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 +700 -427
- package/dist/o-spreadsheet.d.ts +88 -34
- package/dist/o-spreadsheet.esm.js +701 -429
- package/dist/o-spreadsheet.iife.js +700 -427
- package/dist/o-spreadsheet.iife.min.js +394 -383
- package/dist/o_spreadsheet.xml +5 -5
- package/package.json +2 -2
|
@@ -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.0-alpha.
|
|
6
|
-
* @date
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.2.0-alpha.1
|
|
6
|
+
* @date 2025-01-14T11:35:51.135Z
|
|
7
|
+
* @hash 702f816
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -357,6 +357,7 @@ var ComponentsImportance;
|
|
|
357
357
|
ComponentsImportance[ComponentsImportance["Popover"] = 35] = "Popover";
|
|
358
358
|
ComponentsImportance[ComponentsImportance["FigureAnchor"] = 1000] = "FigureAnchor";
|
|
359
359
|
ComponentsImportance[ComponentsImportance["FigureSnapLine"] = 1001] = "FigureSnapLine";
|
|
360
|
+
ComponentsImportance[ComponentsImportance["FigureTooltip"] = 1002] = "FigureTooltip";
|
|
360
361
|
})(ComponentsImportance || (ComponentsImportance = {}));
|
|
361
362
|
let DEFAULT_SHEETVIEW_SIZE = 0;
|
|
362
363
|
function getDefaultSheetViewSize() {
|
|
@@ -976,6 +977,16 @@ function transpose2dPOJO(pojo) {
|
|
|
976
977
|
}
|
|
977
978
|
return result;
|
|
978
979
|
}
|
|
980
|
+
function getUniqueText(text, texts, options = {}) {
|
|
981
|
+
const compute = options.compute ?? ((text, i) => `${text} (${i})`);
|
|
982
|
+
const computeFirstOne = options.computeFirstOne ?? false;
|
|
983
|
+
let i = options.start ?? 1;
|
|
984
|
+
let newText = computeFirstOne ? compute(text, i) : text;
|
|
985
|
+
while (texts.includes(newText)) {
|
|
986
|
+
newText = compute(text, i++);
|
|
987
|
+
}
|
|
988
|
+
return newText;
|
|
989
|
+
}
|
|
979
990
|
|
|
980
991
|
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
981
992
|
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
|
|
@@ -3711,6 +3722,7 @@ exports.CommandResult = void 0;
|
|
|
3711
3722
|
CommandResult["SheetIsHidden"] = "SheetIsHidden";
|
|
3712
3723
|
CommandResult["InvalidTableResize"] = "InvalidTableResize";
|
|
3713
3724
|
CommandResult["PivotIdNotFound"] = "PivotIdNotFound";
|
|
3725
|
+
CommandResult["PivotInError"] = "PivotInError";
|
|
3714
3726
|
CommandResult["EmptyName"] = "EmptyName";
|
|
3715
3727
|
CommandResult["ValueCellIsInvalidFormula"] = "ValueCellIsInvalidFormula";
|
|
3716
3728
|
CommandResult["InvalidDefinition"] = "InvalidDefinition";
|
|
@@ -6028,10 +6040,10 @@ class RangeImpl {
|
|
|
6028
6040
|
}
|
|
6029
6041
|
}
|
|
6030
6042
|
/**
|
|
6031
|
-
*
|
|
6043
|
+
* Duplicate a range. If the range is on the sheetIdFrom, the range will target
|
|
6032
6044
|
* sheetIdTo.
|
|
6033
6045
|
*/
|
|
6034
|
-
function
|
|
6046
|
+
function duplicateRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, range) {
|
|
6035
6047
|
const sheetId = range.sheetId === sheetIdFrom ? sheetIdTo : range.sheetId;
|
|
6036
6048
|
return range.clone({ sheetId });
|
|
6037
6049
|
}
|
|
@@ -7479,18 +7491,18 @@ function predictLinearValues(Y, X, newX, computeIntercept) {
|
|
|
7479
7491
|
});
|
|
7480
7492
|
return newY.length === newX.length ? newY : transposeMatrix(newY);
|
|
7481
7493
|
}
|
|
7482
|
-
function getMovingAverageValues(dataset, windowSize = DEFAULT_WINDOW_SIZE) {
|
|
7494
|
+
function getMovingAverageValues(dataset, labels, windowSize = DEFAULT_WINDOW_SIZE) {
|
|
7483
7495
|
const values = [];
|
|
7484
7496
|
// Fill the starting values with null until we have a full window
|
|
7485
7497
|
for (let i = 0; i < windowSize - 1; i++) {
|
|
7486
|
-
values.push(
|
|
7498
|
+
values.push({ x: labels[i], y: NaN });
|
|
7487
7499
|
}
|
|
7488
7500
|
for (let i = 0; i <= dataset.length - windowSize; i++) {
|
|
7489
7501
|
let sum = 0;
|
|
7490
7502
|
for (let j = i; j < i + windowSize; j++) {
|
|
7491
7503
|
sum += dataset[j];
|
|
7492
7504
|
}
|
|
7493
|
-
values.push(sum / windowSize);
|
|
7505
|
+
values.push({ x: labels[i + windowSize - 1], y: sum / windowSize });
|
|
7494
7506
|
}
|
|
7495
7507
|
return values;
|
|
7496
7508
|
}
|
|
@@ -9464,6 +9476,150 @@ class ComposerFocusStore extends SpreadsheetStore {
|
|
|
9464
9476
|
}
|
|
9465
9477
|
}
|
|
9466
9478
|
|
|
9479
|
+
/**
|
|
9480
|
+
* This file is largely inspired by owl 1.
|
|
9481
|
+
* `css` tag has been removed from owl 2 without workaround to manage css.
|
|
9482
|
+
* So, the solution was to import the behavior of owl 1 directly in our
|
|
9483
|
+
* codebase, with one difference: the css is added to the sheet as soon as the
|
|
9484
|
+
* css tag is executed. In owl 1, the css was added as soon as a Component was
|
|
9485
|
+
* created for the first time.
|
|
9486
|
+
*/
|
|
9487
|
+
const STYLESHEETS = {};
|
|
9488
|
+
let nextId = 0;
|
|
9489
|
+
/**
|
|
9490
|
+
* CSS tag helper for defining inline stylesheets. With this, one can simply define
|
|
9491
|
+
* an inline stylesheet with just the following code:
|
|
9492
|
+
* ```js
|
|
9493
|
+
* css`.component-a { color: red; }`;
|
|
9494
|
+
* ```
|
|
9495
|
+
*/
|
|
9496
|
+
function css(strings, ...args) {
|
|
9497
|
+
const name = `__sheet__${nextId++}`;
|
|
9498
|
+
const value = String.raw(strings, ...args);
|
|
9499
|
+
registerSheet(name, value);
|
|
9500
|
+
activateSheet(name);
|
|
9501
|
+
return name;
|
|
9502
|
+
}
|
|
9503
|
+
function processSheet(str) {
|
|
9504
|
+
const tokens = str.split(/(\{|\}|;)/).map((s) => s.trim());
|
|
9505
|
+
const selectorStack = [];
|
|
9506
|
+
const parts = [];
|
|
9507
|
+
let rules = [];
|
|
9508
|
+
function generateSelector(stackIndex, parentSelector) {
|
|
9509
|
+
const parts = [];
|
|
9510
|
+
for (const selector of selectorStack[stackIndex]) {
|
|
9511
|
+
let part = (parentSelector && parentSelector + " " + selector) || selector;
|
|
9512
|
+
if (part.includes("&")) {
|
|
9513
|
+
part = selector.replace(/&/g, parentSelector || "");
|
|
9514
|
+
}
|
|
9515
|
+
if (stackIndex < selectorStack.length - 1) {
|
|
9516
|
+
part = generateSelector(stackIndex + 1, part);
|
|
9517
|
+
}
|
|
9518
|
+
parts.push(part);
|
|
9519
|
+
}
|
|
9520
|
+
return parts.join(", ");
|
|
9521
|
+
}
|
|
9522
|
+
function generateRules() {
|
|
9523
|
+
if (rules.length) {
|
|
9524
|
+
parts.push(generateSelector(0) + " {");
|
|
9525
|
+
parts.push(...rules);
|
|
9526
|
+
parts.push("}");
|
|
9527
|
+
rules = [];
|
|
9528
|
+
}
|
|
9529
|
+
}
|
|
9530
|
+
while (tokens.length) {
|
|
9531
|
+
let token = tokens.shift();
|
|
9532
|
+
if (token === "}") {
|
|
9533
|
+
generateRules();
|
|
9534
|
+
selectorStack.pop();
|
|
9535
|
+
}
|
|
9536
|
+
else {
|
|
9537
|
+
if (tokens[0] === "{") {
|
|
9538
|
+
generateRules();
|
|
9539
|
+
selectorStack.push(token.split(/\s*,\s*/));
|
|
9540
|
+
tokens.shift();
|
|
9541
|
+
}
|
|
9542
|
+
if (tokens[0] === ";") {
|
|
9543
|
+
rules.push(" " + token + ";");
|
|
9544
|
+
}
|
|
9545
|
+
}
|
|
9546
|
+
}
|
|
9547
|
+
return parts.join("\n");
|
|
9548
|
+
}
|
|
9549
|
+
function registerSheet(id, css) {
|
|
9550
|
+
const sheet = document.createElement("style");
|
|
9551
|
+
sheet.textContent = processSheet(css);
|
|
9552
|
+
STYLESHEETS[id] = sheet;
|
|
9553
|
+
}
|
|
9554
|
+
function activateSheet(id) {
|
|
9555
|
+
const sheet = STYLESHEETS[id];
|
|
9556
|
+
sheet.setAttribute("component", id);
|
|
9557
|
+
document.head.appendChild(sheet);
|
|
9558
|
+
}
|
|
9559
|
+
function getTextDecoration({ strikethrough, underline, }) {
|
|
9560
|
+
if (!strikethrough && !underline) {
|
|
9561
|
+
return "none";
|
|
9562
|
+
}
|
|
9563
|
+
return `${strikethrough ? "line-through" : ""} ${underline ? "underline" : ""}`;
|
|
9564
|
+
}
|
|
9565
|
+
/**
|
|
9566
|
+
* Convert the cell style to CSS properties.
|
|
9567
|
+
*/
|
|
9568
|
+
function cellStyleToCss(style) {
|
|
9569
|
+
const attributes = cellTextStyleToCss(style);
|
|
9570
|
+
if (!style)
|
|
9571
|
+
return attributes;
|
|
9572
|
+
if (style.fillColor) {
|
|
9573
|
+
attributes["background"] = style.fillColor;
|
|
9574
|
+
}
|
|
9575
|
+
return attributes;
|
|
9576
|
+
}
|
|
9577
|
+
/**
|
|
9578
|
+
* Convert the cell text style to CSS properties.
|
|
9579
|
+
*/
|
|
9580
|
+
function cellTextStyleToCss(style) {
|
|
9581
|
+
const attributes = {};
|
|
9582
|
+
if (!style)
|
|
9583
|
+
return attributes;
|
|
9584
|
+
if (style.bold) {
|
|
9585
|
+
attributes["font-weight"] = "bold";
|
|
9586
|
+
}
|
|
9587
|
+
if (style.italic) {
|
|
9588
|
+
attributes["font-style"] = "italic";
|
|
9589
|
+
}
|
|
9590
|
+
if (style.strikethrough || style.underline) {
|
|
9591
|
+
let decoration = style.strikethrough ? "line-through" : "";
|
|
9592
|
+
decoration = style.underline ? decoration + " underline" : decoration;
|
|
9593
|
+
attributes["text-decoration"] = decoration;
|
|
9594
|
+
}
|
|
9595
|
+
if (style.textColor) {
|
|
9596
|
+
attributes["color"] = style.textColor;
|
|
9597
|
+
}
|
|
9598
|
+
return attributes;
|
|
9599
|
+
}
|
|
9600
|
+
/**
|
|
9601
|
+
* Transform CSS properties into a CSS string.
|
|
9602
|
+
*/
|
|
9603
|
+
function cssPropertiesToCss(attributes) {
|
|
9604
|
+
let styleStr = "";
|
|
9605
|
+
for (const attName in attributes) {
|
|
9606
|
+
if (!attributes[attName]) {
|
|
9607
|
+
continue;
|
|
9608
|
+
}
|
|
9609
|
+
styleStr += `${attName}:${attributes[attName]}; `;
|
|
9610
|
+
}
|
|
9611
|
+
return styleStr;
|
|
9612
|
+
}
|
|
9613
|
+
function getElementMargins(el) {
|
|
9614
|
+
const style = window.getComputedStyle(el);
|
|
9615
|
+
return {
|
|
9616
|
+
top: parseInt(style.marginTop, 10) || 0,
|
|
9617
|
+
bottom: parseInt(style.marginBottom, 10) || 0,
|
|
9618
|
+
left: parseInt(style.marginLeft, 10) || 0,
|
|
9619
|
+
right: parseInt(style.marginRight, 10) || 0,
|
|
9620
|
+
};
|
|
9621
|
+
}
|
|
9622
|
+
|
|
9467
9623
|
const TREND_LINE_XAXIS_ID = "x1";
|
|
9468
9624
|
/**
|
|
9469
9625
|
* This file contains helpers that are common to different charts (mainly
|
|
@@ -9516,25 +9672,25 @@ function updateChartRangesWithDataSets(getters, applyChange, chartDataSets, char
|
|
|
9516
9672
|
};
|
|
9517
9673
|
}
|
|
9518
9674
|
/**
|
|
9519
|
-
*
|
|
9675
|
+
* Duplicate the dataSets. All ranges on sheetIdFrom are adapted to target
|
|
9520
9676
|
* sheetIdTo.
|
|
9521
9677
|
*/
|
|
9522
|
-
function
|
|
9678
|
+
function duplicateDataSetsInDuplicatedSheet(sheetIdFrom, sheetIdTo, dataSets) {
|
|
9523
9679
|
return dataSets.map((ds) => {
|
|
9524
9680
|
return {
|
|
9525
|
-
dataRange:
|
|
9681
|
+
dataRange: duplicateRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, ds.dataRange),
|
|
9526
9682
|
labelCell: ds.labelCell
|
|
9527
|
-
?
|
|
9683
|
+
? duplicateRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, ds.labelCell)
|
|
9528
9684
|
: undefined,
|
|
9529
9685
|
};
|
|
9530
9686
|
});
|
|
9531
9687
|
}
|
|
9532
9688
|
/**
|
|
9533
|
-
*
|
|
9689
|
+
* Duplicate a range. If the range is on the sheetIdFrom, the range will target
|
|
9534
9690
|
* sheetIdTo.
|
|
9535
9691
|
*/
|
|
9536
|
-
function
|
|
9537
|
-
return range ?
|
|
9692
|
+
function duplicateLabelRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, range) {
|
|
9693
|
+
return range ? duplicateRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, range) : undefined;
|
|
9538
9694
|
}
|
|
9539
9695
|
/**
|
|
9540
9696
|
* Adapt a single range of a chart
|
|
@@ -9787,10 +9943,11 @@ function formatTickValue(localeFormat) {
|
|
|
9787
9943
|
if (isNaN(value))
|
|
9788
9944
|
return value;
|
|
9789
9945
|
const { locale, format } = localeFormat;
|
|
9790
|
-
|
|
9946
|
+
const formattedValue = formatValue(value, {
|
|
9791
9947
|
locale,
|
|
9792
9948
|
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
|
9793
9949
|
});
|
|
9950
|
+
return truncateLabel(formattedValue);
|
|
9794
9951
|
};
|
|
9795
9952
|
}
|
|
9796
9953
|
const CHART_AXIS_CHOICES = [
|
|
@@ -9805,6 +9962,15 @@ function getPieColors(colors, dataSetsValues) {
|
|
|
9805
9962
|
}
|
|
9806
9963
|
return pieColors;
|
|
9807
9964
|
}
|
|
9965
|
+
function truncateLabel(label) {
|
|
9966
|
+
if (!label) {
|
|
9967
|
+
return "";
|
|
9968
|
+
}
|
|
9969
|
+
if (label.length > MAX_CHAR_LABEL) {
|
|
9970
|
+
return label.substring(0, MAX_CHAR_LABEL) + "…";
|
|
9971
|
+
}
|
|
9972
|
+
return label;
|
|
9973
|
+
}
|
|
9808
9974
|
|
|
9809
9975
|
/** This is a chartJS plugin that will draw the values of each data next to the point/bar/pie slice */
|
|
9810
9976
|
const chartShowValuesPlugin = {
|
|
@@ -10000,6 +10166,18 @@ function getNextNonEmptyBar(bars, startIndex) {
|
|
|
10000
10166
|
|
|
10001
10167
|
window.Chart?.register(waterfallLinesPlugin);
|
|
10002
10168
|
window.Chart?.register(chartShowValuesPlugin);
|
|
10169
|
+
css /* scss */ `
|
|
10170
|
+
.o-spreadsheet {
|
|
10171
|
+
.o-chart-custom-tooltip {
|
|
10172
|
+
font-size: 12px;
|
|
10173
|
+
background-color: #fff;
|
|
10174
|
+
z-index: ${ComponentsImportance.FigureTooltip};
|
|
10175
|
+
table td span {
|
|
10176
|
+
box-sizing: border-box;
|
|
10177
|
+
}
|
|
10178
|
+
}
|
|
10179
|
+
}
|
|
10180
|
+
`;
|
|
10003
10181
|
class ChartJsComponent extends owl.Component {
|
|
10004
10182
|
static template = "o-spreadsheet-ChartJsComponent";
|
|
10005
10183
|
static props = {
|
|
@@ -10238,11 +10416,11 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
|
|
|
10238
10416
|
keyValue: keyValueZone ? zoneToXc(keyValueZone) : undefined,
|
|
10239
10417
|
};
|
|
10240
10418
|
}
|
|
10241
|
-
|
|
10242
|
-
const baseline =
|
|
10243
|
-
const keyValue =
|
|
10244
|
-
const definition = this.getDefinitionWithSpecificRanges(baseline, keyValue,
|
|
10245
|
-
return new ScorecardChart(definition,
|
|
10419
|
+
duplicateInDuplicatedSheet(newSheetId) {
|
|
10420
|
+
const baseline = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.baseline);
|
|
10421
|
+
const keyValue = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.keyValue);
|
|
10422
|
+
const definition = this.getDefinitionWithSpecificRanges(baseline, keyValue, newSheetId);
|
|
10423
|
+
return new ScorecardChart(definition, newSheetId, this.getters);
|
|
10246
10424
|
}
|
|
10247
10425
|
copyInSheetId(sheetId) {
|
|
10248
10426
|
const definition = this.getDefinitionWithSpecificRanges(this.baseline, this.keyValue, sheetId);
|
|
@@ -19932,6 +20110,17 @@ const TEXT = {
|
|
|
19932
20110
|
},
|
|
19933
20111
|
isExported: true,
|
|
19934
20112
|
};
|
|
20113
|
+
// -----------------------------------------------------------------------------
|
|
20114
|
+
// VALUE
|
|
20115
|
+
// -----------------------------------------------------------------------------
|
|
20116
|
+
const VALUE = {
|
|
20117
|
+
description: _t("Converts a string to a numeric value."),
|
|
20118
|
+
args: [arg("value (number)", _t("the string to be converted"))],
|
|
20119
|
+
compute: function (value) {
|
|
20120
|
+
return toNumber(value, this.locale);
|
|
20121
|
+
},
|
|
20122
|
+
isExported: true,
|
|
20123
|
+
};
|
|
19935
20124
|
|
|
19936
20125
|
var text = /*#__PURE__*/Object.freeze({
|
|
19937
20126
|
__proto__: null,
|
|
@@ -19954,7 +20143,8 @@ var text = /*#__PURE__*/Object.freeze({
|
|
|
19954
20143
|
TEXT: TEXT,
|
|
19955
20144
|
TEXTJOIN: TEXTJOIN,
|
|
19956
20145
|
TRIM: TRIM,
|
|
19957
|
-
UPPER: UPPER
|
|
20146
|
+
UPPER: UPPER,
|
|
20147
|
+
VALUE: VALUE
|
|
19958
20148
|
});
|
|
19959
20149
|
|
|
19960
20150
|
// -----------------------------------------------------------------------------
|
|
@@ -22557,15 +22747,6 @@ const CHART_COMMON_OPTIONS = {
|
|
|
22557
22747
|
},
|
|
22558
22748
|
animation: false,
|
|
22559
22749
|
};
|
|
22560
|
-
function truncateLabel(label) {
|
|
22561
|
-
if (!label) {
|
|
22562
|
-
return "";
|
|
22563
|
-
}
|
|
22564
|
-
if (label.length > MAX_CHAR_LABEL) {
|
|
22565
|
-
return label.substring(0, MAX_CHAR_LABEL) + "…";
|
|
22566
|
-
}
|
|
22567
|
-
return label;
|
|
22568
|
-
}
|
|
22569
22750
|
function chartToImage(runtime, figure, type) {
|
|
22570
22751
|
// wrap the canvas in a div with a fixed size because chart.js would
|
|
22571
22752
|
// fill the whole page otherwise
|
|
@@ -22887,150 +23068,6 @@ const CONTENT_TYPES_FILE = "[Content_Types].xml";
|
|
|
22887
23068
|
*/
|
|
22888
23069
|
const iconsOnCellRegistry = new Registry();
|
|
22889
23070
|
|
|
22890
|
-
/**
|
|
22891
|
-
* This file is largely inspired by owl 1.
|
|
22892
|
-
* `css` tag has been removed from owl 2 without workaround to manage css.
|
|
22893
|
-
* So, the solution was to import the behavior of owl 1 directly in our
|
|
22894
|
-
* codebase, with one difference: the css is added to the sheet as soon as the
|
|
22895
|
-
* css tag is executed. In owl 1, the css was added as soon as a Component was
|
|
22896
|
-
* created for the first time.
|
|
22897
|
-
*/
|
|
22898
|
-
const STYLESHEETS = {};
|
|
22899
|
-
let nextId = 0;
|
|
22900
|
-
/**
|
|
22901
|
-
* CSS tag helper for defining inline stylesheets. With this, one can simply define
|
|
22902
|
-
* an inline stylesheet with just the following code:
|
|
22903
|
-
* ```js
|
|
22904
|
-
* css`.component-a { color: red; }`;
|
|
22905
|
-
* ```
|
|
22906
|
-
*/
|
|
22907
|
-
function css(strings, ...args) {
|
|
22908
|
-
const name = `__sheet__${nextId++}`;
|
|
22909
|
-
const value = String.raw(strings, ...args);
|
|
22910
|
-
registerSheet(name, value);
|
|
22911
|
-
activateSheet(name);
|
|
22912
|
-
return name;
|
|
22913
|
-
}
|
|
22914
|
-
function processSheet(str) {
|
|
22915
|
-
const tokens = str.split(/(\{|\}|;)/).map((s) => s.trim());
|
|
22916
|
-
const selectorStack = [];
|
|
22917
|
-
const parts = [];
|
|
22918
|
-
let rules = [];
|
|
22919
|
-
function generateSelector(stackIndex, parentSelector) {
|
|
22920
|
-
const parts = [];
|
|
22921
|
-
for (const selector of selectorStack[stackIndex]) {
|
|
22922
|
-
let part = (parentSelector && parentSelector + " " + selector) || selector;
|
|
22923
|
-
if (part.includes("&")) {
|
|
22924
|
-
part = selector.replace(/&/g, parentSelector || "");
|
|
22925
|
-
}
|
|
22926
|
-
if (stackIndex < selectorStack.length - 1) {
|
|
22927
|
-
part = generateSelector(stackIndex + 1, part);
|
|
22928
|
-
}
|
|
22929
|
-
parts.push(part);
|
|
22930
|
-
}
|
|
22931
|
-
return parts.join(", ");
|
|
22932
|
-
}
|
|
22933
|
-
function generateRules() {
|
|
22934
|
-
if (rules.length) {
|
|
22935
|
-
parts.push(generateSelector(0) + " {");
|
|
22936
|
-
parts.push(...rules);
|
|
22937
|
-
parts.push("}");
|
|
22938
|
-
rules = [];
|
|
22939
|
-
}
|
|
22940
|
-
}
|
|
22941
|
-
while (tokens.length) {
|
|
22942
|
-
let token = tokens.shift();
|
|
22943
|
-
if (token === "}") {
|
|
22944
|
-
generateRules();
|
|
22945
|
-
selectorStack.pop();
|
|
22946
|
-
}
|
|
22947
|
-
else {
|
|
22948
|
-
if (tokens[0] === "{") {
|
|
22949
|
-
generateRules();
|
|
22950
|
-
selectorStack.push(token.split(/\s*,\s*/));
|
|
22951
|
-
tokens.shift();
|
|
22952
|
-
}
|
|
22953
|
-
if (tokens[0] === ";") {
|
|
22954
|
-
rules.push(" " + token + ";");
|
|
22955
|
-
}
|
|
22956
|
-
}
|
|
22957
|
-
}
|
|
22958
|
-
return parts.join("\n");
|
|
22959
|
-
}
|
|
22960
|
-
function registerSheet(id, css) {
|
|
22961
|
-
const sheet = document.createElement("style");
|
|
22962
|
-
sheet.textContent = processSheet(css);
|
|
22963
|
-
STYLESHEETS[id] = sheet;
|
|
22964
|
-
}
|
|
22965
|
-
function activateSheet(id) {
|
|
22966
|
-
const sheet = STYLESHEETS[id];
|
|
22967
|
-
sheet.setAttribute("component", id);
|
|
22968
|
-
document.head.appendChild(sheet);
|
|
22969
|
-
}
|
|
22970
|
-
function getTextDecoration({ strikethrough, underline, }) {
|
|
22971
|
-
if (!strikethrough && !underline) {
|
|
22972
|
-
return "none";
|
|
22973
|
-
}
|
|
22974
|
-
return `${strikethrough ? "line-through" : ""} ${underline ? "underline" : ""}`;
|
|
22975
|
-
}
|
|
22976
|
-
/**
|
|
22977
|
-
* Convert the cell style to CSS properties.
|
|
22978
|
-
*/
|
|
22979
|
-
function cellStyleToCss(style) {
|
|
22980
|
-
const attributes = cellTextStyleToCss(style);
|
|
22981
|
-
if (!style)
|
|
22982
|
-
return attributes;
|
|
22983
|
-
if (style.fillColor) {
|
|
22984
|
-
attributes["background"] = style.fillColor;
|
|
22985
|
-
}
|
|
22986
|
-
return attributes;
|
|
22987
|
-
}
|
|
22988
|
-
/**
|
|
22989
|
-
* Convert the cell text style to CSS properties.
|
|
22990
|
-
*/
|
|
22991
|
-
function cellTextStyleToCss(style) {
|
|
22992
|
-
const attributes = {};
|
|
22993
|
-
if (!style)
|
|
22994
|
-
return attributes;
|
|
22995
|
-
if (style.bold) {
|
|
22996
|
-
attributes["font-weight"] = "bold";
|
|
22997
|
-
}
|
|
22998
|
-
if (style.italic) {
|
|
22999
|
-
attributes["font-style"] = "italic";
|
|
23000
|
-
}
|
|
23001
|
-
if (style.strikethrough || style.underline) {
|
|
23002
|
-
let decoration = style.strikethrough ? "line-through" : "";
|
|
23003
|
-
decoration = style.underline ? decoration + " underline" : decoration;
|
|
23004
|
-
attributes["text-decoration"] = decoration;
|
|
23005
|
-
}
|
|
23006
|
-
if (style.textColor) {
|
|
23007
|
-
attributes["color"] = style.textColor;
|
|
23008
|
-
}
|
|
23009
|
-
return attributes;
|
|
23010
|
-
}
|
|
23011
|
-
/**
|
|
23012
|
-
* Transform CSS properties into a CSS string.
|
|
23013
|
-
*/
|
|
23014
|
-
function cssPropertiesToCss(attributes) {
|
|
23015
|
-
let styleStr = "";
|
|
23016
|
-
for (const attName in attributes) {
|
|
23017
|
-
if (!attributes[attName]) {
|
|
23018
|
-
continue;
|
|
23019
|
-
}
|
|
23020
|
-
styleStr += `${attName}:${attributes[attName]}; `;
|
|
23021
|
-
}
|
|
23022
|
-
return styleStr;
|
|
23023
|
-
}
|
|
23024
|
-
function getElementMargins(el) {
|
|
23025
|
-
const style = window.getComputedStyle(el);
|
|
23026
|
-
return {
|
|
23027
|
-
top: parseInt(style.marginTop, 10) || 0,
|
|
23028
|
-
bottom: parseInt(style.marginBottom, 10) || 0,
|
|
23029
|
-
left: parseInt(style.marginLeft, 10) || 0,
|
|
23030
|
-
right: parseInt(style.marginRight, 10) || 0,
|
|
23031
|
-
};
|
|
23032
|
-
}
|
|
23033
|
-
|
|
23034
23071
|
css /* scss */ `
|
|
23035
23072
|
.o-spreadsheet {
|
|
23036
23073
|
.o-icon {
|
|
@@ -24142,7 +24179,7 @@ function convertWidthFromExcel(width) {
|
|
|
24142
24179
|
return width;
|
|
24143
24180
|
return Math.round((width / WIDTH_FACTOR) * 100) / 100;
|
|
24144
24181
|
}
|
|
24145
|
-
function extractStyle(data, styleId, formatId, borderId) {
|
|
24182
|
+
function extractStyle(data, content, styleId, formatId, borderId) {
|
|
24146
24183
|
const style = styleId ? data.styles[styleId] : {};
|
|
24147
24184
|
const format = formatId ? data.formats[formatId] : undefined;
|
|
24148
24185
|
const styles = {
|
|
@@ -24164,7 +24201,7 @@ function extractStyle(data, styleId, formatId, borderId) {
|
|
|
24164
24201
|
vertical: style.verticalAlign
|
|
24165
24202
|
? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
|
|
24166
24203
|
: undefined,
|
|
24167
|
-
wrapText: style.wrapping === "wrap" || undefined,
|
|
24204
|
+
wrapText: style.wrapping === "wrap" || content?.includes(NEWLINE) ? true : undefined,
|
|
24168
24205
|
},
|
|
24169
24206
|
};
|
|
24170
24207
|
styles.font["strike"] = !!style?.strikethrough || undefined;
|
|
@@ -24395,7 +24432,7 @@ function convertFigure(figure, id, sheetData) {
|
|
|
24395
24432
|
return undefined;
|
|
24396
24433
|
}
|
|
24397
24434
|
function isChartData(data) {
|
|
24398
|
-
return "dataSets" in data;
|
|
24435
|
+
return "dataSets" in data && data.dataSets.length > 0;
|
|
24399
24436
|
}
|
|
24400
24437
|
function isImageData(data) {
|
|
24401
24438
|
return "imageSrc" in data;
|
|
@@ -24741,9 +24778,8 @@ function convertRows(sheet, numberOfRows, headerGroups) {
|
|
|
24741
24778
|
}
|
|
24742
24779
|
return rows;
|
|
24743
24780
|
}
|
|
24744
|
-
/** Remove newlines (\n) in shared strings, We do not support them */
|
|
24745
24781
|
function convertSharedStrings(xlsxSharedStrings) {
|
|
24746
|
-
return xlsxSharedStrings.map(
|
|
24782
|
+
return xlsxSharedStrings.map(replaceNewLines);
|
|
24747
24783
|
}
|
|
24748
24784
|
function convertCells(sheet, data, sheetDims, warningManager) {
|
|
24749
24785
|
const cells = {};
|
|
@@ -25831,15 +25867,10 @@ class XlsxMiscExtractor extends XlsxBaseExtractor {
|
|
|
25831
25867
|
getSharedStrings() {
|
|
25832
25868
|
return this.mapOnElements({ parent: this.rootFile.file.xml, query: "si" }, (ssElement) => {
|
|
25833
25869
|
// Shared string can either be a simple text, or a rich text (text with formatting, possibly in multiple parts)
|
|
25834
|
-
if (ssElement.children[0].tagName === "t") {
|
|
25835
|
-
return this.extractTextContent(ssElement) || "";
|
|
25836
|
-
}
|
|
25837
25870
|
// We don't support rich text formatting, we'll only extract the text
|
|
25838
|
-
|
|
25839
|
-
return this.
|
|
25840
|
-
|
|
25841
|
-
}).join("");
|
|
25842
|
-
}
|
|
25871
|
+
return this.mapOnElements({ parent: ssElement, query: "t" }, (textElement) => {
|
|
25872
|
+
return this.extractTextContent(textElement) || "";
|
|
25873
|
+
}).join("");
|
|
25843
25874
|
});
|
|
25844
25875
|
}
|
|
25845
25876
|
}
|
|
@@ -27156,12 +27187,9 @@ migrationStepRegistry
|
|
|
27156
27187
|
}
|
|
27157
27188
|
const oldName = sheet.name;
|
|
27158
27189
|
const escapedName = sanitizeSheetName(oldName, "_");
|
|
27159
|
-
|
|
27160
|
-
|
|
27161
|
-
|
|
27162
|
-
newName = `${escapedName}${i}`;
|
|
27163
|
-
i++;
|
|
27164
|
-
}
|
|
27190
|
+
const newName = getUniqueText(escapedName, namesTaken, {
|
|
27191
|
+
compute: (name, i) => `${name}${i}`,
|
|
27192
|
+
});
|
|
27165
27193
|
sheet.name = newName;
|
|
27166
27194
|
namesTaken.push(newName);
|
|
27167
27195
|
const replaceName = (str) => {
|
|
@@ -27480,6 +27508,13 @@ migrationStepRegistry
|
|
|
27480
27508
|
}
|
|
27481
27509
|
return data;
|
|
27482
27510
|
},
|
|
27511
|
+
})
|
|
27512
|
+
.add("migration_24", {
|
|
27513
|
+
// Empty migration to allow odoo migrate pivot custom sorting.
|
|
27514
|
+
versionFrom: "24",
|
|
27515
|
+
migrate(data) {
|
|
27516
|
+
return data;
|
|
27517
|
+
},
|
|
27483
27518
|
});
|
|
27484
27519
|
function fixOverlappingFilters(data) {
|
|
27485
27520
|
for (let sheet of data.sheets || []) {
|
|
@@ -27507,7 +27542,7 @@ function fixOverlappingFilters(data) {
|
|
|
27507
27542
|
* a breaking change is made in the way the state is handled, and an upgrade
|
|
27508
27543
|
* function should be defined
|
|
27509
27544
|
*/
|
|
27510
|
-
const CURRENT_VERSION =
|
|
27545
|
+
const CURRENT_VERSION = 25;
|
|
27511
27546
|
const INITIAL_SHEET_ID = "Sheet1";
|
|
27512
27547
|
/**
|
|
27513
27548
|
* This function tries to load anything that could look like a valid
|
|
@@ -28408,12 +28443,12 @@ function getTrendDatasetForLineChart(config, data, labels, axisType, locale) {
|
|
|
28408
28443
|
}
|
|
28409
28444
|
const numberOfStep = 5 * trendLabels.length;
|
|
28410
28445
|
const step = (xmax - xmin) / numberOfStep;
|
|
28411
|
-
const
|
|
28412
|
-
const
|
|
28413
|
-
if (!
|
|
28446
|
+
const trendNewLabels = range(xmin, xmax + step / 2, step);
|
|
28447
|
+
const trendValues = interpolateData(config, filteredValues, filteredLabels, trendNewLabels);
|
|
28448
|
+
if (!trendValues.length) {
|
|
28414
28449
|
return;
|
|
28415
28450
|
}
|
|
28416
|
-
return
|
|
28451
|
+
return trendValues;
|
|
28417
28452
|
}
|
|
28418
28453
|
function interpolateData(config, values, labels, newLabels) {
|
|
28419
28454
|
if (values.length < 2 || labels.length < 2 || newLabels.length === 0) {
|
|
@@ -28429,13 +28464,16 @@ function interpolateData(config, values, labels, newLabels) {
|
|
|
28429
28464
|
case "polynomial": {
|
|
28430
28465
|
const order = config.order;
|
|
28431
28466
|
if (!order) {
|
|
28432
|
-
return
|
|
28467
|
+
return newLabels.map((x) => ({ x, y: NaN }));
|
|
28433
28468
|
}
|
|
28434
28469
|
if (order === 1) {
|
|
28435
|
-
return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0];
|
|
28470
|
+
return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0].map((y, i) => ({ x: newLabels[i], y }));
|
|
28436
28471
|
}
|
|
28437
28472
|
const coeffs = polynomialRegression(values, normalizedLabels, order, true).flat();
|
|
28438
|
-
return normalizedNewLabels.map((
|
|
28473
|
+
return normalizedNewLabels.map((x, i) => ({
|
|
28474
|
+
x: newLabels[i],
|
|
28475
|
+
y: evaluatePolynomial(coeffs, x, order),
|
|
28476
|
+
}));
|
|
28439
28477
|
}
|
|
28440
28478
|
case "exponential": {
|
|
28441
28479
|
const positiveLogValues = [];
|
|
@@ -28447,22 +28485,22 @@ function interpolateData(config, values, labels, newLabels) {
|
|
|
28447
28485
|
}
|
|
28448
28486
|
}
|
|
28449
28487
|
if (!filteredLabels.length) {
|
|
28450
|
-
return
|
|
28488
|
+
return newLabels.map((x) => ({ x, y: NaN }));
|
|
28451
28489
|
}
|
|
28452
|
-
return expM(predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true))[0];
|
|
28490
|
+
return expM(predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true))[0].map((y, i) => ({ x: newLabels[i], y }));
|
|
28453
28491
|
}
|
|
28454
28492
|
case "logarithmic": {
|
|
28455
|
-
return predictLinearValues([values], logM([normalizedLabels]), logM([normalizedNewLabels]), true)[0];
|
|
28493
|
+
return predictLinearValues([values], logM([normalizedLabels]), logM([normalizedNewLabels]), true)[0].map((y, i) => ({ x: newLabels[i], y }));
|
|
28456
28494
|
}
|
|
28457
28495
|
case "trailingMovingAverage": {
|
|
28458
|
-
return getMovingAverageValues(values, config.window);
|
|
28496
|
+
return getMovingAverageValues(values, labels, config.window);
|
|
28459
28497
|
}
|
|
28460
28498
|
default:
|
|
28461
|
-
return
|
|
28499
|
+
return newLabels.map((x) => ({ x, y: NaN }));
|
|
28462
28500
|
}
|
|
28463
28501
|
}
|
|
28464
28502
|
catch (e) {
|
|
28465
|
-
return
|
|
28503
|
+
return newLabels.map((x) => ({ x, y: NaN }));
|
|
28466
28504
|
}
|
|
28467
28505
|
}
|
|
28468
28506
|
function getChartAxisType(chart, labelRange, getters) {
|
|
@@ -28684,7 +28722,7 @@ function getChartDatasetValues(getters, dataSets) {
|
|
|
28684
28722
|
: undefined;
|
|
28685
28723
|
label =
|
|
28686
28724
|
cell && labelRange
|
|
28687
|
-
?
|
|
28725
|
+
? cell.formattedValue
|
|
28688
28726
|
: (label = `${ChartTerms.Series} ${parseInt(dsIndex) + 1}`);
|
|
28689
28727
|
}
|
|
28690
28728
|
else {
|
|
@@ -28698,7 +28736,7 @@ function getChartDatasetValues(getters, dataSets) {
|
|
|
28698
28736
|
// then using the classical aggregation method to sum the values.
|
|
28699
28737
|
data.fill(1);
|
|
28700
28738
|
}
|
|
28701
|
-
else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(),
|
|
28739
|
+
else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(), DEFAULT_LOCALE))) {
|
|
28702
28740
|
continue;
|
|
28703
28741
|
}
|
|
28704
28742
|
datasetValues.push({ data, label });
|
|
@@ -28774,7 +28812,7 @@ function getWaterfallDatasetAndLabels(definition, args) {
|
|
|
28774
28812
|
}
|
|
28775
28813
|
return {
|
|
28776
28814
|
datasets: [dataset],
|
|
28777
|
-
labels: labelsWithSubTotals
|
|
28815
|
+
labels: labelsWithSubTotals,
|
|
28778
28816
|
};
|
|
28779
28817
|
}
|
|
28780
28818
|
function getLineChartDatasets(definition, args) {
|
|
@@ -29023,7 +29061,7 @@ function getPieChartLegend(definition, args) {
|
|
|
29023
29061
|
generateLabels: (c) =>
|
|
29024
29062
|
//@ts-ignore
|
|
29025
29063
|
c.data.labels.map((label, index) => ({
|
|
29026
|
-
text: label,
|
|
29064
|
+
text: truncateLabel(String(label)),
|
|
29027
29065
|
strokeStyle: colors[index],
|
|
29028
29066
|
fillStyle: colors[index],
|
|
29029
29067
|
pointStyle: "rect",
|
|
@@ -29092,6 +29130,7 @@ function getWaterfallChartLegend(definition, args) {
|
|
|
29092
29130
|
return legendValues;
|
|
29093
29131
|
},
|
|
29094
29132
|
},
|
|
29133
|
+
onClick: () => { }, // Disables click interaction with the waterfall chart legend items
|
|
29095
29134
|
};
|
|
29096
29135
|
}
|
|
29097
29136
|
function getRadarChartLegend(definition, args) {
|
|
@@ -29153,7 +29192,7 @@ function getCustomLegendLabels(fontColor, legendLabelConfig) {
|
|
|
29153
29192
|
generateLabels: (chart) => chart.data.datasets.map((dataset, index) => {
|
|
29154
29193
|
if (dataset["xAxisID"] === TREND_LINE_XAXIS_ID) {
|
|
29155
29194
|
return {
|
|
29156
|
-
text: dataset.label
|
|
29195
|
+
text: truncateLabel(dataset.label),
|
|
29157
29196
|
fontColor,
|
|
29158
29197
|
strokeStyle: dataset.borderColor,
|
|
29159
29198
|
hidden: !chart.isDatasetVisible(index),
|
|
@@ -29163,7 +29202,7 @@ function getCustomLegendLabels(fontColor, legendLabelConfig) {
|
|
|
29163
29202
|
};
|
|
29164
29203
|
}
|
|
29165
29204
|
return {
|
|
29166
|
-
text: dataset.label
|
|
29205
|
+
text: truncateLabel(dataset.label),
|
|
29167
29206
|
fontColor,
|
|
29168
29207
|
strokeStyle: dataset.borderColor,
|
|
29169
29208
|
fillStyle: dataset.backgroundColor,
|
|
@@ -29233,14 +29272,19 @@ function getLineChartScales(definition, args) {
|
|
|
29233
29272
|
/* We add a second x axis here to draw the trend lines, with the labels length being
|
|
29234
29273
|
* set so that the second axis points match the classical x axis
|
|
29235
29274
|
*/
|
|
29236
|
-
const maxLength = Math.max(...trendDatasets.map((trendDataset) => trendDataset?.length || 0));
|
|
29237
29275
|
scales[TREND_LINE_XAXIS_ID] = {
|
|
29238
29276
|
...scales.x,
|
|
29239
|
-
type: "category",
|
|
29240
|
-
labels: range(0, maxLength).map((x) => x.toString()),
|
|
29241
|
-
offset: false,
|
|
29242
29277
|
display: false,
|
|
29243
29278
|
};
|
|
29279
|
+
if (axisType === "category" || axisType === "time") {
|
|
29280
|
+
/* We add a second x axis here to draw the trend lines, with the labels length being
|
|
29281
|
+
* set so that the second axis points match the classical x axis
|
|
29282
|
+
*/
|
|
29283
|
+
const maxLength = Math.max(...trendDatasets.map((trendDataset) => trendDataset?.length || 0));
|
|
29284
|
+
scales[TREND_LINE_XAXIS_ID]["type"] = "category";
|
|
29285
|
+
scales[TREND_LINE_XAXIS_ID]["labels"] = range(0, maxLength).map((x) => x.toString());
|
|
29286
|
+
scales[TREND_LINE_XAXIS_ID]["offset"] = false;
|
|
29287
|
+
}
|
|
29244
29288
|
}
|
|
29245
29289
|
return scales;
|
|
29246
29290
|
}
|
|
@@ -29305,7 +29349,10 @@ function getRadarChartScales(definition, args) {
|
|
|
29305
29349
|
callback: formatTickValue({ format: axisFormats?.r, locale }),
|
|
29306
29350
|
backdropColor: definition.background || "#FFFFFF",
|
|
29307
29351
|
},
|
|
29308
|
-
pointLabels: {
|
|
29352
|
+
pointLabels: {
|
|
29353
|
+
color: chartFontColor(definition.background),
|
|
29354
|
+
callback: truncateLabel,
|
|
29355
|
+
},
|
|
29309
29356
|
suggestedMin: minValue < 0 ? minValue - 1 : 0,
|
|
29310
29357
|
},
|
|
29311
29358
|
};
|
|
@@ -29402,6 +29449,11 @@ function getChartAxis(definition, position, type, options) {
|
|
|
29402
29449
|
ticks: {
|
|
29403
29450
|
padding: 5,
|
|
29404
29451
|
color: fontColor,
|
|
29452
|
+
callback: function (tickValue) {
|
|
29453
|
+
// Category axis callback's internal tick value is the index of the label
|
|
29454
|
+
// https://www.chartjs.org/docs/latest/axes/labelling.html#creating-custom-tick-formats
|
|
29455
|
+
return truncateLabel(this.getLabelForValue(tickValue));
|
|
29456
|
+
},
|
|
29405
29457
|
},
|
|
29406
29458
|
grid: {
|
|
29407
29459
|
display: false,
|
|
@@ -29481,8 +29533,70 @@ function getChartTitle(definition) {
|
|
|
29481
29533
|
};
|
|
29482
29534
|
}
|
|
29483
29535
|
|
|
29536
|
+
/**
|
|
29537
|
+
* Custom tooltip for the charts. Mostly copied from Odoo's custom tooltip, with some slight changes to make it work
|
|
29538
|
+
* with o-spreadsheet chart data and CSS.
|
|
29539
|
+
*
|
|
29540
|
+
* https://github.com/odoo/odoo/blob/18.0/addons/web/static/src/views/graph/graph_renderer.xml
|
|
29541
|
+
*/
|
|
29542
|
+
const templates = /* xml */ `
|
|
29543
|
+
<templates>
|
|
29544
|
+
<t t-name="o-spreadsheet-CustomTooltip">
|
|
29545
|
+
<div
|
|
29546
|
+
class="o-chart-custom-tooltip border rounded px-2 py-1 pe-none mw-100 position-absolute text-nowrap shadow opacity-100">
|
|
29547
|
+
<table class="overflow-hidden m-0">
|
|
29548
|
+
<thead>
|
|
29549
|
+
<tr>
|
|
29550
|
+
<th class="o-tooltip-title align-baseline border-0 text-truncate" t-esc="title" t-attf-style="max-width: {{ labelsMaxWidth }}"/>
|
|
29551
|
+
</tr>
|
|
29552
|
+
</thead>
|
|
29553
|
+
<tbody>
|
|
29554
|
+
<tr t-foreach="tooltipItems" t-as="tooltipItem" t-key="tooltipItem_index">
|
|
29555
|
+
<td>
|
|
29556
|
+
<span
|
|
29557
|
+
class="badge ps-2 py-2 rounded-0 align-middle"
|
|
29558
|
+
t-attf-style="background-color: {{ tooltipItem.boxColor }}"
|
|
29559
|
+
> </span>
|
|
29560
|
+
<small
|
|
29561
|
+
t-if="tooltipItem.label"
|
|
29562
|
+
class="o-tooltip-label d-inline-block text-truncate align-middle smaller ms-2"
|
|
29563
|
+
t-esc="tooltipItem.label"
|
|
29564
|
+
t-attf-style="max-width: {{ labelsMaxWidth }}"
|
|
29565
|
+
/>
|
|
29566
|
+
</td>
|
|
29567
|
+
<td class="o-tooltip-value ps-2 fw-bolder text-end">
|
|
29568
|
+
<small class="smaller d-inline-block text-truncate align-middle" t-attf-style="max-width: {{ valuesMaxWidth }}">
|
|
29569
|
+
<t t-esc="tooltipItem.value"/>
|
|
29570
|
+
<t t-if="tooltipItem.percentage">
|
|
29571
|
+
(
|
|
29572
|
+
<t t-esc="tooltipItem.percentage"/>
|
|
29573
|
+
%)
|
|
29574
|
+
</t>
|
|
29575
|
+
</small>
|
|
29576
|
+
</td>
|
|
29577
|
+
</tr>
|
|
29578
|
+
</tbody>
|
|
29579
|
+
</table>
|
|
29580
|
+
</div>
|
|
29581
|
+
</t>
|
|
29582
|
+
</templates>
|
|
29583
|
+
`;
|
|
29584
|
+
const app = new owl.App(owl.Component, { templates, translateFn: _t });
|
|
29585
|
+
function renderToString(templateName, context = {}) {
|
|
29586
|
+
return render(templateName, context).innerHTML;
|
|
29587
|
+
}
|
|
29588
|
+
function render(templateName, context = {}) {
|
|
29589
|
+
const templateFn = app.getTemplate(templateName);
|
|
29590
|
+
const bdom = templateFn(context, {});
|
|
29591
|
+
const div = document.createElement("div");
|
|
29592
|
+
owl.blockDom.mount(bdom, div);
|
|
29593
|
+
return div;
|
|
29594
|
+
}
|
|
29595
|
+
|
|
29484
29596
|
function getBarChartTooltip(definition, args) {
|
|
29485
29597
|
return {
|
|
29598
|
+
enabled: false,
|
|
29599
|
+
external: customTooltipHandler,
|
|
29486
29600
|
callbacks: {
|
|
29487
29601
|
title: function (tooltipItems) {
|
|
29488
29602
|
return tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID)
|
|
@@ -29506,11 +29620,17 @@ function getBarChartTooltip(definition, args) {
|
|
|
29506
29620
|
function getLineChartTooltip(definition, args) {
|
|
29507
29621
|
const { axisType, locale, axisFormats } = args;
|
|
29508
29622
|
const labelFormat = axisFormats?.x;
|
|
29509
|
-
const tooltip = {
|
|
29623
|
+
const tooltip = {
|
|
29624
|
+
enabled: false,
|
|
29625
|
+
external: customTooltipHandler,
|
|
29626
|
+
callbacks: {},
|
|
29627
|
+
};
|
|
29510
29628
|
if (axisType === "linear") {
|
|
29511
29629
|
tooltip.callbacks.label = (tooltipItem) => {
|
|
29512
29630
|
const dataSetPoint = tooltipItem.parsed.y;
|
|
29513
|
-
let label = tooltipItem.
|
|
29631
|
+
let label = tooltipItem.dataset.xAxisID === TREND_LINE_XAXIS_ID
|
|
29632
|
+
? ""
|
|
29633
|
+
: tooltipItem.parsed.x;
|
|
29514
29634
|
if (typeof label === "string" && isNumber(label, locale)) {
|
|
29515
29635
|
label = toNumber(label, locale);
|
|
29516
29636
|
}
|
|
@@ -29543,6 +29663,8 @@ function getPieChartTooltip(definition, args) {
|
|
|
29543
29663
|
const { locale, axisFormats } = args;
|
|
29544
29664
|
const format = axisFormats?.y || axisFormats?.y1;
|
|
29545
29665
|
return {
|
|
29666
|
+
enabled: false,
|
|
29667
|
+
external: customTooltipHandler,
|
|
29546
29668
|
callbacks: {
|
|
29547
29669
|
title: function (tooltipItems) {
|
|
29548
29670
|
return tooltipItems[0].dataset.label;
|
|
@@ -29567,6 +29689,8 @@ function getWaterfallChartTooltip(definition, args) {
|
|
|
29567
29689
|
const format = axisFormats?.y || axisFormats?.y1;
|
|
29568
29690
|
const dataSeriesLabels = dataSetsValues.map((dataSet) => dataSet.label);
|
|
29569
29691
|
return {
|
|
29692
|
+
enabled: false,
|
|
29693
|
+
external: customTooltipHandler,
|
|
29570
29694
|
callbacks: {
|
|
29571
29695
|
label: function (tooltipItem) {
|
|
29572
29696
|
const [lastValue, currentValue] = tooltipItem.raw;
|
|
@@ -29598,6 +29722,8 @@ function getPyramidChartTooltip(definition, args) {
|
|
|
29598
29722
|
function getRadarChartTooltip(definition, args) {
|
|
29599
29723
|
const { locale, axisFormats } = args;
|
|
29600
29724
|
return {
|
|
29725
|
+
enabled: false,
|
|
29726
|
+
external: customTooltipHandler,
|
|
29601
29727
|
callbacks: {
|
|
29602
29728
|
label: function (tooltipItem) {
|
|
29603
29729
|
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
@@ -29636,6 +29762,48 @@ function calculatePercentage(dataset, dataIndex) {
|
|
|
29636
29762
|
const percentage = (dataset[dataIndex] / total) * 100;
|
|
29637
29763
|
return percentage.toFixed(2);
|
|
29638
29764
|
}
|
|
29765
|
+
function customTooltipHandler({ chart, tooltip }) {
|
|
29766
|
+
chart.canvas.parentNode.querySelector("div.o-chart-custom-tooltip")?.remove();
|
|
29767
|
+
if (tooltip.opacity === 0 || tooltip.dataPoints.length === 0) {
|
|
29768
|
+
return;
|
|
29769
|
+
}
|
|
29770
|
+
const tooltipItems = tooltip.body.map((body, index) => {
|
|
29771
|
+
let [label, value] = body.lines[0].split(":").map((str) => str.trim());
|
|
29772
|
+
if (!value) {
|
|
29773
|
+
value = label;
|
|
29774
|
+
label = "";
|
|
29775
|
+
}
|
|
29776
|
+
const color = tooltip.labelColors[index].backgroundColor;
|
|
29777
|
+
return {
|
|
29778
|
+
label,
|
|
29779
|
+
value,
|
|
29780
|
+
boxColor: typeof color === "string" ? setColorAlpha(color, 1) : color,
|
|
29781
|
+
};
|
|
29782
|
+
});
|
|
29783
|
+
const innerHTML = renderToString("o-spreadsheet-CustomTooltip", {
|
|
29784
|
+
labelsMaxWidth: Math.floor(chart.canvas.clientWidth * 0.5) + "px",
|
|
29785
|
+
valuesMaxWidth: Math.floor(chart.canvas.clientWidth * 0.25) + "px",
|
|
29786
|
+
title: tooltip.title[0],
|
|
29787
|
+
tooltipItems,
|
|
29788
|
+
});
|
|
29789
|
+
const template = Object.assign(document.createElement("template"), { innerHTML });
|
|
29790
|
+
const newTooltipEl = template.content.firstChild;
|
|
29791
|
+
chart.canvas.parentNode?.appendChild(newTooltipEl);
|
|
29792
|
+
Object.assign(newTooltipEl.style, {
|
|
29793
|
+
left: getTooltipLeftPosition(chart, tooltip, newTooltipEl.clientWidth) + "px",
|
|
29794
|
+
top: Math.floor(tooltip.caretY - newTooltipEl.clientHeight / 2) + "px",
|
|
29795
|
+
});
|
|
29796
|
+
}
|
|
29797
|
+
/**
|
|
29798
|
+
* Get the left position for the tooltip, making sure it doesn't go out of the chart area.
|
|
29799
|
+
*/
|
|
29800
|
+
function getTooltipLeftPosition(chart, tooltip, tooltipWidth) {
|
|
29801
|
+
const x = tooltip.caretX;
|
|
29802
|
+
if (x + tooltipWidth > chart.chartArea.right) {
|
|
29803
|
+
return Math.max(0, x - tooltipWidth);
|
|
29804
|
+
}
|
|
29805
|
+
return x;
|
|
29806
|
+
}
|
|
29639
29807
|
|
|
29640
29808
|
var CHART_RUNTIME_HELPERS = /*#__PURE__*/Object.freeze({
|
|
29641
29809
|
__proto__: null,
|
|
@@ -29749,11 +29917,11 @@ class BarChart extends AbstractChart {
|
|
|
29749
29917
|
: undefined,
|
|
29750
29918
|
};
|
|
29751
29919
|
}
|
|
29752
|
-
|
|
29753
|
-
const dataSets =
|
|
29754
|
-
const labelRange =
|
|
29755
|
-
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange,
|
|
29756
|
-
return new BarChart(definition,
|
|
29920
|
+
duplicateInDuplicatedSheet(newSheetId) {
|
|
29921
|
+
const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
|
|
29922
|
+
const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
|
|
29923
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
|
|
29924
|
+
return new BarChart(definition, newSheetId, this.getters);
|
|
29757
29925
|
}
|
|
29758
29926
|
copyInSheetId(sheetId) {
|
|
29759
29927
|
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
@@ -29820,7 +29988,7 @@ function createBarChartRuntime(chart, getters) {
|
|
|
29820
29988
|
const config = {
|
|
29821
29989
|
type: "bar",
|
|
29822
29990
|
data: {
|
|
29823
|
-
labels: chartData.labels
|
|
29991
|
+
labels: chartData.labels,
|
|
29824
29992
|
datasets: getBarChartDatasets(definition, chartData),
|
|
29825
29993
|
},
|
|
29826
29994
|
options: {
|
|
@@ -29956,11 +30124,11 @@ class ComboChart extends AbstractChart {
|
|
|
29956
30124
|
showValues: context.showValues,
|
|
29957
30125
|
};
|
|
29958
30126
|
}
|
|
29959
|
-
|
|
29960
|
-
const dataSets =
|
|
29961
|
-
const labelRange =
|
|
29962
|
-
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange,
|
|
29963
|
-
return new ComboChart(definition,
|
|
30127
|
+
duplicateInDuplicatedSheet(newSheetId) {
|
|
30128
|
+
const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
|
|
30129
|
+
const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
|
|
30130
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
|
|
30131
|
+
return new ComboChart(definition, newSheetId, this.getters);
|
|
29964
30132
|
}
|
|
29965
30133
|
copyInSheetId(sheetId) {
|
|
29966
30134
|
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
@@ -29973,7 +30141,7 @@ function createComboChartRuntime(chart, getters) {
|
|
|
29973
30141
|
const config = {
|
|
29974
30142
|
type: "bar",
|
|
29975
30143
|
data: {
|
|
29976
|
-
labels: chartData.labels
|
|
30144
|
+
labels: chartData.labels,
|
|
29977
30145
|
datasets: getComboChartDatasets(definition, chartData),
|
|
29978
30146
|
},
|
|
29979
30147
|
options: {
|
|
@@ -30107,10 +30275,10 @@ class GaugeChart extends AbstractChart {
|
|
|
30107
30275
|
},
|
|
30108
30276
|
};
|
|
30109
30277
|
}
|
|
30110
|
-
|
|
30111
|
-
const dataRange =
|
|
30112
|
-
const definition = this.getDefinitionWithSpecificRanges(dataRange,
|
|
30113
|
-
return new GaugeChart(definition,
|
|
30278
|
+
duplicateInDuplicatedSheet(newSheetId) {
|
|
30279
|
+
const dataRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.dataRange);
|
|
30280
|
+
const definition = this.getDefinitionWithSpecificRanges(dataRange, newSheetId);
|
|
30281
|
+
return new GaugeChart(definition, newSheetId, this.getters);
|
|
30114
30282
|
}
|
|
30115
30283
|
copyInSheetId(sheetId) {
|
|
30116
30284
|
const definition = this.getDefinitionWithSpecificRanges(this.dataRange, sheetId);
|
|
@@ -30203,7 +30371,11 @@ function createGaugeChartRuntime(chart, getters) {
|
|
|
30203
30371
|
colors.push(chartColors.upperColor);
|
|
30204
30372
|
return {
|
|
30205
30373
|
background: getters.getStyleOfSingleCellChart(chart.background, dataRange).background,
|
|
30206
|
-
title:
|
|
30374
|
+
title: {
|
|
30375
|
+
...chart.title,
|
|
30376
|
+
// chart titles are extracted from .json files and they are translated at runtime here
|
|
30377
|
+
text: _t(chart.title.text ?? ""),
|
|
30378
|
+
},
|
|
30207
30379
|
minValue: {
|
|
30208
30380
|
value: minValue,
|
|
30209
30381
|
label: formatValue(minValue, { locale, format }),
|
|
@@ -30287,11 +30459,11 @@ class GeoChart extends AbstractChart {
|
|
|
30287
30459
|
: undefined,
|
|
30288
30460
|
};
|
|
30289
30461
|
}
|
|
30290
|
-
|
|
30291
|
-
const dataSets =
|
|
30292
|
-
const labelRange =
|
|
30293
|
-
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange,
|
|
30294
|
-
return new GeoChart(definition,
|
|
30462
|
+
duplicateInDuplicatedSheet(newSheetId) {
|
|
30463
|
+
const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
|
|
30464
|
+
const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
|
|
30465
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
|
|
30466
|
+
return new GeoChart(definition, newSheetId, this.getters);
|
|
30295
30467
|
}
|
|
30296
30468
|
copyInSheetId(sheetId) {
|
|
30297
30469
|
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
@@ -30484,11 +30656,11 @@ class LineChart extends AbstractChart {
|
|
|
30484
30656
|
verticalAxis: getDefinedAxis(definition),
|
|
30485
30657
|
};
|
|
30486
30658
|
}
|
|
30487
|
-
|
|
30488
|
-
const dataSets =
|
|
30489
|
-
const labelRange =
|
|
30490
|
-
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange,
|
|
30491
|
-
return new LineChart(definition,
|
|
30659
|
+
duplicateInDuplicatedSheet(newSheetId) {
|
|
30660
|
+
const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
|
|
30661
|
+
const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
|
|
30662
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
|
|
30663
|
+
return new LineChart(definition, newSheetId, this.getters);
|
|
30492
30664
|
}
|
|
30493
30665
|
copyInSheetId(sheetId) {
|
|
30494
30666
|
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
@@ -30501,7 +30673,7 @@ function createLineChartRuntime(chart, getters) {
|
|
|
30501
30673
|
const config = {
|
|
30502
30674
|
type: "line",
|
|
30503
30675
|
data: {
|
|
30504
|
-
labels: chartData.
|
|
30676
|
+
labels: chartData.labels,
|
|
30505
30677
|
datasets: getLineChartDatasets(definition, chartData),
|
|
30506
30678
|
},
|
|
30507
30679
|
options: {
|
|
@@ -30595,11 +30767,11 @@ class PieChart extends AbstractChart {
|
|
|
30595
30767
|
showValues: this.showValues,
|
|
30596
30768
|
};
|
|
30597
30769
|
}
|
|
30598
|
-
|
|
30599
|
-
const dataSets =
|
|
30600
|
-
const labelRange =
|
|
30601
|
-
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange,
|
|
30602
|
-
return new PieChart(definition,
|
|
30770
|
+
duplicateInDuplicatedSheet(newSheetId) {
|
|
30771
|
+
const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
|
|
30772
|
+
const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
|
|
30773
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
|
|
30774
|
+
return new PieChart(definition, newSheetId, this.getters);
|
|
30603
30775
|
}
|
|
30604
30776
|
copyInSheetId(sheetId) {
|
|
30605
30777
|
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
@@ -30636,7 +30808,7 @@ function createPieChartRuntime(chart, getters) {
|
|
|
30636
30808
|
const config = {
|
|
30637
30809
|
type: chart.isDoughnut ? "doughnut" : "pie",
|
|
30638
30810
|
data: {
|
|
30639
|
-
labels: chartData.labels
|
|
30811
|
+
labels: chartData.labels,
|
|
30640
30812
|
datasets: getPieChartDatasets(definition, chartData),
|
|
30641
30813
|
},
|
|
30642
30814
|
options: {
|
|
@@ -30716,11 +30888,11 @@ class PyramidChart extends AbstractChart {
|
|
|
30716
30888
|
: undefined,
|
|
30717
30889
|
};
|
|
30718
30890
|
}
|
|
30719
|
-
|
|
30720
|
-
const dataSets =
|
|
30721
|
-
const labelRange =
|
|
30722
|
-
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange,
|
|
30723
|
-
return new PyramidChart(definition,
|
|
30891
|
+
duplicateInDuplicatedSheet(newSheetId) {
|
|
30892
|
+
const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
|
|
30893
|
+
const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
|
|
30894
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
|
|
30895
|
+
return new PyramidChart(definition, newSheetId, this.getters);
|
|
30724
30896
|
}
|
|
30725
30897
|
copyInSheetId(sheetId) {
|
|
30726
30898
|
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
@@ -30772,7 +30944,7 @@ function createPyramidChartRuntime(chart, getters) {
|
|
|
30772
30944
|
const config = {
|
|
30773
30945
|
type: "bar",
|
|
30774
30946
|
data: {
|
|
30775
|
-
labels: chartData.labels
|
|
30947
|
+
labels: chartData.labels,
|
|
30776
30948
|
datasets: getBarChartDatasets(definition, chartData),
|
|
30777
30949
|
},
|
|
30778
30950
|
options: {
|
|
@@ -30853,11 +31025,11 @@ class RadarChart extends AbstractChart {
|
|
|
30853
31025
|
: undefined,
|
|
30854
31026
|
};
|
|
30855
31027
|
}
|
|
30856
|
-
|
|
30857
|
-
const dataSets =
|
|
30858
|
-
const labelRange =
|
|
30859
|
-
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange,
|
|
30860
|
-
return new RadarChart(definition,
|
|
31028
|
+
duplicateInDuplicatedSheet(newSheetId) {
|
|
31029
|
+
const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
|
|
31030
|
+
const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
|
|
31031
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
|
|
31032
|
+
return new RadarChart(definition, newSheetId, this.getters);
|
|
30861
31033
|
}
|
|
30862
31034
|
copyInSheetId(sheetId) {
|
|
30863
31035
|
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
@@ -30922,7 +31094,7 @@ function createRadarChartRuntime(chart, getters) {
|
|
|
30922
31094
|
const config = {
|
|
30923
31095
|
type: "radar",
|
|
30924
31096
|
data: {
|
|
30925
|
-
labels: chartData.labels
|
|
31097
|
+
labels: chartData.labels,
|
|
30926
31098
|
datasets: getRadarChartDatasets(definition, chartData),
|
|
30927
31099
|
},
|
|
30928
31100
|
options: {
|
|
@@ -31056,11 +31228,11 @@ class ScatterChart extends AbstractChart {
|
|
|
31056
31228
|
verticalAxis: getDefinedAxis(definition),
|
|
31057
31229
|
};
|
|
31058
31230
|
}
|
|
31059
|
-
|
|
31060
|
-
const dataSets =
|
|
31061
|
-
const labelRange =
|
|
31062
|
-
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange,
|
|
31063
|
-
return new ScatterChart(definition,
|
|
31231
|
+
duplicateInDuplicatedSheet(newSheetId) {
|
|
31232
|
+
const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
|
|
31233
|
+
const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
|
|
31234
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
|
|
31235
|
+
return new ScatterChart(definition, newSheetId, this.getters);
|
|
31064
31236
|
}
|
|
31065
31237
|
copyInSheetId(sheetId) {
|
|
31066
31238
|
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
@@ -31075,7 +31247,7 @@ function createScatterChartRuntime(chart, getters) {
|
|
|
31075
31247
|
// have less options than the line chart (it only works with linear labels)
|
|
31076
31248
|
type: "line",
|
|
31077
31249
|
data: {
|
|
31078
|
-
labels: chartData.
|
|
31250
|
+
labels: chartData.labels,
|
|
31079
31251
|
datasets: getScatterChartDatasets(definition, chartData),
|
|
31080
31252
|
},
|
|
31081
31253
|
options: {
|
|
@@ -31173,11 +31345,11 @@ class WaterfallChart extends AbstractChart {
|
|
|
31173
31345
|
: undefined,
|
|
31174
31346
|
};
|
|
31175
31347
|
}
|
|
31176
|
-
|
|
31177
|
-
const dataSets =
|
|
31178
|
-
const labelRange =
|
|
31179
|
-
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange,
|
|
31180
|
-
return new WaterfallChart(definition,
|
|
31348
|
+
duplicateInDuplicatedSheet(newSheetId) {
|
|
31349
|
+
const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
|
|
31350
|
+
const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
|
|
31351
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
|
|
31352
|
+
return new WaterfallChart(definition, newSheetId, this.getters);
|
|
31181
31353
|
}
|
|
31182
31354
|
copyInSheetId(sheetId) {
|
|
31183
31355
|
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
@@ -33604,8 +33776,6 @@ var CHART_HELPERS = /*#__PURE__*/Object.freeze({
|
|
|
33604
33776
|
chartToImage: chartToImage,
|
|
33605
33777
|
checkDataset: checkDataset,
|
|
33606
33778
|
checkLabelRange: checkLabelRange,
|
|
33607
|
-
copyDataSetsWithNewSheetId: copyDataSetsWithNewSheetId,
|
|
33608
|
-
copyLabelRangeWithNewSheetId: copyLabelRangeWithNewSheetId,
|
|
33609
33779
|
createBarChartRuntime: createBarChartRuntime,
|
|
33610
33780
|
createDataSets: createDataSets,
|
|
33611
33781
|
createGaugeChartRuntime: createGaugeChartRuntime,
|
|
@@ -33614,6 +33784,8 @@ var CHART_HELPERS = /*#__PURE__*/Object.freeze({
|
|
|
33614
33784
|
createScorecardChartRuntime: createScorecardChartRuntime,
|
|
33615
33785
|
createWaterfallChartRuntime: createWaterfallChartRuntime,
|
|
33616
33786
|
drawScoreChart: drawScoreChart,
|
|
33787
|
+
duplicateDataSetsInDuplicatedSheet: duplicateDataSetsInDuplicatedSheet,
|
|
33788
|
+
duplicateLabelRangeInDuplicatedSheet: duplicateLabelRangeInDuplicatedSheet,
|
|
33617
33789
|
formatChartDatasetValue: formatChartDatasetValue,
|
|
33618
33790
|
formatTickValue: formatTickValue,
|
|
33619
33791
|
getChartPositionAtCenterOfViewport: getChartPositionAtCenterOfViewport,
|
|
@@ -35334,12 +35506,20 @@ function fontSizeMenuBuilder() {
|
|
|
35334
35506
|
});
|
|
35335
35507
|
}
|
|
35336
35508
|
function isAutomaticFormatSelected(env) {
|
|
35337
|
-
const
|
|
35338
|
-
|
|
35509
|
+
const activePosition = env.model.getters.getActivePosition();
|
|
35510
|
+
const pivotCell = env.model.getters.getPivotCellFromPosition(activePosition);
|
|
35511
|
+
if (pivotCell.type === "VALUE") {
|
|
35512
|
+
return !env.model.getters.getEvaluatedCell(activePosition).format;
|
|
35513
|
+
}
|
|
35514
|
+
return !env.model.getters.getCell(activePosition)?.format;
|
|
35339
35515
|
}
|
|
35340
35516
|
function isFormatSelected(env, format) {
|
|
35341
|
-
const
|
|
35342
|
-
|
|
35517
|
+
const activePosition = env.model.getters.getActivePosition();
|
|
35518
|
+
const pivotCell = env.model.getters.getPivotCellFromPosition(activePosition);
|
|
35519
|
+
if (pivotCell.type === "VALUE") {
|
|
35520
|
+
return env.model.getters.getEvaluatedCell(activePosition).format === format;
|
|
35521
|
+
}
|
|
35522
|
+
return env.model.getters.getCell(activePosition)?.format === format;
|
|
35343
35523
|
}
|
|
35344
35524
|
function isFontSizeSelected(env, fontSize) {
|
|
35345
35525
|
const currentFontSize = env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
|
|
@@ -39678,14 +39858,11 @@ class ChartPanel extends owl.Component {
|
|
|
39678
39858
|
}
|
|
39679
39859
|
|
|
39680
39860
|
class DOMFocusableElementStore {
|
|
39681
|
-
mutators = ["setFocusableElement"
|
|
39861
|
+
mutators = ["setFocusableElement"];
|
|
39682
39862
|
focusableElement = undefined;
|
|
39683
39863
|
setFocusableElement(element) {
|
|
39684
39864
|
this.focusableElement = element;
|
|
39685
39865
|
}
|
|
39686
|
-
focus() {
|
|
39687
|
-
this.focusableElement?.focus();
|
|
39688
|
-
}
|
|
39689
39866
|
}
|
|
39690
39867
|
|
|
39691
39868
|
css /* scss */ `
|
|
@@ -40333,7 +40510,7 @@ class Composer extends owl.Component {
|
|
|
40333
40510
|
if (document.activeElement === this.contentHelper.el &&
|
|
40334
40511
|
this.props.composerStore.editionMode === "inactive" &&
|
|
40335
40512
|
!this.props.isDefaultFocus) {
|
|
40336
|
-
this.DOMFocusableElementStore.focus();
|
|
40513
|
+
this.DOMFocusableElementStore.focusableElement?.focus();
|
|
40337
40514
|
}
|
|
40338
40515
|
});
|
|
40339
40516
|
owl.useEffect(() => {
|
|
@@ -44314,16 +44491,21 @@ class TextInput extends owl.Component {
|
|
|
44314
44491
|
}
|
|
44315
44492
|
this.inputRef.el?.blur();
|
|
44316
44493
|
}
|
|
44317
|
-
|
|
44318
|
-
|
|
44319
|
-
if (
|
|
44320
|
-
|
|
44321
|
-
|
|
44322
|
-
|
|
44323
|
-
|
|
44324
|
-
|
|
44325
|
-
|
|
44326
|
-
|
|
44494
|
+
onMouseDown(ev) {
|
|
44495
|
+
// Stop the event if the input is not focused, we handle everything in onMouseUp
|
|
44496
|
+
if (ev.target !== document.activeElement) {
|
|
44497
|
+
ev.preventDefault();
|
|
44498
|
+
ev.stopPropagation();
|
|
44499
|
+
}
|
|
44500
|
+
}
|
|
44501
|
+
onMouseUp(ev) {
|
|
44502
|
+
const target = ev.target;
|
|
44503
|
+
if (target !== document.activeElement) {
|
|
44504
|
+
target.focus();
|
|
44505
|
+
target.select();
|
|
44506
|
+
ev.preventDefault();
|
|
44507
|
+
ev.stopPropagation();
|
|
44508
|
+
}
|
|
44327
44509
|
}
|
|
44328
44510
|
}
|
|
44329
44511
|
|
|
@@ -44876,7 +45058,16 @@ class PivotTitleSection extends owl.Component {
|
|
|
44876
45058
|
newPivotId,
|
|
44877
45059
|
newSheetId,
|
|
44878
45060
|
});
|
|
44879
|
-
|
|
45061
|
+
let text;
|
|
45062
|
+
if (result.isSuccessful) {
|
|
45063
|
+
text = _t("Pivot duplicated.");
|
|
45064
|
+
}
|
|
45065
|
+
else if (result.isCancelledBecause("PivotInError" /* CommandResult.PivotInError */)) {
|
|
45066
|
+
text = _t("Cannot duplicate a pivot in error.");
|
|
45067
|
+
}
|
|
45068
|
+
else {
|
|
45069
|
+
text = _t("Pivot duplication failed.");
|
|
45070
|
+
}
|
|
44880
45071
|
const type = result.isSuccessful ? "success" : "danger";
|
|
44881
45072
|
this.env.notifyUser({
|
|
44882
45073
|
text,
|
|
@@ -46027,12 +46218,10 @@ class SpreadsheetPivot {
|
|
|
46027
46218
|
* Take cares of double names
|
|
46028
46219
|
*/
|
|
46029
46220
|
findName(name, fields) {
|
|
46030
|
-
|
|
46031
|
-
|
|
46032
|
-
|
|
46033
|
-
|
|
46034
|
-
}
|
|
46035
|
-
return name;
|
|
46221
|
+
return getUniqueText(name, Object.keys(fields), {
|
|
46222
|
+
compute: (name, i) => `${name}${i}`,
|
|
46223
|
+
start: 2,
|
|
46224
|
+
});
|
|
46036
46225
|
}
|
|
46037
46226
|
extractDataEntriesFromRange(range) {
|
|
46038
46227
|
const dataEntries = [];
|
|
@@ -46215,7 +46404,9 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
46215
46404
|
pivot: this.draft,
|
|
46216
46405
|
});
|
|
46217
46406
|
this.draft = null;
|
|
46218
|
-
if (!this.alreadyNotified &&
|
|
46407
|
+
if (!this.alreadyNotified &&
|
|
46408
|
+
!this.isDynamicPivotInViewport() &&
|
|
46409
|
+
this.isStaticPivotInViewport()) {
|
|
46219
46410
|
const formulaId = this.getters.getPivotFormulaId(this.pivotId);
|
|
46220
46411
|
const pivotExample = `=PIVOT(${formulaId})`;
|
|
46221
46412
|
this.alreadyNotified = true;
|
|
@@ -46272,11 +46463,20 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
46272
46463
|
}
|
|
46273
46464
|
}
|
|
46274
46465
|
isDynamicPivotInViewport() {
|
|
46275
|
-
const
|
|
46276
|
-
|
|
46277
|
-
|
|
46278
|
-
|
|
46279
|
-
|
|
46466
|
+
for (const position of this.getters.getVisibleCellPositions()) {
|
|
46467
|
+
const isDynamicPivot = this.getters.isSpillPivotFormula(position);
|
|
46468
|
+
if (isDynamicPivot) {
|
|
46469
|
+
return true;
|
|
46470
|
+
}
|
|
46471
|
+
}
|
|
46472
|
+
return false;
|
|
46473
|
+
}
|
|
46474
|
+
isStaticPivotInViewport() {
|
|
46475
|
+
for (const position of this.getters.getVisibleCellPositions()) {
|
|
46476
|
+
const cell = this.getters.getCell(position);
|
|
46477
|
+
if (cell?.isFormula) {
|
|
46478
|
+
const pivotFunction = getFirstPivotFunction(cell.compiledFormula.tokens);
|
|
46479
|
+
if (pivotFunction && pivotFunction.functionName !== "PIVOT") {
|
|
46280
46480
|
return true;
|
|
46281
46481
|
}
|
|
46282
46482
|
}
|
|
@@ -51695,7 +51895,7 @@ class Grid extends owl.Component {
|
|
|
51695
51895
|
this.cellPopovers = useStore(CellPopoverStore);
|
|
51696
51896
|
owl.useEffect(() => {
|
|
51697
51897
|
if (!this.sidePanel.isOpen) {
|
|
51698
|
-
this.DOMFocusableElementStore.focus();
|
|
51898
|
+
this.DOMFocusableElementStore.focusableElement?.focus();
|
|
51699
51899
|
}
|
|
51700
51900
|
}, () => [this.sidePanel.isOpen]);
|
|
51701
51901
|
}
|
|
@@ -51901,7 +52101,7 @@ class Grid extends owl.Component {
|
|
|
51901
52101
|
focusDefaultElement() {
|
|
51902
52102
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
51903
52103
|
this.composerFocusStore.activeComposer.editionMode === "inactive") {
|
|
51904
|
-
this.DOMFocusableElementStore.focus();
|
|
52104
|
+
this.DOMFocusableElementStore.focusableElement?.focus();
|
|
51905
52105
|
}
|
|
51906
52106
|
}
|
|
51907
52107
|
get gridEl() {
|
|
@@ -52260,15 +52460,11 @@ class Grid extends owl.Component {
|
|
|
52260
52460
|
class BasePlugin {
|
|
52261
52461
|
static getters = [];
|
|
52262
52462
|
history;
|
|
52263
|
-
|
|
52264
|
-
canDispatch;
|
|
52265
|
-
constructor(stateObserver, dispatch, canDispatch) {
|
|
52463
|
+
constructor(stateObserver) {
|
|
52266
52464
|
this.history = Object.assign(Object.create(stateObserver), {
|
|
52267
52465
|
update: stateObserver.addChange.bind(stateObserver, this),
|
|
52268
52466
|
selectCell: () => { },
|
|
52269
52467
|
});
|
|
52270
|
-
this.dispatch = dispatch;
|
|
52271
|
-
this.canDispatch = canDispatch;
|
|
52272
52468
|
}
|
|
52273
52469
|
/**
|
|
52274
52470
|
* Export for excel should be available for all plugins, even for the UI.
|
|
@@ -52346,10 +52542,14 @@ class BasePlugin {
|
|
|
52346
52542
|
*/
|
|
52347
52543
|
class CorePlugin extends BasePlugin {
|
|
52348
52544
|
getters;
|
|
52545
|
+
dispatch;
|
|
52546
|
+
canDispatch;
|
|
52349
52547
|
constructor({ getters, stateObserver, range, dispatch, canDispatch }) {
|
|
52350
|
-
super(stateObserver
|
|
52548
|
+
super(stateObserver);
|
|
52351
52549
|
range.addRangeProvider(this.adaptRanges.bind(this));
|
|
52352
52550
|
this.getters = getters;
|
|
52551
|
+
this.dispatch = dispatch;
|
|
52552
|
+
this.canDispatch = canDispatch;
|
|
52353
52553
|
}
|
|
52354
52554
|
// ---------------------------------------------------------------------------
|
|
52355
52555
|
// Import/Export
|
|
@@ -52438,10 +52638,34 @@ class BordersPlugin extends CorePlugin {
|
|
|
52438
52638
|
const elements = [...cmd.elements].sort((a, b) => b - a);
|
|
52439
52639
|
for (const group of groupConsecutive(elements)) {
|
|
52440
52640
|
if (cmd.dimension === "COL") {
|
|
52441
|
-
|
|
52641
|
+
if (group[0] >= this.getters.getNumberCols(cmd.sheetId)) {
|
|
52642
|
+
for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
|
|
52643
|
+
this.history.update("borders", cmd.sheetId, group[0] + 1, row, "vertical", undefined);
|
|
52644
|
+
}
|
|
52645
|
+
}
|
|
52646
|
+
if (group[group.length - 1] === 0) {
|
|
52647
|
+
for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
|
|
52648
|
+
this.history.update("borders", cmd.sheetId, 0, row, "vertical", undefined);
|
|
52649
|
+
}
|
|
52650
|
+
}
|
|
52651
|
+
const zone = this.getters.getColsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
|
|
52652
|
+
this.clearInsideBorders(cmd.sheetId, [zone]);
|
|
52653
|
+
this.shiftBordersHorizontally(cmd.sheetId, group[0] + 1, -group.length);
|
|
52442
52654
|
}
|
|
52443
52655
|
else {
|
|
52444
|
-
|
|
52656
|
+
if (group[0] >= this.getters.getNumberRows(cmd.sheetId)) {
|
|
52657
|
+
for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
|
|
52658
|
+
this.history.update("borders", cmd.sheetId, col, group[0] + 1, "horizontal", undefined);
|
|
52659
|
+
}
|
|
52660
|
+
}
|
|
52661
|
+
if (group[group.length - 1] === 0) {
|
|
52662
|
+
for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
|
|
52663
|
+
this.history.update("borders", cmd.sheetId, col, 0, "horizontal", undefined);
|
|
52664
|
+
}
|
|
52665
|
+
}
|
|
52666
|
+
const zone = this.getters.getRowsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
|
|
52667
|
+
this.clearInsideBorders(cmd.sheetId, [zone]);
|
|
52668
|
+
this.shiftBordersVertically(cmd.sheetId, group[0] + 1, -group.length);
|
|
52445
52669
|
}
|
|
52446
52670
|
}
|
|
52447
52671
|
break;
|
|
@@ -52748,6 +52972,18 @@ class BordersPlugin extends CorePlugin {
|
|
|
52748
52972
|
}
|
|
52749
52973
|
}
|
|
52750
52974
|
}
|
|
52975
|
+
/**
|
|
52976
|
+
* Remove the borders inside of a zone
|
|
52977
|
+
*/
|
|
52978
|
+
clearInsideBorders(sheetId, zones) {
|
|
52979
|
+
for (let zone of zones) {
|
|
52980
|
+
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
52981
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
52982
|
+
this.history.update("borders", sheetId, col, row, undefined);
|
|
52983
|
+
}
|
|
52984
|
+
}
|
|
52985
|
+
}
|
|
52986
|
+
}
|
|
52751
52987
|
/**
|
|
52752
52988
|
* Add a border to the existing one to a cell
|
|
52753
52989
|
*/
|
|
@@ -53550,7 +53786,7 @@ class ChartPlugin extends CorePlugin {
|
|
|
53550
53786
|
if (fig.tag === "chart") {
|
|
53551
53787
|
const figureIdBase = fig.id.split(FIGURE_ID_SPLITTER).pop();
|
|
53552
53788
|
const duplicatedFigureId = `${cmd.sheetIdTo}${FIGURE_ID_SPLITTER}${figureIdBase}`;
|
|
53553
|
-
const chart = this.charts[fig.id]?.
|
|
53789
|
+
const chart = this.charts[fig.id]?.duplicateInDuplicatedSheet(cmd.sheetIdTo);
|
|
53554
53790
|
if (chart) {
|
|
53555
53791
|
this.dispatch("CREATE_CHART", {
|
|
53556
53792
|
id: duplicatedFigureId,
|
|
@@ -54194,7 +54430,7 @@ class DataValidationPlugin extends CorePlugin {
|
|
|
54194
54430
|
case "DUPLICATE_SHEET": {
|
|
54195
54431
|
const rules = deepCopy(this.rules[cmd.sheetId]).map((rule) => ({
|
|
54196
54432
|
...rule,
|
|
54197
|
-
ranges: rule.ranges.map((range) =>
|
|
54433
|
+
ranges: rule.ranges.map((range) => duplicateRangeInDuplicatedSheet(cmd.sheetId, cmd.sheetIdTo, range)),
|
|
54198
54434
|
}));
|
|
54199
54435
|
this.history.update("rules", cmd.sheetIdTo, rules);
|
|
54200
54436
|
break;
|
|
@@ -56243,14 +56479,11 @@ class SheetPlugin extends CorePlugin {
|
|
|
56243
56479
|
return dimension === "COL" ? this.getNumberCols(sheetId) : this.getNumberRows(sheetId);
|
|
56244
56480
|
}
|
|
56245
56481
|
getNextSheetName(baseName = "Sheet") {
|
|
56246
|
-
let i = 1;
|
|
56247
56482
|
const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
|
|
56248
|
-
|
|
56249
|
-
|
|
56250
|
-
|
|
56251
|
-
|
|
56252
|
-
}
|
|
56253
|
-
return name;
|
|
56483
|
+
return getUniqueText(baseName, names, {
|
|
56484
|
+
compute: (name, i) => `${name}${i}`,
|
|
56485
|
+
computeFirstOne: true,
|
|
56486
|
+
});
|
|
56254
56487
|
}
|
|
56255
56488
|
getSheetSize(sheetId) {
|
|
56256
56489
|
return {
|
|
@@ -56530,15 +56763,9 @@ class SheetPlugin extends CorePlugin {
|
|
|
56530
56763
|
this.history.update("sheetIdsMapName", sheetIdsMapName);
|
|
56531
56764
|
}
|
|
56532
56765
|
getDuplicateSheetName(sheetName) {
|
|
56533
|
-
let i = 1;
|
|
56534
56766
|
const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
|
|
56535
56767
|
const baseName = _t("Copy of %s", sheetName);
|
|
56536
|
-
|
|
56537
|
-
while (names.includes(name)) {
|
|
56538
|
-
name = `${baseName} (${i})`;
|
|
56539
|
-
i++;
|
|
56540
|
-
}
|
|
56541
|
-
return name;
|
|
56768
|
+
return getUniqueText(baseName.toString(), names);
|
|
56542
56769
|
}
|
|
56543
56770
|
deleteSheet(sheet) {
|
|
56544
56771
|
const name = sheet.name;
|
|
@@ -58068,15 +58295,8 @@ class TableStylePlugin extends CorePlugin {
|
|
|
58068
58295
|
}
|
|
58069
58296
|
getNewCustomTableStyleName() {
|
|
58070
58297
|
let name = _t("Custom Table Style");
|
|
58071
|
-
const styleNames =
|
|
58072
|
-
|
|
58073
|
-
return name;
|
|
58074
|
-
}
|
|
58075
|
-
let i = 2;
|
|
58076
|
-
while (styleNames.has(`${name} ${i}`)) {
|
|
58077
|
-
i++;
|
|
58078
|
-
}
|
|
58079
|
-
return `${name} ${i}`;
|
|
58298
|
+
const styleNames = Object.values(this.styles).map((style) => style.displayName);
|
|
58299
|
+
return getUniqueText(name, styleNames, { compute: (name, i) => `${name} ${i}`, start: 2 });
|
|
58080
58300
|
}
|
|
58081
58301
|
isTableStyleEditable(styleId) {
|
|
58082
58302
|
return !TABLE_PRESETS[styleId];
|
|
@@ -58106,24 +58326,15 @@ class TableStylePlugin extends CorePlugin {
|
|
|
58106
58326
|
}
|
|
58107
58327
|
|
|
58108
58328
|
/**
|
|
58109
|
-
*
|
|
58110
|
-
* They
|
|
58329
|
+
* Core view plugins handle any data derived from core date (i.e. evaluation).
|
|
58330
|
+
* They cannot impact the model data (i.e. cannot dispatch commands).
|
|
58111
58331
|
*/
|
|
58112
|
-
class
|
|
58113
|
-
static layers = [];
|
|
58332
|
+
class CoreViewPlugin extends BasePlugin {
|
|
58114
58333
|
getters;
|
|
58115
|
-
|
|
58116
|
-
|
|
58117
|
-
constructor({ getters, stateObserver, dispatch, canDispatch, uiActions, selection, }) {
|
|
58118
|
-
super(stateObserver, dispatch, canDispatch);
|
|
58334
|
+
constructor({ getters, stateObserver }) {
|
|
58335
|
+
super(stateObserver);
|
|
58119
58336
|
this.getters = getters;
|
|
58120
|
-
this.ui = uiActions;
|
|
58121
|
-
this.selection = selection;
|
|
58122
58337
|
}
|
|
58123
|
-
// ---------------------------------------------------------------------------
|
|
58124
|
-
// Grid rendering
|
|
58125
|
-
// ---------------------------------------------------------------------------
|
|
58126
|
-
drawLayer(ctx, layer) { }
|
|
58127
58338
|
}
|
|
58128
58339
|
|
|
58129
58340
|
/**
|
|
@@ -59818,7 +60029,7 @@ function updateEvalContextAndExecute(compiledFormula, compilationParams, sheetId
|
|
|
59818
60029
|
// as necessary in several iterations, where evaluated cells can trigger the evaluation
|
|
59819
60030
|
// of other cells depending on it, at the next iteration.
|
|
59820
60031
|
//#endregion
|
|
59821
|
-
class EvaluationPlugin extends
|
|
60032
|
+
class EvaluationPlugin extends CoreViewPlugin {
|
|
59822
60033
|
static getters = [
|
|
59823
60034
|
"evaluateFormula",
|
|
59824
60035
|
"evaluateFormulaResult",
|
|
@@ -60085,7 +60296,7 @@ function colorDistance(color1, color2) {
|
|
|
60085
60296
|
* This plugins aims to compute and keep to custom colors used in the
|
|
60086
60297
|
* current spreadsheet
|
|
60087
60298
|
*/
|
|
60088
|
-
class CustomColorsPlugin extends
|
|
60299
|
+
class CustomColorsPlugin extends CoreViewPlugin {
|
|
60089
60300
|
customColors = {};
|
|
60090
60301
|
shouldUpdateColors = true;
|
|
60091
60302
|
static getters = ["getCustomColors"];
|
|
@@ -60221,7 +60432,7 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
60221
60432
|
}
|
|
60222
60433
|
}
|
|
60223
60434
|
|
|
60224
|
-
class EvaluationChartPlugin extends
|
|
60435
|
+
class EvaluationChartPlugin extends CoreViewPlugin {
|
|
60225
60436
|
static getters = ["getChartRuntime", "getStyleOfSingleCellChart"];
|
|
60226
60437
|
charts = {};
|
|
60227
60438
|
createRuntimeChart = chartRuntimeFactory(this.getters);
|
|
@@ -60325,7 +60536,7 @@ class EvaluationChartPlugin extends UIPlugin {
|
|
|
60325
60536
|
}
|
|
60326
60537
|
}
|
|
60327
60538
|
|
|
60328
|
-
class EvaluationConditionalFormatPlugin extends
|
|
60539
|
+
class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
|
|
60329
60540
|
static getters = [
|
|
60330
60541
|
"getConditionalIcon",
|
|
60331
60542
|
"getCellConditionalFormatStyle",
|
|
@@ -60643,7 +60854,7 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
60643
60854
|
}
|
|
60644
60855
|
|
|
60645
60856
|
const VALID_RESULT = { isValid: true };
|
|
60646
|
-
class EvaluationDataValidationPlugin extends
|
|
60857
|
+
class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
60647
60858
|
static getters = [
|
|
60648
60859
|
"getDataValidationInvalidCriterionValueMessage",
|
|
60649
60860
|
"getInvalidDataValidationMessage",
|
|
@@ -60774,7 +60985,7 @@ class EvaluationDataValidationPlugin extends UIPlugin {
|
|
|
60774
60985
|
}
|
|
60775
60986
|
}
|
|
60776
60987
|
|
|
60777
|
-
class DynamicTablesPlugin extends
|
|
60988
|
+
class DynamicTablesPlugin extends CoreViewPlugin {
|
|
60778
60989
|
static getters = [
|
|
60779
60990
|
"canCreateDynamicTableOnZones",
|
|
60780
60991
|
"doesZonesContainFilter",
|
|
@@ -60948,7 +61159,7 @@ class DynamicTablesPlugin extends UIPlugin {
|
|
|
60948
61159
|
}
|
|
60949
61160
|
}
|
|
60950
61161
|
|
|
60951
|
-
class HeaderSizeUIPlugin extends
|
|
61162
|
+
class HeaderSizeUIPlugin extends CoreViewPlugin {
|
|
60952
61163
|
static getters = ["getRowSize", "getHeaderSize"];
|
|
60953
61164
|
tallestCellInRow = {};
|
|
60954
61165
|
ctx = document.createElement("canvas").getContext("2d");
|
|
@@ -61654,7 +61865,7 @@ const UNDO_REDO_PIVOT_COMMANDS = ["ADD_PIVOT", "UPDATE_PIVOT"];
|
|
|
61654
61865
|
function isPivotCommand(cmd) {
|
|
61655
61866
|
return UNDO_REDO_PIVOT_COMMANDS.includes(cmd.type);
|
|
61656
61867
|
}
|
|
61657
|
-
class PivotUIPlugin extends
|
|
61868
|
+
class PivotUIPlugin extends CoreViewPlugin {
|
|
61658
61869
|
static getters = [
|
|
61659
61870
|
"getPivot",
|
|
61660
61871
|
"getFirstPivotFunction",
|
|
@@ -61858,13 +62069,9 @@ class PivotUIPlugin extends UIPlugin {
|
|
|
61858
62069
|
}
|
|
61859
62070
|
generateNewCalculatedMeasureName(measures) {
|
|
61860
62071
|
const existingMeasures = measures.map((m) => m.fieldName);
|
|
61861
|
-
|
|
61862
|
-
|
|
61863
|
-
|
|
61864
|
-
i++;
|
|
61865
|
-
name = _t("Calculated measure %s", i);
|
|
61866
|
-
}
|
|
61867
|
-
return name;
|
|
62072
|
+
return getUniqueText(_t("Calculated measure 1"), existingMeasures, {
|
|
62073
|
+
compute: (name, i) => _t("Calculated measure %s", i),
|
|
62074
|
+
});
|
|
61868
62075
|
}
|
|
61869
62076
|
getPivot(pivotId) {
|
|
61870
62077
|
if (!this.getters.isExistingPivot(pivotId)) {
|
|
@@ -61918,6 +62125,31 @@ class PivotUIPlugin extends UIPlugin {
|
|
|
61918
62125
|
}
|
|
61919
62126
|
}
|
|
61920
62127
|
|
|
62128
|
+
/**
|
|
62129
|
+
* UI plugins handle any transient data required to display a spreadsheet.
|
|
62130
|
+
* They can draw on the grid canvas.
|
|
62131
|
+
*/
|
|
62132
|
+
class UIPlugin extends BasePlugin {
|
|
62133
|
+
static layers = [];
|
|
62134
|
+
getters;
|
|
62135
|
+
ui;
|
|
62136
|
+
selection;
|
|
62137
|
+
dispatch;
|
|
62138
|
+
canDispatch;
|
|
62139
|
+
constructor({ getters, stateObserver, dispatch, canDispatch, uiActions, selection, }) {
|
|
62140
|
+
super(stateObserver);
|
|
62141
|
+
this.getters = getters;
|
|
62142
|
+
this.ui = uiActions;
|
|
62143
|
+
this.selection = selection;
|
|
62144
|
+
this.dispatch = dispatch;
|
|
62145
|
+
this.canDispatch = canDispatch;
|
|
62146
|
+
}
|
|
62147
|
+
// ---------------------------------------------------------------------------
|
|
62148
|
+
// Grid rendering
|
|
62149
|
+
// ---------------------------------------------------------------------------
|
|
62150
|
+
drawLayer(ctx, layer) { }
|
|
62151
|
+
}
|
|
62152
|
+
|
|
61921
62153
|
/**
|
|
61922
62154
|
* This plugin manage the autofill.
|
|
61923
62155
|
*
|
|
@@ -63294,6 +63526,9 @@ class Session extends EventBus {
|
|
|
63294
63526
|
}
|
|
63295
63527
|
}
|
|
63296
63528
|
this.acknowledge(message);
|
|
63529
|
+
if (message.type === "REMOTE_REVISION" && message.clientId === this.clientId) {
|
|
63530
|
+
return;
|
|
63531
|
+
}
|
|
63297
63532
|
this.trigger("collaborative-event-received");
|
|
63298
63533
|
}
|
|
63299
63534
|
onClientMoved(message) {
|
|
@@ -63944,6 +64179,19 @@ class HeaderVisibilityUIPlugin extends UIPlugin {
|
|
|
63944
64179
|
|
|
63945
64180
|
class InsertPivotPlugin extends UIPlugin {
|
|
63946
64181
|
static getters = [];
|
|
64182
|
+
allowDispatch(cmd) {
|
|
64183
|
+
switch (cmd.type) {
|
|
64184
|
+
case "DUPLICATE_PIVOT_IN_NEW_SHEET":
|
|
64185
|
+
if (!this.getters.isExistingPivot(cmd.pivotId)) {
|
|
64186
|
+
return "PivotIdNotFound" /* CommandResult.PivotIdNotFound */;
|
|
64187
|
+
}
|
|
64188
|
+
if (!this.getters.getPivot(cmd.pivotId).isValid()) {
|
|
64189
|
+
return "PivotInError" /* CommandResult.PivotInError */;
|
|
64190
|
+
}
|
|
64191
|
+
break;
|
|
64192
|
+
}
|
|
64193
|
+
return "Success" /* CommandResult.Success */;
|
|
64194
|
+
}
|
|
63947
64195
|
handle(cmd) {
|
|
63948
64196
|
switch (cmd.type) {
|
|
63949
64197
|
case "INSERT_NEW_PIVOT":
|
|
@@ -64017,15 +64265,9 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
64017
64265
|
}
|
|
64018
64266
|
}
|
|
64019
64267
|
getPivotDuplicateSheetName(pivotName) {
|
|
64020
|
-
let i = 1;
|
|
64021
64268
|
const names = this.getters.getSheetIds().map((id) => this.getters.getSheetName(id));
|
|
64022
64269
|
const sanitizedName = sanitizeSheetName(pivotName);
|
|
64023
|
-
|
|
64024
|
-
while (names.includes(name)) {
|
|
64025
|
-
name = `${sanitizedName} (${i})`;
|
|
64026
|
-
i++;
|
|
64027
|
-
}
|
|
64028
|
-
return name;
|
|
64270
|
+
return getUniqueText(sanitizedName, names);
|
|
64029
64271
|
}
|
|
64030
64272
|
insertPivotWithTable(sheetId, col, row, pivotId, table, mode) {
|
|
64031
64273
|
const { cols, rows, measures, fieldsType } = table;
|
|
@@ -66132,13 +66374,10 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
66132
66374
|
if (!colName) {
|
|
66133
66375
|
colName = `Column${colIndex}`;
|
|
66134
66376
|
}
|
|
66135
|
-
|
|
66136
|
-
|
|
66137
|
-
|
|
66138
|
-
|
|
66139
|
-
i++;
|
|
66140
|
-
}
|
|
66141
|
-
return currentColName;
|
|
66377
|
+
return getUniqueText(colName, usedColNames, {
|
|
66378
|
+
compute: (name, i) => colName + String(i),
|
|
66379
|
+
start: 2,
|
|
66380
|
+
});
|
|
66142
66381
|
}
|
|
66143
66382
|
}
|
|
66144
66383
|
|
|
@@ -68180,11 +68419,6 @@ class BottomBarSheet extends owl.Component {
|
|
|
68180
68419
|
editionState = "initializing";
|
|
68181
68420
|
DOMFocusableElementStore;
|
|
68182
68421
|
setup() {
|
|
68183
|
-
owl.onMounted(() => {
|
|
68184
|
-
if (this.isSheetActive) {
|
|
68185
|
-
this.scrollToSheet();
|
|
68186
|
-
}
|
|
68187
|
-
});
|
|
68188
68422
|
owl.onPatched(() => {
|
|
68189
68423
|
if (this.sheetNameRef.el && this.state.isEditing && this.editionState === "initializing") {
|
|
68190
68424
|
this.editionState = "editing";
|
|
@@ -68193,6 +68427,11 @@ class BottomBarSheet extends owl.Component {
|
|
|
68193
68427
|
});
|
|
68194
68428
|
this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
|
|
68195
68429
|
owl.useExternalListener(window, "click", () => (this.state.pickerOpened = false));
|
|
68430
|
+
owl.useEffect((sheetId) => {
|
|
68431
|
+
if (this.props.sheetId === sheetId) {
|
|
68432
|
+
this.scrollToSheet();
|
|
68433
|
+
}
|
|
68434
|
+
}, () => [this.env.model.getters.getActiveSheetId()]);
|
|
68196
68435
|
}
|
|
68197
68436
|
focusInputAndSelectContent() {
|
|
68198
68437
|
if (!this.state.isEditing || !this.sheetNameRef.el)
|
|
@@ -68204,7 +68443,10 @@ class BottomBarSheet extends owl.Component {
|
|
|
68204
68443
|
}
|
|
68205
68444
|
}
|
|
68206
68445
|
scrollToSheet() {
|
|
68207
|
-
this.sheetDivRef.el?.scrollIntoView?.(
|
|
68446
|
+
this.sheetDivRef.el?.scrollIntoView?.({
|
|
68447
|
+
behavior: "smooth",
|
|
68448
|
+
inline: "nearest",
|
|
68449
|
+
});
|
|
68208
68450
|
}
|
|
68209
68451
|
onFocusOut() {
|
|
68210
68452
|
if (this.state.isEditing && this.editionState !== "initializing") {
|
|
@@ -68234,11 +68476,11 @@ class BottomBarSheet extends owl.Component {
|
|
|
68234
68476
|
if (ev.key === "Enter") {
|
|
68235
68477
|
ev.preventDefault();
|
|
68236
68478
|
this.stopEdition();
|
|
68237
|
-
this.DOMFocusableElementStore.focus();
|
|
68479
|
+
this.DOMFocusableElementStore.focusableElement?.focus();
|
|
68238
68480
|
}
|
|
68239
68481
|
if (ev.key === "Escape") {
|
|
68240
68482
|
this.cancelEdition();
|
|
68241
|
-
this.DOMFocusableElementStore.focus();
|
|
68483
|
+
this.DOMFocusableElementStore.focusableElement?.focus();
|
|
68242
68484
|
}
|
|
68243
68485
|
}
|
|
68244
68486
|
onMouseEventSheetName(ev) {
|
|
@@ -68787,23 +69029,17 @@ class ClickableCellsStore extends SpreadsheetStore {
|
|
|
68787
69029
|
const cells = [];
|
|
68788
69030
|
const getters = this.getters;
|
|
68789
69031
|
const sheetId = getters.getActiveSheetId();
|
|
68790
|
-
for (const
|
|
68791
|
-
|
|
68792
|
-
|
|
68793
|
-
|
|
68794
|
-
continue;
|
|
68795
|
-
}
|
|
68796
|
-
const action = this.getClickableAction(position);
|
|
68797
|
-
if (!action) {
|
|
68798
|
-
continue;
|
|
68799
|
-
}
|
|
68800
|
-
const zone = getters.expandZone(sheetId, positionToZone(position));
|
|
68801
|
-
cells.push({
|
|
68802
|
-
coordinates: getters.getVisibleRect(zone),
|
|
68803
|
-
position,
|
|
68804
|
-
action,
|
|
68805
|
-
});
|
|
69032
|
+
for (const position of this.getters.getVisibleCellPositions()) {
|
|
69033
|
+
const action = this.getClickableAction(position);
|
|
69034
|
+
if (!action) {
|
|
69035
|
+
continue;
|
|
68806
69036
|
}
|
|
69037
|
+
const zone = getters.expandZone(sheetId, positionToZone(position));
|
|
69038
|
+
cells.push({
|
|
69039
|
+
coordinates: getters.getVisibleRect(zone),
|
|
69040
|
+
position,
|
|
69041
|
+
action,
|
|
69042
|
+
});
|
|
68807
69043
|
}
|
|
68808
69044
|
return cells;
|
|
68809
69045
|
}
|
|
@@ -73614,7 +73850,7 @@ function addRows(construct, data, sheet) {
|
|
|
73614
73850
|
if (content || styleId || formatId || borderId || value !== undefined) {
|
|
73615
73851
|
const attributes = [["r", xc]];
|
|
73616
73852
|
// style
|
|
73617
|
-
const id = normalizeStyle(construct, extractStyle(data, styleId, formatId, borderId));
|
|
73853
|
+
const id = normalizeStyle(construct, extractStyle(data, content, styleId, formatId, borderId));
|
|
73618
73854
|
// don't add style if default
|
|
73619
73855
|
if (id) {
|
|
73620
73856
|
attributes.push(["s", id]);
|
|
@@ -73968,7 +74204,12 @@ function createSharedStrings(strings) {
|
|
|
73968
74204
|
["count", strings.length],
|
|
73969
74205
|
["uniqueCount", strings.length],
|
|
73970
74206
|
];
|
|
73971
|
-
const stringNodes = strings.map((string) =>
|
|
74207
|
+
const stringNodes = strings.map((string) => {
|
|
74208
|
+
if (string.trim() !== string) {
|
|
74209
|
+
return escapeXml /*xml*/ `<si><t xml:space="preserve">${string}</t></si>`;
|
|
74210
|
+
}
|
|
74211
|
+
return escapeXml /*xml*/ `<si><t>${string}</t></si>`;
|
|
74212
|
+
});
|
|
73972
74213
|
const xml = escapeXml /*xml*/ `
|
|
73973
74214
|
<sst ${formatAttributes(namespaces)}>
|
|
73974
74215
|
${joinXmlNodes(stringNodes)}
|
|
@@ -74049,14 +74290,13 @@ function createRelRoot() {
|
|
|
74049
74290
|
*/
|
|
74050
74291
|
function fixLengthySheetNames(data) {
|
|
74051
74292
|
const nameMapping = {};
|
|
74052
|
-
const newNames =
|
|
74293
|
+
const newNames = [];
|
|
74053
74294
|
for (const sheet of data.sheets) {
|
|
74054
74295
|
let newName = sheet.name.slice(0, 31);
|
|
74055
|
-
|
|
74056
|
-
|
|
74057
|
-
|
|
74058
|
-
|
|
74059
|
-
newNames.add(newName);
|
|
74296
|
+
newName = getUniqueText(newName, newNames, {
|
|
74297
|
+
compute: (name, i) => name.slice(0, 31 - String(i).length) + i,
|
|
74298
|
+
});
|
|
74299
|
+
newNames.push(newName);
|
|
74060
74300
|
if (newName !== sheet.name) {
|
|
74061
74301
|
nameMapping[sheet.name] = newName;
|
|
74062
74302
|
sheet.name = newName;
|
|
@@ -74121,6 +74361,7 @@ class Model extends EventBus {
|
|
|
74121
74361
|
*/
|
|
74122
74362
|
config;
|
|
74123
74363
|
corePluginConfig;
|
|
74364
|
+
coreViewPluginConfig;
|
|
74124
74365
|
uiPluginConfig;
|
|
74125
74366
|
state;
|
|
74126
74367
|
selection;
|
|
@@ -74173,6 +74414,7 @@ class Model extends EventBus {
|
|
|
74173
74414
|
this.coreHandlers.push(this.range);
|
|
74174
74415
|
this.handlers.push(this.range);
|
|
74175
74416
|
this.corePluginConfig = this.setupCorePluginConfig();
|
|
74417
|
+
this.coreViewPluginConfig = this.setupCoreViewPluginConfig();
|
|
74176
74418
|
this.uiPluginConfig = this.setupUiPluginConfig();
|
|
74177
74419
|
// registering plugins
|
|
74178
74420
|
for (let Plugin of corePluginRegistry.getAll()) {
|
|
@@ -74181,7 +74423,7 @@ class Model extends EventBus {
|
|
|
74181
74423
|
Object.assign(this.getters, this.coreGetters);
|
|
74182
74424
|
this.session.loadInitialMessages(stateUpdateMessages);
|
|
74183
74425
|
for (let Plugin of coreViewsPluginRegistry.getAll()) {
|
|
74184
|
-
const plugin = this.
|
|
74426
|
+
const plugin = this.setupCoreViewPlugin(Plugin);
|
|
74185
74427
|
this.handlers.push(plugin);
|
|
74186
74428
|
this.uiHandlers.push(plugin);
|
|
74187
74429
|
this.coreHandlers.push(plugin);
|
|
@@ -74208,7 +74450,7 @@ class Model extends EventBus {
|
|
|
74208
74450
|
// events
|
|
74209
74451
|
this.setupSessionEvents();
|
|
74210
74452
|
this.joinSession();
|
|
74211
|
-
if (config.snapshotRequested) {
|
|
74453
|
+
if (config.snapshotRequested || (data["[Content_Types].xml"] && !this.getters.isReadonly())) {
|
|
74212
74454
|
const startSnapshot = performance.now();
|
|
74213
74455
|
console.debug("Snapshot requested");
|
|
74214
74456
|
this.session.snapshot(this.exportData());
|
|
@@ -74247,6 +74489,19 @@ class Model extends EventBus {
|
|
|
74247
74489
|
}
|
|
74248
74490
|
return plugin;
|
|
74249
74491
|
}
|
|
74492
|
+
setupCoreViewPlugin(Plugin) {
|
|
74493
|
+
const plugin = new Plugin(this.coreViewPluginConfig);
|
|
74494
|
+
for (let name of Plugin.getters) {
|
|
74495
|
+
if (!(name in plugin)) {
|
|
74496
|
+
throw new Error(`Invalid getter name: ${name} for plugin ${plugin.constructor}`);
|
|
74497
|
+
}
|
|
74498
|
+
if (name in this.getters) {
|
|
74499
|
+
throw new Error(`Getter "${name}" is already defined.`);
|
|
74500
|
+
}
|
|
74501
|
+
this.getters[name] = plugin[name].bind(plugin);
|
|
74502
|
+
}
|
|
74503
|
+
return plugin;
|
|
74504
|
+
}
|
|
74250
74505
|
/**
|
|
74251
74506
|
* Initialize and properly configure a plugin.
|
|
74252
74507
|
*
|
|
@@ -74348,6 +74603,20 @@ class Model extends EventBus {
|
|
|
74348
74603
|
external: this.config.external,
|
|
74349
74604
|
};
|
|
74350
74605
|
}
|
|
74606
|
+
setupCoreViewPluginConfig() {
|
|
74607
|
+
return {
|
|
74608
|
+
getters: this.getters,
|
|
74609
|
+
stateObserver: this.state,
|
|
74610
|
+
selection: this.selection,
|
|
74611
|
+
moveClient: this.session.move.bind(this.session),
|
|
74612
|
+
custom: this.config.custom,
|
|
74613
|
+
uiActions: this.config,
|
|
74614
|
+
session: this.session,
|
|
74615
|
+
defaultCurrency: this.config.defaultCurrency,
|
|
74616
|
+
customColors: this.config.customColors || [],
|
|
74617
|
+
external: this.config.external,
|
|
74618
|
+
};
|
|
74619
|
+
}
|
|
74351
74620
|
setupUiPluginConfig() {
|
|
74352
74621
|
return {
|
|
74353
74622
|
getters: this.getters,
|
|
@@ -74695,6 +74964,9 @@ const helpers = {
|
|
|
74695
74964
|
areDomainArgsFieldsValid,
|
|
74696
74965
|
splitReference,
|
|
74697
74966
|
sanitizeSheetName,
|
|
74967
|
+
getUniqueText,
|
|
74968
|
+
isNumber,
|
|
74969
|
+
isDateTime,
|
|
74698
74970
|
};
|
|
74699
74971
|
const links = {
|
|
74700
74972
|
isMarkdownLink,
|
|
@@ -74791,6 +75063,7 @@ exports.AbstractChart = AbstractChart;
|
|
|
74791
75063
|
exports.AbstractFigureClipboardHandler = AbstractFigureClipboardHandler;
|
|
74792
75064
|
exports.CellErrorType = CellErrorType;
|
|
74793
75065
|
exports.CorePlugin = CorePlugin;
|
|
75066
|
+
exports.CoreViewPlugin = CoreViewPlugin;
|
|
74794
75067
|
exports.DispatchResult = DispatchResult;
|
|
74795
75068
|
exports.EvaluationError = EvaluationError;
|
|
74796
75069
|
exports.Model = Model;
|
|
@@ -74833,6 +75106,6 @@ exports.tokenColors = tokenColors;
|
|
|
74833
75106
|
exports.tokenize = tokenize;
|
|
74834
75107
|
|
|
74835
75108
|
|
|
74836
|
-
__info__.version = "18.2.0-alpha.
|
|
74837
|
-
__info__.date = "
|
|
74838
|
-
__info__.hash = "
|
|
75109
|
+
__info__.version = "18.2.0-alpha.1";
|
|
75110
|
+
__info__.date = "2025-01-14T11:35:51.135Z";
|
|
75111
|
+
__info__.hash = "702f816";
|