@odoo/o-spreadsheet 18.1.0-alpha.1 → 18.1.0-alpha.2
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 +908 -549
- package/dist/o-spreadsheet.d.ts +310 -244
- package/dist/o-spreadsheet.esm.js +908 -549
- package/dist/o-spreadsheet.iife.js +908 -549
- package/dist/o-spreadsheet.iife.min.js +438 -408
- package/dist/o_spreadsheet.xml +264 -341
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 18.1.0-alpha.
|
|
6
|
-
* @date 2024-10-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.1.0-alpha.2
|
|
6
|
+
* @date 2024-10-24T08:53:21.828Z
|
|
7
|
+
* @hash 2a01250
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -331,6 +331,7 @@ const DEFAULT_SCORECARD_BASELINE_MODE = "difference";
|
|
|
331
331
|
const DEFAULT_SCORECARD_BASELINE_COLOR_UP = "#43C5B1";
|
|
332
332
|
const DEFAULT_SCORECARD_BASELINE_COLOR_DOWN = "#EA6175";
|
|
333
333
|
const LINE_FILL_TRANSPARENCY = 0.4;
|
|
334
|
+
const DEFAULT_WINDOW_SIZE = 2;
|
|
334
335
|
// session
|
|
335
336
|
const DEBOUNCE_TIME = 200;
|
|
336
337
|
const MESSAGE_VERSION = 1;
|
|
@@ -376,7 +377,7 @@ const PIVOT_TABLE_CONFIG = {
|
|
|
376
377
|
bandedRows: true,
|
|
377
378
|
bandedColumns: false,
|
|
378
379
|
styleId: "TableStyleMedium5",
|
|
379
|
-
automaticAutofill:
|
|
380
|
+
automaticAutofill: false,
|
|
380
381
|
};
|
|
381
382
|
const DEFAULT_CURRENCY = {
|
|
382
383
|
symbol: "$",
|
|
@@ -592,7 +593,7 @@ function buildSheetLink(sheetId) {
|
|
|
592
593
|
*/
|
|
593
594
|
function parseSheetUrl(sheetLink) {
|
|
594
595
|
if (sheetLink.startsWith(O_SPREADSHEET_LINK_PREFIX)) {
|
|
595
|
-
return sheetLink.
|
|
596
|
+
return sheetLink.slice(O_SPREADSHEET_LINK_PREFIX.length);
|
|
596
597
|
}
|
|
597
598
|
throw new Error(`${sheetLink} is not a valid sheet link`);
|
|
598
599
|
}
|
|
@@ -3157,8 +3158,7 @@ const getNumberRegex = memoize(function getNumberRegex(locale) {
|
|
|
3157
3158
|
const p2 = pMinus + pNumber + pCurrencyFormat;
|
|
3158
3159
|
const p3 = pCurrencyFormat + pMinus + pNumber;
|
|
3159
3160
|
const pNumberExp = "^(?:(?:" + [p1, p2, p3].join(")|(?:") + "))$";
|
|
3160
|
-
|
|
3161
|
-
return numberRegexp;
|
|
3161
|
+
return new RegExp(pNumberExp, "i");
|
|
3162
3162
|
});
|
|
3163
3163
|
/**
|
|
3164
3164
|
* Return true if the argument is a "number string".
|
|
@@ -5832,8 +5832,7 @@ function computeCachedTextWidth(context, text) {
|
|
|
5832
5832
|
textWidthCache[font] = {};
|
|
5833
5833
|
}
|
|
5834
5834
|
if (textWidthCache[font][text] === undefined) {
|
|
5835
|
-
|
|
5836
|
-
textWidthCache[font][text] = textWidth;
|
|
5835
|
+
textWidthCache[font][text] = context.measureText(text).width;
|
|
5837
5836
|
}
|
|
5838
5837
|
return textWidthCache[font][text];
|
|
5839
5838
|
}
|
|
@@ -6085,7 +6084,7 @@ class UuidGenerator {
|
|
|
6085
6084
|
else {
|
|
6086
6085
|
// mainly for jest and other browsers that do not have the crypto functionality
|
|
6087
6086
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
6088
|
-
|
|
6087
|
+
const r = (Math.random() * 16) | 0, v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
6089
6088
|
return v.toString(16);
|
|
6090
6089
|
});
|
|
6091
6090
|
}
|
|
@@ -6582,10 +6581,9 @@ function localizeNumberLiteral(literal, locale) {
|
|
|
6582
6581
|
return literal;
|
|
6583
6582
|
}
|
|
6584
6583
|
const decimalNumberRegex = getDecimalNumberRegex(DEFAULT_LOCALE);
|
|
6585
|
-
|
|
6584
|
+
return literal.replace(decimalNumberRegex, (match) => {
|
|
6586
6585
|
return match.replace(".", locale.decimalSeparator);
|
|
6587
6586
|
});
|
|
6588
|
-
return localized;
|
|
6589
6587
|
}
|
|
6590
6588
|
/**
|
|
6591
6589
|
* Change a literal string from its canonical form (en_US locale) to the given locale. Also convert date string.
|
|
@@ -7070,6 +7068,21 @@ function predictLinearValues(Y, X, newX, computeIntercept) {
|
|
|
7070
7068
|
});
|
|
7071
7069
|
return newY.length === newX.length ? newY : transposeMatrix(newY);
|
|
7072
7070
|
}
|
|
7071
|
+
function getMovingAverageValues(dataset, windowSize = DEFAULT_WINDOW_SIZE) {
|
|
7072
|
+
const values = [];
|
|
7073
|
+
// Fill the starting values with null until we have a full window
|
|
7074
|
+
for (let i = 0; i < windowSize - 1; i++) {
|
|
7075
|
+
values.push(null);
|
|
7076
|
+
}
|
|
7077
|
+
for (let i = 0; i <= dataset.length - windowSize; i++) {
|
|
7078
|
+
let sum = 0;
|
|
7079
|
+
for (let j = i; j < i + windowSize; j++) {
|
|
7080
|
+
sum += dataset[j];
|
|
7081
|
+
}
|
|
7082
|
+
values.push(sum / windowSize);
|
|
7083
|
+
}
|
|
7084
|
+
return values;
|
|
7085
|
+
}
|
|
7073
7086
|
|
|
7074
7087
|
const PREVIOUS_VALUE = "(previous)";
|
|
7075
7088
|
const NEXT_VALUE = "(next)";
|
|
@@ -7605,8 +7618,7 @@ function getMaxObjectId(o) {
|
|
|
7605
7618
|
return 0;
|
|
7606
7619
|
}
|
|
7607
7620
|
const nums = keys.map((id) => parseInt(id, 10));
|
|
7608
|
-
|
|
7609
|
-
return max;
|
|
7621
|
+
return Math.max(...nums);
|
|
7610
7622
|
}
|
|
7611
7623
|
const ALL_PERIODS = {
|
|
7612
7624
|
year: _t("Year"),
|
|
@@ -8459,10 +8471,6 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
8459
8471
|
tableZone &&
|
|
8460
8472
|
zones.some((z) => isZoneInside(tableZone, z))) {
|
|
8461
8473
|
copiedTablesIds.add(table.id);
|
|
8462
|
-
const values = [];
|
|
8463
|
-
for (const col of range(tableZone.left, tableZone.right + 1)) {
|
|
8464
|
-
values.push(this.getters.getFilterHiddenValues({ sheetId, col, row: tableZone.top }));
|
|
8465
|
-
}
|
|
8466
8474
|
copiedTable = {
|
|
8467
8475
|
range: coreTable.range.rangeData,
|
|
8468
8476
|
config: coreTable.config,
|
|
@@ -9243,11 +9251,10 @@ function getChartPositionAtCenterOfViewport(getters, chartSize) {
|
|
|
9243
9251
|
const { x, y } = getters.getMainViewportCoordinates();
|
|
9244
9252
|
const { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
|
|
9245
9253
|
const { width, height } = getters.getVisibleRect(getters.getActiveMainViewport());
|
|
9246
|
-
|
|
9254
|
+
return {
|
|
9247
9255
|
x: x + scrollX + Math.max(0, (width - chartSize.width) / 2),
|
|
9248
9256
|
y: y + scrollY + Math.max(0, (height - chartSize.height) / 2),
|
|
9249
9257
|
}; // Position at the center of the scrollable viewport
|
|
9250
|
-
return position;
|
|
9251
9258
|
}
|
|
9252
9259
|
function getChartAxisTitleRuntime(design) {
|
|
9253
9260
|
if (design?.title?.text) {
|
|
@@ -9364,7 +9371,7 @@ function getFullTrendingLineDataSet(dataset, config, data) {
|
|
|
9364
9371
|
return {
|
|
9365
9372
|
...dataset,
|
|
9366
9373
|
type: "line",
|
|
9367
|
-
xAxisID: TREND_LINE_XAXIS_ID,
|
|
9374
|
+
xAxisID: config.type !== "trailingMovingAverage" ? TREND_LINE_XAXIS_ID : "x",
|
|
9368
9375
|
label: dataset.label ? _t("Trend line for %s", dataset.label) : "",
|
|
9369
9376
|
data,
|
|
9370
9377
|
order: -1,
|
|
@@ -9406,6 +9413,9 @@ function interpolateData(config, values, labels, newLabels) {
|
|
|
9406
9413
|
case "logarithmic": {
|
|
9407
9414
|
return predictLinearValues([values], logM([labels]), logM([newLabels]), true)[0];
|
|
9408
9415
|
}
|
|
9416
|
+
case "trailingMovingAverage": {
|
|
9417
|
+
return getMovingAverageValues(values, config.window);
|
|
9418
|
+
}
|
|
9409
9419
|
default:
|
|
9410
9420
|
return [];
|
|
9411
9421
|
}
|
|
@@ -9451,72 +9461,115 @@ const chartShowValuesPlugin = {
|
|
|
9451
9461
|
ctx.save();
|
|
9452
9462
|
ctx.textAlign = "center";
|
|
9453
9463
|
ctx.textBaseline = "middle";
|
|
9454
|
-
ctx.
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
const midRadius = (innerRadius + outerRadius) / 2;
|
|
9468
|
-
const x = bar.x + midRadius * Math.cos(midAngle);
|
|
9469
|
-
const y = bar.y + midRadius * Math.sin(midAngle) + 7;
|
|
9470
|
-
ctx.fillStyle = chartFontColor(bar.options.backgroundColor);
|
|
9471
|
-
ctx.strokeStyle = chartFontColor(ctx.fillStyle);
|
|
9472
|
-
const value = options.callback(dataset._parsed[i]);
|
|
9473
|
-
ctx.strokeText(value, x, y);
|
|
9474
|
-
ctx.fillText(value, x, y);
|
|
9475
|
-
}
|
|
9476
|
-
break;
|
|
9477
|
-
}
|
|
9478
|
-
case "bar":
|
|
9479
|
-
case "line": {
|
|
9480
|
-
const yOffset = dataset.type === "bar" && !options.horizontal ? 0 : 3;
|
|
9481
|
-
const horizontalChart = dataset.type === "bar" && options.horizontal;
|
|
9482
|
-
const axisId = horizontalChart ? dataset.xAxisID : dataset.yAxisID;
|
|
9483
|
-
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
9484
|
-
const point = dataset.data[i];
|
|
9485
|
-
const value = options.horizontal ? dataset._parsed[i].x : dataset._parsed[i].y;
|
|
9486
|
-
const displayedValue = options.callback(value - 0, axisId);
|
|
9487
|
-
let xPosition = 0, yPosition = 0;
|
|
9488
|
-
if (options.horizontal) {
|
|
9489
|
-
yPosition = point.y;
|
|
9490
|
-
if (value < 0) {
|
|
9491
|
-
ctx.textAlign = "right";
|
|
9492
|
-
xPosition = point.x - yOffset;
|
|
9493
|
-
}
|
|
9494
|
-
else {
|
|
9495
|
-
ctx.textAlign = "left";
|
|
9496
|
-
xPosition = point.x + yOffset;
|
|
9497
|
-
}
|
|
9498
|
-
}
|
|
9499
|
-
else {
|
|
9500
|
-
xPosition = point.x;
|
|
9501
|
-
if (value < 0) {
|
|
9502
|
-
ctx.textBaseline = "top";
|
|
9503
|
-
yPosition = point.y + yOffset;
|
|
9504
|
-
}
|
|
9505
|
-
else {
|
|
9506
|
-
ctx.textBaseline = "bottom";
|
|
9507
|
-
yPosition = point.y - yOffset;
|
|
9508
|
-
}
|
|
9509
|
-
}
|
|
9510
|
-
ctx.strokeText(displayedValue, xPosition, yPosition);
|
|
9511
|
-
ctx.fillText(displayedValue, xPosition, yPosition);
|
|
9512
|
-
}
|
|
9513
|
-
break;
|
|
9514
|
-
}
|
|
9515
|
-
}
|
|
9516
|
-
});
|
|
9464
|
+
ctx.miterLimit = 1; // Avoid sharp artifacts on strokeText
|
|
9465
|
+
switch (chart.config.type) {
|
|
9466
|
+
case "pie":
|
|
9467
|
+
case "doughnut":
|
|
9468
|
+
drawPieChartValues(chart, options, ctx);
|
|
9469
|
+
break;
|
|
9470
|
+
case "bar":
|
|
9471
|
+
case "line":
|
|
9472
|
+
options.horizontal
|
|
9473
|
+
? drawHorizontalBarChartValues(chart, options, ctx)
|
|
9474
|
+
: drawLineOrBarChartValues(chart, options, ctx);
|
|
9475
|
+
break;
|
|
9476
|
+
}
|
|
9517
9477
|
ctx.restore();
|
|
9518
9478
|
},
|
|
9519
9479
|
};
|
|
9480
|
+
function drawTextWithBackground(text, x, y, ctx) {
|
|
9481
|
+
ctx.lineWidth = 3; // Stroke the text with a big lineWidth width to have some kind of background
|
|
9482
|
+
ctx.strokeText(text, x, y);
|
|
9483
|
+
ctx.lineWidth = 1;
|
|
9484
|
+
ctx.fillText(text, x, y);
|
|
9485
|
+
}
|
|
9486
|
+
function drawLineOrBarChartValues(chart, options, ctx) {
|
|
9487
|
+
const yMax = chart.chartArea.bottom;
|
|
9488
|
+
const yMin = chart.chartArea.top;
|
|
9489
|
+
const textsPositions = {};
|
|
9490
|
+
for (const dataset of chart._metasets) {
|
|
9491
|
+
if (dataset.xAxisID === TREND_LINE_XAXIS_ID) {
|
|
9492
|
+
return; // ignore trend lines
|
|
9493
|
+
}
|
|
9494
|
+
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
9495
|
+
const value = dataset._parsed[i].y;
|
|
9496
|
+
const displayValue = options.callback(value - 0, dataset.yAxisID);
|
|
9497
|
+
const point = dataset.data[i];
|
|
9498
|
+
const xPosition = point.x;
|
|
9499
|
+
let yPosition = 0;
|
|
9500
|
+
if (chart.config.type === "line") {
|
|
9501
|
+
yPosition = point.y - 10;
|
|
9502
|
+
}
|
|
9503
|
+
else {
|
|
9504
|
+
yPosition = value < 0 ? point.y - point.height / 2 : point.y + point.height / 2;
|
|
9505
|
+
}
|
|
9506
|
+
yPosition = Math.min(yPosition, yMax);
|
|
9507
|
+
yPosition = Math.max(yPosition, yMin);
|
|
9508
|
+
// Avoid overlapping texts with same X
|
|
9509
|
+
if (!textsPositions[xPosition]) {
|
|
9510
|
+
textsPositions[xPosition] = [];
|
|
9511
|
+
}
|
|
9512
|
+
for (const otherPosition of textsPositions[xPosition] || []) {
|
|
9513
|
+
if (Math.abs(otherPosition - yPosition) < 13) {
|
|
9514
|
+
yPosition = otherPosition - 13;
|
|
9515
|
+
}
|
|
9516
|
+
}
|
|
9517
|
+
textsPositions[xPosition].push(yPosition);
|
|
9518
|
+
ctx.fillStyle = point.options.backgroundColor;
|
|
9519
|
+
ctx.strokeStyle = options.background || "#ffffff";
|
|
9520
|
+
drawTextWithBackground(displayValue, xPosition, yPosition, ctx);
|
|
9521
|
+
}
|
|
9522
|
+
}
|
|
9523
|
+
}
|
|
9524
|
+
function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
9525
|
+
const xMax = chart.chartArea.right;
|
|
9526
|
+
const xMin = chart.chartArea.left;
|
|
9527
|
+
const textsPositions = {};
|
|
9528
|
+
for (const dataset of chart._metasets) {
|
|
9529
|
+
if (dataset.xAxisID === TREND_LINE_XAXIS_ID) {
|
|
9530
|
+
return; // ignore trend lines
|
|
9531
|
+
}
|
|
9532
|
+
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
9533
|
+
const value = dataset._parsed[i].x;
|
|
9534
|
+
const displayValue = options.callback(value - 0, dataset.xAxisID);
|
|
9535
|
+
const point = dataset.data[i];
|
|
9536
|
+
const yPosition = point.y;
|
|
9537
|
+
let xPosition = value < 0 ? point.x + point.width / 2 : point.x - point.width / 2;
|
|
9538
|
+
xPosition = Math.min(xPosition, xMax);
|
|
9539
|
+
xPosition = Math.max(xPosition, xMin);
|
|
9540
|
+
// Avoid overlapping texts with same Y
|
|
9541
|
+
if (!textsPositions[yPosition]) {
|
|
9542
|
+
textsPositions[yPosition] = [];
|
|
9543
|
+
}
|
|
9544
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
9545
|
+
for (const otherPosition of textsPositions[yPosition]) {
|
|
9546
|
+
if (Math.abs(otherPosition - xPosition) < textWidth) {
|
|
9547
|
+
xPosition = otherPosition + textWidth + 3;
|
|
9548
|
+
}
|
|
9549
|
+
}
|
|
9550
|
+
textsPositions[yPosition].push(xPosition);
|
|
9551
|
+
ctx.fillStyle = point.options.backgroundColor;
|
|
9552
|
+
ctx.strokeStyle = options.background || "#ffffff";
|
|
9553
|
+
drawTextWithBackground(displayValue, xPosition, yPosition, ctx);
|
|
9554
|
+
}
|
|
9555
|
+
}
|
|
9556
|
+
}
|
|
9557
|
+
function drawPieChartValues(chart, options, ctx) {
|
|
9558
|
+
for (const dataset of chart._metasets) {
|
|
9559
|
+
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
9560
|
+
const bar = dataset.data[i];
|
|
9561
|
+
const { startAngle, endAngle, innerRadius, outerRadius } = bar;
|
|
9562
|
+
const midAngle = (startAngle + endAngle) / 2;
|
|
9563
|
+
const midRadius = (innerRadius + outerRadius) / 2;
|
|
9564
|
+
const x = bar.x + midRadius * Math.cos(midAngle);
|
|
9565
|
+
const y = bar.y + midRadius * Math.sin(midAngle) + 7;
|
|
9566
|
+
ctx.fillStyle = chartFontColor(options.background);
|
|
9567
|
+
ctx.strokeStyle = options.background || "#ffffff";
|
|
9568
|
+
const value = options.callback(dataset._parsed[i]);
|
|
9569
|
+
drawTextWithBackground(value, x, y, ctx);
|
|
9570
|
+
}
|
|
9571
|
+
}
|
|
9572
|
+
}
|
|
9520
9573
|
|
|
9521
9574
|
/** This is a chartJS plugin that will draw connector lines between the bars of a Waterfall chart */
|
|
9522
9575
|
const waterfallLinesPlugin = {
|
|
@@ -10294,8 +10347,7 @@ function getHtmlContentFromPattern(pattern, value, highlightColor, className) {
|
|
|
10294
10347
|
value = value.slice(index + 1);
|
|
10295
10348
|
}
|
|
10296
10349
|
pendingHtmlContent.push({ value });
|
|
10297
|
-
|
|
10298
|
-
return htmlContent;
|
|
10350
|
+
return pendingHtmlContent.filter((content) => content.value);
|
|
10299
10351
|
}
|
|
10300
10352
|
|
|
10301
10353
|
//------------------------------------------------------------------------------
|
|
@@ -10699,7 +10751,7 @@ const MINVERSE = {
|
|
|
10699
10751
|
assertSquareMatrix(_t("The argument square_matrix must have the same number of columns and rows."), _matrix);
|
|
10700
10752
|
const { inverted } = invertMatrix(_matrix);
|
|
10701
10753
|
if (!inverted) {
|
|
10702
|
-
|
|
10754
|
+
return new EvaluationError(_t("The matrix is not invertible."));
|
|
10703
10755
|
}
|
|
10704
10756
|
return inverted;
|
|
10705
10757
|
},
|
|
@@ -10778,7 +10830,7 @@ function getSumXAndY(arrayX, arrayY, cb) {
|
|
|
10778
10830
|
}
|
|
10779
10831
|
}
|
|
10780
10832
|
if (!validPairFound) {
|
|
10781
|
-
|
|
10833
|
+
return new EvaluationError(_t("The arguments array_x and array_y must contain at least one pair of numbers."));
|
|
10782
10834
|
}
|
|
10783
10835
|
return result;
|
|
10784
10836
|
}
|
|
@@ -10859,7 +10911,7 @@ const TOCOL = {
|
|
|
10859
10911
|
.flat()
|
|
10860
10912
|
.filter(shouldKeepValue(_ignore));
|
|
10861
10913
|
if (result.length === 0) {
|
|
10862
|
-
|
|
10914
|
+
return new NotAvailableError(_t("No results for the given arguments of TOCOL."));
|
|
10863
10915
|
}
|
|
10864
10916
|
return [result];
|
|
10865
10917
|
},
|
|
@@ -10880,7 +10932,7 @@ const TOROW = {
|
|
|
10880
10932
|
.filter(shouldKeepValue(_ignore))
|
|
10881
10933
|
.map((item) => [item]);
|
|
10882
10934
|
if (result.length === 0 || result[0].length === 0) {
|
|
10883
|
-
|
|
10935
|
+
return new NotAvailableError(_t("No results for the given arguments of TOROW."));
|
|
10884
10936
|
}
|
|
10885
10937
|
return result;
|
|
10886
10938
|
},
|
|
@@ -11440,7 +11492,7 @@ const DECIMAL = {
|
|
|
11440
11492
|
* Return error if 'value' is positive.
|
|
11441
11493
|
* Remove '-?' in the next regex to catch this error.
|
|
11442
11494
|
*/
|
|
11443
|
-
assert(() =>
|
|
11495
|
+
assert(() => DECIMAL_REPRESENTATION.test(_value), _t("The value (%s) must be a valid base %s representation.", _value, _base.toString()));
|
|
11444
11496
|
const deci = parseInt(_value, _base);
|
|
11445
11497
|
assert(() => !isNaN(deci), _t("The value (%s) must be a valid base %s representation.", _value, _base.toString()));
|
|
11446
11498
|
return deci;
|
|
@@ -11708,7 +11760,7 @@ const PRODUCT = {
|
|
|
11708
11760
|
count += 1;
|
|
11709
11761
|
}
|
|
11710
11762
|
if (isEvaluationError(f)) {
|
|
11711
|
-
|
|
11763
|
+
return j;
|
|
11712
11764
|
}
|
|
11713
11765
|
}
|
|
11714
11766
|
}
|
|
@@ -12211,9 +12263,8 @@ function covariance(dataY, dataX, isSample) {
|
|
|
12211
12263
|
}
|
|
12212
12264
|
function variance(args, isSample, textAs0, locale) {
|
|
12213
12265
|
let count = 0;
|
|
12214
|
-
let sum = 0;
|
|
12215
12266
|
const reduceFunction = textAs0 ? reduceNumbersTextAs0 : reduceNumbers;
|
|
12216
|
-
sum = reduceFunction(args, (acc, a) => {
|
|
12267
|
+
const sum = reduceFunction(args, (acc, a) => {
|
|
12217
12268
|
count += 1;
|
|
12218
12269
|
return acc + a;
|
|
12219
12270
|
}, 0, locale);
|
|
@@ -12610,7 +12661,7 @@ const MATTHEWS = {
|
|
|
12610
12661
|
const flatY = dataY.flat();
|
|
12611
12662
|
assertSameNumberOfElements(flatX, flatY);
|
|
12612
12663
|
if (flatX.length === 0) {
|
|
12613
|
-
|
|
12664
|
+
return new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
|
|
12614
12665
|
}
|
|
12615
12666
|
const n = flatX.length;
|
|
12616
12667
|
let trueN = 0, trueP = 0, falseP = 0, falseN = 0;
|
|
@@ -13410,9 +13461,8 @@ function getMatchingCells(database, field, criteria, locale) {
|
|
|
13410
13461
|
// 4 - return for each database row corresponding, the cells corresponding to the field parameter
|
|
13411
13462
|
const fieldCol = database[index];
|
|
13412
13463
|
// Example continuation:: fieldCol = ["C", "j", "k", 7]
|
|
13413
|
-
const matchingCells = [...matchingRows].map((x) => fieldCol[x + 1]);
|
|
13414
13464
|
// Example continuation:: matchingCells = ["j", 7]
|
|
13415
|
-
return
|
|
13465
|
+
return [...matchingRows].map((x) => fieldCol[x + 1]);
|
|
13416
13466
|
}
|
|
13417
13467
|
const databaseArgs = [
|
|
13418
13468
|
arg("database (range)", _t("The array or range containing the data to consider, structured in such a way that the first row contains the labels for each column's values.")),
|
|
@@ -14597,7 +14647,7 @@ const FILTER = {
|
|
|
14597
14647
|
}
|
|
14598
14648
|
}
|
|
14599
14649
|
if (!result.length) {
|
|
14600
|
-
|
|
14650
|
+
return new NotAvailableError(_t("No match found in FILTER evaluation"));
|
|
14601
14651
|
}
|
|
14602
14652
|
return mode === "row" ? transposeMatrix(result) : result;
|
|
14603
14653
|
},
|
|
@@ -17295,7 +17345,7 @@ function mapParentFunction(tokens) {
|
|
|
17295
17345
|
argsTokens[argPosition].push({ value: token.value, type: token.type });
|
|
17296
17346
|
}
|
|
17297
17347
|
}
|
|
17298
|
-
|
|
17348
|
+
return tokens.map((token, i) => {
|
|
17299
17349
|
if (!["SPACE", "LEFT_PAREN"].includes(token.type)) {
|
|
17300
17350
|
functionStarted = "";
|
|
17301
17351
|
}
|
|
@@ -17333,7 +17383,6 @@ function mapParentFunction(tokens) {
|
|
|
17333
17383
|
}
|
|
17334
17384
|
return token;
|
|
17335
17385
|
});
|
|
17336
|
-
return res;
|
|
17337
17386
|
}
|
|
17338
17387
|
/**
|
|
17339
17388
|
* Parse the list of tokens that compose the arguments of a function to
|
|
@@ -17789,7 +17838,7 @@ const IFS = {
|
|
|
17789
17838
|
return result;
|
|
17790
17839
|
}
|
|
17791
17840
|
}
|
|
17792
|
-
|
|
17841
|
+
return new EvaluationError(_t("No match."));
|
|
17793
17842
|
},
|
|
17794
17843
|
isExported: true,
|
|
17795
17844
|
};
|
|
@@ -17953,8 +18002,8 @@ const ADDRESS = {
|
|
|
17953
18002
|
let cellReference;
|
|
17954
18003
|
if (_useA1Notation) {
|
|
17955
18004
|
const rangePart = {
|
|
17956
|
-
rowFixed: [1, 2].includes(_absoluteRelativeMode)
|
|
17957
|
-
colFixed: [1, 3].includes(_absoluteRelativeMode)
|
|
18005
|
+
rowFixed: [1, 2].includes(_absoluteRelativeMode),
|
|
18006
|
+
colFixed: [1, 3].includes(_absoluteRelativeMode),
|
|
17958
18007
|
};
|
|
17959
18008
|
cellReference = toXC(colNumber - 1, rowNumber - 1, rangePart);
|
|
17960
18009
|
}
|
|
@@ -17980,7 +18029,7 @@ const COLUMN = {
|
|
|
17980
18029
|
],
|
|
17981
18030
|
compute: function (cellReference) {
|
|
17982
18031
|
if (isEvaluationError(cellReference?.value)) {
|
|
17983
|
-
|
|
18032
|
+
return cellReference;
|
|
17984
18033
|
}
|
|
17985
18034
|
const column = cellReference === undefined
|
|
17986
18035
|
? this.__originCellPosition?.col
|
|
@@ -17998,7 +18047,7 @@ const COLUMNS = {
|
|
|
17998
18047
|
args: [arg("range (meta)", _t("The range whose column count will be returned."))],
|
|
17999
18048
|
compute: function (range) {
|
|
18000
18049
|
if (isEvaluationError(range?.value)) {
|
|
18001
|
-
|
|
18050
|
+
return range;
|
|
18002
18051
|
}
|
|
18003
18052
|
const zone = toZone(range.value);
|
|
18004
18053
|
return zone.right - zone.left + 1;
|
|
@@ -18078,11 +18127,11 @@ const INDIRECT = {
|
|
|
18078
18127
|
compute: function (reference, useA1Notation = { value: true }) {
|
|
18079
18128
|
let _reference = reference?.value?.toString();
|
|
18080
18129
|
if (!_reference) {
|
|
18081
|
-
|
|
18130
|
+
return new InvalidReferenceError(_t("Reference should be defined."));
|
|
18082
18131
|
}
|
|
18083
18132
|
const _useA1Notation = toBoolean(useA1Notation);
|
|
18084
18133
|
if (!_useA1Notation) {
|
|
18085
|
-
|
|
18134
|
+
return new EvaluationError(_t("R1C1 notation is not supported."));
|
|
18086
18135
|
}
|
|
18087
18136
|
const sheetId = this.__originSheetId;
|
|
18088
18137
|
const originPosition = this.__originCellPosition;
|
|
@@ -18094,7 +18143,7 @@ const INDIRECT = {
|
|
|
18094
18143
|
}
|
|
18095
18144
|
const range = this.getters.getRangeFromSheetXC(sheetId, _reference);
|
|
18096
18145
|
if (range === undefined || range.invalidXc || range.invalidSheetName) {
|
|
18097
|
-
|
|
18146
|
+
return new InvalidReferenceError();
|
|
18098
18147
|
}
|
|
18099
18148
|
if (originPosition) {
|
|
18100
18149
|
this.addDependencies?.(originPosition, [range]);
|
|
@@ -18202,7 +18251,7 @@ const ROW = {
|
|
|
18202
18251
|
],
|
|
18203
18252
|
compute: function (cellReference) {
|
|
18204
18253
|
if (isEvaluationError(cellReference?.value)) {
|
|
18205
|
-
|
|
18254
|
+
return cellReference;
|
|
18206
18255
|
}
|
|
18207
18256
|
const row = cellReference === undefined
|
|
18208
18257
|
? this.__originCellPosition?.row
|
|
@@ -18220,7 +18269,7 @@ const ROWS = {
|
|
|
18220
18269
|
args: [arg("range (meta)", _t("The range whose row count will be returned."))],
|
|
18221
18270
|
compute: function (range) {
|
|
18222
18271
|
if (isEvaluationError(range?.value)) {
|
|
18223
|
-
|
|
18272
|
+
return range;
|
|
18224
18273
|
}
|
|
18225
18274
|
const zone = toZone(range.value);
|
|
18226
18275
|
return zone.bottom - zone.top + 1;
|
|
@@ -18407,11 +18456,11 @@ const PIVOT = {
|
|
|
18407
18456
|
const _pivotFormulaId = toString(pivotFormulaId);
|
|
18408
18457
|
const _rowCount = toNumber(rowCount, this.locale);
|
|
18409
18458
|
if (_rowCount < 0) {
|
|
18410
|
-
|
|
18459
|
+
return new EvaluationError(_t("The number of rows must be positive."));
|
|
18411
18460
|
}
|
|
18412
18461
|
const _columnCount = toNumber(columnCount, this.locale);
|
|
18413
18462
|
if (_columnCount < 0) {
|
|
18414
|
-
|
|
18463
|
+
return new EvaluationError(_t("The number of columns must be positive."));
|
|
18415
18464
|
}
|
|
18416
18465
|
const _includeColumnHeaders = toBoolean(includeColumnHeaders);
|
|
18417
18466
|
const _includedTotal = toBoolean(includeTotal);
|
|
@@ -18610,6 +18659,12 @@ const EQ = {
|
|
|
18610
18659
|
arg("value2 (any)", _t("The value to test against value1 for equality.")),
|
|
18611
18660
|
],
|
|
18612
18661
|
compute: function (value1, value2) {
|
|
18662
|
+
if (isEvaluationError(value1?.value)) {
|
|
18663
|
+
return value1;
|
|
18664
|
+
}
|
|
18665
|
+
if (isEvaluationError(value2?.value)) {
|
|
18666
|
+
return value2;
|
|
18667
|
+
}
|
|
18613
18668
|
let _value1 = isEmpty(value1) ? getNeutral[typeof value2?.value] : value1?.value;
|
|
18614
18669
|
let _value2 = isEmpty(value2) ? getNeutral[typeof value1?.value] : value2?.value;
|
|
18615
18670
|
if (typeof _value1 === "string") {
|
|
@@ -18618,27 +18673,21 @@ const EQ = {
|
|
|
18618
18673
|
if (typeof _value2 === "string") {
|
|
18619
18674
|
_value2 = _value2.toUpperCase();
|
|
18620
18675
|
}
|
|
18621
|
-
|
|
18622
|
-
throw value1;
|
|
18623
|
-
}
|
|
18624
|
-
if (isEvaluationError(_value2)) {
|
|
18625
|
-
throw value2;
|
|
18626
|
-
}
|
|
18627
|
-
return _value1 === _value2;
|
|
18676
|
+
return { value: _value1 === _value2 };
|
|
18628
18677
|
},
|
|
18629
18678
|
};
|
|
18630
18679
|
// -----------------------------------------------------------------------------
|
|
18631
18680
|
// GT
|
|
18632
18681
|
// -----------------------------------------------------------------------------
|
|
18633
18682
|
function applyRelationalOperator(value1, value2, cb) {
|
|
18634
|
-
|
|
18635
|
-
|
|
18636
|
-
if (isEvaluationError(_value1)) {
|
|
18637
|
-
throw value1;
|
|
18683
|
+
if (isEvaluationError(value1?.value)) {
|
|
18684
|
+
return value1;
|
|
18638
18685
|
}
|
|
18639
|
-
if (isEvaluationError(
|
|
18640
|
-
|
|
18686
|
+
if (isEvaluationError(value2?.value)) {
|
|
18687
|
+
return value2;
|
|
18641
18688
|
}
|
|
18689
|
+
let _value1 = isEmpty(value1) ? getNeutral[typeof value2?.value] : value1?.value;
|
|
18690
|
+
let _value2 = isEmpty(value2) ? getNeutral[typeof value1?.value] : value2?.value;
|
|
18642
18691
|
if (typeof _value1 !== "number") {
|
|
18643
18692
|
_value1 = toString(_value1).toUpperCase();
|
|
18644
18693
|
}
|
|
@@ -18648,12 +18697,12 @@ function applyRelationalOperator(value1, value2, cb) {
|
|
|
18648
18697
|
const tV1 = typeof _value1;
|
|
18649
18698
|
const tV2 = typeof _value2;
|
|
18650
18699
|
if (tV1 === "string" && tV2 === "number") {
|
|
18651
|
-
return true;
|
|
18700
|
+
return { value: true };
|
|
18652
18701
|
}
|
|
18653
18702
|
if (tV2 === "string" && tV1 === "number") {
|
|
18654
|
-
return false;
|
|
18703
|
+
return { value: false };
|
|
18655
18704
|
}
|
|
18656
|
-
return cb(_value1, _value2);
|
|
18705
|
+
return { value: cb(_value1, _value2) };
|
|
18657
18706
|
}
|
|
18658
18707
|
const GT = {
|
|
18659
18708
|
description: _t("Strictly greater than."),
|
|
@@ -18692,7 +18741,11 @@ const LT = {
|
|
|
18692
18741
|
arg("value2 (any)", _t("The second value.")),
|
|
18693
18742
|
],
|
|
18694
18743
|
compute: function (value1, value2) {
|
|
18695
|
-
|
|
18744
|
+
const result = GTE.compute.bind(this)(value1, value2);
|
|
18745
|
+
if (isEvaluationError(result.value)) {
|
|
18746
|
+
return result;
|
|
18747
|
+
}
|
|
18748
|
+
return { value: !result.value };
|
|
18696
18749
|
},
|
|
18697
18750
|
};
|
|
18698
18751
|
// -----------------------------------------------------------------------------
|
|
@@ -18705,7 +18758,11 @@ const LTE = {
|
|
|
18705
18758
|
arg("value2 (any)", _t("The second value.")),
|
|
18706
18759
|
],
|
|
18707
18760
|
compute: function (value1, value2) {
|
|
18708
|
-
|
|
18761
|
+
const result = GT.compute.bind(this)(value1, value2);
|
|
18762
|
+
if (isEvaluationError(result.value)) {
|
|
18763
|
+
return result;
|
|
18764
|
+
}
|
|
18765
|
+
return { value: !result.value };
|
|
18709
18766
|
},
|
|
18710
18767
|
};
|
|
18711
18768
|
// -----------------------------------------------------------------------------
|
|
@@ -18750,7 +18807,11 @@ const NE = {
|
|
|
18750
18807
|
arg("value2 (any)", _t("The value to test against value1 for inequality.")),
|
|
18751
18808
|
],
|
|
18752
18809
|
compute: function (value1, value2) {
|
|
18753
|
-
|
|
18810
|
+
const result = EQ.compute.bind(this)(value1, value2);
|
|
18811
|
+
if (isEvaluationError(result.value)) {
|
|
18812
|
+
return result;
|
|
18813
|
+
}
|
|
18814
|
+
return { value: !result.value };
|
|
18754
18815
|
},
|
|
18755
18816
|
};
|
|
18756
18817
|
// -----------------------------------------------------------------------------
|
|
@@ -19909,13 +19970,12 @@ function cssPropertiesToCss(attributes) {
|
|
|
19909
19970
|
}
|
|
19910
19971
|
function getElementMargins(el) {
|
|
19911
19972
|
const style = window.getComputedStyle(el);
|
|
19912
|
-
|
|
19973
|
+
return {
|
|
19913
19974
|
top: parseInt(style.marginTop, 10) || 0,
|
|
19914
19975
|
bottom: parseInt(style.marginBottom, 10) || 0,
|
|
19915
19976
|
left: parseInt(style.marginLeft, 10) || 0,
|
|
19916
19977
|
right: parseInt(style.marginRight, 10) || 0,
|
|
19917
19978
|
};
|
|
19918
|
-
return margins;
|
|
19919
19979
|
}
|
|
19920
19980
|
|
|
19921
19981
|
const macRegex = /Mac/i;
|
|
@@ -21790,9 +21850,13 @@ autoCompleteProviders.add("pivot_group_fields", {
|
|
|
21790
21850
|
const colFields = columns.map((groupBy) => groupBy.nameWithGranularity);
|
|
21791
21851
|
const rowFields = rows.map((groupBy) => groupBy.nameWithGranularity);
|
|
21792
21852
|
const proposals = [];
|
|
21793
|
-
|
|
21853
|
+
let previousGroupBy = ["ARG_SEPARATOR", "SPACE"].includes(tokenAtCursor.type)
|
|
21794
21854
|
? argGroupBys.at(-1)
|
|
21795
21855
|
: argGroupBys.at(-2);
|
|
21856
|
+
const isPositionalSupported = supportedPivotPositionalFormulaRegistry.get(pivot.type);
|
|
21857
|
+
if (isPositionalSupported && previousGroupBy?.startsWith("#")) {
|
|
21858
|
+
previousGroupBy = previousGroupBy.slice(1);
|
|
21859
|
+
}
|
|
21796
21860
|
if (previousGroupBy === undefined) {
|
|
21797
21861
|
proposals.push(colFields[0]);
|
|
21798
21862
|
proposals.push(rowFields[0]);
|
|
@@ -21814,7 +21878,7 @@ autoCompleteProviders.add("pivot_group_fields", {
|
|
|
21814
21878
|
return field ? makeFieldProposal(field, granularity) : undefined;
|
|
21815
21879
|
})
|
|
21816
21880
|
.concat(groupBys.map((groupBy) => {
|
|
21817
|
-
if (!
|
|
21881
|
+
if (!isPositionalSupported) {
|
|
21818
21882
|
return undefined;
|
|
21819
21883
|
}
|
|
21820
21884
|
const fieldName = groupBy.split(":")[0];
|
|
@@ -21823,13 +21887,12 @@ autoCompleteProviders.add("pivot_group_fields", {
|
|
|
21823
21887
|
return undefined;
|
|
21824
21888
|
}
|
|
21825
21889
|
const positionalFieldArg = `"#${groupBy}"`;
|
|
21826
|
-
|
|
21890
|
+
return {
|
|
21827
21891
|
text: positionalFieldArg,
|
|
21828
21892
|
description: _t("%s (positional)", field.string) + (field.help ? ` (${field.help})` : ""),
|
|
21829
21893
|
htmlContent: [{ value: positionalFieldArg, color: tokenColors.STRING }],
|
|
21830
21894
|
fuzzySearchKey: field.string + positionalFieldArg, // search on translated name and on technical name
|
|
21831
21895
|
};
|
|
21832
|
-
return positionalProposal;
|
|
21833
21896
|
}))
|
|
21834
21897
|
.filter(isDefined);
|
|
21835
21898
|
},
|
|
@@ -22098,7 +22161,7 @@ function parseLiteral(content, locale) {
|
|
|
22098
22161
|
return internalDate.value;
|
|
22099
22162
|
}
|
|
22100
22163
|
if (isBoolean(content)) {
|
|
22101
|
-
return content.toUpperCase() === "TRUE"
|
|
22164
|
+
return content.toUpperCase() === "TRUE";
|
|
22102
22165
|
}
|
|
22103
22166
|
return content;
|
|
22104
22167
|
}
|
|
@@ -22439,8 +22502,7 @@ function calculateDateIncrementBasedOnGroup(group) {
|
|
|
22439
22502
|
return 0;
|
|
22440
22503
|
}
|
|
22441
22504
|
const previous = jsDates[index - 1];
|
|
22442
|
-
|
|
22443
|
-
return days;
|
|
22505
|
+
return Math.floor(date.getTime()) - Math.floor(previous.getTime());
|
|
22444
22506
|
})
|
|
22445
22507
|
.slice(1);
|
|
22446
22508
|
const equidistantDates = timeIntervals.every((interval) => interval === timeIntervals[0]);
|
|
@@ -22999,6 +23061,7 @@ const XLSX_CHART_TYPES = [
|
|
|
22999
23061
|
"surface3DChart",
|
|
23000
23062
|
"bubbleChart",
|
|
23001
23063
|
"comboChart",
|
|
23064
|
+
"radarChart",
|
|
23002
23065
|
];
|
|
23003
23066
|
|
|
23004
23067
|
/** In XLSX color format (no #) */
|
|
@@ -23539,7 +23602,7 @@ const CHART_TYPE_CONVERSION_MAP = {
|
|
|
23539
23602
|
lineChart: "line",
|
|
23540
23603
|
line3DChart: undefined,
|
|
23541
23604
|
stockChart: undefined,
|
|
23542
|
-
radarChart:
|
|
23605
|
+
radarChart: "radar",
|
|
23543
23606
|
scatterChart: "scatter",
|
|
23544
23607
|
pieChart: "pie",
|
|
23545
23608
|
pie3DChart: undefined,
|
|
@@ -24952,7 +25015,7 @@ const TABLE_STYLE_CATEGORIES = {
|
|
|
24952
25015
|
custom: _t("Custom"),
|
|
24953
25016
|
};
|
|
24954
25017
|
const DEFAULT_TABLE_CONFIG = {
|
|
24955
|
-
hasFilters:
|
|
25018
|
+
hasFilters: false,
|
|
24956
25019
|
totalRow: false,
|
|
24957
25020
|
firstColumn: false,
|
|
24958
25021
|
lastColumn: false,
|
|
@@ -25621,12 +25684,11 @@ class XlsxBaseExtractor {
|
|
|
25621
25684
|
* Get the list of all the XLSX files in the XLSX file structure
|
|
25622
25685
|
*/
|
|
25623
25686
|
getListOfXMLFiles() {
|
|
25624
|
-
|
|
25687
|
+
return Object.entries(this.xlsxFileStructure)
|
|
25625
25688
|
.filter(([key]) => key !== "images")
|
|
25626
25689
|
.map(([_, value]) => value)
|
|
25627
25690
|
.flat()
|
|
25628
25691
|
.filter(isDefined);
|
|
25629
|
-
return XMLFiles;
|
|
25630
25692
|
}
|
|
25631
25693
|
/**
|
|
25632
25694
|
* Return an array containing the return value of the given function applied to all the XML elements
|
|
@@ -25790,13 +25852,12 @@ class XlsxBaseExtractor {
|
|
|
25790
25852
|
rgb = this.extractAttr(colorElement, "rgb")?.asString();
|
|
25791
25853
|
rgb = rgb === DEFAULT_SYSTEM_COLOR ? undefined : rgb;
|
|
25792
25854
|
}
|
|
25793
|
-
|
|
25855
|
+
return {
|
|
25794
25856
|
rgb: rgb || defaultColor,
|
|
25795
25857
|
auto: this.extractAttr(colorElement, "auto")?.asBool(),
|
|
25796
25858
|
indexed: this.extractAttr(colorElement, "indexed")?.asNum(),
|
|
25797
25859
|
tint: this.extractAttr(colorElement, "tint")?.asNum(),
|
|
25798
25860
|
};
|
|
25799
|
-
return color;
|
|
25800
25861
|
}
|
|
25801
25862
|
/**
|
|
25802
25863
|
* Returns the xml file targeted by a relationship.
|
|
@@ -26388,7 +26449,7 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
|
|
|
26388
26449
|
hyperlinks: this.extractHyperLinks(sheetElement),
|
|
26389
26450
|
tables: this.extractTables(sheetElement),
|
|
26390
26451
|
pivotTables: this.extractPivotTables(),
|
|
26391
|
-
isVisible: sheetWorkbookInfo.state === "visible"
|
|
26452
|
+
isVisible: sheetWorkbookInfo.state === "visible",
|
|
26392
26453
|
};
|
|
26393
26454
|
})[0];
|
|
26394
26455
|
}
|
|
@@ -26459,8 +26520,7 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
|
|
|
26459
26520
|
const figures = this.mapOnElements({ parent: worksheet, query: "drawing" }, (drawingElement) => {
|
|
26460
26521
|
const drawingId = this.extractAttr(drawingElement, "r:id", { required: true })?.asString();
|
|
26461
26522
|
const drawingFile = this.getTargetXmlFile(this.relationships[drawingId]);
|
|
26462
|
-
|
|
26463
|
-
return figures;
|
|
26523
|
+
return new XlsxFigureExtractor(drawingFile, this.xlsxFileStructure, this.warningManager).extractFigures();
|
|
26464
26524
|
})[0];
|
|
26465
26525
|
return figures || [];
|
|
26466
26526
|
}
|
|
@@ -26478,8 +26538,7 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
|
|
|
26478
26538
|
.filter((relationship) => relationship.type.endsWith("pivotTable"))
|
|
26479
26539
|
.map((pivotRelationship) => {
|
|
26480
26540
|
const pivotFile = this.getTargetXmlFile(pivotRelationship);
|
|
26481
|
-
|
|
26482
|
-
return pivot;
|
|
26541
|
+
return new XlsxPivotExtractor(pivotFile, this.xlsxFileStructure, this.warningManager).getPivotTable();
|
|
26483
26542
|
});
|
|
26484
26543
|
}
|
|
26485
26544
|
catch (e) {
|
|
@@ -26878,8 +26937,7 @@ class XlsxReader {
|
|
|
26878
26937
|
}
|
|
26879
26938
|
convertXlsx() {
|
|
26880
26939
|
const xlsxData = this.getXlsxData();
|
|
26881
|
-
|
|
26882
|
-
return convertedData;
|
|
26940
|
+
return this.convertImportedData(xlsxData);
|
|
26883
26941
|
}
|
|
26884
26942
|
// ---------------------------------------------------------------------------
|
|
26885
26943
|
// Parsing XMLs
|
|
@@ -27470,6 +27528,20 @@ migrationStepRegistry
|
|
|
27470
27528
|
}
|
|
27471
27529
|
return data;
|
|
27472
27530
|
},
|
|
27531
|
+
})
|
|
27532
|
+
.add("migration_22", {
|
|
27533
|
+
// "tables are no longer inserted with filters by default",
|
|
27534
|
+
versionFrom: "22",
|
|
27535
|
+
migrate(data) {
|
|
27536
|
+
for (const sheet of data.sheets || []) {
|
|
27537
|
+
for (const table of sheet.tables || []) {
|
|
27538
|
+
if (!table.config) {
|
|
27539
|
+
table.config = { ...DEFAULT_TABLE_CONFIG, hasFilters: true };
|
|
27540
|
+
}
|
|
27541
|
+
}
|
|
27542
|
+
}
|
|
27543
|
+
return data;
|
|
27544
|
+
},
|
|
27473
27545
|
});
|
|
27474
27546
|
function fixOverlappingFilters(data) {
|
|
27475
27547
|
for (let sheet of data.sheets || []) {
|
|
@@ -27497,7 +27569,7 @@ function fixOverlappingFilters(data) {
|
|
|
27497
27569
|
* a breaking change is made in the way the state is handled, and an upgrade
|
|
27498
27570
|
* function should be defined
|
|
27499
27571
|
*/
|
|
27500
|
-
const CURRENT_VERSION =
|
|
27572
|
+
const CURRENT_VERSION = 23;
|
|
27501
27573
|
const INITIAL_SHEET_ID = "Sheet1";
|
|
27502
27574
|
/**
|
|
27503
27575
|
* This function tries to load anything that could look like a valid
|
|
@@ -27510,7 +27582,7 @@ function load(data, verboseImport) {
|
|
|
27510
27582
|
if (!data) {
|
|
27511
27583
|
return createEmptyWorkbookData();
|
|
27512
27584
|
}
|
|
27513
|
-
console.
|
|
27585
|
+
console.debug("### Loading data ###");
|
|
27514
27586
|
const start = performance.now();
|
|
27515
27587
|
if (data["[Content_Types].xml"]) {
|
|
27516
27588
|
const reader = new XlsxReader(data);
|
|
@@ -27524,13 +27596,13 @@ function load(data, verboseImport) {
|
|
|
27524
27596
|
// apply migrations, if needed
|
|
27525
27597
|
if ("version" in data) {
|
|
27526
27598
|
if (data.version < CURRENT_VERSION) {
|
|
27527
|
-
console.
|
|
27599
|
+
console.debug("Migrating data from version", data.version);
|
|
27528
27600
|
data = migrate(data);
|
|
27529
27601
|
}
|
|
27530
27602
|
}
|
|
27531
27603
|
data = repairData(data);
|
|
27532
|
-
console.
|
|
27533
|
-
console.
|
|
27604
|
+
console.debug("Data loaded in", performance.now() - start, "ms");
|
|
27605
|
+
console.debug("###");
|
|
27534
27606
|
return data;
|
|
27535
27607
|
}
|
|
27536
27608
|
// -----------------------------------------------------------------------------
|
|
@@ -27560,7 +27632,7 @@ function migrate(data) {
|
|
|
27560
27632
|
for (let i = index; i < steps.length; i++) {
|
|
27561
27633
|
data = steps[i].migrate(data);
|
|
27562
27634
|
}
|
|
27563
|
-
console.
|
|
27635
|
+
console.debug("Data migrated in", performance.now() - start, "ms");
|
|
27564
27636
|
return data;
|
|
27565
27637
|
}
|
|
27566
27638
|
/**
|
|
@@ -27742,7 +27814,7 @@ function createEmptySheet(sheetId, name) {
|
|
|
27742
27814
|
};
|
|
27743
27815
|
}
|
|
27744
27816
|
function createEmptyWorkbookData(sheetName = "Sheet1") {
|
|
27745
|
-
|
|
27817
|
+
return {
|
|
27746
27818
|
version: CURRENT_VERSION,
|
|
27747
27819
|
sheets: [createEmptySheet(INITIAL_SHEET_ID, sheetName)],
|
|
27748
27820
|
styles: {},
|
|
@@ -27755,7 +27827,6 @@ function createEmptyWorkbookData(sheetName = "Sheet1") {
|
|
|
27755
27827
|
pivotNextId: 1,
|
|
27756
27828
|
customTableStyles: {},
|
|
27757
27829
|
};
|
|
27758
|
-
return data;
|
|
27759
27830
|
}
|
|
27760
27831
|
function createEmptyExcelSheet(sheetId, name) {
|
|
27761
27832
|
return {
|
|
@@ -28139,7 +28210,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { axisFormats, local
|
|
|
28139
28210
|
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
28140
28211
|
// tooltipItem.parsed can be an object or a number for pie charts
|
|
28141
28212
|
let yLabel = horizontalChart ? tooltipItem.parsed.x : tooltipItem.parsed.y;
|
|
28142
|
-
if (
|
|
28213
|
+
if (yLabel === undefined || yLabel === null) {
|
|
28143
28214
|
yLabel = tooltipItem.parsed;
|
|
28144
28215
|
}
|
|
28145
28216
|
const axisId = horizontalChart
|
|
@@ -28533,8 +28604,7 @@ function createBarChartRuntime(chart, getters) {
|
|
|
28533
28604
|
};
|
|
28534
28605
|
config.data.datasets.push(dataset);
|
|
28535
28606
|
if (definition.dataSets?.[index]?.label) {
|
|
28536
|
-
|
|
28537
|
-
dataset.label = label;
|
|
28607
|
+
dataset.label = definition.dataSets[index].label;
|
|
28538
28608
|
}
|
|
28539
28609
|
dataset.yAxisID = chart.horizontal ? "y" : definition.dataSets[index].yAxisId || "y";
|
|
28540
28610
|
dataset.xAxisID = "x";
|
|
@@ -28562,13 +28632,10 @@ function createBarChartRuntime(chart, getters) {
|
|
|
28562
28632
|
* datasets to ensure the way we distinguish the originals and trendLine datasets after
|
|
28563
28633
|
*/
|
|
28564
28634
|
trendDatasets.forEach((x) => config.data.datasets.push(x));
|
|
28565
|
-
const originalTooltipTitle = config.options.plugins.tooltip.callbacks.title;
|
|
28566
28635
|
config.options.plugins.tooltip.callbacks.title = function (tooltipItems) {
|
|
28567
|
-
|
|
28568
|
-
|
|
28569
|
-
|
|
28570
|
-
}
|
|
28571
|
-
return "";
|
|
28636
|
+
return tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID)
|
|
28637
|
+
? undefined
|
|
28638
|
+
: "";
|
|
28572
28639
|
};
|
|
28573
28640
|
}
|
|
28574
28641
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
@@ -28906,7 +28973,6 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28906
28973
|
else if (axisType === "linear") {
|
|
28907
28974
|
config.options.scales.x.type = "linear";
|
|
28908
28975
|
config.options.scales.x.ticks.callback = (value) => formatValue(value, { format: labelFormat, locale });
|
|
28909
|
-
config.options.plugins.tooltip.callbacks.title = () => "";
|
|
28910
28976
|
config.options.plugins.tooltip.callbacks.label = (tooltipItem) => {
|
|
28911
28977
|
const dataSetPoint = dataSetsValues[tooltipItem.datasetIndex].data[tooltipItem.dataIndex];
|
|
28912
28978
|
let label = tooltipItem.label || labelValues.values[tooltipItem.dataIndex];
|
|
@@ -28961,8 +29027,7 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28961
29027
|
const trendDatasets = [];
|
|
28962
29028
|
for (const [index, dataset] of config.data.datasets.entries()) {
|
|
28963
29029
|
if (definition.dataSets?.[index]?.label) {
|
|
28964
|
-
|
|
28965
|
-
dataset.label = label;
|
|
29030
|
+
dataset.label = definition.dataSets[index].label;
|
|
28966
29031
|
}
|
|
28967
29032
|
dataset["yAxisID"] = definition.dataSets[index].yAxisId || "y";
|
|
28968
29033
|
const trend = definition.dataSets?.[index].trend;
|
|
@@ -28991,15 +29056,12 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28991
29056
|
* distinguish the originals and trendLine datasets after
|
|
28992
29057
|
*/
|
|
28993
29058
|
trendDatasets.forEach((x) => config.data.datasets.push(x));
|
|
28994
|
-
const originalTooltipTitle = config.options.plugins.tooltip.callbacks.title;
|
|
28995
|
-
config.options.plugins.tooltip.callbacks.title = function (tooltipItems) {
|
|
28996
|
-
if (tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID)) {
|
|
28997
|
-
// @ts-expect-error
|
|
28998
|
-
return originalTooltipTitle?.(tooltipItems);
|
|
28999
|
-
}
|
|
29000
|
-
return "";
|
|
29001
|
-
};
|
|
29002
29059
|
}
|
|
29060
|
+
config.options.plugins.tooltip.callbacks.title = function (tooltipItems) {
|
|
29061
|
+
const displayTooltipTitle = axisType !== "linear" &&
|
|
29062
|
+
tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID);
|
|
29063
|
+
return displayTooltipTitle ? undefined : "";
|
|
29064
|
+
};
|
|
29003
29065
|
return {
|
|
29004
29066
|
chartJsConfig: config,
|
|
29005
29067
|
background: chart.background || BACKGROUND_CHART_COLOR,
|
|
@@ -29222,13 +29284,10 @@ function createComboChartRuntime(chart, getters) {
|
|
|
29222
29284
|
* distinguish the originals and trendLine datasets after
|
|
29223
29285
|
*/
|
|
29224
29286
|
trendDatasets.forEach((x) => config.data.datasets.push(x));
|
|
29225
|
-
const originalTooltipTitle = config.options.plugins.tooltip.callbacks.title;
|
|
29226
29287
|
config.options.plugins.tooltip.callbacks.title = function (tooltipItems) {
|
|
29227
|
-
|
|
29228
|
-
|
|
29229
|
-
|
|
29230
|
-
}
|
|
29231
|
-
return "";
|
|
29288
|
+
return tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID)
|
|
29289
|
+
? undefined
|
|
29290
|
+
: "";
|
|
29232
29291
|
};
|
|
29233
29292
|
}
|
|
29234
29293
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
@@ -29967,6 +30026,198 @@ function createPyramidChartRuntime(chart, getters) {
|
|
|
29967
30026
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
29968
30027
|
}
|
|
29969
30028
|
|
|
30029
|
+
class RadarChart extends AbstractChart {
|
|
30030
|
+
dataSets;
|
|
30031
|
+
labelRange;
|
|
30032
|
+
background;
|
|
30033
|
+
legendPosition;
|
|
30034
|
+
stacked;
|
|
30035
|
+
aggregated;
|
|
30036
|
+
type = "radar";
|
|
30037
|
+
dataSetsHaveTitle;
|
|
30038
|
+
dataSetDesign;
|
|
30039
|
+
fillArea;
|
|
30040
|
+
constructor(definition, sheetId, getters) {
|
|
30041
|
+
super(definition, sheetId, getters);
|
|
30042
|
+
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
30043
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
30044
|
+
this.background = definition.background;
|
|
30045
|
+
this.legendPosition = definition.legendPosition;
|
|
30046
|
+
this.stacked = definition.stacked;
|
|
30047
|
+
this.aggregated = definition.aggregated;
|
|
30048
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
30049
|
+
this.dataSetDesign = definition.dataSets;
|
|
30050
|
+
this.fillArea = definition.fillArea;
|
|
30051
|
+
}
|
|
30052
|
+
static transformDefinition(definition, executed) {
|
|
30053
|
+
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
30054
|
+
}
|
|
30055
|
+
static validateChartDefinition(validator, definition) {
|
|
30056
|
+
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
30057
|
+
}
|
|
30058
|
+
static getDefinitionFromContextCreation(context) {
|
|
30059
|
+
return {
|
|
30060
|
+
background: context.background,
|
|
30061
|
+
dataSets: context.range ?? [],
|
|
30062
|
+
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
30063
|
+
stacked: context.stacked ?? false,
|
|
30064
|
+
aggregated: context.aggregated ?? false,
|
|
30065
|
+
legendPosition: context.legendPosition ?? "top",
|
|
30066
|
+
title: context.title || { text: "" },
|
|
30067
|
+
type: "radar",
|
|
30068
|
+
labelRange: context.auxiliaryRange || undefined,
|
|
30069
|
+
fillArea: context.fillArea ?? false,
|
|
30070
|
+
};
|
|
30071
|
+
}
|
|
30072
|
+
getContextCreation() {
|
|
30073
|
+
const range = [];
|
|
30074
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
30075
|
+
range.push({
|
|
30076
|
+
...this.dataSetDesign?.[i],
|
|
30077
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
30078
|
+
});
|
|
30079
|
+
}
|
|
30080
|
+
return {
|
|
30081
|
+
...this,
|
|
30082
|
+
range,
|
|
30083
|
+
auxiliaryRange: this.labelRange
|
|
30084
|
+
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
30085
|
+
: undefined,
|
|
30086
|
+
};
|
|
30087
|
+
}
|
|
30088
|
+
copyForSheetId(sheetId) {
|
|
30089
|
+
const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
|
|
30090
|
+
const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
|
|
30091
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
|
|
30092
|
+
return new RadarChart(definition, sheetId, this.getters);
|
|
30093
|
+
}
|
|
30094
|
+
copyInSheetId(sheetId) {
|
|
30095
|
+
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
30096
|
+
return new RadarChart(definition, sheetId, this.getters);
|
|
30097
|
+
}
|
|
30098
|
+
getDefinition() {
|
|
30099
|
+
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
30100
|
+
}
|
|
30101
|
+
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
30102
|
+
const ranges = [];
|
|
30103
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
30104
|
+
ranges.push({
|
|
30105
|
+
...this.dataSetDesign?.[i],
|
|
30106
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
30107
|
+
});
|
|
30108
|
+
}
|
|
30109
|
+
return {
|
|
30110
|
+
type: "radar",
|
|
30111
|
+
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
30112
|
+
background: this.background,
|
|
30113
|
+
dataSets: ranges,
|
|
30114
|
+
legendPosition: this.legendPosition,
|
|
30115
|
+
labelRange: labelRange
|
|
30116
|
+
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
30117
|
+
: undefined,
|
|
30118
|
+
title: this.title,
|
|
30119
|
+
stacked: this.stacked,
|
|
30120
|
+
aggregated: this.aggregated,
|
|
30121
|
+
fillArea: this.fillArea,
|
|
30122
|
+
};
|
|
30123
|
+
}
|
|
30124
|
+
getDefinitionForExcel() {
|
|
30125
|
+
if (this.aggregated) {
|
|
30126
|
+
return undefined;
|
|
30127
|
+
}
|
|
30128
|
+
const dataSets = this.dataSets
|
|
30129
|
+
.map((ds) => toExcelDataset(this.getters, ds))
|
|
30130
|
+
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
30131
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
30132
|
+
const definition = this.getDefinition();
|
|
30133
|
+
return {
|
|
30134
|
+
...definition,
|
|
30135
|
+
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
30136
|
+
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
30137
|
+
dataSets,
|
|
30138
|
+
labelRange,
|
|
30139
|
+
};
|
|
30140
|
+
}
|
|
30141
|
+
updateRanges(applyChange) {
|
|
30142
|
+
const { dataSets, labelRange, isStale } = updateChartRangesWithDataSets(this.getters, applyChange, this.dataSets, this.labelRange);
|
|
30143
|
+
if (!isStale) {
|
|
30144
|
+
return this;
|
|
30145
|
+
}
|
|
30146
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange);
|
|
30147
|
+
return new RadarChart(definition, this.sheetId, this.getters);
|
|
30148
|
+
}
|
|
30149
|
+
}
|
|
30150
|
+
function createRadarChartRuntime(chart, getters) {
|
|
30151
|
+
const definition = chart.getDefinition();
|
|
30152
|
+
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
30153
|
+
let labels = labelValues.formattedValues;
|
|
30154
|
+
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
30155
|
+
if (chart.dataSetsHaveTitle &&
|
|
30156
|
+
dataSetsValues[0] &&
|
|
30157
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
30158
|
+
labels.shift();
|
|
30159
|
+
}
|
|
30160
|
+
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
30161
|
+
if (chart.aggregated) {
|
|
30162
|
+
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
30163
|
+
}
|
|
30164
|
+
const leftAxisFormat = getChartDatasetFormat(getters, chart.dataSets, "left");
|
|
30165
|
+
const rightAxisFormat = getChartDatasetFormat(getters, chart.dataSets, "right");
|
|
30166
|
+
const axisFormats = { y: leftAxisFormat, y1: rightAxisFormat };
|
|
30167
|
+
const locale = getters.getLocale();
|
|
30168
|
+
const fontColor = chartFontColor(chart.background);
|
|
30169
|
+
const config = getDefaultChartJsRuntime(chart, labels, fontColor, {
|
|
30170
|
+
axisFormats,
|
|
30171
|
+
locale,
|
|
30172
|
+
});
|
|
30173
|
+
const legend = {
|
|
30174
|
+
labels: { color: fontColor },
|
|
30175
|
+
};
|
|
30176
|
+
if ((!chart.labelRange && chart.dataSets.length === 1) || chart.legendPosition === "none") {
|
|
30177
|
+
legend.display = false;
|
|
30178
|
+
}
|
|
30179
|
+
else {
|
|
30180
|
+
legend.position = chart.legendPosition;
|
|
30181
|
+
}
|
|
30182
|
+
const fill = definition.fillArea ?? false;
|
|
30183
|
+
if (!fill) {
|
|
30184
|
+
legend.labels["boxHeight"] = 0;
|
|
30185
|
+
}
|
|
30186
|
+
config.options.plugins.legend = { ...config.options.plugins?.legend, ...legend };
|
|
30187
|
+
config.options.plugins.tooltip = {
|
|
30188
|
+
...config.options.plugins?.tooltip,
|
|
30189
|
+
callbacks: {
|
|
30190
|
+
label: function (tooltipItem) {
|
|
30191
|
+
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
30192
|
+
const yLabel = tooltipItem.parsed.r;
|
|
30193
|
+
return xLabel ? `${xLabel}: ${yLabel}` : yLabel.toString();
|
|
30194
|
+
},
|
|
30195
|
+
},
|
|
30196
|
+
};
|
|
30197
|
+
config.options.layout = {
|
|
30198
|
+
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
|
|
30199
|
+
};
|
|
30200
|
+
const colorGenerator = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
30201
|
+
for (let i = 0; i < dataSetsValues.length; i++) {
|
|
30202
|
+
let { label, data } = dataSetsValues[i];
|
|
30203
|
+
if (definition.dataSets?.[i]?.label) {
|
|
30204
|
+
label = definition.dataSets[i].label;
|
|
30205
|
+
}
|
|
30206
|
+
const borderColor = colorGenerator.next();
|
|
30207
|
+
const dataset = {
|
|
30208
|
+
label,
|
|
30209
|
+
data,
|
|
30210
|
+
borderColor,
|
|
30211
|
+
};
|
|
30212
|
+
if (fill) {
|
|
30213
|
+
dataset.backgroundColor = setColorAlpha(borderColor, 0.3);
|
|
30214
|
+
dataset["fill"] = true;
|
|
30215
|
+
}
|
|
30216
|
+
config.data.datasets.push(dataset);
|
|
30217
|
+
}
|
|
30218
|
+
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
30219
|
+
}
|
|
30220
|
+
|
|
29970
30221
|
class ScatterChart extends AbstractChart {
|
|
29971
30222
|
dataSets;
|
|
29972
30223
|
labelRange;
|
|
@@ -30489,6 +30740,15 @@ chartRegistry.add("pyramid", {
|
|
|
30489
30740
|
getChartDefinitionFromContextCreation: PyramidChart.getDefinitionFromContextCreation,
|
|
30490
30741
|
sequence: 80,
|
|
30491
30742
|
});
|
|
30743
|
+
chartRegistry.add("radar", {
|
|
30744
|
+
match: (type) => type === "radar",
|
|
30745
|
+
createChart: (definition, sheetId, getters) => new RadarChart(definition, sheetId, getters),
|
|
30746
|
+
getChartRuntime: createRadarChartRuntime,
|
|
30747
|
+
validateChartDefinition: RadarChart.validateChartDefinition,
|
|
30748
|
+
transformDefinition: RadarChart.transformDefinition,
|
|
30749
|
+
getChartDefinitionFromContextCreation: RadarChart.getDefinitionFromContextCreation,
|
|
30750
|
+
sequence: 80,
|
|
30751
|
+
});
|
|
30492
30752
|
const chartComponentRegistry = new Registry();
|
|
30493
30753
|
chartComponentRegistry.add("line", ChartJsComponent);
|
|
30494
30754
|
chartComponentRegistry.add("bar", ChartJsComponent);
|
|
@@ -30499,6 +30759,7 @@ chartComponentRegistry.add("scatter", ChartJsComponent);
|
|
|
30499
30759
|
chartComponentRegistry.add("scorecard", ScorecardChart);
|
|
30500
30760
|
chartComponentRegistry.add("waterfall", ChartJsComponent);
|
|
30501
30761
|
chartComponentRegistry.add("pyramid", ChartJsComponent);
|
|
30762
|
+
chartComponentRegistry.add("radar", ChartJsComponent);
|
|
30502
30763
|
const chartCategories = {
|
|
30503
30764
|
line: _t("Line"),
|
|
30504
30765
|
column: _t("Column"),
|
|
@@ -30640,6 +30901,24 @@ chartSubtypeRegistry
|
|
|
30640
30901
|
chartType: "pyramid",
|
|
30641
30902
|
category: "misc",
|
|
30642
30903
|
preview: "o-spreadsheet-ChartPreview.POPULATION_PYRAMID_CHART",
|
|
30904
|
+
})
|
|
30905
|
+
.add("radar", {
|
|
30906
|
+
matcher: (definition) => definition.type === "radar" && !definition.fillArea,
|
|
30907
|
+
displayName: _t("Radar"),
|
|
30908
|
+
chartSubtype: "radar",
|
|
30909
|
+
chartType: "radar",
|
|
30910
|
+
subtypeDefinition: { fillArea: false },
|
|
30911
|
+
category: "misc",
|
|
30912
|
+
preview: "o-spreadsheet-ChartPreview.RADAR_CHART",
|
|
30913
|
+
})
|
|
30914
|
+
.add("filled_radar", {
|
|
30915
|
+
matcher: (definition) => definition.type === "radar" && !!definition.fillArea,
|
|
30916
|
+
displayName: _t("Filled Radar"),
|
|
30917
|
+
chartType: "radar",
|
|
30918
|
+
chartSubtype: "filled_radar",
|
|
30919
|
+
subtypeDefinition: { fillArea: true },
|
|
30920
|
+
category: "misc",
|
|
30921
|
+
preview: "o-spreadsheet-ChartPreview.FILLED_RADAR_CHART",
|
|
30643
30922
|
});
|
|
30644
30923
|
|
|
30645
30924
|
/**
|
|
@@ -30707,11 +30986,10 @@ function centerFigurePosition(getters, size) {
|
|
|
30707
30986
|
const rect = getters.getVisibleRect(getters.getActiveMainViewport());
|
|
30708
30987
|
const scrollableViewportWidth = Math.min(rect.width, dim.width - offsetCorrectionX);
|
|
30709
30988
|
const scrollableViewportHeight = Math.min(rect.height, dim.height - offsetCorrectionY);
|
|
30710
|
-
|
|
30989
|
+
return {
|
|
30711
30990
|
x: offsetCorrectionX + scrollX + Math.max(0, (scrollableViewportWidth - size.width) / 2),
|
|
30712
30991
|
y: offsetCorrectionY + scrollY + Math.max(0, (scrollableViewportHeight - size.height) / 2),
|
|
30713
30992
|
}; // Position at the center of the scrollable viewport
|
|
30714
|
-
return position;
|
|
30715
30993
|
}
|
|
30716
30994
|
function getMaxFigureSize(getters, figureSize) {
|
|
30717
30995
|
const size = deepCopy(figureSize);
|
|
@@ -31284,14 +31562,13 @@ class PopoverPositionContext {
|
|
|
31284
31562
|
const shouldRenderAtBottom = this.shouldRenderAtBottom(elDims.height);
|
|
31285
31563
|
const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
|
|
31286
31564
|
verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
|
|
31287
|
-
|
|
31565
|
+
return {
|
|
31288
31566
|
top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
|
|
31289
31567
|
this.spreadsheetOffset.y -
|
|
31290
31568
|
verticalOffset +
|
|
31291
31569
|
"px",
|
|
31292
31570
|
left: this.getLeftCoordinate(actualWidth, shouldRenderAtRight) - this.spreadsheetOffset.x + "px",
|
|
31293
31571
|
};
|
|
31294
|
-
return cssProperties;
|
|
31295
31572
|
}
|
|
31296
31573
|
getCurrentPosition(elDims) {
|
|
31297
31574
|
const shouldRenderAtBottom = this.shouldRenderAtBottom(elDims.height);
|
|
@@ -32519,7 +32796,7 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
32519
32796
|
* Create a table on the selected zone, with UI warnings to the user if the creation fails.
|
|
32520
32797
|
* If a single cell is selected, expand the selection to non-empty adjacent cells to create a table.
|
|
32521
32798
|
*/
|
|
32522
|
-
function interactiveCreateTable(env, sheetId, tableConfig) {
|
|
32799
|
+
function interactiveCreateTable(env, sheetId, tableConfig = DEFAULT_TABLE_CONFIG) {
|
|
32523
32800
|
let target = env.model.getters.getSelectedZones();
|
|
32524
32801
|
let isDynamic = env.model.getters.canCreateDynamicTableOnZones(sheetId, target);
|
|
32525
32802
|
if (target.length === 1 && !isDynamic && getZoneArea(target[0]) === 1) {
|
|
@@ -33578,7 +33855,7 @@ function getColumnsNumber(env) {
|
|
|
33578
33855
|
}
|
|
33579
33856
|
|
|
33580
33857
|
const pivotProperties = {
|
|
33581
|
-
name: _t("
|
|
33858
|
+
name: _t("See pivot properties"),
|
|
33582
33859
|
execute(env) {
|
|
33583
33860
|
const position = env.model.getters.getActivePosition();
|
|
33584
33861
|
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
@@ -33732,8 +34009,7 @@ cellMenuRegistry
|
|
|
33732
34009
|
})
|
|
33733
34010
|
.add("pivot_properties", {
|
|
33734
34011
|
...pivotProperties,
|
|
33735
|
-
sequence:
|
|
33736
|
-
separator: true,
|
|
34012
|
+
sequence: 170,
|
|
33737
34013
|
});
|
|
33738
34014
|
|
|
33739
34015
|
const sortRange = {
|
|
@@ -35480,6 +35756,7 @@ class Section extends owl.Component {
|
|
|
35480
35756
|
static template = "o_spreadsheet.Section";
|
|
35481
35757
|
static props = {
|
|
35482
35758
|
class: { type: String, optional: true },
|
|
35759
|
+
title: { type: String, optional: true },
|
|
35483
35760
|
slots: Object,
|
|
35484
35761
|
};
|
|
35485
35762
|
}
|
|
@@ -36209,17 +36486,11 @@ class BarConfigPanel extends GenericChartConfigPanel {
|
|
|
36209
36486
|
stacked,
|
|
36210
36487
|
});
|
|
36211
36488
|
}
|
|
36212
|
-
onUpdateAggregated(aggregated) {
|
|
36213
|
-
this.props.updateChart(this.props.figureId, {
|
|
36214
|
-
aggregated,
|
|
36215
|
-
});
|
|
36216
|
-
}
|
|
36217
36489
|
}
|
|
36218
36490
|
|
|
36219
36491
|
css /* scss */ `
|
|
36220
36492
|
.o_side_panel_collapsible_title {
|
|
36221
36493
|
font-size: 16px;
|
|
36222
|
-
font-weight: bold;
|
|
36223
36494
|
cursor: pointer;
|
|
36224
36495
|
padding: 6px 0px 6px 6px !important;
|
|
36225
36496
|
|
|
@@ -36256,49 +36527,40 @@ class SidePanelCollapsible extends owl.Component {
|
|
|
36256
36527
|
static template = "o-spreadsheet-SidePanelCollapsible";
|
|
36257
36528
|
static props = {
|
|
36258
36529
|
slots: Object,
|
|
36530
|
+
title: { type: String, optional: true },
|
|
36259
36531
|
collapsedAtInit: { type: Boolean, optional: true },
|
|
36260
36532
|
class: { type: String, optional: true },
|
|
36261
36533
|
};
|
|
36262
36534
|
currentId = (CURRENT_COLLAPSIBLE_ID++).toString();
|
|
36263
36535
|
}
|
|
36264
36536
|
|
|
36265
|
-
const CIRCLE_SVG = /*xml*/ `
|
|
36266
|
-
<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'>
|
|
36267
|
-
<circle r="2" fill="#FFF"/>
|
|
36268
|
-
</svg>
|
|
36269
|
-
`;
|
|
36270
36537
|
css /* scss */ `
|
|
36271
|
-
.o-
|
|
36272
|
-
|
|
36273
|
-
|
|
36274
|
-
-
|
|
36275
|
-
|
|
36276
|
-
|
|
36277
|
-
height: 14px;
|
|
36278
|
-
border: 1px solid ${GRAY_300};
|
|
36279
|
-
box-sizing: border-box;
|
|
36280
|
-
outline: none;
|
|
36281
|
-
border-radius: 8px;
|
|
36282
|
-
|
|
36283
|
-
&:checked {
|
|
36284
|
-
background: url("data:image/svg+xml,${encodeURIComponent(CIRCLE_SVG)}");
|
|
36285
|
-
background-color: ${ACTION_COLOR};
|
|
36538
|
+
.o-badge-selection {
|
|
36539
|
+
gap: 1px;
|
|
36540
|
+
button.o-button {
|
|
36541
|
+
border-radius: 0;
|
|
36542
|
+
&.selected {
|
|
36543
|
+
color: ${GRAY_900};
|
|
36286
36544
|
border-color: ${ACTION_COLOR};
|
|
36545
|
+
background: ${BADGE_SELECTED_COLOR};
|
|
36546
|
+
font-weight: 600;
|
|
36547
|
+
}
|
|
36548
|
+
|
|
36549
|
+
&:first-child {
|
|
36550
|
+
border-radius: 4px 0 0 4px;
|
|
36551
|
+
}
|
|
36552
|
+
&:last-child {
|
|
36553
|
+
border-radius: 0 4px 4px 0;
|
|
36287
36554
|
}
|
|
36288
36555
|
}
|
|
36289
36556
|
}
|
|
36290
36557
|
`;
|
|
36291
|
-
class
|
|
36292
|
-
static template = "o-spreadsheet.
|
|
36558
|
+
class BadgeSelection extends owl.Component {
|
|
36559
|
+
static template = "o-spreadsheet.BadgeSelection";
|
|
36293
36560
|
static props = {
|
|
36294
36561
|
choices: Array,
|
|
36295
36562
|
onChange: Function,
|
|
36296
|
-
selectedValue:
|
|
36297
|
-
name: String,
|
|
36298
|
-
direction: { type: String, optional: true },
|
|
36299
|
-
};
|
|
36300
|
-
static defaultProps = {
|
|
36301
|
-
direction: "horizontal",
|
|
36563
|
+
selectedValue: String,
|
|
36302
36564
|
};
|
|
36303
36565
|
}
|
|
36304
36566
|
|
|
@@ -36843,86 +37105,6 @@ class ColorPickerWidget extends owl.Component {
|
|
|
36843
37105
|
}
|
|
36844
37106
|
}
|
|
36845
37107
|
|
|
36846
|
-
const TRANSPARENT_BACKGROUND_SVG = /*xml*/ `
|
|
36847
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">
|
|
36848
|
-
<path fill="#d9d9d9" d="M5 5h5v5H5zH0V0h5"/>
|
|
36849
|
-
</svg>
|
|
36850
|
-
`;
|
|
36851
|
-
css /* scss */ `
|
|
36852
|
-
.o-round-color-picker-button {
|
|
36853
|
-
width: 18px;
|
|
36854
|
-
height: 18px;
|
|
36855
|
-
cursor: pointer;
|
|
36856
|
-
border: 1px solid ${GRAY_300};
|
|
36857
|
-
background-position: 1px 1px;
|
|
36858
|
-
background-image: url("data:image/svg+xml,${encodeURIComponent(TRANSPARENT_BACKGROUND_SVG)}");
|
|
36859
|
-
}
|
|
36860
|
-
`;
|
|
36861
|
-
class RoundColorPicker extends owl.Component {
|
|
36862
|
-
static template = "o-spreadsheet.RoundColorPicker";
|
|
36863
|
-
static components = { ColorPickerWidget, Section, ColorPicker };
|
|
36864
|
-
static props = {
|
|
36865
|
-
currentColor: { type: String, optional: true },
|
|
36866
|
-
title: { type: String, optional: true },
|
|
36867
|
-
onColorPicked: Function,
|
|
36868
|
-
};
|
|
36869
|
-
colorPickerButtonRef = owl.useRef("colorPickerButton");
|
|
36870
|
-
state;
|
|
36871
|
-
setup() {
|
|
36872
|
-
this.state = owl.useState({ pickerOpened: false });
|
|
36873
|
-
owl.useExternalListener(window, "click", this.closePicker);
|
|
36874
|
-
}
|
|
36875
|
-
closePicker() {
|
|
36876
|
-
this.state.pickerOpened = false;
|
|
36877
|
-
}
|
|
36878
|
-
togglePicker() {
|
|
36879
|
-
this.state.pickerOpened = !this.state.pickerOpened;
|
|
36880
|
-
}
|
|
36881
|
-
onColorPicked(color) {
|
|
36882
|
-
this.props.onColorPicked(color);
|
|
36883
|
-
this.state.pickerOpened = false;
|
|
36884
|
-
}
|
|
36885
|
-
get colorPickerAnchorRect() {
|
|
36886
|
-
const button = this.colorPickerButtonRef.el;
|
|
36887
|
-
return getBoundingRectAsPOJO(button);
|
|
36888
|
-
}
|
|
36889
|
-
get buttonStyle() {
|
|
36890
|
-
return cssPropertiesToCss({
|
|
36891
|
-
background: this.props.currentColor,
|
|
36892
|
-
});
|
|
36893
|
-
}
|
|
36894
|
-
}
|
|
36895
|
-
|
|
36896
|
-
css /* scss */ `
|
|
36897
|
-
.o-badge-selection {
|
|
36898
|
-
gap: 1px;
|
|
36899
|
-
button.o-button {
|
|
36900
|
-
border-radius: 0;
|
|
36901
|
-
&.selected {
|
|
36902
|
-
color: ${GRAY_900};
|
|
36903
|
-
border-color: ${ACTION_COLOR};
|
|
36904
|
-
background: ${BADGE_SELECTED_COLOR};
|
|
36905
|
-
font-weight: 600;
|
|
36906
|
-
}
|
|
36907
|
-
|
|
36908
|
-
&:first-child {
|
|
36909
|
-
border-radius: 4px 0 0 4px;
|
|
36910
|
-
}
|
|
36911
|
-
&:last-child {
|
|
36912
|
-
border-radius: 0 4px 4px 0;
|
|
36913
|
-
}
|
|
36914
|
-
}
|
|
36915
|
-
}
|
|
36916
|
-
`;
|
|
36917
|
-
class BadgeSelection extends owl.Component {
|
|
36918
|
-
static template = "o-spreadsheet.BadgeSelection";
|
|
36919
|
-
static props = {
|
|
36920
|
-
choices: Array,
|
|
36921
|
-
onChange: Function,
|
|
36922
|
-
selectedValue: String,
|
|
36923
|
-
};
|
|
36924
|
-
}
|
|
36925
|
-
|
|
36926
37108
|
css /* scss */ `
|
|
36927
37109
|
.o-chart-title-designer {
|
|
36928
37110
|
> span {
|
|
@@ -37077,8 +37259,7 @@ class AxisDesignEditor extends owl.Component {
|
|
|
37077
37259
|
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
37078
37260
|
}
|
|
37079
37261
|
updateAxisEditor(ev) {
|
|
37080
|
-
|
|
37081
|
-
this.state.currentAxis = axis;
|
|
37262
|
+
this.state.currentAxis = ev.target.value;
|
|
37082
37263
|
}
|
|
37083
37264
|
getAxisTitle() {
|
|
37084
37265
|
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
@@ -37097,6 +37278,56 @@ class AxisDesignEditor extends owl.Component {
|
|
|
37097
37278
|
}
|
|
37098
37279
|
}
|
|
37099
37280
|
|
|
37281
|
+
const TRANSPARENT_BACKGROUND_SVG = /*xml*/ `
|
|
37282
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">
|
|
37283
|
+
<path fill="#d9d9d9" d="M5 5h5v5H5zH0V0h5"/>
|
|
37284
|
+
</svg>
|
|
37285
|
+
`;
|
|
37286
|
+
css /* scss */ `
|
|
37287
|
+
.o-round-color-picker-button {
|
|
37288
|
+
width: 18px;
|
|
37289
|
+
height: 18px;
|
|
37290
|
+
cursor: pointer;
|
|
37291
|
+
border: 1px solid ${GRAY_300};
|
|
37292
|
+
background-position: 1px 1px;
|
|
37293
|
+
background-image: url("data:image/svg+xml,${encodeURIComponent(TRANSPARENT_BACKGROUND_SVG)}");
|
|
37294
|
+
}
|
|
37295
|
+
`;
|
|
37296
|
+
class RoundColorPicker extends owl.Component {
|
|
37297
|
+
static template = "o-spreadsheet.RoundColorPicker";
|
|
37298
|
+
static components = { Section, ColorPicker };
|
|
37299
|
+
static props = {
|
|
37300
|
+
currentColor: { type: String, optional: true },
|
|
37301
|
+
title: { type: String, optional: true },
|
|
37302
|
+
onColorPicked: Function,
|
|
37303
|
+
};
|
|
37304
|
+
colorPickerButtonRef = owl.useRef("colorPickerButton");
|
|
37305
|
+
state;
|
|
37306
|
+
setup() {
|
|
37307
|
+
this.state = owl.useState({ pickerOpened: false });
|
|
37308
|
+
owl.useExternalListener(window, "click", this.closePicker);
|
|
37309
|
+
}
|
|
37310
|
+
closePicker() {
|
|
37311
|
+
this.state.pickerOpened = false;
|
|
37312
|
+
}
|
|
37313
|
+
togglePicker() {
|
|
37314
|
+
this.state.pickerOpened = !this.state.pickerOpened;
|
|
37315
|
+
}
|
|
37316
|
+
onColorPicked(color) {
|
|
37317
|
+
this.props.onColorPicked(color);
|
|
37318
|
+
this.state.pickerOpened = false;
|
|
37319
|
+
}
|
|
37320
|
+
get colorPickerAnchorRect() {
|
|
37321
|
+
const button = this.colorPickerButtonRef.el;
|
|
37322
|
+
return getBoundingRectAsPOJO(button);
|
|
37323
|
+
}
|
|
37324
|
+
get buttonStyle() {
|
|
37325
|
+
return cssPropertiesToCss({
|
|
37326
|
+
background: this.props.currentColor,
|
|
37327
|
+
});
|
|
37328
|
+
}
|
|
37329
|
+
}
|
|
37330
|
+
|
|
37100
37331
|
class GeneralDesignEditor extends owl.Component {
|
|
37101
37332
|
static template = "o-spreadsheet-GeneralDesignEditor";
|
|
37102
37333
|
static components = {
|
|
@@ -37161,58 +37392,75 @@ class GeneralDesignEditor extends owl.Component {
|
|
|
37161
37392
|
}
|
|
37162
37393
|
}
|
|
37163
37394
|
|
|
37164
|
-
|
|
37165
|
-
|
|
37395
|
+
const CIRCLE_SVG = /*xml*/ `
|
|
37396
|
+
<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'>
|
|
37397
|
+
<circle r="2" fill="#FFF"/>
|
|
37398
|
+
</svg>
|
|
37399
|
+
`;
|
|
37400
|
+
css /* scss */ `
|
|
37401
|
+
.o-radio {
|
|
37402
|
+
input {
|
|
37403
|
+
appearance: none;
|
|
37404
|
+
-webkit-appearance: none;
|
|
37405
|
+
-moz-appearance: none;
|
|
37406
|
+
width: 14px;
|
|
37407
|
+
height: 14px;
|
|
37408
|
+
border: 1px solid ${GRAY_300};
|
|
37409
|
+
box-sizing: border-box;
|
|
37410
|
+
outline: none;
|
|
37411
|
+
border-radius: 8px;
|
|
37412
|
+
|
|
37413
|
+
&:checked {
|
|
37414
|
+
background: url("data:image/svg+xml,${encodeURIComponent(CIRCLE_SVG)}");
|
|
37415
|
+
background-color: ${ACTION_COLOR};
|
|
37416
|
+
border-color: ${ACTION_COLOR};
|
|
37417
|
+
}
|
|
37418
|
+
}
|
|
37419
|
+
}
|
|
37420
|
+
`;
|
|
37421
|
+
class RadioSelection extends owl.Component {
|
|
37422
|
+
static template = "o-spreadsheet.RadioSelection";
|
|
37423
|
+
static props = {
|
|
37424
|
+
choices: Array,
|
|
37425
|
+
onChange: Function,
|
|
37426
|
+
selectedValue: { optional: false },
|
|
37427
|
+
name: String,
|
|
37428
|
+
direction: { type: String, optional: true },
|
|
37429
|
+
};
|
|
37430
|
+
static defaultProps = {
|
|
37431
|
+
direction: "horizontal",
|
|
37432
|
+
};
|
|
37433
|
+
}
|
|
37434
|
+
|
|
37435
|
+
class SeriesDesignEditor extends owl.Component {
|
|
37436
|
+
static template = "o-spreadsheet-SeriesDesignEditor";
|
|
37166
37437
|
static components = {
|
|
37167
|
-
GeneralDesignEditor,
|
|
37168
37438
|
SidePanelCollapsible,
|
|
37169
37439
|
Section,
|
|
37170
|
-
AxisDesignEditor,
|
|
37171
37440
|
RoundColorPicker,
|
|
37172
|
-
Checkbox,
|
|
37173
|
-
RadioSelection,
|
|
37174
37441
|
};
|
|
37175
37442
|
static props = {
|
|
37176
37443
|
figureId: String,
|
|
37177
37444
|
definition: Object,
|
|
37178
|
-
canUpdateChart: Function,
|
|
37179
37445
|
updateChart: Function,
|
|
37446
|
+
canUpdateChart: Function,
|
|
37447
|
+
slots: { type: Object, optional: true },
|
|
37180
37448
|
};
|
|
37181
|
-
axisChoices = CHART_AXIS_CHOICES;
|
|
37182
37449
|
state = owl.useState({ index: 0 });
|
|
37183
|
-
get axesList() {
|
|
37184
|
-
const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
|
|
37185
|
-
let axes = [{ id: "x", name: _t("Horizontal axis") }];
|
|
37186
|
-
if (useLeftAxis) {
|
|
37187
|
-
axes.push({ id: "y", name: useRightAxis ? _t("Left axis") : _t("Vertical axis") });
|
|
37188
|
-
}
|
|
37189
|
-
if (useRightAxis) {
|
|
37190
|
-
axes.push({ id: "y1", name: useLeftAxis ? _t("Right axis") : _t("Vertical axis") });
|
|
37191
|
-
}
|
|
37192
|
-
return axes;
|
|
37193
|
-
}
|
|
37194
|
-
updateLegendPosition(ev) {
|
|
37195
|
-
this.props.updateChart(this.props.figureId, {
|
|
37196
|
-
legendPosition: ev.target.value,
|
|
37197
|
-
});
|
|
37198
|
-
}
|
|
37199
37450
|
getDataSeries() {
|
|
37200
|
-
|
|
37451
|
+
const runtime = this.env.model.getters.getChartRuntime(this.props.figureId);
|
|
37452
|
+
if (!runtime || !("chartJsConfig" in runtime)) {
|
|
37453
|
+
return [];
|
|
37454
|
+
}
|
|
37455
|
+
return runtime.chartJsConfig.data.datasets.map((d) => d.label);
|
|
37201
37456
|
}
|
|
37202
37457
|
updateSerieEditor(ev) {
|
|
37203
|
-
|
|
37204
|
-
const selectedIndex = ev.target.selectedIndex;
|
|
37205
|
-
const runtime = this.env.model.getters.getChartRuntime(chartId);
|
|
37206
|
-
if (!runtime) {
|
|
37207
|
-
return;
|
|
37208
|
-
}
|
|
37209
|
-
this.state.index = selectedIndex;
|
|
37458
|
+
this.state.index = ev.target.selectedIndex;
|
|
37210
37459
|
}
|
|
37211
37460
|
updateDataSeriesColor(color) {
|
|
37212
|
-
const dataSets =
|
|
37213
|
-
if (!dataSets?.[this.state.index])
|
|
37461
|
+
const dataSets = this.props.definition.dataSets;
|
|
37462
|
+
if (!dataSets?.[this.state.index])
|
|
37214
37463
|
return;
|
|
37215
|
-
}
|
|
37216
37464
|
dataSets[this.state.index] = {
|
|
37217
37465
|
...dataSets[this.state.index],
|
|
37218
37466
|
backgroundColor: color,
|
|
@@ -37221,71 +37469,87 @@ class ChartWithAxisDesignPanel extends owl.Component {
|
|
|
37221
37469
|
}
|
|
37222
37470
|
getDataSerieColor() {
|
|
37223
37471
|
const dataSets = this.props.definition.dataSets;
|
|
37224
|
-
if (!dataSets?.[this.state.index])
|
|
37472
|
+
if (!dataSets?.[this.state.index])
|
|
37225
37473
|
return "";
|
|
37226
|
-
}
|
|
37227
37474
|
const color = dataSets[this.state.index].backgroundColor;
|
|
37228
|
-
return color
|
|
37475
|
+
return color
|
|
37476
|
+
? toHex(color)
|
|
37477
|
+
: getNthColor(this.state.index, getColorsPalette(this.props.definition.dataSets.length));
|
|
37229
37478
|
}
|
|
37230
|
-
|
|
37231
|
-
const
|
|
37232
|
-
|
|
37479
|
+
updateDataSeriesLabel(ev) {
|
|
37480
|
+
const label = ev.target.value;
|
|
37481
|
+
const dataSets = this.props.definition.dataSets;
|
|
37482
|
+
if (!dataSets?.[this.state.index])
|
|
37233
37483
|
return;
|
|
37234
|
-
}
|
|
37235
37484
|
dataSets[this.state.index] = {
|
|
37236
37485
|
...dataSets[this.state.index],
|
|
37237
|
-
|
|
37486
|
+
label,
|
|
37238
37487
|
};
|
|
37239
37488
|
this.props.updateChart(this.props.figureId, { dataSets });
|
|
37240
37489
|
}
|
|
37241
|
-
|
|
37490
|
+
getDataSerieLabel() {
|
|
37242
37491
|
const dataSets = this.props.definition.dataSets;
|
|
37243
|
-
|
|
37244
|
-
return "left";
|
|
37245
|
-
}
|
|
37246
|
-
return dataSets[this.state.index].yAxisId === "y1" ? "right" : "left";
|
|
37247
|
-
}
|
|
37248
|
-
get canHaveTwoVerticalAxis() {
|
|
37249
|
-
return "horizontal" in this.props.definition ? !this.props.definition.horizontal : true;
|
|
37492
|
+
return dataSets[this.state.index]?.label || this.getDataSeries()[this.state.index];
|
|
37250
37493
|
}
|
|
37251
|
-
|
|
37252
|
-
|
|
37494
|
+
}
|
|
37495
|
+
|
|
37496
|
+
class SeriesWithAxisDesignEditor extends owl.Component {
|
|
37497
|
+
static template = "o-spreadsheet-SeriesWithAxisDesignEditor";
|
|
37498
|
+
static components = {
|
|
37499
|
+
SeriesDesignEditor,
|
|
37500
|
+
Checkbox,
|
|
37501
|
+
RadioSelection,
|
|
37502
|
+
Section,
|
|
37503
|
+
RoundColorPicker,
|
|
37504
|
+
};
|
|
37505
|
+
static props = {
|
|
37506
|
+
figureId: String,
|
|
37507
|
+
definition: Object,
|
|
37508
|
+
canUpdateChart: Function,
|
|
37509
|
+
updateChart: Function,
|
|
37510
|
+
slots: { type: Object, optional: true },
|
|
37511
|
+
};
|
|
37512
|
+
axisChoices = CHART_AXIS_CHOICES;
|
|
37513
|
+
updateDataSeriesAxis(index, axis) {
|
|
37253
37514
|
const dataSets = [...this.props.definition.dataSets];
|
|
37254
|
-
if (!dataSets?.[
|
|
37515
|
+
if (!dataSets?.[index]) {
|
|
37255
37516
|
return;
|
|
37256
37517
|
}
|
|
37257
|
-
dataSets[
|
|
37258
|
-
...dataSets[
|
|
37259
|
-
|
|
37518
|
+
dataSets[index] = {
|
|
37519
|
+
...dataSets[index],
|
|
37520
|
+
yAxisId: axis === "left" ? "y" : "y1",
|
|
37260
37521
|
};
|
|
37261
37522
|
this.props.updateChart(this.props.figureId, { dataSets });
|
|
37262
37523
|
}
|
|
37263
|
-
|
|
37524
|
+
getDataSerieAxis(index) {
|
|
37264
37525
|
const dataSets = this.props.definition.dataSets;
|
|
37265
|
-
|
|
37526
|
+
if (!dataSets?.[index]) {
|
|
37527
|
+
return "left";
|
|
37528
|
+
}
|
|
37529
|
+
return dataSets[index].yAxisId === "y1" ? "right" : "left";
|
|
37266
37530
|
}
|
|
37267
|
-
|
|
37268
|
-
this.props.
|
|
37531
|
+
get canHaveTwoVerticalAxis() {
|
|
37532
|
+
return !("horizontal" in this.props.definition && this.props.definition.horizontal);
|
|
37269
37533
|
}
|
|
37270
|
-
toggleDataTrend(display) {
|
|
37534
|
+
toggleDataTrend(index, display) {
|
|
37271
37535
|
const dataSets = [...this.props.definition.dataSets];
|
|
37272
|
-
if (!dataSets?.[
|
|
37536
|
+
if (!dataSets?.[index]) {
|
|
37273
37537
|
return;
|
|
37274
37538
|
}
|
|
37275
|
-
dataSets[
|
|
37276
|
-
...dataSets[
|
|
37539
|
+
dataSets[index] = {
|
|
37540
|
+
...dataSets[index],
|
|
37277
37541
|
trend: {
|
|
37278
37542
|
type: "polynomial",
|
|
37279
37543
|
order: 1,
|
|
37280
|
-
...dataSets[
|
|
37544
|
+
...dataSets[index].trend,
|
|
37281
37545
|
display,
|
|
37282
37546
|
},
|
|
37283
37547
|
};
|
|
37284
37548
|
this.props.updateChart(this.props.figureId, { dataSets });
|
|
37285
37549
|
}
|
|
37286
|
-
getTrendLineConfiguration() {
|
|
37550
|
+
getTrendLineConfiguration(index) {
|
|
37287
37551
|
const dataSets = this.props.definition.dataSets;
|
|
37288
|
-
return dataSets?.[
|
|
37552
|
+
return dataSets?.[index]?.trend;
|
|
37289
37553
|
}
|
|
37290
37554
|
getTrendType(config) {
|
|
37291
37555
|
if (!config) {
|
|
@@ -37293,7 +37557,7 @@ class ChartWithAxisDesignPanel extends owl.Component {
|
|
|
37293
37557
|
}
|
|
37294
37558
|
return config.type === "polynomial" && config.order === 1 ? "linear" : config.type;
|
|
37295
37559
|
}
|
|
37296
|
-
onChangeTrendType(ev) {
|
|
37560
|
+
onChangeTrendType(index, ev) {
|
|
37297
37561
|
const type = ev.target.value;
|
|
37298
37562
|
let config;
|
|
37299
37563
|
switch (type) {
|
|
@@ -37306,37 +37570,59 @@ class ChartWithAxisDesignPanel extends owl.Component {
|
|
|
37306
37570
|
break;
|
|
37307
37571
|
case "exponential":
|
|
37308
37572
|
case "logarithmic":
|
|
37573
|
+
case "trailingMovingAverage":
|
|
37309
37574
|
config = { type };
|
|
37310
37575
|
break;
|
|
37311
37576
|
default:
|
|
37312
37577
|
return;
|
|
37313
37578
|
}
|
|
37314
|
-
this.updateTrendLineValue(config);
|
|
37579
|
+
this.updateTrendLineValue(index, config);
|
|
37315
37580
|
}
|
|
37316
|
-
onChangePolynomialDegree(ev) {
|
|
37581
|
+
onChangePolynomialDegree(index, ev) {
|
|
37317
37582
|
const element = ev.target;
|
|
37318
37583
|
const order = parseInt(element.value || "1");
|
|
37319
37584
|
if (order < 2) {
|
|
37320
|
-
element.value = `${this.getTrendLineConfiguration()?.order ?? 2}`;
|
|
37585
|
+
element.value = `${this.getTrendLineConfiguration(index)?.order ?? 2}`;
|
|
37321
37586
|
return;
|
|
37322
37587
|
}
|
|
37323
|
-
this.updateTrendLineValue({ order });
|
|
37588
|
+
this.updateTrendLineValue(index, { order });
|
|
37324
37589
|
}
|
|
37325
|
-
|
|
37326
|
-
return
|
|
37590
|
+
get defaultWindowSize() {
|
|
37591
|
+
return DEFAULT_WINDOW_SIZE;
|
|
37327
37592
|
}
|
|
37328
|
-
|
|
37329
|
-
|
|
37593
|
+
onChangeMovingAverageWindow(index, ev) {
|
|
37594
|
+
const element = ev.target;
|
|
37595
|
+
let window = parseInt(element.value) || DEFAULT_WINDOW_SIZE;
|
|
37596
|
+
if (window <= 1) {
|
|
37597
|
+
window = DEFAULT_WINDOW_SIZE;
|
|
37598
|
+
}
|
|
37599
|
+
this.updateTrendLineValue(index, { window });
|
|
37330
37600
|
}
|
|
37331
|
-
|
|
37601
|
+
getDataSerieColor(index) {
|
|
37602
|
+
const dataSets = this.props.definition.dataSets;
|
|
37603
|
+
if (!dataSets?.[index])
|
|
37604
|
+
return "";
|
|
37605
|
+
const color = dataSets[index].backgroundColor;
|
|
37606
|
+
return color
|
|
37607
|
+
? toHex(color)
|
|
37608
|
+
: getNthColor(index, getColorsPalette(this.props.definition.dataSets.length));
|
|
37609
|
+
}
|
|
37610
|
+
getTrendLineColor(index) {
|
|
37611
|
+
return (this.getTrendLineConfiguration(index)?.color ??
|
|
37612
|
+
setColorAlpha(this.getDataSerieColor(index), 0.5));
|
|
37613
|
+
}
|
|
37614
|
+
updateTrendLineColor(index, color) {
|
|
37615
|
+
this.updateTrendLineValue(index, { color });
|
|
37616
|
+
}
|
|
37617
|
+
updateTrendLineValue(index, config) {
|
|
37332
37618
|
const dataSets = [...this.props.definition.dataSets];
|
|
37333
|
-
if (!dataSets?.[
|
|
37619
|
+
if (!dataSets?.[index]) {
|
|
37334
37620
|
return;
|
|
37335
37621
|
}
|
|
37336
|
-
dataSets[
|
|
37337
|
-
...dataSets[
|
|
37622
|
+
dataSets[index] = {
|
|
37623
|
+
...dataSets[index],
|
|
37338
37624
|
trend: {
|
|
37339
|
-
...dataSets[
|
|
37625
|
+
...dataSets[index].trend,
|
|
37340
37626
|
...config,
|
|
37341
37627
|
},
|
|
37342
37628
|
};
|
|
@@ -37344,29 +37630,67 @@ class ChartWithAxisDesignPanel extends owl.Component {
|
|
|
37344
37630
|
}
|
|
37345
37631
|
}
|
|
37346
37632
|
|
|
37633
|
+
class ChartWithAxisDesignPanel extends owl.Component {
|
|
37634
|
+
static template = "o-spreadsheet-ChartWithAxisDesignPanel";
|
|
37635
|
+
static components = {
|
|
37636
|
+
GeneralDesignEditor,
|
|
37637
|
+
SidePanelCollapsible,
|
|
37638
|
+
Section,
|
|
37639
|
+
AxisDesignEditor,
|
|
37640
|
+
Checkbox,
|
|
37641
|
+
SeriesWithAxisDesignEditor,
|
|
37642
|
+
};
|
|
37643
|
+
static props = {
|
|
37644
|
+
figureId: String,
|
|
37645
|
+
definition: Object,
|
|
37646
|
+
canUpdateChart: Function,
|
|
37647
|
+
updateChart: Function,
|
|
37648
|
+
};
|
|
37649
|
+
get axesList() {
|
|
37650
|
+
const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
|
|
37651
|
+
let axes = [{ id: "x", name: _t("Horizontal axis") }];
|
|
37652
|
+
if (useLeftAxis) {
|
|
37653
|
+
axes.push({ id: "y", name: useRightAxis ? _t("Left axis") : _t("Vertical axis") });
|
|
37654
|
+
}
|
|
37655
|
+
if (useRightAxis) {
|
|
37656
|
+
axes.push({ id: "y1", name: useLeftAxis ? _t("Right axis") : _t("Vertical axis") });
|
|
37657
|
+
}
|
|
37658
|
+
return axes;
|
|
37659
|
+
}
|
|
37660
|
+
updateLegendPosition(ev) {
|
|
37661
|
+
this.props.updateChart(this.props.figureId, {
|
|
37662
|
+
legendPosition: ev.target.value,
|
|
37663
|
+
});
|
|
37664
|
+
}
|
|
37665
|
+
}
|
|
37666
|
+
|
|
37347
37667
|
class ComboChartDesignPanel extends ChartWithAxisDesignPanel {
|
|
37348
37668
|
static template = "o-spreadsheet-ComboChartDesignPanel";
|
|
37669
|
+
static components = {
|
|
37670
|
+
...ChartWithAxisDesignPanel.components,
|
|
37671
|
+
RadioSelection,
|
|
37672
|
+
};
|
|
37349
37673
|
seriesTypeChoices = [
|
|
37350
37674
|
{ value: "bar", label: _t("Bar") },
|
|
37351
37675
|
{ value: "line", label: _t("Line") },
|
|
37352
37676
|
];
|
|
37353
|
-
updateDataSeriesType(type) {
|
|
37677
|
+
updateDataSeriesType(index, type) {
|
|
37354
37678
|
const dataSets = [...this.props.definition.dataSets];
|
|
37355
|
-
if (!dataSets?.[
|
|
37679
|
+
if (!dataSets?.[index]) {
|
|
37356
37680
|
return;
|
|
37357
37681
|
}
|
|
37358
|
-
dataSets[
|
|
37359
|
-
...dataSets[
|
|
37682
|
+
dataSets[index] = {
|
|
37683
|
+
...dataSets[index],
|
|
37360
37684
|
type,
|
|
37361
37685
|
};
|
|
37362
37686
|
this.props.updateChart(this.props.figureId, { dataSets });
|
|
37363
37687
|
}
|
|
37364
|
-
getDataSeriesType() {
|
|
37688
|
+
getDataSeriesType(index) {
|
|
37365
37689
|
const dataSets = this.props.definition.dataSets;
|
|
37366
|
-
if (!dataSets?.[
|
|
37690
|
+
if (!dataSets?.[index]) {
|
|
37367
37691
|
return "bar";
|
|
37368
37692
|
}
|
|
37369
|
-
return dataSets[
|
|
37693
|
+
return dataSets[index].type ?? "line";
|
|
37370
37694
|
}
|
|
37371
37695
|
}
|
|
37372
37696
|
|
|
@@ -37549,11 +37873,6 @@ class LineConfigPanel extends GenericChartConfigPanel {
|
|
|
37549
37873
|
stacked,
|
|
37550
37874
|
});
|
|
37551
37875
|
}
|
|
37552
|
-
onUpdateAggregated(aggregated) {
|
|
37553
|
-
this.props.updateChart(this.props.figureId, {
|
|
37554
|
-
aggregated,
|
|
37555
|
-
});
|
|
37556
|
-
}
|
|
37557
37876
|
onUpdateCumulative(cumulative) {
|
|
37558
37877
|
this.props.updateChart(this.props.figureId, {
|
|
37559
37878
|
cumulative,
|
|
@@ -37581,6 +37900,27 @@ class PieChartDesignPanel extends owl.Component {
|
|
|
37581
37900
|
}
|
|
37582
37901
|
}
|
|
37583
37902
|
|
|
37903
|
+
class RadarChartDesignPanel extends owl.Component {
|
|
37904
|
+
static template = "o-spreadsheet-RadarChartDesignPanel";
|
|
37905
|
+
static components = {
|
|
37906
|
+
GeneralDesignEditor,
|
|
37907
|
+
SeriesDesignEditor,
|
|
37908
|
+
Section,
|
|
37909
|
+
Checkbox,
|
|
37910
|
+
};
|
|
37911
|
+
static props = {
|
|
37912
|
+
figureId: String,
|
|
37913
|
+
definition: Object,
|
|
37914
|
+
canUpdateChart: Function,
|
|
37915
|
+
updateChart: Function,
|
|
37916
|
+
};
|
|
37917
|
+
updateLegendPosition(ev) {
|
|
37918
|
+
this.props.updateChart(this.props.figureId, {
|
|
37919
|
+
legendPosition: ev.target.value,
|
|
37920
|
+
});
|
|
37921
|
+
}
|
|
37922
|
+
}
|
|
37923
|
+
|
|
37584
37924
|
class ScatterConfigPanel extends GenericChartConfigPanel {
|
|
37585
37925
|
static template = "o-spreadsheet-ScatterConfigPanel";
|
|
37586
37926
|
get canTreatLabelsAsText() {
|
|
@@ -37775,9 +38115,6 @@ class WaterfallChartDesignPanel extends owl.Component {
|
|
|
37775
38115
|
verticalAxisPosition: value,
|
|
37776
38116
|
});
|
|
37777
38117
|
}
|
|
37778
|
-
updateShowValues(showValues) {
|
|
37779
|
-
this.props.updateChart(this.props.figureId, { showValues });
|
|
37780
|
-
}
|
|
37781
38118
|
}
|
|
37782
38119
|
|
|
37783
38120
|
const chartSidePanelComponentRegistry = new Registry();
|
|
@@ -37817,6 +38154,10 @@ chartSidePanelComponentRegistry
|
|
|
37817
38154
|
.add("pyramid", {
|
|
37818
38155
|
configuration: GenericChartConfigPanel,
|
|
37819
38156
|
design: ChartWithAxisDesignPanel,
|
|
38157
|
+
})
|
|
38158
|
+
.add("radar", {
|
|
38159
|
+
configuration: GenericChartConfigPanel,
|
|
38160
|
+
design: RadarChartDesignPanel,
|
|
37820
38161
|
});
|
|
37821
38162
|
|
|
37822
38163
|
css /* scss */ `
|
|
@@ -39019,13 +39360,6 @@ class DOMDndHelper {
|
|
|
39019
39360
|
return;
|
|
39020
39361
|
this.edgeScrollIntervalId = window.setInterval(() => {
|
|
39021
39362
|
const offset = direction * 3;
|
|
39022
|
-
let newPosition = this.currentMousePosition + offset;
|
|
39023
|
-
if (newPosition < Math.min(this.container.start, this.minPosition)) {
|
|
39024
|
-
newPosition = Math.min(this.container.start, this.minPosition);
|
|
39025
|
-
}
|
|
39026
|
-
else if (newPosition > Math.max(this.container.end, this.maxPosition)) {
|
|
39027
|
-
newPosition = Math.max(this.container.end, this.maxPosition);
|
|
39028
|
-
}
|
|
39029
39363
|
this.container.scroll += offset;
|
|
39030
39364
|
}, 5);
|
|
39031
39365
|
}
|
|
@@ -39202,7 +39536,6 @@ css /* scss */ `
|
|
|
39202
39536
|
width: 142px;
|
|
39203
39537
|
.o-cf-preview-description-rule {
|
|
39204
39538
|
margin-bottom: 4px;
|
|
39205
|
-
font-weight: 600;
|
|
39206
39539
|
max-height: 2.8em;
|
|
39207
39540
|
line-height: 1.4em;
|
|
39208
39541
|
}
|
|
@@ -39674,7 +40007,7 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
39674
40007
|
setColorScaleColor(target, color) {
|
|
39675
40008
|
const point = this.state.rules.colorScale[target];
|
|
39676
40009
|
if (point) {
|
|
39677
|
-
point.color = Number.parseInt(color.
|
|
40010
|
+
point.color = Number.parseInt(color.slice(1), 16);
|
|
39678
40011
|
}
|
|
39679
40012
|
this.closeMenus();
|
|
39680
40013
|
}
|
|
@@ -39785,7 +40118,7 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
39785
40118
|
return [this.state.rules.dataBar.rangeValues || ""];
|
|
39786
40119
|
}
|
|
39787
40120
|
updateDataBarColor(color) {
|
|
39788
|
-
this.state.rules.dataBar.color = Number.parseInt(color.
|
|
40121
|
+
this.state.rules.dataBar.color = Number.parseInt(color.slice(1), 16);
|
|
39789
40122
|
}
|
|
39790
40123
|
onDataBarRangeUpdate(ranges) {
|
|
39791
40124
|
this.state.rules.dataBar.rangeValues = ranges[0];
|
|
@@ -41198,10 +41531,11 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41198
41531
|
activeSheetMatches = [];
|
|
41199
41532
|
specificRangeMatches = [];
|
|
41200
41533
|
currentSearchRegex = null;
|
|
41201
|
-
isSearchDirty = false;
|
|
41202
41534
|
initialShowFormulaState;
|
|
41203
41535
|
preserveSelectedMatchIndex = false;
|
|
41204
41536
|
irreplaceableMatchCount = 0;
|
|
41537
|
+
isSearchDirty = false;
|
|
41538
|
+
shouldFinalizeUpdateSelection = false;
|
|
41205
41539
|
notificationStore = this.get(NotificationStore);
|
|
41206
41540
|
// fixme: why do we make selectedMatchIndex on top of a selected
|
|
41207
41541
|
// property in the matches?
|
|
@@ -41247,10 +41581,13 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41247
41581
|
this.updateSearchOptions({ searchFormulas: showFormula });
|
|
41248
41582
|
}
|
|
41249
41583
|
selectPreviousMatch() {
|
|
41250
|
-
this.selectNextCell(Direction.previous
|
|
41584
|
+
this.selectNextCell(Direction.previous, {
|
|
41585
|
+
jumpToMatchSheet: true,
|
|
41586
|
+
updateSelection: true,
|
|
41587
|
+
});
|
|
41251
41588
|
}
|
|
41252
41589
|
selectNextMatch() {
|
|
41253
|
-
this.selectNextCell(Direction.next);
|
|
41590
|
+
this.selectNextCell(Direction.next, { jumpToMatchSheet: true, updateSelection: true });
|
|
41254
41591
|
}
|
|
41255
41592
|
handle(cmd) {
|
|
41256
41593
|
switch (cmd.type) {
|
|
@@ -41267,8 +41604,11 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41267
41604
|
case "ADD_COLUMNS_ROWS":
|
|
41268
41605
|
case "EVALUATE_CELLS":
|
|
41269
41606
|
case "UPDATE_CELL":
|
|
41607
|
+
this.isSearchDirty = true;
|
|
41608
|
+
break;
|
|
41270
41609
|
case "ACTIVATE_SHEET":
|
|
41271
41610
|
this.isSearchDirty = true;
|
|
41611
|
+
this.shouldFinalizeUpdateSelection = true;
|
|
41272
41612
|
break;
|
|
41273
41613
|
case "REPLACE_SEARCH":
|
|
41274
41614
|
for (const match of cmd.matches) {
|
|
@@ -41283,7 +41623,11 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41283
41623
|
}
|
|
41284
41624
|
finalize() {
|
|
41285
41625
|
if (this.isSearchDirty) {
|
|
41286
|
-
this.refreshSearch(
|
|
41626
|
+
this.refreshSearch({
|
|
41627
|
+
jumpToMatchSheet: false,
|
|
41628
|
+
updateSelection: this.shouldFinalizeUpdateSelection,
|
|
41629
|
+
});
|
|
41630
|
+
this.shouldFinalizeUpdateSelection = false;
|
|
41287
41631
|
this.isSearchDirty = false;
|
|
41288
41632
|
}
|
|
41289
41633
|
}
|
|
@@ -41310,17 +41654,17 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41310
41654
|
}
|
|
41311
41655
|
this.toSearch = toSearch;
|
|
41312
41656
|
this.currentSearchRegex = getSearchRegex(this.toSearch, this.searchOptions);
|
|
41313
|
-
this.refreshSearch();
|
|
41657
|
+
this.refreshSearch({ jumpToMatchSheet: true, updateSelection: true });
|
|
41314
41658
|
}
|
|
41315
41659
|
/**
|
|
41316
41660
|
* refresh the matches according to the current search options
|
|
41317
41661
|
*/
|
|
41318
|
-
refreshSearch(
|
|
41662
|
+
refreshSearch(options) {
|
|
41319
41663
|
if (!this.preserveSelectedMatchIndex) {
|
|
41320
41664
|
this.selectedMatchIndex = null;
|
|
41321
41665
|
}
|
|
41322
41666
|
this.findMatches();
|
|
41323
|
-
this.selectNextCell(Direction.current,
|
|
41667
|
+
this.selectNextCell(Direction.current, options);
|
|
41324
41668
|
}
|
|
41325
41669
|
getSheetsInSearchOrder() {
|
|
41326
41670
|
switch (this.searchOptions.searchScope) {
|
|
@@ -41390,7 +41734,7 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41390
41734
|
* It is also used to keep coherence between the selected searchMatch
|
|
41391
41735
|
* and selectedMatchIndex.
|
|
41392
41736
|
*/
|
|
41393
|
-
selectNextCell(indexChange,
|
|
41737
|
+
selectNextCell(indexChange, options) {
|
|
41394
41738
|
const matches = this.searchMatches;
|
|
41395
41739
|
if (!matches.length) {
|
|
41396
41740
|
this.selectedMatchIndex = null;
|
|
@@ -41416,7 +41760,7 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41416
41760
|
this.selectedMatchIndex = nextIndex;
|
|
41417
41761
|
const selectedMatch = matches[nextIndex];
|
|
41418
41762
|
// Switch to the sheet where the match is located
|
|
41419
|
-
if (jumpToMatchSheet && this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
41763
|
+
if (options.jumpToMatchSheet && this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
41420
41764
|
// We set `preserveSelectedMatchIndex` to true to avoid resetting the selected search
|
|
41421
41765
|
// index in the `refreshSearch` function when a new sheet is activated. The reason being
|
|
41422
41766
|
// that, when we automatically go back to previous sheet while performing a search, the
|
|
@@ -41432,7 +41776,9 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41432
41776
|
}
|
|
41433
41777
|
// we want grid selection to capture the selection stream
|
|
41434
41778
|
this.model.selection.getBackToDefault();
|
|
41435
|
-
|
|
41779
|
+
if (options.updateSelection) {
|
|
41780
|
+
this.model.selection.selectCell(selectedMatch.col, selectedMatch.row);
|
|
41781
|
+
}
|
|
41436
41782
|
}
|
|
41437
41783
|
/**
|
|
41438
41784
|
* Replace the value of the currently selected match
|
|
@@ -41447,7 +41793,7 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41447
41793
|
matches: [this.searchMatches[this.selectedMatchIndex]],
|
|
41448
41794
|
searchOptions: this.searchOptions,
|
|
41449
41795
|
});
|
|
41450
|
-
this.selectNextCell(Direction.next);
|
|
41796
|
+
this.selectNextCell(Direction.next, { jumpToMatchSheet: true, updateSelection: true });
|
|
41451
41797
|
}
|
|
41452
41798
|
/**
|
|
41453
41799
|
* Apply the replace function to all the matches one time.
|
|
@@ -41629,6 +41975,14 @@ class FindAndReplacePanel extends owl.Component {
|
|
|
41629
41975
|
owl.onMounted(() => this.searchInput.el?.focus());
|
|
41630
41976
|
owl.onWillUnmount(() => this.updateSearchContent.stopDebounce());
|
|
41631
41977
|
this.updateSearchContent = debounce(this.store.updateSearchContent, 200);
|
|
41978
|
+
owl.useExternalListener(window, "keydown", (ev) => {
|
|
41979
|
+
const code = keyboardEventToShortcutString(ev);
|
|
41980
|
+
if (code === "Ctrl+F" || code === "Ctrl+H") {
|
|
41981
|
+
this.searchInput.el?.focus();
|
|
41982
|
+
ev.preventDefault();
|
|
41983
|
+
ev.stopPropagation();
|
|
41984
|
+
}
|
|
41985
|
+
}, { capture: true });
|
|
41632
41986
|
}
|
|
41633
41987
|
onFocusSearch() {
|
|
41634
41988
|
this.updateDataRange();
|
|
@@ -42204,7 +42558,6 @@ function createMeasureAutoComplete(pivot, forComputedMeasure) {
|
|
|
42204
42558
|
sequence: 0,
|
|
42205
42559
|
autoSelectFirstProposal: true,
|
|
42206
42560
|
getProposals(tokenAtCursor) {
|
|
42207
|
-
// return []
|
|
42208
42561
|
const measureProposals = pivot.measures
|
|
42209
42562
|
.filter((m) => m !== forComputedMeasure)
|
|
42210
42563
|
.map((measure) => {
|
|
@@ -43785,13 +44138,15 @@ pivotRegistry.add("SPREADSHEET", {
|
|
|
43785
44138
|
class PivotSidePanelStore extends SpreadsheetStore {
|
|
43786
44139
|
pivotId;
|
|
43787
44140
|
mutators = ["reset", "deferUpdates", "applyUpdate", "discardPendingUpdate", "update"];
|
|
43788
|
-
updatesAreDeferred
|
|
44141
|
+
updatesAreDeferred;
|
|
43789
44142
|
draft = null;
|
|
43790
44143
|
notification = this.get(NotificationStore);
|
|
43791
44144
|
alreadyNotified = false;
|
|
43792
44145
|
constructor(get, pivotId) {
|
|
43793
44146
|
super(get);
|
|
43794
44147
|
this.pivotId = pivotId;
|
|
44148
|
+
this.updatesAreDeferred =
|
|
44149
|
+
this.getters.getPivotCoreDefinition(this.pivotId).deferUpdates ?? false;
|
|
43795
44150
|
}
|
|
43796
44151
|
handle(cmd) {
|
|
43797
44152
|
switch (cmd.type) {
|
|
@@ -43879,10 +44234,14 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
43879
44234
|
this.draft = null;
|
|
43880
44235
|
}
|
|
43881
44236
|
deferUpdates(shouldDefer) {
|
|
43882
|
-
this.updatesAreDeferred = shouldDefer;
|
|
43883
44237
|
if (shouldDefer === false && this.draft) {
|
|
44238
|
+
this.draft.deferUpdates = false;
|
|
43884
44239
|
this.applyUpdate();
|
|
43885
44240
|
}
|
|
44241
|
+
else {
|
|
44242
|
+
this.update({ deferUpdates: shouldDefer });
|
|
44243
|
+
}
|
|
44244
|
+
this.updatesAreDeferred = shouldDefer;
|
|
43886
44245
|
}
|
|
43887
44246
|
applyUpdate() {
|
|
43888
44247
|
if (this.draft) {
|
|
@@ -44140,7 +44499,7 @@ class RemoveDuplicatesPanel extends owl.Component {
|
|
|
44140
44499
|
return colLabel;
|
|
44141
44500
|
}
|
|
44142
44501
|
get isEveryColumnSelected() {
|
|
44143
|
-
return Object.values(this.state.columns).every((value) => value
|
|
44502
|
+
return Object.values(this.state.columns).every((value) => value);
|
|
44144
44503
|
}
|
|
44145
44504
|
get errorMessages() {
|
|
44146
44505
|
const cancelledReasons = this.env.model.canDispatch("REMOVE_DUPLICATES", {
|
|
@@ -44240,8 +44599,7 @@ class SettingsPanel extends owl.Component {
|
|
|
44240
44599
|
const currentLocale = this.currentLocale;
|
|
44241
44600
|
const localeInLoadedLocales = this.loadedLocales.find((l) => l.code === currentLocale.code);
|
|
44242
44601
|
if (!localeInLoadedLocales) {
|
|
44243
|
-
|
|
44244
|
-
return locales;
|
|
44602
|
+
return [...this.loadedLocales, currentLocale].sort((a, b) => a.name.localeCompare(b.name));
|
|
44245
44603
|
}
|
|
44246
44604
|
else if (!deepEquals(currentLocale, localeInLoadedLocales)) {
|
|
44247
44605
|
const index = this.loadedLocales.indexOf(localeInLoadedLocales);
|
|
@@ -46135,10 +46493,9 @@ class GridComposer extends owl.Component {
|
|
|
46135
46493
|
});
|
|
46136
46494
|
}
|
|
46137
46495
|
get focus() {
|
|
46138
|
-
|
|
46496
|
+
return this.composerFocusStore.activeComposer === this.composerInterface
|
|
46139
46497
|
? this.composerFocusStore.focusMode
|
|
46140
46498
|
: "inactive";
|
|
46141
|
-
return focus;
|
|
46142
46499
|
}
|
|
46143
46500
|
get composerProps() {
|
|
46144
46501
|
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
@@ -47145,6 +47502,7 @@ class PaintFormatStore extends SpreadsheetStore {
|
|
|
47145
47502
|
new CellClipboardHandler(this.getters, this.model.dispatch),
|
|
47146
47503
|
new BorderClipboardHandler(this.getters, this.model.dispatch),
|
|
47147
47504
|
new TableClipboardHandler(this.getters, this.model.dispatch),
|
|
47505
|
+
new ConditionalFormatClipboardHandler(this.getters, this.model.dispatch),
|
|
47148
47506
|
];
|
|
47149
47507
|
status = "inactive";
|
|
47150
47508
|
copiedData;
|
|
@@ -47155,6 +47513,13 @@ class PaintFormatStore extends SpreadsheetStore {
|
|
|
47155
47513
|
this.highlightStore.unRegister(this);
|
|
47156
47514
|
});
|
|
47157
47515
|
}
|
|
47516
|
+
handle(cmd) {
|
|
47517
|
+
switch (cmd.type) {
|
|
47518
|
+
case "PAINT_FORMAT":
|
|
47519
|
+
this.paintFormat(cmd.sheetId, cmd.target);
|
|
47520
|
+
break;
|
|
47521
|
+
}
|
|
47522
|
+
}
|
|
47158
47523
|
activate(args) {
|
|
47159
47524
|
this.copiedData = this.copyFormats();
|
|
47160
47525
|
this.status = args.persistent ? "persistent" : "oneOff";
|
|
@@ -47164,18 +47529,7 @@ class PaintFormatStore extends SpreadsheetStore {
|
|
|
47164
47529
|
this.copiedData = undefined;
|
|
47165
47530
|
}
|
|
47166
47531
|
pasteFormat(target) {
|
|
47167
|
-
|
|
47168
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
47169
|
-
for (const handler of this.clipboardHandlers) {
|
|
47170
|
-
handler.paste({ zones: target, sheetId }, this.copiedData, {
|
|
47171
|
-
isCutOperation: false,
|
|
47172
|
-
pasteOption: "onlyFormat",
|
|
47173
|
-
});
|
|
47174
|
-
}
|
|
47175
|
-
}
|
|
47176
|
-
if (this.status === "oneOff") {
|
|
47177
|
-
this.cancel();
|
|
47178
|
-
}
|
|
47532
|
+
this.model.dispatch("PAINT_FORMAT", { target, sheetId: this.getters.getActiveSheetId() });
|
|
47179
47533
|
}
|
|
47180
47534
|
get isActive() {
|
|
47181
47535
|
return this.status !== "inactive";
|
|
@@ -47189,6 +47543,19 @@ class PaintFormatStore extends SpreadsheetStore {
|
|
|
47189
47543
|
}
|
|
47190
47544
|
return copiedData;
|
|
47191
47545
|
}
|
|
47546
|
+
paintFormat(sheetId, target) {
|
|
47547
|
+
if (this.copiedData) {
|
|
47548
|
+
for (const handler of this.clipboardHandlers) {
|
|
47549
|
+
handler.paste({ zones: target, sheetId }, this.copiedData, {
|
|
47550
|
+
isCutOperation: false,
|
|
47551
|
+
pasteOption: "onlyFormat",
|
|
47552
|
+
});
|
|
47553
|
+
}
|
|
47554
|
+
}
|
|
47555
|
+
if (this.status === "oneOff") {
|
|
47556
|
+
this.cancel();
|
|
47557
|
+
}
|
|
47558
|
+
}
|
|
47192
47559
|
get highlights() {
|
|
47193
47560
|
const data = this.copiedData;
|
|
47194
47561
|
if (!data) {
|
|
@@ -47565,7 +47932,7 @@ class AbstractResizer extends owl.Component {
|
|
|
47565
47932
|
if (index < 0) {
|
|
47566
47933
|
return;
|
|
47567
47934
|
}
|
|
47568
|
-
if (this.state.waitingForMove
|
|
47935
|
+
if (this.state.waitingForMove) {
|
|
47569
47936
|
if (!this.env.model.getters.isGridSelectionActive()) {
|
|
47570
47937
|
this._selectElement(index, false);
|
|
47571
47938
|
}
|
|
@@ -49124,7 +49491,7 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
49124
49491
|
}
|
|
49125
49492
|
open(componentTag, panelProps = {}) {
|
|
49126
49493
|
const state = this.computeState(componentTag, panelProps);
|
|
49127
|
-
if (state.isOpen
|
|
49494
|
+
if (!state.isOpen) {
|
|
49128
49495
|
return;
|
|
49129
49496
|
}
|
|
49130
49497
|
if (this.isOpen && componentTag !== this.componentTag) {
|
|
@@ -49463,6 +49830,8 @@ class Grid extends owl.Component {
|
|
|
49463
49830
|
},
|
|
49464
49831
|
"Ctrl+D": async () => this.env.model.dispatch("COPY_PASTE_CELLS_ABOVE"),
|
|
49465
49832
|
"Ctrl+R": async () => this.env.model.dispatch("COPY_PASTE_CELLS_ON_LEFT"),
|
|
49833
|
+
"Ctrl+H": () => this.sidePanel.open("FindAndReplace", {}),
|
|
49834
|
+
"Ctrl+F": () => this.sidePanel.open("FindAndReplace", {}),
|
|
49466
49835
|
"Ctrl+Shift+E": () => this.setHorizontalAlign("center"),
|
|
49467
49836
|
"Ctrl+Shift+L": () => this.setHorizontalAlign("left"),
|
|
49468
49837
|
"Ctrl+Shift+R": () => this.setHorizontalAlign("right"),
|
|
@@ -49870,31 +50239,6 @@ class Grid extends owl.Component {
|
|
|
49870
50239
|
}
|
|
49871
50240
|
}
|
|
49872
50241
|
|
|
49873
|
-
/** @odoo-module */
|
|
49874
|
-
class EditableName extends owl.Component {
|
|
49875
|
-
static template = "o-spreadsheet-EditableName";
|
|
49876
|
-
static props = {
|
|
49877
|
-
name: String,
|
|
49878
|
-
displayName: String,
|
|
49879
|
-
onChanged: Function,
|
|
49880
|
-
};
|
|
49881
|
-
state;
|
|
49882
|
-
setup() {
|
|
49883
|
-
this.state = owl.useState({
|
|
49884
|
-
isEditing: false,
|
|
49885
|
-
name: "",
|
|
49886
|
-
});
|
|
49887
|
-
}
|
|
49888
|
-
rename() {
|
|
49889
|
-
this.state.isEditing = true;
|
|
49890
|
-
this.state.name = this.props.name;
|
|
49891
|
-
}
|
|
49892
|
-
save() {
|
|
49893
|
-
this.props.onChanged(this.state.name.trim());
|
|
49894
|
-
this.state.isEditing = false;
|
|
49895
|
-
}
|
|
49896
|
-
}
|
|
49897
|
-
|
|
49898
50242
|
/**
|
|
49899
50243
|
* BasePlugin
|
|
49900
50244
|
*
|
|
@@ -53812,7 +54156,7 @@ class SheetPlugin extends CorePlugin {
|
|
|
53812
54156
|
this.sheetIdsMapName[sheet.name] = sheet.id;
|
|
53813
54157
|
}
|
|
53814
54158
|
for (let sheetData of data.sheets) {
|
|
53815
|
-
const name = sheetData.name ||
|
|
54159
|
+
const name = sheetData.name || "Sheet" + (Object.keys(this.sheets).length + 1);
|
|
53816
54160
|
const { colNumber, rowNumber } = this.getImportedSheetSize(sheetData);
|
|
53817
54161
|
const sheet = {
|
|
53818
54162
|
id: sheetData.id,
|
|
@@ -55431,7 +55775,7 @@ class PivotCorePlugin extends CorePlugin {
|
|
|
55431
55775
|
case "DUPLICATE_PIVOT": {
|
|
55432
55776
|
const { pivotId, newPivotId } = cmd;
|
|
55433
55777
|
const pivot = deepCopy(this.getPivotCore(pivotId).definition);
|
|
55434
|
-
pivot.name =
|
|
55778
|
+
pivot.name = cmd.duplicatedPivotName ?? pivot.name + " (copy)";
|
|
55435
55779
|
this.addPivot(newPivotId, pivot);
|
|
55436
55780
|
break;
|
|
55437
55781
|
}
|
|
@@ -55471,7 +55815,7 @@ class PivotCorePlugin extends CorePlugin {
|
|
|
55471
55815
|
return `(#${formulaId}) ${this.getPivotName(pivotId)}`;
|
|
55472
55816
|
}
|
|
55473
55817
|
getPivotName(pivotId) {
|
|
55474
|
-
return
|
|
55818
|
+
return this.getPivotCore(pivotId).definition.name;
|
|
55475
55819
|
}
|
|
55476
55820
|
/**
|
|
55477
55821
|
* Returns the pivot core definition of the pivot with the given id.
|
|
@@ -57113,7 +57457,7 @@ class Evaluator {
|
|
|
57113
57457
|
cellsToCompute.addMany(arrayFormulasPositions);
|
|
57114
57458
|
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositions));
|
|
57115
57459
|
this.evaluate(cellsToCompute);
|
|
57116
|
-
console.
|
|
57460
|
+
console.debug("evaluate Cells", performance.now() - start, "ms");
|
|
57117
57461
|
}
|
|
57118
57462
|
getArrayFormulasImpactedByChangesOf(positions) {
|
|
57119
57463
|
const impactedPositions = this.createEmptyPositionSet();
|
|
@@ -57157,7 +57501,7 @@ class Evaluator {
|
|
|
57157
57501
|
const start = performance.now();
|
|
57158
57502
|
this.evaluatedCells = new PositionMap();
|
|
57159
57503
|
this.evaluate(this.getAllCells());
|
|
57160
|
-
console.
|
|
57504
|
+
console.debug("evaluate all cells", performance.now() - start, "ms");
|
|
57161
57505
|
}
|
|
57162
57506
|
evaluateFormulaResult(sheetId, formulaString) {
|
|
57163
57507
|
const compiledFormula = compile(formulaString);
|
|
@@ -58163,8 +58507,7 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
58163
58507
|
.map((cell) => cell.value);
|
|
58164
58508
|
switch (threshold.type) {
|
|
58165
58509
|
case "value":
|
|
58166
|
-
|
|
58167
|
-
return result;
|
|
58510
|
+
return functionName === "max" ? largeMax(rangeValues) : largeMin(rangeValues);
|
|
58168
58511
|
case "number":
|
|
58169
58512
|
return Number(threshold.value);
|
|
58170
58513
|
case "percentage":
|
|
@@ -59368,8 +59711,7 @@ function withPivotPresentationLayer (PivotClass) {
|
|
|
59368
59711
|
throw new NotAvailableError();
|
|
59369
59712
|
}
|
|
59370
59713
|
const comparedValue = this._getPivotCellValueAndFormat(measure.id, comparedDomain);
|
|
59371
|
-
|
|
59372
|
-
return comparedValueNumber;
|
|
59714
|
+
return this.strictMeasureValueToNumber(comparedValue);
|
|
59373
59715
|
}
|
|
59374
59716
|
getPivotValueCells(measureId) {
|
|
59375
59717
|
return this.getTableStructure()
|
|
@@ -60903,7 +61245,7 @@ class Session extends EventBus {
|
|
|
60903
61245
|
this.onMessageReceived(message);
|
|
60904
61246
|
}
|
|
60905
61247
|
this.isReplayingInitialRevisions = false;
|
|
60906
|
-
console.
|
|
61248
|
+
console.debug("Replayed", numberOfCommands, "commands in", performance.now() - start, "ms");
|
|
60907
61249
|
}
|
|
60908
61250
|
/**
|
|
60909
61251
|
* Notify the server that the user client left the collaborative session
|
|
@@ -61075,7 +61417,6 @@ class Session extends EventBus {
|
|
|
61075
61417
|
if (this.waitingAck) {
|
|
61076
61418
|
return;
|
|
61077
61419
|
}
|
|
61078
|
-
this.waitingAck = true;
|
|
61079
61420
|
this.sendPendingMessage();
|
|
61080
61421
|
}
|
|
61081
61422
|
/**
|
|
@@ -61112,6 +61453,7 @@ class Session extends EventBus {
|
|
|
61112
61453
|
throw new Error(`Trying to send a new revision while replaying initial revision. This can lead to endless dispatches every time the spreadsheet is open.
|
|
61113
61454
|
${JSON.stringify(message)}`);
|
|
61114
61455
|
}
|
|
61456
|
+
this.waitingAck = true;
|
|
61115
61457
|
this.transportService.sendMessage({
|
|
61116
61458
|
...message,
|
|
61117
61459
|
serverRevisionId: this.serverRevisionId,
|
|
@@ -61271,8 +61613,7 @@ class CollaborativePlugin extends UIPlugin {
|
|
|
61271
61613
|
}
|
|
61272
61614
|
const color = client.color;
|
|
61273
61615
|
/* Cell background */
|
|
61274
|
-
|
|
61275
|
-
ctx.fillStyle = cellBackgroundColor;
|
|
61616
|
+
ctx.fillStyle = `${color}10`;
|
|
61276
61617
|
ctx.lineWidth = 4 * thinLineWidth;
|
|
61277
61618
|
ctx.strokeStyle = color;
|
|
61278
61619
|
ctx.globalCompositeOperation = "multiply";
|
|
@@ -61639,8 +61980,7 @@ class HeaderVisibilityUIPlugin extends UIPlugin {
|
|
|
61639
61980
|
exportForExcel(data) {
|
|
61640
61981
|
for (const sheetData of data.sheets) {
|
|
61641
61982
|
for (const [row, rowData] of Object.entries(sheetData.rows)) {
|
|
61642
|
-
|
|
61643
|
-
rowData.isHidden = isHidden;
|
|
61983
|
+
rowData.isHidden = this.isRowHidden(sheetData.id, Number(row));
|
|
61644
61984
|
}
|
|
61645
61985
|
}
|
|
61646
61986
|
}
|
|
@@ -61700,6 +62040,7 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
61700
62040
|
this.dispatch("DUPLICATE_PIVOT", {
|
|
61701
62041
|
pivotId,
|
|
61702
62042
|
newPivotId,
|
|
62043
|
+
duplicatedPivotName: _t("%s (copy)", this.getters.getPivotCoreDefinition(pivotId).name),
|
|
61703
62044
|
});
|
|
61704
62045
|
const activeSheetId = this.getters.getActiveSheetId();
|
|
61705
62046
|
const position = this.getters.getSheetIds().indexOf(activeSheetId) + 1;
|
|
@@ -62164,7 +62505,6 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
62164
62505
|
if (!isEqual(zone, newZone)) {
|
|
62165
62506
|
hasExpanded = true;
|
|
62166
62507
|
zone = newZone;
|
|
62167
|
-
continue;
|
|
62168
62508
|
}
|
|
62169
62509
|
} while (hasExpanded);
|
|
62170
62510
|
return zone;
|
|
@@ -63257,7 +63597,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
63257
63597
|
case "ADD_COLUMNS_ROWS": {
|
|
63258
63598
|
this.status = "invisible";
|
|
63259
63599
|
// If we add a col/row inside or before the cut area, we invalidate the clipboard
|
|
63260
|
-
if (this._isCutOperation
|
|
63600
|
+
if (!this._isCutOperation || cmd.sheetId !== this.copiedData?.sheetId) {
|
|
63261
63601
|
return;
|
|
63262
63602
|
}
|
|
63263
63603
|
const isClipboardDirty = this.isColRowDirtyingClipboard(cmd.position === "before" ? cmd.base : cmd.base + 1, cmd.dimension);
|
|
@@ -63269,7 +63609,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
63269
63609
|
case "REMOVE_COLUMNS_ROWS": {
|
|
63270
63610
|
this.status = "invisible";
|
|
63271
63611
|
// If we remove a col/row inside or before the cut area, we invalidate the clipboard
|
|
63272
|
-
if (this._isCutOperation
|
|
63612
|
+
if (!this._isCutOperation || cmd.sheetId !== this.copiedData?.sheetId) {
|
|
63273
63613
|
return;
|
|
63274
63614
|
}
|
|
63275
63615
|
for (let el of cmd.elements) {
|
|
@@ -63291,7 +63631,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
63291
63631
|
break;
|
|
63292
63632
|
}
|
|
63293
63633
|
case "DELETE_SHEET":
|
|
63294
|
-
if (this._isCutOperation
|
|
63634
|
+
if (!this._isCutOperation) {
|
|
63295
63635
|
return;
|
|
63296
63636
|
}
|
|
63297
63637
|
if (this.originSheetId === cmd.sheetId) {
|
|
@@ -64184,8 +64524,7 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
64184
64524
|
this.setSelectionMixin({ zone, cell: { col, row } }, [zone]);
|
|
64185
64525
|
}
|
|
64186
64526
|
setActiveSheet(id) {
|
|
64187
|
-
|
|
64188
|
-
this.activeSheet = sheet;
|
|
64527
|
+
this.activeSheet = this.getters.getSheet(id);
|
|
64189
64528
|
}
|
|
64190
64529
|
activateNextSheet(direction) {
|
|
64191
64530
|
const sheetIds = this.getters.getSheetIds();
|
|
@@ -64879,9 +65218,6 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
64879
65218
|
case "UNFREEZE_COLUMNS_ROWS":
|
|
64880
65219
|
this.resetViewports(this.getters.getActiveSheetId());
|
|
64881
65220
|
break;
|
|
64882
|
-
case "DELETE_SHEET":
|
|
64883
|
-
this.sheetsWithDirtyViewports.delete(cmd.sheetId);
|
|
64884
|
-
break;
|
|
64885
65221
|
case "SCROLL_TO_CELL":
|
|
64886
65222
|
this.refreshViewport(this.getters.getActiveSheetId(), { col: cmd.col, row: cmd.row });
|
|
64887
65223
|
break;
|
|
@@ -66833,10 +67169,9 @@ css /* scss */ `
|
|
|
66833
67169
|
user-select: none;
|
|
66834
67170
|
color: ${TEXT_BODY};
|
|
66835
67171
|
|
|
66836
|
-
.o-
|
|
67172
|
+
.o-sidePanelTitle {
|
|
66837
67173
|
line-height: 20px;
|
|
66838
67174
|
font-size: 16px;
|
|
66839
|
-
font-weight: 600;
|
|
66840
67175
|
}
|
|
66841
67176
|
|
|
66842
67177
|
.o-sidePanelHeader {
|
|
@@ -66921,6 +67256,10 @@ css /* scss */ `
|
|
|
66921
67256
|
}
|
|
66922
67257
|
}
|
|
66923
67258
|
}
|
|
67259
|
+
|
|
67260
|
+
.o-fw-bold {
|
|
67261
|
+
font-weight: 500;
|
|
67262
|
+
}
|
|
66924
67263
|
`;
|
|
66925
67264
|
class SidePanel extends owl.Component {
|
|
66926
67265
|
static template = "o-spreadsheet-SidePanel";
|
|
@@ -67752,8 +68091,7 @@ class WebClipboardWrapper {
|
|
|
67752
68091
|
for (const item of clipboardItems) {
|
|
67753
68092
|
for (const type of item.types) {
|
|
67754
68093
|
const blob = await item.getType(type);
|
|
67755
|
-
|
|
67756
|
-
clipboardContent[type] = text;
|
|
68094
|
+
clipboardContent[type] = await blob.text();
|
|
67757
68095
|
}
|
|
67758
68096
|
}
|
|
67759
68097
|
return { status: "ok", content: clipboardContent };
|
|
@@ -68065,7 +68403,6 @@ class Spreadsheet extends owl.Component {
|
|
|
68065
68403
|
spreadsheetRef = owl.useRef("spreadsheet");
|
|
68066
68404
|
spreadsheetRect = useSpreadsheetRect();
|
|
68067
68405
|
_focusGrid;
|
|
68068
|
-
keyDownMapping;
|
|
68069
68406
|
isViewportTooSmall = false;
|
|
68070
68407
|
notificationStore;
|
|
68071
68408
|
composerFocusStore;
|
|
@@ -68089,10 +68426,6 @@ class Spreadsheet extends owl.Component {
|
|
|
68089
68426
|
this.notificationStore = useStore(NotificationStore);
|
|
68090
68427
|
this.composerFocusStore = useStore(ComposerFocusStore);
|
|
68091
68428
|
this.sidePanel = useStore(SidePanelStore);
|
|
68092
|
-
this.keyDownMapping = {
|
|
68093
|
-
"CTRL+H": () => this.sidePanel.toggle("FindAndReplace", {}),
|
|
68094
|
-
"CTRL+F": () => this.sidePanel.toggle("FindAndReplace", {}),
|
|
68095
|
-
};
|
|
68096
68429
|
const fileStore = this.model.config.external.fileStore;
|
|
68097
68430
|
owl.useSubEnv({
|
|
68098
68431
|
model: this.model,
|
|
@@ -68192,20 +68525,6 @@ class Spreadsheet extends owl.Component {
|
|
|
68192
68525
|
}
|
|
68193
68526
|
this._focusGrid();
|
|
68194
68527
|
}
|
|
68195
|
-
onKeydown(ev) {
|
|
68196
|
-
let keyDownString = "";
|
|
68197
|
-
if (isCtrlKey(ev)) {
|
|
68198
|
-
keyDownString += "CTRL+";
|
|
68199
|
-
}
|
|
68200
|
-
keyDownString += ev.key.toUpperCase();
|
|
68201
|
-
let handler = this.keyDownMapping[keyDownString];
|
|
68202
|
-
if (handler) {
|
|
68203
|
-
ev.preventDefault();
|
|
68204
|
-
ev.stopPropagation();
|
|
68205
|
-
handler();
|
|
68206
|
-
return;
|
|
68207
|
-
}
|
|
68208
|
-
}
|
|
68209
68528
|
get gridHeight() {
|
|
68210
68529
|
const { height } = this.env.model.getters.getSheetViewDimension();
|
|
68211
68530
|
return height;
|
|
@@ -69620,10 +69939,10 @@ class SelectionStreamProcessorImpl {
|
|
|
69620
69939
|
getNextCellPosition(currentPosition, dimension, direction) {
|
|
69621
69940
|
const dimOfInterest = dimension === "cols" ? "col" : "row";
|
|
69622
69941
|
const startingPosition = { ...currentPosition };
|
|
69623
|
-
|
|
69624
|
-
|
|
69625
|
-
|
|
69626
|
-
|
|
69942
|
+
startingPosition[dimOfInterest] =
|
|
69943
|
+
dimension === "cols"
|
|
69944
|
+
? this.getNextAvailableCol(direction, startingPosition.col, startingPosition.row)
|
|
69945
|
+
: this.getNextAvailableRow(direction, startingPosition.col, startingPosition.row);
|
|
69627
69946
|
return { col: startingPosition.col, row: startingPosition.row };
|
|
69628
69947
|
}
|
|
69629
69948
|
getPosition() {
|
|
@@ -69747,6 +70066,8 @@ function createChart(chart, chartSheetIndex, data) {
|
|
|
69747
70066
|
case "pie":
|
|
69748
70067
|
plot = addDoughnutChart(chart.data, chartSheetIndex, data, { holeSize: 0 });
|
|
69749
70068
|
break;
|
|
70069
|
+
case "radar":
|
|
70070
|
+
plot = addRadarChart(chart.data);
|
|
69750
70071
|
}
|
|
69751
70072
|
let position = "t";
|
|
69752
70073
|
switch (chart.data.legendPosition) {
|
|
@@ -70205,6 +70526,53 @@ function addScatterChart(chart) {
|
|
|
70205
70526
|
`
|
|
70206
70527
|
: ""}`;
|
|
70207
70528
|
}
|
|
70529
|
+
function addRadarChart(chart) {
|
|
70530
|
+
const dataSetsColors = chart.dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
70531
|
+
const colors = new ColorGenerator(chart.dataSets.length, dataSetsColors);
|
|
70532
|
+
const dataSetsNodes = [];
|
|
70533
|
+
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
70534
|
+
const color = toXlsxHexColor(colors.next());
|
|
70535
|
+
const dataShapeProperty = shapeProperty({
|
|
70536
|
+
line: {
|
|
70537
|
+
width: 2.5,
|
|
70538
|
+
style: "solid",
|
|
70539
|
+
color,
|
|
70540
|
+
},
|
|
70541
|
+
});
|
|
70542
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
70543
|
+
<c:ser>
|
|
70544
|
+
<c:idx val="${dsIndex}"/>
|
|
70545
|
+
<c:order val="${dsIndex}"/>
|
|
70546
|
+
<c:smooth val="0"/>
|
|
70547
|
+
<c:marker>
|
|
70548
|
+
<c:symbol val="circle" />
|
|
70549
|
+
<c:size val="5"/>
|
|
70550
|
+
${shapeProperty({ backgroundColor: color, line: { color } })}
|
|
70551
|
+
</c:marker>
|
|
70552
|
+
${extractDataSetLabel(dataset.label)}
|
|
70553
|
+
${dataShapeProperty}
|
|
70554
|
+
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
70555
|
+
<c:val> <!-- x-coordinate values -->
|
|
70556
|
+
${numberRef(dataset.range)}
|
|
70557
|
+
</c:val>
|
|
70558
|
+
</c:ser>
|
|
70559
|
+
`;
|
|
70560
|
+
dataSetsNodes.push(dataSetNode);
|
|
70561
|
+
}
|
|
70562
|
+
return escapeXml /*xml*/ `
|
|
70563
|
+
${escapeXml /*xml*/ `
|
|
70564
|
+
<c:radarChart>
|
|
70565
|
+
<c:radarStyle val="marker"/>
|
|
70566
|
+
<c:varyColors val="0"/>
|
|
70567
|
+
${joinXmlNodes(dataSetsNodes)}
|
|
70568
|
+
<c:axId val="${catAxId}" />
|
|
70569
|
+
<c:axId val="${valAxId}" />
|
|
70570
|
+
</c:radarChart>
|
|
70571
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor)}
|
|
70572
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
70573
|
+
`}
|
|
70574
|
+
`;
|
|
70575
|
+
}
|
|
70208
70576
|
function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
|
|
70209
70577
|
const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
|
|
70210
70578
|
const colors = new ColorGenerator(maxLength);
|
|
@@ -71312,25 +71680,23 @@ function addSheetViews(sheet) {
|
|
|
71312
71680
|
["showGridLines", sheet.areGridLinesVisible ? 1 : 0],
|
|
71313
71681
|
["workbookViewId", 0],
|
|
71314
71682
|
];
|
|
71315
|
-
|
|
71683
|
+
return escapeXml /*xml*/ `
|
|
71316
71684
|
<sheetViews>
|
|
71317
71685
|
<sheetView ${formatAttributes(sheetViewAttrs)}>
|
|
71318
71686
|
${splitPanes}
|
|
71319
71687
|
</sheetView>
|
|
71320
71688
|
</sheetViews>
|
|
71321
71689
|
`;
|
|
71322
|
-
return sheetView;
|
|
71323
71690
|
}
|
|
71324
71691
|
function addSheetProperties(sheet) {
|
|
71325
71692
|
if (!sheet.color) {
|
|
71326
71693
|
return "";
|
|
71327
71694
|
}
|
|
71328
|
-
|
|
71695
|
+
return escapeXml /*xml*/ `
|
|
71329
71696
|
<sheetPr>
|
|
71330
71697
|
<tabColor ${formatAttributes([["rgb", toXlsxHexColor(sheet.color)]])} />
|
|
71331
71698
|
</sheetPr>
|
|
71332
71699
|
`;
|
|
71333
|
-
return sheetView;
|
|
71334
71700
|
}
|
|
71335
71701
|
|
|
71336
71702
|
/**
|
|
@@ -71643,9 +72009,7 @@ var Status;
|
|
|
71643
72009
|
})(Status || (Status = {}));
|
|
71644
72010
|
class Model extends EventBus {
|
|
71645
72011
|
corePlugins = [];
|
|
71646
|
-
featurePlugins = [];
|
|
71647
72012
|
statefulUIPlugins = [];
|
|
71648
|
-
coreViewsPlugins = [];
|
|
71649
72013
|
range;
|
|
71650
72014
|
session;
|
|
71651
72015
|
/**
|
|
@@ -71690,7 +72054,7 @@ class Model extends EventBus {
|
|
|
71690
72054
|
coreHandlers = [];
|
|
71691
72055
|
constructor(data = {}, config = {}, stateUpdateMessages = [], uuidGenerator = new UuidGenerator(), verboseImport = false) {
|
|
71692
72056
|
const start = performance.now();
|
|
71693
|
-
console.
|
|
72057
|
+
console.debug("##### Model creation #####");
|
|
71694
72058
|
super();
|
|
71695
72059
|
setDefaultTranslationMethod();
|
|
71696
72060
|
stateUpdateMessages = repairInitialMessages(data, stateUpdateMessages);
|
|
@@ -71731,7 +72095,6 @@ class Model extends EventBus {
|
|
|
71731
72095
|
this.session.loadInitialMessages(stateUpdateMessages);
|
|
71732
72096
|
for (let Plugin of coreViewsPluginRegistry.getAll()) {
|
|
71733
72097
|
const plugin = this.setupUiPlugin(Plugin);
|
|
71734
|
-
this.coreViewsPlugins.push(plugin);
|
|
71735
72098
|
this.handlers.push(plugin);
|
|
71736
72099
|
this.uiHandlers.push(plugin);
|
|
71737
72100
|
this.coreHandlers.push(plugin);
|
|
@@ -71744,7 +72107,6 @@ class Model extends EventBus {
|
|
|
71744
72107
|
}
|
|
71745
72108
|
for (let Plugin of featurePluginRegistry.getAll()) {
|
|
71746
72109
|
const plugin = this.setupUiPlugin(Plugin);
|
|
71747
|
-
this.featurePlugins.push(plugin);
|
|
71748
72110
|
this.handlers.push(plugin);
|
|
71749
72111
|
this.uiHandlers.push(plugin);
|
|
71750
72112
|
}
|
|
@@ -71761,16 +72123,16 @@ class Model extends EventBus {
|
|
|
71761
72123
|
this.joinSession();
|
|
71762
72124
|
if (config.snapshotRequested) {
|
|
71763
72125
|
const startSnapshot = performance.now();
|
|
71764
|
-
console.
|
|
72126
|
+
console.debug("Snapshot requested");
|
|
71765
72127
|
this.session.snapshot(this.exportData());
|
|
71766
72128
|
this.garbageCollectExternalResources();
|
|
71767
|
-
console.
|
|
72129
|
+
console.debug("Snapshot taken in", performance.now() - startSnapshot, "ms");
|
|
71768
72130
|
}
|
|
71769
72131
|
// mark all models as "raw", so they will not be turned into reactive objects
|
|
71770
72132
|
// by owl, since we do not rely on reactivity
|
|
71771
72133
|
owl.markRaw(this);
|
|
71772
|
-
console.
|
|
71773
|
-
console.
|
|
72134
|
+
console.debug("Model created in", performance.now() - start, "ms");
|
|
72135
|
+
console.debug("######");
|
|
71774
72136
|
}
|
|
71775
72137
|
joinSession() {
|
|
71776
72138
|
this.session.join(this.config.client);
|
|
@@ -71829,7 +72191,7 @@ class Model extends EventBus {
|
|
|
71829
72191
|
this.finalize();
|
|
71830
72192
|
}
|
|
71831
72193
|
setupSession(revisionId) {
|
|
71832
|
-
|
|
72194
|
+
return new Session(buildRevisionLog({
|
|
71833
72195
|
initialRevisionId: revisionId,
|
|
71834
72196
|
recordChanges: this.state.recordChanges.bind(this.state),
|
|
71835
72197
|
dispatch: (command) => {
|
|
@@ -71842,7 +72204,6 @@ class Model extends EventBus {
|
|
|
71842
72204
|
this.isReplayingCommand = false;
|
|
71843
72205
|
},
|
|
71844
72206
|
}), this.config.transportService, revisionId);
|
|
71845
|
-
return session;
|
|
71846
72207
|
}
|
|
71847
72208
|
setupSessionEvents() {
|
|
71848
72209
|
this.session.on("remote-revision-received", this, this.onRemoteRevisionReceived);
|
|
@@ -71935,8 +72296,7 @@ class Model extends EventBus {
|
|
|
71935
72296
|
return results;
|
|
71936
72297
|
}
|
|
71937
72298
|
checkDispatchAllowedLocalCommand(command) {
|
|
71938
|
-
|
|
71939
|
-
return results;
|
|
72299
|
+
return this.uiHandlers.map((handler) => handler.allowDispatch(command));
|
|
71940
72300
|
}
|
|
71941
72301
|
finalize() {
|
|
71942
72302
|
this.status = 3 /* Status.Finalizing */;
|
|
@@ -71993,7 +72353,7 @@ class Model extends EventBus {
|
|
|
71993
72353
|
this.finalize();
|
|
71994
72354
|
const time = performance.now() - start;
|
|
71995
72355
|
if (time > 5) {
|
|
71996
|
-
console.
|
|
72356
|
+
console.debug(type, time, "ms");
|
|
71997
72357
|
}
|
|
71998
72358
|
});
|
|
71999
72359
|
this.session.save(command, commands, changes);
|
|
@@ -72296,7 +72656,6 @@ const components = {
|
|
|
72296
72656
|
PivotDimensionOrder,
|
|
72297
72657
|
PivotDimension,
|
|
72298
72658
|
PivotLayoutConfigurator,
|
|
72299
|
-
EditableName,
|
|
72300
72659
|
PivotDeferUpdate,
|
|
72301
72660
|
PivotTitleSection,
|
|
72302
72661
|
CogWheelMenu,
|
|
@@ -72388,6 +72747,6 @@ exports.tokenColors = tokenColors;
|
|
|
72388
72747
|
exports.tokenize = tokenize;
|
|
72389
72748
|
|
|
72390
72749
|
|
|
72391
|
-
__info__.version = "18.1.0-alpha.
|
|
72392
|
-
__info__.date = "2024-10-
|
|
72393
|
-
__info__.hash = "
|
|
72750
|
+
__info__.version = "18.1.0-alpha.2";
|
|
72751
|
+
__info__.date = "2024-10-24T08:53:21.828Z";
|
|
72752
|
+
__info__.hash = "2a01250";
|