@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
|
import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
|
|
@@ -329,6 +329,7 @@ const DEFAULT_SCORECARD_BASELINE_MODE = "difference";
|
|
|
329
329
|
const DEFAULT_SCORECARD_BASELINE_COLOR_UP = "#43C5B1";
|
|
330
330
|
const DEFAULT_SCORECARD_BASELINE_COLOR_DOWN = "#EA6175";
|
|
331
331
|
const LINE_FILL_TRANSPARENCY = 0.4;
|
|
332
|
+
const DEFAULT_WINDOW_SIZE = 2;
|
|
332
333
|
// session
|
|
333
334
|
const DEBOUNCE_TIME = 200;
|
|
334
335
|
const MESSAGE_VERSION = 1;
|
|
@@ -374,7 +375,7 @@ const PIVOT_TABLE_CONFIG = {
|
|
|
374
375
|
bandedRows: true,
|
|
375
376
|
bandedColumns: false,
|
|
376
377
|
styleId: "TableStyleMedium5",
|
|
377
|
-
automaticAutofill:
|
|
378
|
+
automaticAutofill: false,
|
|
378
379
|
};
|
|
379
380
|
const DEFAULT_CURRENCY = {
|
|
380
381
|
symbol: "$",
|
|
@@ -590,7 +591,7 @@ function buildSheetLink(sheetId) {
|
|
|
590
591
|
*/
|
|
591
592
|
function parseSheetUrl(sheetLink) {
|
|
592
593
|
if (sheetLink.startsWith(O_SPREADSHEET_LINK_PREFIX)) {
|
|
593
|
-
return sheetLink.
|
|
594
|
+
return sheetLink.slice(O_SPREADSHEET_LINK_PREFIX.length);
|
|
594
595
|
}
|
|
595
596
|
throw new Error(`${sheetLink} is not a valid sheet link`);
|
|
596
597
|
}
|
|
@@ -3155,8 +3156,7 @@ const getNumberRegex = memoize(function getNumberRegex(locale) {
|
|
|
3155
3156
|
const p2 = pMinus + pNumber + pCurrencyFormat;
|
|
3156
3157
|
const p3 = pCurrencyFormat + pMinus + pNumber;
|
|
3157
3158
|
const pNumberExp = "^(?:(?:" + [p1, p2, p3].join(")|(?:") + "))$";
|
|
3158
|
-
|
|
3159
|
-
return numberRegexp;
|
|
3159
|
+
return new RegExp(pNumberExp, "i");
|
|
3160
3160
|
});
|
|
3161
3161
|
/**
|
|
3162
3162
|
* Return true if the argument is a "number string".
|
|
@@ -5830,8 +5830,7 @@ function computeCachedTextWidth(context, text) {
|
|
|
5830
5830
|
textWidthCache[font] = {};
|
|
5831
5831
|
}
|
|
5832
5832
|
if (textWidthCache[font][text] === undefined) {
|
|
5833
|
-
|
|
5834
|
-
textWidthCache[font][text] = textWidth;
|
|
5833
|
+
textWidthCache[font][text] = context.measureText(text).width;
|
|
5835
5834
|
}
|
|
5836
5835
|
return textWidthCache[font][text];
|
|
5837
5836
|
}
|
|
@@ -6083,7 +6082,7 @@ class UuidGenerator {
|
|
|
6083
6082
|
else {
|
|
6084
6083
|
// mainly for jest and other browsers that do not have the crypto functionality
|
|
6085
6084
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
6086
|
-
|
|
6085
|
+
const r = (Math.random() * 16) | 0, v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
6087
6086
|
return v.toString(16);
|
|
6088
6087
|
});
|
|
6089
6088
|
}
|
|
@@ -6580,10 +6579,9 @@ function localizeNumberLiteral(literal, locale) {
|
|
|
6580
6579
|
return literal;
|
|
6581
6580
|
}
|
|
6582
6581
|
const decimalNumberRegex = getDecimalNumberRegex(DEFAULT_LOCALE);
|
|
6583
|
-
|
|
6582
|
+
return literal.replace(decimalNumberRegex, (match) => {
|
|
6584
6583
|
return match.replace(".", locale.decimalSeparator);
|
|
6585
6584
|
});
|
|
6586
|
-
return localized;
|
|
6587
6585
|
}
|
|
6588
6586
|
/**
|
|
6589
6587
|
* Change a literal string from its canonical form (en_US locale) to the given locale. Also convert date string.
|
|
@@ -7068,6 +7066,21 @@ function predictLinearValues(Y, X, newX, computeIntercept) {
|
|
|
7068
7066
|
});
|
|
7069
7067
|
return newY.length === newX.length ? newY : transposeMatrix(newY);
|
|
7070
7068
|
}
|
|
7069
|
+
function getMovingAverageValues(dataset, windowSize = DEFAULT_WINDOW_SIZE) {
|
|
7070
|
+
const values = [];
|
|
7071
|
+
// Fill the starting values with null until we have a full window
|
|
7072
|
+
for (let i = 0; i < windowSize - 1; i++) {
|
|
7073
|
+
values.push(null);
|
|
7074
|
+
}
|
|
7075
|
+
for (let i = 0; i <= dataset.length - windowSize; i++) {
|
|
7076
|
+
let sum = 0;
|
|
7077
|
+
for (let j = i; j < i + windowSize; j++) {
|
|
7078
|
+
sum += dataset[j];
|
|
7079
|
+
}
|
|
7080
|
+
values.push(sum / windowSize);
|
|
7081
|
+
}
|
|
7082
|
+
return values;
|
|
7083
|
+
}
|
|
7071
7084
|
|
|
7072
7085
|
const PREVIOUS_VALUE = "(previous)";
|
|
7073
7086
|
const NEXT_VALUE = "(next)";
|
|
@@ -7603,8 +7616,7 @@ function getMaxObjectId(o) {
|
|
|
7603
7616
|
return 0;
|
|
7604
7617
|
}
|
|
7605
7618
|
const nums = keys.map((id) => parseInt(id, 10));
|
|
7606
|
-
|
|
7607
|
-
return max;
|
|
7619
|
+
return Math.max(...nums);
|
|
7608
7620
|
}
|
|
7609
7621
|
const ALL_PERIODS = {
|
|
7610
7622
|
year: _t("Year"),
|
|
@@ -8457,10 +8469,6 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
8457
8469
|
tableZone &&
|
|
8458
8470
|
zones.some((z) => isZoneInside(tableZone, z))) {
|
|
8459
8471
|
copiedTablesIds.add(table.id);
|
|
8460
|
-
const values = [];
|
|
8461
|
-
for (const col of range(tableZone.left, tableZone.right + 1)) {
|
|
8462
|
-
values.push(this.getters.getFilterHiddenValues({ sheetId, col, row: tableZone.top }));
|
|
8463
|
-
}
|
|
8464
8472
|
copiedTable = {
|
|
8465
8473
|
range: coreTable.range.rangeData,
|
|
8466
8474
|
config: coreTable.config,
|
|
@@ -9241,11 +9249,10 @@ function getChartPositionAtCenterOfViewport(getters, chartSize) {
|
|
|
9241
9249
|
const { x, y } = getters.getMainViewportCoordinates();
|
|
9242
9250
|
const { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
|
|
9243
9251
|
const { width, height } = getters.getVisibleRect(getters.getActiveMainViewport());
|
|
9244
|
-
|
|
9252
|
+
return {
|
|
9245
9253
|
x: x + scrollX + Math.max(0, (width - chartSize.width) / 2),
|
|
9246
9254
|
y: y + scrollY + Math.max(0, (height - chartSize.height) / 2),
|
|
9247
9255
|
}; // Position at the center of the scrollable viewport
|
|
9248
|
-
return position;
|
|
9249
9256
|
}
|
|
9250
9257
|
function getChartAxisTitleRuntime(design) {
|
|
9251
9258
|
if (design?.title?.text) {
|
|
@@ -9362,7 +9369,7 @@ function getFullTrendingLineDataSet(dataset, config, data) {
|
|
|
9362
9369
|
return {
|
|
9363
9370
|
...dataset,
|
|
9364
9371
|
type: "line",
|
|
9365
|
-
xAxisID: TREND_LINE_XAXIS_ID,
|
|
9372
|
+
xAxisID: config.type !== "trailingMovingAverage" ? TREND_LINE_XAXIS_ID : "x",
|
|
9366
9373
|
label: dataset.label ? _t("Trend line for %s", dataset.label) : "",
|
|
9367
9374
|
data,
|
|
9368
9375
|
order: -1,
|
|
@@ -9404,6 +9411,9 @@ function interpolateData(config, values, labels, newLabels) {
|
|
|
9404
9411
|
case "logarithmic": {
|
|
9405
9412
|
return predictLinearValues([values], logM([labels]), logM([newLabels]), true)[0];
|
|
9406
9413
|
}
|
|
9414
|
+
case "trailingMovingAverage": {
|
|
9415
|
+
return getMovingAverageValues(values, config.window);
|
|
9416
|
+
}
|
|
9407
9417
|
default:
|
|
9408
9418
|
return [];
|
|
9409
9419
|
}
|
|
@@ -9449,72 +9459,115 @@ const chartShowValuesPlugin = {
|
|
|
9449
9459
|
ctx.save();
|
|
9450
9460
|
ctx.textAlign = "center";
|
|
9451
9461
|
ctx.textBaseline = "middle";
|
|
9452
|
-
ctx.
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
const midRadius = (innerRadius + outerRadius) / 2;
|
|
9466
|
-
const x = bar.x + midRadius * Math.cos(midAngle);
|
|
9467
|
-
const y = bar.y + midRadius * Math.sin(midAngle) + 7;
|
|
9468
|
-
ctx.fillStyle = chartFontColor(bar.options.backgroundColor);
|
|
9469
|
-
ctx.strokeStyle = chartFontColor(ctx.fillStyle);
|
|
9470
|
-
const value = options.callback(dataset._parsed[i]);
|
|
9471
|
-
ctx.strokeText(value, x, y);
|
|
9472
|
-
ctx.fillText(value, x, y);
|
|
9473
|
-
}
|
|
9474
|
-
break;
|
|
9475
|
-
}
|
|
9476
|
-
case "bar":
|
|
9477
|
-
case "line": {
|
|
9478
|
-
const yOffset = dataset.type === "bar" && !options.horizontal ? 0 : 3;
|
|
9479
|
-
const horizontalChart = dataset.type === "bar" && options.horizontal;
|
|
9480
|
-
const axisId = horizontalChart ? dataset.xAxisID : dataset.yAxisID;
|
|
9481
|
-
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
9482
|
-
const point = dataset.data[i];
|
|
9483
|
-
const value = options.horizontal ? dataset._parsed[i].x : dataset._parsed[i].y;
|
|
9484
|
-
const displayedValue = options.callback(value - 0, axisId);
|
|
9485
|
-
let xPosition = 0, yPosition = 0;
|
|
9486
|
-
if (options.horizontal) {
|
|
9487
|
-
yPosition = point.y;
|
|
9488
|
-
if (value < 0) {
|
|
9489
|
-
ctx.textAlign = "right";
|
|
9490
|
-
xPosition = point.x - yOffset;
|
|
9491
|
-
}
|
|
9492
|
-
else {
|
|
9493
|
-
ctx.textAlign = "left";
|
|
9494
|
-
xPosition = point.x + yOffset;
|
|
9495
|
-
}
|
|
9496
|
-
}
|
|
9497
|
-
else {
|
|
9498
|
-
xPosition = point.x;
|
|
9499
|
-
if (value < 0) {
|
|
9500
|
-
ctx.textBaseline = "top";
|
|
9501
|
-
yPosition = point.y + yOffset;
|
|
9502
|
-
}
|
|
9503
|
-
else {
|
|
9504
|
-
ctx.textBaseline = "bottom";
|
|
9505
|
-
yPosition = point.y - yOffset;
|
|
9506
|
-
}
|
|
9507
|
-
}
|
|
9508
|
-
ctx.strokeText(displayedValue, xPosition, yPosition);
|
|
9509
|
-
ctx.fillText(displayedValue, xPosition, yPosition);
|
|
9510
|
-
}
|
|
9511
|
-
break;
|
|
9512
|
-
}
|
|
9513
|
-
}
|
|
9514
|
-
});
|
|
9462
|
+
ctx.miterLimit = 1; // Avoid sharp artifacts on strokeText
|
|
9463
|
+
switch (chart.config.type) {
|
|
9464
|
+
case "pie":
|
|
9465
|
+
case "doughnut":
|
|
9466
|
+
drawPieChartValues(chart, options, ctx);
|
|
9467
|
+
break;
|
|
9468
|
+
case "bar":
|
|
9469
|
+
case "line":
|
|
9470
|
+
options.horizontal
|
|
9471
|
+
? drawHorizontalBarChartValues(chart, options, ctx)
|
|
9472
|
+
: drawLineOrBarChartValues(chart, options, ctx);
|
|
9473
|
+
break;
|
|
9474
|
+
}
|
|
9515
9475
|
ctx.restore();
|
|
9516
9476
|
},
|
|
9517
9477
|
};
|
|
9478
|
+
function drawTextWithBackground(text, x, y, ctx) {
|
|
9479
|
+
ctx.lineWidth = 3; // Stroke the text with a big lineWidth width to have some kind of background
|
|
9480
|
+
ctx.strokeText(text, x, y);
|
|
9481
|
+
ctx.lineWidth = 1;
|
|
9482
|
+
ctx.fillText(text, x, y);
|
|
9483
|
+
}
|
|
9484
|
+
function drawLineOrBarChartValues(chart, options, ctx) {
|
|
9485
|
+
const yMax = chart.chartArea.bottom;
|
|
9486
|
+
const yMin = chart.chartArea.top;
|
|
9487
|
+
const textsPositions = {};
|
|
9488
|
+
for (const dataset of chart._metasets) {
|
|
9489
|
+
if (dataset.xAxisID === TREND_LINE_XAXIS_ID) {
|
|
9490
|
+
return; // ignore trend lines
|
|
9491
|
+
}
|
|
9492
|
+
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
9493
|
+
const value = dataset._parsed[i].y;
|
|
9494
|
+
const displayValue = options.callback(value - 0, dataset.yAxisID);
|
|
9495
|
+
const point = dataset.data[i];
|
|
9496
|
+
const xPosition = point.x;
|
|
9497
|
+
let yPosition = 0;
|
|
9498
|
+
if (chart.config.type === "line") {
|
|
9499
|
+
yPosition = point.y - 10;
|
|
9500
|
+
}
|
|
9501
|
+
else {
|
|
9502
|
+
yPosition = value < 0 ? point.y - point.height / 2 : point.y + point.height / 2;
|
|
9503
|
+
}
|
|
9504
|
+
yPosition = Math.min(yPosition, yMax);
|
|
9505
|
+
yPosition = Math.max(yPosition, yMin);
|
|
9506
|
+
// Avoid overlapping texts with same X
|
|
9507
|
+
if (!textsPositions[xPosition]) {
|
|
9508
|
+
textsPositions[xPosition] = [];
|
|
9509
|
+
}
|
|
9510
|
+
for (const otherPosition of textsPositions[xPosition] || []) {
|
|
9511
|
+
if (Math.abs(otherPosition - yPosition) < 13) {
|
|
9512
|
+
yPosition = otherPosition - 13;
|
|
9513
|
+
}
|
|
9514
|
+
}
|
|
9515
|
+
textsPositions[xPosition].push(yPosition);
|
|
9516
|
+
ctx.fillStyle = point.options.backgroundColor;
|
|
9517
|
+
ctx.strokeStyle = options.background || "#ffffff";
|
|
9518
|
+
drawTextWithBackground(displayValue, xPosition, yPosition, ctx);
|
|
9519
|
+
}
|
|
9520
|
+
}
|
|
9521
|
+
}
|
|
9522
|
+
function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
9523
|
+
const xMax = chart.chartArea.right;
|
|
9524
|
+
const xMin = chart.chartArea.left;
|
|
9525
|
+
const textsPositions = {};
|
|
9526
|
+
for (const dataset of chart._metasets) {
|
|
9527
|
+
if (dataset.xAxisID === TREND_LINE_XAXIS_ID) {
|
|
9528
|
+
return; // ignore trend lines
|
|
9529
|
+
}
|
|
9530
|
+
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
9531
|
+
const value = dataset._parsed[i].x;
|
|
9532
|
+
const displayValue = options.callback(value - 0, dataset.xAxisID);
|
|
9533
|
+
const point = dataset.data[i];
|
|
9534
|
+
const yPosition = point.y;
|
|
9535
|
+
let xPosition = value < 0 ? point.x + point.width / 2 : point.x - point.width / 2;
|
|
9536
|
+
xPosition = Math.min(xPosition, xMax);
|
|
9537
|
+
xPosition = Math.max(xPosition, xMin);
|
|
9538
|
+
// Avoid overlapping texts with same Y
|
|
9539
|
+
if (!textsPositions[yPosition]) {
|
|
9540
|
+
textsPositions[yPosition] = [];
|
|
9541
|
+
}
|
|
9542
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
9543
|
+
for (const otherPosition of textsPositions[yPosition]) {
|
|
9544
|
+
if (Math.abs(otherPosition - xPosition) < textWidth) {
|
|
9545
|
+
xPosition = otherPosition + textWidth + 3;
|
|
9546
|
+
}
|
|
9547
|
+
}
|
|
9548
|
+
textsPositions[yPosition].push(xPosition);
|
|
9549
|
+
ctx.fillStyle = point.options.backgroundColor;
|
|
9550
|
+
ctx.strokeStyle = options.background || "#ffffff";
|
|
9551
|
+
drawTextWithBackground(displayValue, xPosition, yPosition, ctx);
|
|
9552
|
+
}
|
|
9553
|
+
}
|
|
9554
|
+
}
|
|
9555
|
+
function drawPieChartValues(chart, options, ctx) {
|
|
9556
|
+
for (const dataset of chart._metasets) {
|
|
9557
|
+
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
9558
|
+
const bar = dataset.data[i];
|
|
9559
|
+
const { startAngle, endAngle, innerRadius, outerRadius } = bar;
|
|
9560
|
+
const midAngle = (startAngle + endAngle) / 2;
|
|
9561
|
+
const midRadius = (innerRadius + outerRadius) / 2;
|
|
9562
|
+
const x = bar.x + midRadius * Math.cos(midAngle);
|
|
9563
|
+
const y = bar.y + midRadius * Math.sin(midAngle) + 7;
|
|
9564
|
+
ctx.fillStyle = chartFontColor(options.background);
|
|
9565
|
+
ctx.strokeStyle = options.background || "#ffffff";
|
|
9566
|
+
const value = options.callback(dataset._parsed[i]);
|
|
9567
|
+
drawTextWithBackground(value, x, y, ctx);
|
|
9568
|
+
}
|
|
9569
|
+
}
|
|
9570
|
+
}
|
|
9518
9571
|
|
|
9519
9572
|
/** This is a chartJS plugin that will draw connector lines between the bars of a Waterfall chart */
|
|
9520
9573
|
const waterfallLinesPlugin = {
|
|
@@ -10292,8 +10345,7 @@ function getHtmlContentFromPattern(pattern, value, highlightColor, className) {
|
|
|
10292
10345
|
value = value.slice(index + 1);
|
|
10293
10346
|
}
|
|
10294
10347
|
pendingHtmlContent.push({ value });
|
|
10295
|
-
|
|
10296
|
-
return htmlContent;
|
|
10348
|
+
return pendingHtmlContent.filter((content) => content.value);
|
|
10297
10349
|
}
|
|
10298
10350
|
|
|
10299
10351
|
//------------------------------------------------------------------------------
|
|
@@ -10697,7 +10749,7 @@ const MINVERSE = {
|
|
|
10697
10749
|
assertSquareMatrix(_t("The argument square_matrix must have the same number of columns and rows."), _matrix);
|
|
10698
10750
|
const { inverted } = invertMatrix(_matrix);
|
|
10699
10751
|
if (!inverted) {
|
|
10700
|
-
|
|
10752
|
+
return new EvaluationError(_t("The matrix is not invertible."));
|
|
10701
10753
|
}
|
|
10702
10754
|
return inverted;
|
|
10703
10755
|
},
|
|
@@ -10776,7 +10828,7 @@ function getSumXAndY(arrayX, arrayY, cb) {
|
|
|
10776
10828
|
}
|
|
10777
10829
|
}
|
|
10778
10830
|
if (!validPairFound) {
|
|
10779
|
-
|
|
10831
|
+
return new EvaluationError(_t("The arguments array_x and array_y must contain at least one pair of numbers."));
|
|
10780
10832
|
}
|
|
10781
10833
|
return result;
|
|
10782
10834
|
}
|
|
@@ -10857,7 +10909,7 @@ const TOCOL = {
|
|
|
10857
10909
|
.flat()
|
|
10858
10910
|
.filter(shouldKeepValue(_ignore));
|
|
10859
10911
|
if (result.length === 0) {
|
|
10860
|
-
|
|
10912
|
+
return new NotAvailableError(_t("No results for the given arguments of TOCOL."));
|
|
10861
10913
|
}
|
|
10862
10914
|
return [result];
|
|
10863
10915
|
},
|
|
@@ -10878,7 +10930,7 @@ const TOROW = {
|
|
|
10878
10930
|
.filter(shouldKeepValue(_ignore))
|
|
10879
10931
|
.map((item) => [item]);
|
|
10880
10932
|
if (result.length === 0 || result[0].length === 0) {
|
|
10881
|
-
|
|
10933
|
+
return new NotAvailableError(_t("No results for the given arguments of TOROW."));
|
|
10882
10934
|
}
|
|
10883
10935
|
return result;
|
|
10884
10936
|
},
|
|
@@ -11438,7 +11490,7 @@ const DECIMAL = {
|
|
|
11438
11490
|
* Return error if 'value' is positive.
|
|
11439
11491
|
* Remove '-?' in the next regex to catch this error.
|
|
11440
11492
|
*/
|
|
11441
|
-
assert(() =>
|
|
11493
|
+
assert(() => DECIMAL_REPRESENTATION.test(_value), _t("The value (%s) must be a valid base %s representation.", _value, _base.toString()));
|
|
11442
11494
|
const deci = parseInt(_value, _base);
|
|
11443
11495
|
assert(() => !isNaN(deci), _t("The value (%s) must be a valid base %s representation.", _value, _base.toString()));
|
|
11444
11496
|
return deci;
|
|
@@ -11706,7 +11758,7 @@ const PRODUCT = {
|
|
|
11706
11758
|
count += 1;
|
|
11707
11759
|
}
|
|
11708
11760
|
if (isEvaluationError(f)) {
|
|
11709
|
-
|
|
11761
|
+
return j;
|
|
11710
11762
|
}
|
|
11711
11763
|
}
|
|
11712
11764
|
}
|
|
@@ -12209,9 +12261,8 @@ function covariance(dataY, dataX, isSample) {
|
|
|
12209
12261
|
}
|
|
12210
12262
|
function variance(args, isSample, textAs0, locale) {
|
|
12211
12263
|
let count = 0;
|
|
12212
|
-
let sum = 0;
|
|
12213
12264
|
const reduceFunction = textAs0 ? reduceNumbersTextAs0 : reduceNumbers;
|
|
12214
|
-
sum = reduceFunction(args, (acc, a) => {
|
|
12265
|
+
const sum = reduceFunction(args, (acc, a) => {
|
|
12215
12266
|
count += 1;
|
|
12216
12267
|
return acc + a;
|
|
12217
12268
|
}, 0, locale);
|
|
@@ -12608,7 +12659,7 @@ const MATTHEWS = {
|
|
|
12608
12659
|
const flatY = dataY.flat();
|
|
12609
12660
|
assertSameNumberOfElements(flatX, flatY);
|
|
12610
12661
|
if (flatX.length === 0) {
|
|
12611
|
-
|
|
12662
|
+
return new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
|
|
12612
12663
|
}
|
|
12613
12664
|
const n = flatX.length;
|
|
12614
12665
|
let trueN = 0, trueP = 0, falseP = 0, falseN = 0;
|
|
@@ -13408,9 +13459,8 @@ function getMatchingCells(database, field, criteria, locale) {
|
|
|
13408
13459
|
// 4 - return for each database row corresponding, the cells corresponding to the field parameter
|
|
13409
13460
|
const fieldCol = database[index];
|
|
13410
13461
|
// Example continuation:: fieldCol = ["C", "j", "k", 7]
|
|
13411
|
-
const matchingCells = [...matchingRows].map((x) => fieldCol[x + 1]);
|
|
13412
13462
|
// Example continuation:: matchingCells = ["j", 7]
|
|
13413
|
-
return
|
|
13463
|
+
return [...matchingRows].map((x) => fieldCol[x + 1]);
|
|
13414
13464
|
}
|
|
13415
13465
|
const databaseArgs = [
|
|
13416
13466
|
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.")),
|
|
@@ -14595,7 +14645,7 @@ const FILTER = {
|
|
|
14595
14645
|
}
|
|
14596
14646
|
}
|
|
14597
14647
|
if (!result.length) {
|
|
14598
|
-
|
|
14648
|
+
return new NotAvailableError(_t("No match found in FILTER evaluation"));
|
|
14599
14649
|
}
|
|
14600
14650
|
return mode === "row" ? transposeMatrix(result) : result;
|
|
14601
14651
|
},
|
|
@@ -17293,7 +17343,7 @@ function mapParentFunction(tokens) {
|
|
|
17293
17343
|
argsTokens[argPosition].push({ value: token.value, type: token.type });
|
|
17294
17344
|
}
|
|
17295
17345
|
}
|
|
17296
|
-
|
|
17346
|
+
return tokens.map((token, i) => {
|
|
17297
17347
|
if (!["SPACE", "LEFT_PAREN"].includes(token.type)) {
|
|
17298
17348
|
functionStarted = "";
|
|
17299
17349
|
}
|
|
@@ -17331,7 +17381,6 @@ function mapParentFunction(tokens) {
|
|
|
17331
17381
|
}
|
|
17332
17382
|
return token;
|
|
17333
17383
|
});
|
|
17334
|
-
return res;
|
|
17335
17384
|
}
|
|
17336
17385
|
/**
|
|
17337
17386
|
* Parse the list of tokens that compose the arguments of a function to
|
|
@@ -17787,7 +17836,7 @@ const IFS = {
|
|
|
17787
17836
|
return result;
|
|
17788
17837
|
}
|
|
17789
17838
|
}
|
|
17790
|
-
|
|
17839
|
+
return new EvaluationError(_t("No match."));
|
|
17791
17840
|
},
|
|
17792
17841
|
isExported: true,
|
|
17793
17842
|
};
|
|
@@ -17951,8 +18000,8 @@ const ADDRESS = {
|
|
|
17951
18000
|
let cellReference;
|
|
17952
18001
|
if (_useA1Notation) {
|
|
17953
18002
|
const rangePart = {
|
|
17954
|
-
rowFixed: [1, 2].includes(_absoluteRelativeMode)
|
|
17955
|
-
colFixed: [1, 3].includes(_absoluteRelativeMode)
|
|
18003
|
+
rowFixed: [1, 2].includes(_absoluteRelativeMode),
|
|
18004
|
+
colFixed: [1, 3].includes(_absoluteRelativeMode),
|
|
17956
18005
|
};
|
|
17957
18006
|
cellReference = toXC(colNumber - 1, rowNumber - 1, rangePart);
|
|
17958
18007
|
}
|
|
@@ -17978,7 +18027,7 @@ const COLUMN = {
|
|
|
17978
18027
|
],
|
|
17979
18028
|
compute: function (cellReference) {
|
|
17980
18029
|
if (isEvaluationError(cellReference?.value)) {
|
|
17981
|
-
|
|
18030
|
+
return cellReference;
|
|
17982
18031
|
}
|
|
17983
18032
|
const column = cellReference === undefined
|
|
17984
18033
|
? this.__originCellPosition?.col
|
|
@@ -17996,7 +18045,7 @@ const COLUMNS = {
|
|
|
17996
18045
|
args: [arg("range (meta)", _t("The range whose column count will be returned."))],
|
|
17997
18046
|
compute: function (range) {
|
|
17998
18047
|
if (isEvaluationError(range?.value)) {
|
|
17999
|
-
|
|
18048
|
+
return range;
|
|
18000
18049
|
}
|
|
18001
18050
|
const zone = toZone(range.value);
|
|
18002
18051
|
return zone.right - zone.left + 1;
|
|
@@ -18076,11 +18125,11 @@ const INDIRECT = {
|
|
|
18076
18125
|
compute: function (reference, useA1Notation = { value: true }) {
|
|
18077
18126
|
let _reference = reference?.value?.toString();
|
|
18078
18127
|
if (!_reference) {
|
|
18079
|
-
|
|
18128
|
+
return new InvalidReferenceError(_t("Reference should be defined."));
|
|
18080
18129
|
}
|
|
18081
18130
|
const _useA1Notation = toBoolean(useA1Notation);
|
|
18082
18131
|
if (!_useA1Notation) {
|
|
18083
|
-
|
|
18132
|
+
return new EvaluationError(_t("R1C1 notation is not supported."));
|
|
18084
18133
|
}
|
|
18085
18134
|
const sheetId = this.__originSheetId;
|
|
18086
18135
|
const originPosition = this.__originCellPosition;
|
|
@@ -18092,7 +18141,7 @@ const INDIRECT = {
|
|
|
18092
18141
|
}
|
|
18093
18142
|
const range = this.getters.getRangeFromSheetXC(sheetId, _reference);
|
|
18094
18143
|
if (range === undefined || range.invalidXc || range.invalidSheetName) {
|
|
18095
|
-
|
|
18144
|
+
return new InvalidReferenceError();
|
|
18096
18145
|
}
|
|
18097
18146
|
if (originPosition) {
|
|
18098
18147
|
this.addDependencies?.(originPosition, [range]);
|
|
@@ -18200,7 +18249,7 @@ const ROW = {
|
|
|
18200
18249
|
],
|
|
18201
18250
|
compute: function (cellReference) {
|
|
18202
18251
|
if (isEvaluationError(cellReference?.value)) {
|
|
18203
|
-
|
|
18252
|
+
return cellReference;
|
|
18204
18253
|
}
|
|
18205
18254
|
const row = cellReference === undefined
|
|
18206
18255
|
? this.__originCellPosition?.row
|
|
@@ -18218,7 +18267,7 @@ const ROWS = {
|
|
|
18218
18267
|
args: [arg("range (meta)", _t("The range whose row count will be returned."))],
|
|
18219
18268
|
compute: function (range) {
|
|
18220
18269
|
if (isEvaluationError(range?.value)) {
|
|
18221
|
-
|
|
18270
|
+
return range;
|
|
18222
18271
|
}
|
|
18223
18272
|
const zone = toZone(range.value);
|
|
18224
18273
|
return zone.bottom - zone.top + 1;
|
|
@@ -18405,11 +18454,11 @@ const PIVOT = {
|
|
|
18405
18454
|
const _pivotFormulaId = toString(pivotFormulaId);
|
|
18406
18455
|
const _rowCount = toNumber(rowCount, this.locale);
|
|
18407
18456
|
if (_rowCount < 0) {
|
|
18408
|
-
|
|
18457
|
+
return new EvaluationError(_t("The number of rows must be positive."));
|
|
18409
18458
|
}
|
|
18410
18459
|
const _columnCount = toNumber(columnCount, this.locale);
|
|
18411
18460
|
if (_columnCount < 0) {
|
|
18412
|
-
|
|
18461
|
+
return new EvaluationError(_t("The number of columns must be positive."));
|
|
18413
18462
|
}
|
|
18414
18463
|
const _includeColumnHeaders = toBoolean(includeColumnHeaders);
|
|
18415
18464
|
const _includedTotal = toBoolean(includeTotal);
|
|
@@ -18608,6 +18657,12 @@ const EQ = {
|
|
|
18608
18657
|
arg("value2 (any)", _t("The value to test against value1 for equality.")),
|
|
18609
18658
|
],
|
|
18610
18659
|
compute: function (value1, value2) {
|
|
18660
|
+
if (isEvaluationError(value1?.value)) {
|
|
18661
|
+
return value1;
|
|
18662
|
+
}
|
|
18663
|
+
if (isEvaluationError(value2?.value)) {
|
|
18664
|
+
return value2;
|
|
18665
|
+
}
|
|
18611
18666
|
let _value1 = isEmpty(value1) ? getNeutral[typeof value2?.value] : value1?.value;
|
|
18612
18667
|
let _value2 = isEmpty(value2) ? getNeutral[typeof value1?.value] : value2?.value;
|
|
18613
18668
|
if (typeof _value1 === "string") {
|
|
@@ -18616,27 +18671,21 @@ const EQ = {
|
|
|
18616
18671
|
if (typeof _value2 === "string") {
|
|
18617
18672
|
_value2 = _value2.toUpperCase();
|
|
18618
18673
|
}
|
|
18619
|
-
|
|
18620
|
-
throw value1;
|
|
18621
|
-
}
|
|
18622
|
-
if (isEvaluationError(_value2)) {
|
|
18623
|
-
throw value2;
|
|
18624
|
-
}
|
|
18625
|
-
return _value1 === _value2;
|
|
18674
|
+
return { value: _value1 === _value2 };
|
|
18626
18675
|
},
|
|
18627
18676
|
};
|
|
18628
18677
|
// -----------------------------------------------------------------------------
|
|
18629
18678
|
// GT
|
|
18630
18679
|
// -----------------------------------------------------------------------------
|
|
18631
18680
|
function applyRelationalOperator(value1, value2, cb) {
|
|
18632
|
-
|
|
18633
|
-
|
|
18634
|
-
if (isEvaluationError(_value1)) {
|
|
18635
|
-
throw value1;
|
|
18681
|
+
if (isEvaluationError(value1?.value)) {
|
|
18682
|
+
return value1;
|
|
18636
18683
|
}
|
|
18637
|
-
if (isEvaluationError(
|
|
18638
|
-
|
|
18684
|
+
if (isEvaluationError(value2?.value)) {
|
|
18685
|
+
return value2;
|
|
18639
18686
|
}
|
|
18687
|
+
let _value1 = isEmpty(value1) ? getNeutral[typeof value2?.value] : value1?.value;
|
|
18688
|
+
let _value2 = isEmpty(value2) ? getNeutral[typeof value1?.value] : value2?.value;
|
|
18640
18689
|
if (typeof _value1 !== "number") {
|
|
18641
18690
|
_value1 = toString(_value1).toUpperCase();
|
|
18642
18691
|
}
|
|
@@ -18646,12 +18695,12 @@ function applyRelationalOperator(value1, value2, cb) {
|
|
|
18646
18695
|
const tV1 = typeof _value1;
|
|
18647
18696
|
const tV2 = typeof _value2;
|
|
18648
18697
|
if (tV1 === "string" && tV2 === "number") {
|
|
18649
|
-
return true;
|
|
18698
|
+
return { value: true };
|
|
18650
18699
|
}
|
|
18651
18700
|
if (tV2 === "string" && tV1 === "number") {
|
|
18652
|
-
return false;
|
|
18701
|
+
return { value: false };
|
|
18653
18702
|
}
|
|
18654
|
-
return cb(_value1, _value2);
|
|
18703
|
+
return { value: cb(_value1, _value2) };
|
|
18655
18704
|
}
|
|
18656
18705
|
const GT = {
|
|
18657
18706
|
description: _t("Strictly greater than."),
|
|
@@ -18690,7 +18739,11 @@ const LT = {
|
|
|
18690
18739
|
arg("value2 (any)", _t("The second value.")),
|
|
18691
18740
|
],
|
|
18692
18741
|
compute: function (value1, value2) {
|
|
18693
|
-
|
|
18742
|
+
const result = GTE.compute.bind(this)(value1, value2);
|
|
18743
|
+
if (isEvaluationError(result.value)) {
|
|
18744
|
+
return result;
|
|
18745
|
+
}
|
|
18746
|
+
return { value: !result.value };
|
|
18694
18747
|
},
|
|
18695
18748
|
};
|
|
18696
18749
|
// -----------------------------------------------------------------------------
|
|
@@ -18703,7 +18756,11 @@ const LTE = {
|
|
|
18703
18756
|
arg("value2 (any)", _t("The second value.")),
|
|
18704
18757
|
],
|
|
18705
18758
|
compute: function (value1, value2) {
|
|
18706
|
-
|
|
18759
|
+
const result = GT.compute.bind(this)(value1, value2);
|
|
18760
|
+
if (isEvaluationError(result.value)) {
|
|
18761
|
+
return result;
|
|
18762
|
+
}
|
|
18763
|
+
return { value: !result.value };
|
|
18707
18764
|
},
|
|
18708
18765
|
};
|
|
18709
18766
|
// -----------------------------------------------------------------------------
|
|
@@ -18748,7 +18805,11 @@ const NE = {
|
|
|
18748
18805
|
arg("value2 (any)", _t("The value to test against value1 for inequality.")),
|
|
18749
18806
|
],
|
|
18750
18807
|
compute: function (value1, value2) {
|
|
18751
|
-
|
|
18808
|
+
const result = EQ.compute.bind(this)(value1, value2);
|
|
18809
|
+
if (isEvaluationError(result.value)) {
|
|
18810
|
+
return result;
|
|
18811
|
+
}
|
|
18812
|
+
return { value: !result.value };
|
|
18752
18813
|
},
|
|
18753
18814
|
};
|
|
18754
18815
|
// -----------------------------------------------------------------------------
|
|
@@ -19907,13 +19968,12 @@ function cssPropertiesToCss(attributes) {
|
|
|
19907
19968
|
}
|
|
19908
19969
|
function getElementMargins(el) {
|
|
19909
19970
|
const style = window.getComputedStyle(el);
|
|
19910
|
-
|
|
19971
|
+
return {
|
|
19911
19972
|
top: parseInt(style.marginTop, 10) || 0,
|
|
19912
19973
|
bottom: parseInt(style.marginBottom, 10) || 0,
|
|
19913
19974
|
left: parseInt(style.marginLeft, 10) || 0,
|
|
19914
19975
|
right: parseInt(style.marginRight, 10) || 0,
|
|
19915
19976
|
};
|
|
19916
|
-
return margins;
|
|
19917
19977
|
}
|
|
19918
19978
|
|
|
19919
19979
|
const macRegex = /Mac/i;
|
|
@@ -21788,9 +21848,13 @@ autoCompleteProviders.add("pivot_group_fields", {
|
|
|
21788
21848
|
const colFields = columns.map((groupBy) => groupBy.nameWithGranularity);
|
|
21789
21849
|
const rowFields = rows.map((groupBy) => groupBy.nameWithGranularity);
|
|
21790
21850
|
const proposals = [];
|
|
21791
|
-
|
|
21851
|
+
let previousGroupBy = ["ARG_SEPARATOR", "SPACE"].includes(tokenAtCursor.type)
|
|
21792
21852
|
? argGroupBys.at(-1)
|
|
21793
21853
|
: argGroupBys.at(-2);
|
|
21854
|
+
const isPositionalSupported = supportedPivotPositionalFormulaRegistry.get(pivot.type);
|
|
21855
|
+
if (isPositionalSupported && previousGroupBy?.startsWith("#")) {
|
|
21856
|
+
previousGroupBy = previousGroupBy.slice(1);
|
|
21857
|
+
}
|
|
21794
21858
|
if (previousGroupBy === undefined) {
|
|
21795
21859
|
proposals.push(colFields[0]);
|
|
21796
21860
|
proposals.push(rowFields[0]);
|
|
@@ -21812,7 +21876,7 @@ autoCompleteProviders.add("pivot_group_fields", {
|
|
|
21812
21876
|
return field ? makeFieldProposal(field, granularity) : undefined;
|
|
21813
21877
|
})
|
|
21814
21878
|
.concat(groupBys.map((groupBy) => {
|
|
21815
|
-
if (!
|
|
21879
|
+
if (!isPositionalSupported) {
|
|
21816
21880
|
return undefined;
|
|
21817
21881
|
}
|
|
21818
21882
|
const fieldName = groupBy.split(":")[0];
|
|
@@ -21821,13 +21885,12 @@ autoCompleteProviders.add("pivot_group_fields", {
|
|
|
21821
21885
|
return undefined;
|
|
21822
21886
|
}
|
|
21823
21887
|
const positionalFieldArg = `"#${groupBy}"`;
|
|
21824
|
-
|
|
21888
|
+
return {
|
|
21825
21889
|
text: positionalFieldArg,
|
|
21826
21890
|
description: _t("%s (positional)", field.string) + (field.help ? ` (${field.help})` : ""),
|
|
21827
21891
|
htmlContent: [{ value: positionalFieldArg, color: tokenColors.STRING }],
|
|
21828
21892
|
fuzzySearchKey: field.string + positionalFieldArg, // search on translated name and on technical name
|
|
21829
21893
|
};
|
|
21830
|
-
return positionalProposal;
|
|
21831
21894
|
}))
|
|
21832
21895
|
.filter(isDefined);
|
|
21833
21896
|
},
|
|
@@ -22096,7 +22159,7 @@ function parseLiteral(content, locale) {
|
|
|
22096
22159
|
return internalDate.value;
|
|
22097
22160
|
}
|
|
22098
22161
|
if (isBoolean(content)) {
|
|
22099
|
-
return content.toUpperCase() === "TRUE"
|
|
22162
|
+
return content.toUpperCase() === "TRUE";
|
|
22100
22163
|
}
|
|
22101
22164
|
return content;
|
|
22102
22165
|
}
|
|
@@ -22437,8 +22500,7 @@ function calculateDateIncrementBasedOnGroup(group) {
|
|
|
22437
22500
|
return 0;
|
|
22438
22501
|
}
|
|
22439
22502
|
const previous = jsDates[index - 1];
|
|
22440
|
-
|
|
22441
|
-
return days;
|
|
22503
|
+
return Math.floor(date.getTime()) - Math.floor(previous.getTime());
|
|
22442
22504
|
})
|
|
22443
22505
|
.slice(1);
|
|
22444
22506
|
const equidistantDates = timeIntervals.every((interval) => interval === timeIntervals[0]);
|
|
@@ -22997,6 +23059,7 @@ const XLSX_CHART_TYPES = [
|
|
|
22997
23059
|
"surface3DChart",
|
|
22998
23060
|
"bubbleChart",
|
|
22999
23061
|
"comboChart",
|
|
23062
|
+
"radarChart",
|
|
23000
23063
|
];
|
|
23001
23064
|
|
|
23002
23065
|
/** In XLSX color format (no #) */
|
|
@@ -23537,7 +23600,7 @@ const CHART_TYPE_CONVERSION_MAP = {
|
|
|
23537
23600
|
lineChart: "line",
|
|
23538
23601
|
line3DChart: undefined,
|
|
23539
23602
|
stockChart: undefined,
|
|
23540
|
-
radarChart:
|
|
23603
|
+
radarChart: "radar",
|
|
23541
23604
|
scatterChart: "scatter",
|
|
23542
23605
|
pieChart: "pie",
|
|
23543
23606
|
pie3DChart: undefined,
|
|
@@ -24950,7 +25013,7 @@ const TABLE_STYLE_CATEGORIES = {
|
|
|
24950
25013
|
custom: _t("Custom"),
|
|
24951
25014
|
};
|
|
24952
25015
|
const DEFAULT_TABLE_CONFIG = {
|
|
24953
|
-
hasFilters:
|
|
25016
|
+
hasFilters: false,
|
|
24954
25017
|
totalRow: false,
|
|
24955
25018
|
firstColumn: false,
|
|
24956
25019
|
lastColumn: false,
|
|
@@ -25619,12 +25682,11 @@ class XlsxBaseExtractor {
|
|
|
25619
25682
|
* Get the list of all the XLSX files in the XLSX file structure
|
|
25620
25683
|
*/
|
|
25621
25684
|
getListOfXMLFiles() {
|
|
25622
|
-
|
|
25685
|
+
return Object.entries(this.xlsxFileStructure)
|
|
25623
25686
|
.filter(([key]) => key !== "images")
|
|
25624
25687
|
.map(([_, value]) => value)
|
|
25625
25688
|
.flat()
|
|
25626
25689
|
.filter(isDefined);
|
|
25627
|
-
return XMLFiles;
|
|
25628
25690
|
}
|
|
25629
25691
|
/**
|
|
25630
25692
|
* Return an array containing the return value of the given function applied to all the XML elements
|
|
@@ -25788,13 +25850,12 @@ class XlsxBaseExtractor {
|
|
|
25788
25850
|
rgb = this.extractAttr(colorElement, "rgb")?.asString();
|
|
25789
25851
|
rgb = rgb === DEFAULT_SYSTEM_COLOR ? undefined : rgb;
|
|
25790
25852
|
}
|
|
25791
|
-
|
|
25853
|
+
return {
|
|
25792
25854
|
rgb: rgb || defaultColor,
|
|
25793
25855
|
auto: this.extractAttr(colorElement, "auto")?.asBool(),
|
|
25794
25856
|
indexed: this.extractAttr(colorElement, "indexed")?.asNum(),
|
|
25795
25857
|
tint: this.extractAttr(colorElement, "tint")?.asNum(),
|
|
25796
25858
|
};
|
|
25797
|
-
return color;
|
|
25798
25859
|
}
|
|
25799
25860
|
/**
|
|
25800
25861
|
* Returns the xml file targeted by a relationship.
|
|
@@ -26386,7 +26447,7 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
|
|
|
26386
26447
|
hyperlinks: this.extractHyperLinks(sheetElement),
|
|
26387
26448
|
tables: this.extractTables(sheetElement),
|
|
26388
26449
|
pivotTables: this.extractPivotTables(),
|
|
26389
|
-
isVisible: sheetWorkbookInfo.state === "visible"
|
|
26450
|
+
isVisible: sheetWorkbookInfo.state === "visible",
|
|
26390
26451
|
};
|
|
26391
26452
|
})[0];
|
|
26392
26453
|
}
|
|
@@ -26457,8 +26518,7 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
|
|
|
26457
26518
|
const figures = this.mapOnElements({ parent: worksheet, query: "drawing" }, (drawingElement) => {
|
|
26458
26519
|
const drawingId = this.extractAttr(drawingElement, "r:id", { required: true })?.asString();
|
|
26459
26520
|
const drawingFile = this.getTargetXmlFile(this.relationships[drawingId]);
|
|
26460
|
-
|
|
26461
|
-
return figures;
|
|
26521
|
+
return new XlsxFigureExtractor(drawingFile, this.xlsxFileStructure, this.warningManager).extractFigures();
|
|
26462
26522
|
})[0];
|
|
26463
26523
|
return figures || [];
|
|
26464
26524
|
}
|
|
@@ -26476,8 +26536,7 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
|
|
|
26476
26536
|
.filter((relationship) => relationship.type.endsWith("pivotTable"))
|
|
26477
26537
|
.map((pivotRelationship) => {
|
|
26478
26538
|
const pivotFile = this.getTargetXmlFile(pivotRelationship);
|
|
26479
|
-
|
|
26480
|
-
return pivot;
|
|
26539
|
+
return new XlsxPivotExtractor(pivotFile, this.xlsxFileStructure, this.warningManager).getPivotTable();
|
|
26481
26540
|
});
|
|
26482
26541
|
}
|
|
26483
26542
|
catch (e) {
|
|
@@ -26876,8 +26935,7 @@ class XlsxReader {
|
|
|
26876
26935
|
}
|
|
26877
26936
|
convertXlsx() {
|
|
26878
26937
|
const xlsxData = this.getXlsxData();
|
|
26879
|
-
|
|
26880
|
-
return convertedData;
|
|
26938
|
+
return this.convertImportedData(xlsxData);
|
|
26881
26939
|
}
|
|
26882
26940
|
// ---------------------------------------------------------------------------
|
|
26883
26941
|
// Parsing XMLs
|
|
@@ -27468,6 +27526,20 @@ migrationStepRegistry
|
|
|
27468
27526
|
}
|
|
27469
27527
|
return data;
|
|
27470
27528
|
},
|
|
27529
|
+
})
|
|
27530
|
+
.add("migration_22", {
|
|
27531
|
+
// "tables are no longer inserted with filters by default",
|
|
27532
|
+
versionFrom: "22",
|
|
27533
|
+
migrate(data) {
|
|
27534
|
+
for (const sheet of data.sheets || []) {
|
|
27535
|
+
for (const table of sheet.tables || []) {
|
|
27536
|
+
if (!table.config) {
|
|
27537
|
+
table.config = { ...DEFAULT_TABLE_CONFIG, hasFilters: true };
|
|
27538
|
+
}
|
|
27539
|
+
}
|
|
27540
|
+
}
|
|
27541
|
+
return data;
|
|
27542
|
+
},
|
|
27471
27543
|
});
|
|
27472
27544
|
function fixOverlappingFilters(data) {
|
|
27473
27545
|
for (let sheet of data.sheets || []) {
|
|
@@ -27495,7 +27567,7 @@ function fixOverlappingFilters(data) {
|
|
|
27495
27567
|
* a breaking change is made in the way the state is handled, and an upgrade
|
|
27496
27568
|
* function should be defined
|
|
27497
27569
|
*/
|
|
27498
|
-
const CURRENT_VERSION =
|
|
27570
|
+
const CURRENT_VERSION = 23;
|
|
27499
27571
|
const INITIAL_SHEET_ID = "Sheet1";
|
|
27500
27572
|
/**
|
|
27501
27573
|
* This function tries to load anything that could look like a valid
|
|
@@ -27508,7 +27580,7 @@ function load(data, verboseImport) {
|
|
|
27508
27580
|
if (!data) {
|
|
27509
27581
|
return createEmptyWorkbookData();
|
|
27510
27582
|
}
|
|
27511
|
-
console.
|
|
27583
|
+
console.debug("### Loading data ###");
|
|
27512
27584
|
const start = performance.now();
|
|
27513
27585
|
if (data["[Content_Types].xml"]) {
|
|
27514
27586
|
const reader = new XlsxReader(data);
|
|
@@ -27522,13 +27594,13 @@ function load(data, verboseImport) {
|
|
|
27522
27594
|
// apply migrations, if needed
|
|
27523
27595
|
if ("version" in data) {
|
|
27524
27596
|
if (data.version < CURRENT_VERSION) {
|
|
27525
|
-
console.
|
|
27597
|
+
console.debug("Migrating data from version", data.version);
|
|
27526
27598
|
data = migrate(data);
|
|
27527
27599
|
}
|
|
27528
27600
|
}
|
|
27529
27601
|
data = repairData(data);
|
|
27530
|
-
console.
|
|
27531
|
-
console.
|
|
27602
|
+
console.debug("Data loaded in", performance.now() - start, "ms");
|
|
27603
|
+
console.debug("###");
|
|
27532
27604
|
return data;
|
|
27533
27605
|
}
|
|
27534
27606
|
// -----------------------------------------------------------------------------
|
|
@@ -27558,7 +27630,7 @@ function migrate(data) {
|
|
|
27558
27630
|
for (let i = index; i < steps.length; i++) {
|
|
27559
27631
|
data = steps[i].migrate(data);
|
|
27560
27632
|
}
|
|
27561
|
-
console.
|
|
27633
|
+
console.debug("Data migrated in", performance.now() - start, "ms");
|
|
27562
27634
|
return data;
|
|
27563
27635
|
}
|
|
27564
27636
|
/**
|
|
@@ -27740,7 +27812,7 @@ function createEmptySheet(sheetId, name) {
|
|
|
27740
27812
|
};
|
|
27741
27813
|
}
|
|
27742
27814
|
function createEmptyWorkbookData(sheetName = "Sheet1") {
|
|
27743
|
-
|
|
27815
|
+
return {
|
|
27744
27816
|
version: CURRENT_VERSION,
|
|
27745
27817
|
sheets: [createEmptySheet(INITIAL_SHEET_ID, sheetName)],
|
|
27746
27818
|
styles: {},
|
|
@@ -27753,7 +27825,6 @@ function createEmptyWorkbookData(sheetName = "Sheet1") {
|
|
|
27753
27825
|
pivotNextId: 1,
|
|
27754
27826
|
customTableStyles: {},
|
|
27755
27827
|
};
|
|
27756
|
-
return data;
|
|
27757
27828
|
}
|
|
27758
27829
|
function createEmptyExcelSheet(sheetId, name) {
|
|
27759
27830
|
return {
|
|
@@ -28137,7 +28208,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { axisFormats, local
|
|
|
28137
28208
|
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
28138
28209
|
// tooltipItem.parsed can be an object or a number for pie charts
|
|
28139
28210
|
let yLabel = horizontalChart ? tooltipItem.parsed.x : tooltipItem.parsed.y;
|
|
28140
|
-
if (
|
|
28211
|
+
if (yLabel === undefined || yLabel === null) {
|
|
28141
28212
|
yLabel = tooltipItem.parsed;
|
|
28142
28213
|
}
|
|
28143
28214
|
const axisId = horizontalChart
|
|
@@ -28531,8 +28602,7 @@ function createBarChartRuntime(chart, getters) {
|
|
|
28531
28602
|
};
|
|
28532
28603
|
config.data.datasets.push(dataset);
|
|
28533
28604
|
if (definition.dataSets?.[index]?.label) {
|
|
28534
|
-
|
|
28535
|
-
dataset.label = label;
|
|
28605
|
+
dataset.label = definition.dataSets[index].label;
|
|
28536
28606
|
}
|
|
28537
28607
|
dataset.yAxisID = chart.horizontal ? "y" : definition.dataSets[index].yAxisId || "y";
|
|
28538
28608
|
dataset.xAxisID = "x";
|
|
@@ -28560,13 +28630,10 @@ function createBarChartRuntime(chart, getters) {
|
|
|
28560
28630
|
* datasets to ensure the way we distinguish the originals and trendLine datasets after
|
|
28561
28631
|
*/
|
|
28562
28632
|
trendDatasets.forEach((x) => config.data.datasets.push(x));
|
|
28563
|
-
const originalTooltipTitle = config.options.plugins.tooltip.callbacks.title;
|
|
28564
28633
|
config.options.plugins.tooltip.callbacks.title = function (tooltipItems) {
|
|
28565
|
-
|
|
28566
|
-
|
|
28567
|
-
|
|
28568
|
-
}
|
|
28569
|
-
return "";
|
|
28634
|
+
return tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID)
|
|
28635
|
+
? undefined
|
|
28636
|
+
: "";
|
|
28570
28637
|
};
|
|
28571
28638
|
}
|
|
28572
28639
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
@@ -28904,7 +28971,6 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28904
28971
|
else if (axisType === "linear") {
|
|
28905
28972
|
config.options.scales.x.type = "linear";
|
|
28906
28973
|
config.options.scales.x.ticks.callback = (value) => formatValue(value, { format: labelFormat, locale });
|
|
28907
|
-
config.options.plugins.tooltip.callbacks.title = () => "";
|
|
28908
28974
|
config.options.plugins.tooltip.callbacks.label = (tooltipItem) => {
|
|
28909
28975
|
const dataSetPoint = dataSetsValues[tooltipItem.datasetIndex].data[tooltipItem.dataIndex];
|
|
28910
28976
|
let label = tooltipItem.label || labelValues.values[tooltipItem.dataIndex];
|
|
@@ -28959,8 +29025,7 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28959
29025
|
const trendDatasets = [];
|
|
28960
29026
|
for (const [index, dataset] of config.data.datasets.entries()) {
|
|
28961
29027
|
if (definition.dataSets?.[index]?.label) {
|
|
28962
|
-
|
|
28963
|
-
dataset.label = label;
|
|
29028
|
+
dataset.label = definition.dataSets[index].label;
|
|
28964
29029
|
}
|
|
28965
29030
|
dataset["yAxisID"] = definition.dataSets[index].yAxisId || "y";
|
|
28966
29031
|
const trend = definition.dataSets?.[index].trend;
|
|
@@ -28989,15 +29054,12 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28989
29054
|
* distinguish the originals and trendLine datasets after
|
|
28990
29055
|
*/
|
|
28991
29056
|
trendDatasets.forEach((x) => config.data.datasets.push(x));
|
|
28992
|
-
const originalTooltipTitle = config.options.plugins.tooltip.callbacks.title;
|
|
28993
|
-
config.options.plugins.tooltip.callbacks.title = function (tooltipItems) {
|
|
28994
|
-
if (tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID)) {
|
|
28995
|
-
// @ts-expect-error
|
|
28996
|
-
return originalTooltipTitle?.(tooltipItems);
|
|
28997
|
-
}
|
|
28998
|
-
return "";
|
|
28999
|
-
};
|
|
29000
29057
|
}
|
|
29058
|
+
config.options.plugins.tooltip.callbacks.title = function (tooltipItems) {
|
|
29059
|
+
const displayTooltipTitle = axisType !== "linear" &&
|
|
29060
|
+
tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID);
|
|
29061
|
+
return displayTooltipTitle ? undefined : "";
|
|
29062
|
+
};
|
|
29001
29063
|
return {
|
|
29002
29064
|
chartJsConfig: config,
|
|
29003
29065
|
background: chart.background || BACKGROUND_CHART_COLOR,
|
|
@@ -29220,13 +29282,10 @@ function createComboChartRuntime(chart, getters) {
|
|
|
29220
29282
|
* distinguish the originals and trendLine datasets after
|
|
29221
29283
|
*/
|
|
29222
29284
|
trendDatasets.forEach((x) => config.data.datasets.push(x));
|
|
29223
|
-
const originalTooltipTitle = config.options.plugins.tooltip.callbacks.title;
|
|
29224
29285
|
config.options.plugins.tooltip.callbacks.title = function (tooltipItems) {
|
|
29225
|
-
|
|
29226
|
-
|
|
29227
|
-
|
|
29228
|
-
}
|
|
29229
|
-
return "";
|
|
29286
|
+
return tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID)
|
|
29287
|
+
? undefined
|
|
29288
|
+
: "";
|
|
29230
29289
|
};
|
|
29231
29290
|
}
|
|
29232
29291
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
@@ -29965,6 +30024,198 @@ function createPyramidChartRuntime(chart, getters) {
|
|
|
29965
30024
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
29966
30025
|
}
|
|
29967
30026
|
|
|
30027
|
+
class RadarChart extends AbstractChart {
|
|
30028
|
+
dataSets;
|
|
30029
|
+
labelRange;
|
|
30030
|
+
background;
|
|
30031
|
+
legendPosition;
|
|
30032
|
+
stacked;
|
|
30033
|
+
aggregated;
|
|
30034
|
+
type = "radar";
|
|
30035
|
+
dataSetsHaveTitle;
|
|
30036
|
+
dataSetDesign;
|
|
30037
|
+
fillArea;
|
|
30038
|
+
constructor(definition, sheetId, getters) {
|
|
30039
|
+
super(definition, sheetId, getters);
|
|
30040
|
+
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
30041
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
30042
|
+
this.background = definition.background;
|
|
30043
|
+
this.legendPosition = definition.legendPosition;
|
|
30044
|
+
this.stacked = definition.stacked;
|
|
30045
|
+
this.aggregated = definition.aggregated;
|
|
30046
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
30047
|
+
this.dataSetDesign = definition.dataSets;
|
|
30048
|
+
this.fillArea = definition.fillArea;
|
|
30049
|
+
}
|
|
30050
|
+
static transformDefinition(definition, executed) {
|
|
30051
|
+
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
30052
|
+
}
|
|
30053
|
+
static validateChartDefinition(validator, definition) {
|
|
30054
|
+
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
30055
|
+
}
|
|
30056
|
+
static getDefinitionFromContextCreation(context) {
|
|
30057
|
+
return {
|
|
30058
|
+
background: context.background,
|
|
30059
|
+
dataSets: context.range ?? [],
|
|
30060
|
+
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
30061
|
+
stacked: context.stacked ?? false,
|
|
30062
|
+
aggregated: context.aggregated ?? false,
|
|
30063
|
+
legendPosition: context.legendPosition ?? "top",
|
|
30064
|
+
title: context.title || { text: "" },
|
|
30065
|
+
type: "radar",
|
|
30066
|
+
labelRange: context.auxiliaryRange || undefined,
|
|
30067
|
+
fillArea: context.fillArea ?? false,
|
|
30068
|
+
};
|
|
30069
|
+
}
|
|
30070
|
+
getContextCreation() {
|
|
30071
|
+
const range = [];
|
|
30072
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
30073
|
+
range.push({
|
|
30074
|
+
...this.dataSetDesign?.[i],
|
|
30075
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
30076
|
+
});
|
|
30077
|
+
}
|
|
30078
|
+
return {
|
|
30079
|
+
...this,
|
|
30080
|
+
range,
|
|
30081
|
+
auxiliaryRange: this.labelRange
|
|
30082
|
+
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
30083
|
+
: undefined,
|
|
30084
|
+
};
|
|
30085
|
+
}
|
|
30086
|
+
copyForSheetId(sheetId) {
|
|
30087
|
+
const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
|
|
30088
|
+
const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
|
|
30089
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
|
|
30090
|
+
return new RadarChart(definition, sheetId, this.getters);
|
|
30091
|
+
}
|
|
30092
|
+
copyInSheetId(sheetId) {
|
|
30093
|
+
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
30094
|
+
return new RadarChart(definition, sheetId, this.getters);
|
|
30095
|
+
}
|
|
30096
|
+
getDefinition() {
|
|
30097
|
+
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
30098
|
+
}
|
|
30099
|
+
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
30100
|
+
const ranges = [];
|
|
30101
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
30102
|
+
ranges.push({
|
|
30103
|
+
...this.dataSetDesign?.[i],
|
|
30104
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
30105
|
+
});
|
|
30106
|
+
}
|
|
30107
|
+
return {
|
|
30108
|
+
type: "radar",
|
|
30109
|
+
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
30110
|
+
background: this.background,
|
|
30111
|
+
dataSets: ranges,
|
|
30112
|
+
legendPosition: this.legendPosition,
|
|
30113
|
+
labelRange: labelRange
|
|
30114
|
+
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
30115
|
+
: undefined,
|
|
30116
|
+
title: this.title,
|
|
30117
|
+
stacked: this.stacked,
|
|
30118
|
+
aggregated: this.aggregated,
|
|
30119
|
+
fillArea: this.fillArea,
|
|
30120
|
+
};
|
|
30121
|
+
}
|
|
30122
|
+
getDefinitionForExcel() {
|
|
30123
|
+
if (this.aggregated) {
|
|
30124
|
+
return undefined;
|
|
30125
|
+
}
|
|
30126
|
+
const dataSets = this.dataSets
|
|
30127
|
+
.map((ds) => toExcelDataset(this.getters, ds))
|
|
30128
|
+
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
30129
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
30130
|
+
const definition = this.getDefinition();
|
|
30131
|
+
return {
|
|
30132
|
+
...definition,
|
|
30133
|
+
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
30134
|
+
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
30135
|
+
dataSets,
|
|
30136
|
+
labelRange,
|
|
30137
|
+
};
|
|
30138
|
+
}
|
|
30139
|
+
updateRanges(applyChange) {
|
|
30140
|
+
const { dataSets, labelRange, isStale } = updateChartRangesWithDataSets(this.getters, applyChange, this.dataSets, this.labelRange);
|
|
30141
|
+
if (!isStale) {
|
|
30142
|
+
return this;
|
|
30143
|
+
}
|
|
30144
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange);
|
|
30145
|
+
return new RadarChart(definition, this.sheetId, this.getters);
|
|
30146
|
+
}
|
|
30147
|
+
}
|
|
30148
|
+
function createRadarChartRuntime(chart, getters) {
|
|
30149
|
+
const definition = chart.getDefinition();
|
|
30150
|
+
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
30151
|
+
let labels = labelValues.formattedValues;
|
|
30152
|
+
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
30153
|
+
if (chart.dataSetsHaveTitle &&
|
|
30154
|
+
dataSetsValues[0] &&
|
|
30155
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
30156
|
+
labels.shift();
|
|
30157
|
+
}
|
|
30158
|
+
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
30159
|
+
if (chart.aggregated) {
|
|
30160
|
+
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
30161
|
+
}
|
|
30162
|
+
const leftAxisFormat = getChartDatasetFormat(getters, chart.dataSets, "left");
|
|
30163
|
+
const rightAxisFormat = getChartDatasetFormat(getters, chart.dataSets, "right");
|
|
30164
|
+
const axisFormats = { y: leftAxisFormat, y1: rightAxisFormat };
|
|
30165
|
+
const locale = getters.getLocale();
|
|
30166
|
+
const fontColor = chartFontColor(chart.background);
|
|
30167
|
+
const config = getDefaultChartJsRuntime(chart, labels, fontColor, {
|
|
30168
|
+
axisFormats,
|
|
30169
|
+
locale,
|
|
30170
|
+
});
|
|
30171
|
+
const legend = {
|
|
30172
|
+
labels: { color: fontColor },
|
|
30173
|
+
};
|
|
30174
|
+
if ((!chart.labelRange && chart.dataSets.length === 1) || chart.legendPosition === "none") {
|
|
30175
|
+
legend.display = false;
|
|
30176
|
+
}
|
|
30177
|
+
else {
|
|
30178
|
+
legend.position = chart.legendPosition;
|
|
30179
|
+
}
|
|
30180
|
+
const fill = definition.fillArea ?? false;
|
|
30181
|
+
if (!fill) {
|
|
30182
|
+
legend.labels["boxHeight"] = 0;
|
|
30183
|
+
}
|
|
30184
|
+
config.options.plugins.legend = { ...config.options.plugins?.legend, ...legend };
|
|
30185
|
+
config.options.plugins.tooltip = {
|
|
30186
|
+
...config.options.plugins?.tooltip,
|
|
30187
|
+
callbacks: {
|
|
30188
|
+
label: function (tooltipItem) {
|
|
30189
|
+
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
30190
|
+
const yLabel = tooltipItem.parsed.r;
|
|
30191
|
+
return xLabel ? `${xLabel}: ${yLabel}` : yLabel.toString();
|
|
30192
|
+
},
|
|
30193
|
+
},
|
|
30194
|
+
};
|
|
30195
|
+
config.options.layout = {
|
|
30196
|
+
padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
|
|
30197
|
+
};
|
|
30198
|
+
const colorGenerator = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
30199
|
+
for (let i = 0; i < dataSetsValues.length; i++) {
|
|
30200
|
+
let { label, data } = dataSetsValues[i];
|
|
30201
|
+
if (definition.dataSets?.[i]?.label) {
|
|
30202
|
+
label = definition.dataSets[i].label;
|
|
30203
|
+
}
|
|
30204
|
+
const borderColor = colorGenerator.next();
|
|
30205
|
+
const dataset = {
|
|
30206
|
+
label,
|
|
30207
|
+
data,
|
|
30208
|
+
borderColor,
|
|
30209
|
+
};
|
|
30210
|
+
if (fill) {
|
|
30211
|
+
dataset.backgroundColor = setColorAlpha(borderColor, 0.3);
|
|
30212
|
+
dataset["fill"] = true;
|
|
30213
|
+
}
|
|
30214
|
+
config.data.datasets.push(dataset);
|
|
30215
|
+
}
|
|
30216
|
+
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
30217
|
+
}
|
|
30218
|
+
|
|
29968
30219
|
class ScatterChart extends AbstractChart {
|
|
29969
30220
|
dataSets;
|
|
29970
30221
|
labelRange;
|
|
@@ -30487,6 +30738,15 @@ chartRegistry.add("pyramid", {
|
|
|
30487
30738
|
getChartDefinitionFromContextCreation: PyramidChart.getDefinitionFromContextCreation,
|
|
30488
30739
|
sequence: 80,
|
|
30489
30740
|
});
|
|
30741
|
+
chartRegistry.add("radar", {
|
|
30742
|
+
match: (type) => type === "radar",
|
|
30743
|
+
createChart: (definition, sheetId, getters) => new RadarChart(definition, sheetId, getters),
|
|
30744
|
+
getChartRuntime: createRadarChartRuntime,
|
|
30745
|
+
validateChartDefinition: RadarChart.validateChartDefinition,
|
|
30746
|
+
transformDefinition: RadarChart.transformDefinition,
|
|
30747
|
+
getChartDefinitionFromContextCreation: RadarChart.getDefinitionFromContextCreation,
|
|
30748
|
+
sequence: 80,
|
|
30749
|
+
});
|
|
30490
30750
|
const chartComponentRegistry = new Registry();
|
|
30491
30751
|
chartComponentRegistry.add("line", ChartJsComponent);
|
|
30492
30752
|
chartComponentRegistry.add("bar", ChartJsComponent);
|
|
@@ -30497,6 +30757,7 @@ chartComponentRegistry.add("scatter", ChartJsComponent);
|
|
|
30497
30757
|
chartComponentRegistry.add("scorecard", ScorecardChart);
|
|
30498
30758
|
chartComponentRegistry.add("waterfall", ChartJsComponent);
|
|
30499
30759
|
chartComponentRegistry.add("pyramid", ChartJsComponent);
|
|
30760
|
+
chartComponentRegistry.add("radar", ChartJsComponent);
|
|
30500
30761
|
const chartCategories = {
|
|
30501
30762
|
line: _t("Line"),
|
|
30502
30763
|
column: _t("Column"),
|
|
@@ -30638,6 +30899,24 @@ chartSubtypeRegistry
|
|
|
30638
30899
|
chartType: "pyramid",
|
|
30639
30900
|
category: "misc",
|
|
30640
30901
|
preview: "o-spreadsheet-ChartPreview.POPULATION_PYRAMID_CHART",
|
|
30902
|
+
})
|
|
30903
|
+
.add("radar", {
|
|
30904
|
+
matcher: (definition) => definition.type === "radar" && !definition.fillArea,
|
|
30905
|
+
displayName: _t("Radar"),
|
|
30906
|
+
chartSubtype: "radar",
|
|
30907
|
+
chartType: "radar",
|
|
30908
|
+
subtypeDefinition: { fillArea: false },
|
|
30909
|
+
category: "misc",
|
|
30910
|
+
preview: "o-spreadsheet-ChartPreview.RADAR_CHART",
|
|
30911
|
+
})
|
|
30912
|
+
.add("filled_radar", {
|
|
30913
|
+
matcher: (definition) => definition.type === "radar" && !!definition.fillArea,
|
|
30914
|
+
displayName: _t("Filled Radar"),
|
|
30915
|
+
chartType: "radar",
|
|
30916
|
+
chartSubtype: "filled_radar",
|
|
30917
|
+
subtypeDefinition: { fillArea: true },
|
|
30918
|
+
category: "misc",
|
|
30919
|
+
preview: "o-spreadsheet-ChartPreview.FILLED_RADAR_CHART",
|
|
30641
30920
|
});
|
|
30642
30921
|
|
|
30643
30922
|
/**
|
|
@@ -30705,11 +30984,10 @@ function centerFigurePosition(getters, size) {
|
|
|
30705
30984
|
const rect = getters.getVisibleRect(getters.getActiveMainViewport());
|
|
30706
30985
|
const scrollableViewportWidth = Math.min(rect.width, dim.width - offsetCorrectionX);
|
|
30707
30986
|
const scrollableViewportHeight = Math.min(rect.height, dim.height - offsetCorrectionY);
|
|
30708
|
-
|
|
30987
|
+
return {
|
|
30709
30988
|
x: offsetCorrectionX + scrollX + Math.max(0, (scrollableViewportWidth - size.width) / 2),
|
|
30710
30989
|
y: offsetCorrectionY + scrollY + Math.max(0, (scrollableViewportHeight - size.height) / 2),
|
|
30711
30990
|
}; // Position at the center of the scrollable viewport
|
|
30712
|
-
return position;
|
|
30713
30991
|
}
|
|
30714
30992
|
function getMaxFigureSize(getters, figureSize) {
|
|
30715
30993
|
const size = deepCopy(figureSize);
|
|
@@ -31282,14 +31560,13 @@ class PopoverPositionContext {
|
|
|
31282
31560
|
const shouldRenderAtBottom = this.shouldRenderAtBottom(elDims.height);
|
|
31283
31561
|
const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
|
|
31284
31562
|
verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
|
|
31285
|
-
|
|
31563
|
+
return {
|
|
31286
31564
|
top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
|
|
31287
31565
|
this.spreadsheetOffset.y -
|
|
31288
31566
|
verticalOffset +
|
|
31289
31567
|
"px",
|
|
31290
31568
|
left: this.getLeftCoordinate(actualWidth, shouldRenderAtRight) - this.spreadsheetOffset.x + "px",
|
|
31291
31569
|
};
|
|
31292
|
-
return cssProperties;
|
|
31293
31570
|
}
|
|
31294
31571
|
getCurrentPosition(elDims) {
|
|
31295
31572
|
const shouldRenderAtBottom = this.shouldRenderAtBottom(elDims.height);
|
|
@@ -32517,7 +32794,7 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
32517
32794
|
* Create a table on the selected zone, with UI warnings to the user if the creation fails.
|
|
32518
32795
|
* If a single cell is selected, expand the selection to non-empty adjacent cells to create a table.
|
|
32519
32796
|
*/
|
|
32520
|
-
function interactiveCreateTable(env, sheetId, tableConfig) {
|
|
32797
|
+
function interactiveCreateTable(env, sheetId, tableConfig = DEFAULT_TABLE_CONFIG) {
|
|
32521
32798
|
let target = env.model.getters.getSelectedZones();
|
|
32522
32799
|
let isDynamic = env.model.getters.canCreateDynamicTableOnZones(sheetId, target);
|
|
32523
32800
|
if (target.length === 1 && !isDynamic && getZoneArea(target[0]) === 1) {
|
|
@@ -33576,7 +33853,7 @@ function getColumnsNumber(env) {
|
|
|
33576
33853
|
}
|
|
33577
33854
|
|
|
33578
33855
|
const pivotProperties = {
|
|
33579
|
-
name: _t("
|
|
33856
|
+
name: _t("See pivot properties"),
|
|
33580
33857
|
execute(env) {
|
|
33581
33858
|
const position = env.model.getters.getActivePosition();
|
|
33582
33859
|
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
@@ -33730,8 +34007,7 @@ cellMenuRegistry
|
|
|
33730
34007
|
})
|
|
33731
34008
|
.add("pivot_properties", {
|
|
33732
34009
|
...pivotProperties,
|
|
33733
|
-
sequence:
|
|
33734
|
-
separator: true,
|
|
34010
|
+
sequence: 170,
|
|
33735
34011
|
});
|
|
33736
34012
|
|
|
33737
34013
|
const sortRange = {
|
|
@@ -35478,6 +35754,7 @@ class Section extends Component {
|
|
|
35478
35754
|
static template = "o_spreadsheet.Section";
|
|
35479
35755
|
static props = {
|
|
35480
35756
|
class: { type: String, optional: true },
|
|
35757
|
+
title: { type: String, optional: true },
|
|
35481
35758
|
slots: Object,
|
|
35482
35759
|
};
|
|
35483
35760
|
}
|
|
@@ -36207,17 +36484,11 @@ class BarConfigPanel extends GenericChartConfigPanel {
|
|
|
36207
36484
|
stacked,
|
|
36208
36485
|
});
|
|
36209
36486
|
}
|
|
36210
|
-
onUpdateAggregated(aggregated) {
|
|
36211
|
-
this.props.updateChart(this.props.figureId, {
|
|
36212
|
-
aggregated,
|
|
36213
|
-
});
|
|
36214
|
-
}
|
|
36215
36487
|
}
|
|
36216
36488
|
|
|
36217
36489
|
css /* scss */ `
|
|
36218
36490
|
.o_side_panel_collapsible_title {
|
|
36219
36491
|
font-size: 16px;
|
|
36220
|
-
font-weight: bold;
|
|
36221
36492
|
cursor: pointer;
|
|
36222
36493
|
padding: 6px 0px 6px 6px !important;
|
|
36223
36494
|
|
|
@@ -36254,49 +36525,40 @@ class SidePanelCollapsible extends Component {
|
|
|
36254
36525
|
static template = "o-spreadsheet-SidePanelCollapsible";
|
|
36255
36526
|
static props = {
|
|
36256
36527
|
slots: Object,
|
|
36528
|
+
title: { type: String, optional: true },
|
|
36257
36529
|
collapsedAtInit: { type: Boolean, optional: true },
|
|
36258
36530
|
class: { type: String, optional: true },
|
|
36259
36531
|
};
|
|
36260
36532
|
currentId = (CURRENT_COLLAPSIBLE_ID++).toString();
|
|
36261
36533
|
}
|
|
36262
36534
|
|
|
36263
|
-
const CIRCLE_SVG = /*xml*/ `
|
|
36264
|
-
<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'>
|
|
36265
|
-
<circle r="2" fill="#FFF"/>
|
|
36266
|
-
</svg>
|
|
36267
|
-
`;
|
|
36268
36535
|
css /* scss */ `
|
|
36269
|
-
.o-
|
|
36270
|
-
|
|
36271
|
-
|
|
36272
|
-
-
|
|
36273
|
-
|
|
36274
|
-
|
|
36275
|
-
height: 14px;
|
|
36276
|
-
border: 1px solid ${GRAY_300};
|
|
36277
|
-
box-sizing: border-box;
|
|
36278
|
-
outline: none;
|
|
36279
|
-
border-radius: 8px;
|
|
36280
|
-
|
|
36281
|
-
&:checked {
|
|
36282
|
-
background: url("data:image/svg+xml,${encodeURIComponent(CIRCLE_SVG)}");
|
|
36283
|
-
background-color: ${ACTION_COLOR};
|
|
36536
|
+
.o-badge-selection {
|
|
36537
|
+
gap: 1px;
|
|
36538
|
+
button.o-button {
|
|
36539
|
+
border-radius: 0;
|
|
36540
|
+
&.selected {
|
|
36541
|
+
color: ${GRAY_900};
|
|
36284
36542
|
border-color: ${ACTION_COLOR};
|
|
36543
|
+
background: ${BADGE_SELECTED_COLOR};
|
|
36544
|
+
font-weight: 600;
|
|
36545
|
+
}
|
|
36546
|
+
|
|
36547
|
+
&:first-child {
|
|
36548
|
+
border-radius: 4px 0 0 4px;
|
|
36549
|
+
}
|
|
36550
|
+
&:last-child {
|
|
36551
|
+
border-radius: 0 4px 4px 0;
|
|
36285
36552
|
}
|
|
36286
36553
|
}
|
|
36287
36554
|
}
|
|
36288
36555
|
`;
|
|
36289
|
-
class
|
|
36290
|
-
static template = "o-spreadsheet.
|
|
36556
|
+
class BadgeSelection extends Component {
|
|
36557
|
+
static template = "o-spreadsheet.BadgeSelection";
|
|
36291
36558
|
static props = {
|
|
36292
36559
|
choices: Array,
|
|
36293
36560
|
onChange: Function,
|
|
36294
|
-
selectedValue:
|
|
36295
|
-
name: String,
|
|
36296
|
-
direction: { type: String, optional: true },
|
|
36297
|
-
};
|
|
36298
|
-
static defaultProps = {
|
|
36299
|
-
direction: "horizontal",
|
|
36561
|
+
selectedValue: String,
|
|
36300
36562
|
};
|
|
36301
36563
|
}
|
|
36302
36564
|
|
|
@@ -36841,86 +37103,6 @@ class ColorPickerWidget extends Component {
|
|
|
36841
37103
|
}
|
|
36842
37104
|
}
|
|
36843
37105
|
|
|
36844
|
-
const TRANSPARENT_BACKGROUND_SVG = /*xml*/ `
|
|
36845
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">
|
|
36846
|
-
<path fill="#d9d9d9" d="M5 5h5v5H5zH0V0h5"/>
|
|
36847
|
-
</svg>
|
|
36848
|
-
`;
|
|
36849
|
-
css /* scss */ `
|
|
36850
|
-
.o-round-color-picker-button {
|
|
36851
|
-
width: 18px;
|
|
36852
|
-
height: 18px;
|
|
36853
|
-
cursor: pointer;
|
|
36854
|
-
border: 1px solid ${GRAY_300};
|
|
36855
|
-
background-position: 1px 1px;
|
|
36856
|
-
background-image: url("data:image/svg+xml,${encodeURIComponent(TRANSPARENT_BACKGROUND_SVG)}");
|
|
36857
|
-
}
|
|
36858
|
-
`;
|
|
36859
|
-
class RoundColorPicker extends Component {
|
|
36860
|
-
static template = "o-spreadsheet.RoundColorPicker";
|
|
36861
|
-
static components = { ColorPickerWidget, Section, ColorPicker };
|
|
36862
|
-
static props = {
|
|
36863
|
-
currentColor: { type: String, optional: true },
|
|
36864
|
-
title: { type: String, optional: true },
|
|
36865
|
-
onColorPicked: Function,
|
|
36866
|
-
};
|
|
36867
|
-
colorPickerButtonRef = useRef("colorPickerButton");
|
|
36868
|
-
state;
|
|
36869
|
-
setup() {
|
|
36870
|
-
this.state = useState({ pickerOpened: false });
|
|
36871
|
-
useExternalListener(window, "click", this.closePicker);
|
|
36872
|
-
}
|
|
36873
|
-
closePicker() {
|
|
36874
|
-
this.state.pickerOpened = false;
|
|
36875
|
-
}
|
|
36876
|
-
togglePicker() {
|
|
36877
|
-
this.state.pickerOpened = !this.state.pickerOpened;
|
|
36878
|
-
}
|
|
36879
|
-
onColorPicked(color) {
|
|
36880
|
-
this.props.onColorPicked(color);
|
|
36881
|
-
this.state.pickerOpened = false;
|
|
36882
|
-
}
|
|
36883
|
-
get colorPickerAnchorRect() {
|
|
36884
|
-
const button = this.colorPickerButtonRef.el;
|
|
36885
|
-
return getBoundingRectAsPOJO(button);
|
|
36886
|
-
}
|
|
36887
|
-
get buttonStyle() {
|
|
36888
|
-
return cssPropertiesToCss({
|
|
36889
|
-
background: this.props.currentColor,
|
|
36890
|
-
});
|
|
36891
|
-
}
|
|
36892
|
-
}
|
|
36893
|
-
|
|
36894
|
-
css /* scss */ `
|
|
36895
|
-
.o-badge-selection {
|
|
36896
|
-
gap: 1px;
|
|
36897
|
-
button.o-button {
|
|
36898
|
-
border-radius: 0;
|
|
36899
|
-
&.selected {
|
|
36900
|
-
color: ${GRAY_900};
|
|
36901
|
-
border-color: ${ACTION_COLOR};
|
|
36902
|
-
background: ${BADGE_SELECTED_COLOR};
|
|
36903
|
-
font-weight: 600;
|
|
36904
|
-
}
|
|
36905
|
-
|
|
36906
|
-
&:first-child {
|
|
36907
|
-
border-radius: 4px 0 0 4px;
|
|
36908
|
-
}
|
|
36909
|
-
&:last-child {
|
|
36910
|
-
border-radius: 0 4px 4px 0;
|
|
36911
|
-
}
|
|
36912
|
-
}
|
|
36913
|
-
}
|
|
36914
|
-
`;
|
|
36915
|
-
class BadgeSelection extends Component {
|
|
36916
|
-
static template = "o-spreadsheet.BadgeSelection";
|
|
36917
|
-
static props = {
|
|
36918
|
-
choices: Array,
|
|
36919
|
-
onChange: Function,
|
|
36920
|
-
selectedValue: String,
|
|
36921
|
-
};
|
|
36922
|
-
}
|
|
36923
|
-
|
|
36924
37106
|
css /* scss */ `
|
|
36925
37107
|
.o-chart-title-designer {
|
|
36926
37108
|
> span {
|
|
@@ -37075,8 +37257,7 @@ class AxisDesignEditor extends Component {
|
|
|
37075
37257
|
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
37076
37258
|
}
|
|
37077
37259
|
updateAxisEditor(ev) {
|
|
37078
|
-
|
|
37079
|
-
this.state.currentAxis = axis;
|
|
37260
|
+
this.state.currentAxis = ev.target.value;
|
|
37080
37261
|
}
|
|
37081
37262
|
getAxisTitle() {
|
|
37082
37263
|
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
@@ -37095,6 +37276,56 @@ class AxisDesignEditor extends Component {
|
|
|
37095
37276
|
}
|
|
37096
37277
|
}
|
|
37097
37278
|
|
|
37279
|
+
const TRANSPARENT_BACKGROUND_SVG = /*xml*/ `
|
|
37280
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">
|
|
37281
|
+
<path fill="#d9d9d9" d="M5 5h5v5H5zH0V0h5"/>
|
|
37282
|
+
</svg>
|
|
37283
|
+
`;
|
|
37284
|
+
css /* scss */ `
|
|
37285
|
+
.o-round-color-picker-button {
|
|
37286
|
+
width: 18px;
|
|
37287
|
+
height: 18px;
|
|
37288
|
+
cursor: pointer;
|
|
37289
|
+
border: 1px solid ${GRAY_300};
|
|
37290
|
+
background-position: 1px 1px;
|
|
37291
|
+
background-image: url("data:image/svg+xml,${encodeURIComponent(TRANSPARENT_BACKGROUND_SVG)}");
|
|
37292
|
+
}
|
|
37293
|
+
`;
|
|
37294
|
+
class RoundColorPicker extends Component {
|
|
37295
|
+
static template = "o-spreadsheet.RoundColorPicker";
|
|
37296
|
+
static components = { Section, ColorPicker };
|
|
37297
|
+
static props = {
|
|
37298
|
+
currentColor: { type: String, optional: true },
|
|
37299
|
+
title: { type: String, optional: true },
|
|
37300
|
+
onColorPicked: Function,
|
|
37301
|
+
};
|
|
37302
|
+
colorPickerButtonRef = useRef("colorPickerButton");
|
|
37303
|
+
state;
|
|
37304
|
+
setup() {
|
|
37305
|
+
this.state = useState({ pickerOpened: false });
|
|
37306
|
+
useExternalListener(window, "click", this.closePicker);
|
|
37307
|
+
}
|
|
37308
|
+
closePicker() {
|
|
37309
|
+
this.state.pickerOpened = false;
|
|
37310
|
+
}
|
|
37311
|
+
togglePicker() {
|
|
37312
|
+
this.state.pickerOpened = !this.state.pickerOpened;
|
|
37313
|
+
}
|
|
37314
|
+
onColorPicked(color) {
|
|
37315
|
+
this.props.onColorPicked(color);
|
|
37316
|
+
this.state.pickerOpened = false;
|
|
37317
|
+
}
|
|
37318
|
+
get colorPickerAnchorRect() {
|
|
37319
|
+
const button = this.colorPickerButtonRef.el;
|
|
37320
|
+
return getBoundingRectAsPOJO(button);
|
|
37321
|
+
}
|
|
37322
|
+
get buttonStyle() {
|
|
37323
|
+
return cssPropertiesToCss({
|
|
37324
|
+
background: this.props.currentColor,
|
|
37325
|
+
});
|
|
37326
|
+
}
|
|
37327
|
+
}
|
|
37328
|
+
|
|
37098
37329
|
class GeneralDesignEditor extends Component {
|
|
37099
37330
|
static template = "o-spreadsheet-GeneralDesignEditor";
|
|
37100
37331
|
static components = {
|
|
@@ -37159,58 +37390,75 @@ class GeneralDesignEditor extends Component {
|
|
|
37159
37390
|
}
|
|
37160
37391
|
}
|
|
37161
37392
|
|
|
37162
|
-
|
|
37163
|
-
|
|
37393
|
+
const CIRCLE_SVG = /*xml*/ `
|
|
37394
|
+
<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'>
|
|
37395
|
+
<circle r="2" fill="#FFF"/>
|
|
37396
|
+
</svg>
|
|
37397
|
+
`;
|
|
37398
|
+
css /* scss */ `
|
|
37399
|
+
.o-radio {
|
|
37400
|
+
input {
|
|
37401
|
+
appearance: none;
|
|
37402
|
+
-webkit-appearance: none;
|
|
37403
|
+
-moz-appearance: none;
|
|
37404
|
+
width: 14px;
|
|
37405
|
+
height: 14px;
|
|
37406
|
+
border: 1px solid ${GRAY_300};
|
|
37407
|
+
box-sizing: border-box;
|
|
37408
|
+
outline: none;
|
|
37409
|
+
border-radius: 8px;
|
|
37410
|
+
|
|
37411
|
+
&:checked {
|
|
37412
|
+
background: url("data:image/svg+xml,${encodeURIComponent(CIRCLE_SVG)}");
|
|
37413
|
+
background-color: ${ACTION_COLOR};
|
|
37414
|
+
border-color: ${ACTION_COLOR};
|
|
37415
|
+
}
|
|
37416
|
+
}
|
|
37417
|
+
}
|
|
37418
|
+
`;
|
|
37419
|
+
class RadioSelection extends Component {
|
|
37420
|
+
static template = "o-spreadsheet.RadioSelection";
|
|
37421
|
+
static props = {
|
|
37422
|
+
choices: Array,
|
|
37423
|
+
onChange: Function,
|
|
37424
|
+
selectedValue: { optional: false },
|
|
37425
|
+
name: String,
|
|
37426
|
+
direction: { type: String, optional: true },
|
|
37427
|
+
};
|
|
37428
|
+
static defaultProps = {
|
|
37429
|
+
direction: "horizontal",
|
|
37430
|
+
};
|
|
37431
|
+
}
|
|
37432
|
+
|
|
37433
|
+
class SeriesDesignEditor extends Component {
|
|
37434
|
+
static template = "o-spreadsheet-SeriesDesignEditor";
|
|
37164
37435
|
static components = {
|
|
37165
|
-
GeneralDesignEditor,
|
|
37166
37436
|
SidePanelCollapsible,
|
|
37167
37437
|
Section,
|
|
37168
|
-
AxisDesignEditor,
|
|
37169
37438
|
RoundColorPicker,
|
|
37170
|
-
Checkbox,
|
|
37171
|
-
RadioSelection,
|
|
37172
37439
|
};
|
|
37173
37440
|
static props = {
|
|
37174
37441
|
figureId: String,
|
|
37175
37442
|
definition: Object,
|
|
37176
|
-
canUpdateChart: Function,
|
|
37177
37443
|
updateChart: Function,
|
|
37444
|
+
canUpdateChart: Function,
|
|
37445
|
+
slots: { type: Object, optional: true },
|
|
37178
37446
|
};
|
|
37179
|
-
axisChoices = CHART_AXIS_CHOICES;
|
|
37180
37447
|
state = useState({ index: 0 });
|
|
37181
|
-
get axesList() {
|
|
37182
|
-
const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
|
|
37183
|
-
let axes = [{ id: "x", name: _t("Horizontal axis") }];
|
|
37184
|
-
if (useLeftAxis) {
|
|
37185
|
-
axes.push({ id: "y", name: useRightAxis ? _t("Left axis") : _t("Vertical axis") });
|
|
37186
|
-
}
|
|
37187
|
-
if (useRightAxis) {
|
|
37188
|
-
axes.push({ id: "y1", name: useLeftAxis ? _t("Right axis") : _t("Vertical axis") });
|
|
37189
|
-
}
|
|
37190
|
-
return axes;
|
|
37191
|
-
}
|
|
37192
|
-
updateLegendPosition(ev) {
|
|
37193
|
-
this.props.updateChart(this.props.figureId, {
|
|
37194
|
-
legendPosition: ev.target.value,
|
|
37195
|
-
});
|
|
37196
|
-
}
|
|
37197
37448
|
getDataSeries() {
|
|
37198
|
-
|
|
37449
|
+
const runtime = this.env.model.getters.getChartRuntime(this.props.figureId);
|
|
37450
|
+
if (!runtime || !("chartJsConfig" in runtime)) {
|
|
37451
|
+
return [];
|
|
37452
|
+
}
|
|
37453
|
+
return runtime.chartJsConfig.data.datasets.map((d) => d.label);
|
|
37199
37454
|
}
|
|
37200
37455
|
updateSerieEditor(ev) {
|
|
37201
|
-
|
|
37202
|
-
const selectedIndex = ev.target.selectedIndex;
|
|
37203
|
-
const runtime = this.env.model.getters.getChartRuntime(chartId);
|
|
37204
|
-
if (!runtime) {
|
|
37205
|
-
return;
|
|
37206
|
-
}
|
|
37207
|
-
this.state.index = selectedIndex;
|
|
37456
|
+
this.state.index = ev.target.selectedIndex;
|
|
37208
37457
|
}
|
|
37209
37458
|
updateDataSeriesColor(color) {
|
|
37210
|
-
const dataSets =
|
|
37211
|
-
if (!dataSets?.[this.state.index])
|
|
37459
|
+
const dataSets = this.props.definition.dataSets;
|
|
37460
|
+
if (!dataSets?.[this.state.index])
|
|
37212
37461
|
return;
|
|
37213
|
-
}
|
|
37214
37462
|
dataSets[this.state.index] = {
|
|
37215
37463
|
...dataSets[this.state.index],
|
|
37216
37464
|
backgroundColor: color,
|
|
@@ -37219,71 +37467,87 @@ class ChartWithAxisDesignPanel extends Component {
|
|
|
37219
37467
|
}
|
|
37220
37468
|
getDataSerieColor() {
|
|
37221
37469
|
const dataSets = this.props.definition.dataSets;
|
|
37222
|
-
if (!dataSets?.[this.state.index])
|
|
37470
|
+
if (!dataSets?.[this.state.index])
|
|
37223
37471
|
return "";
|
|
37224
|
-
}
|
|
37225
37472
|
const color = dataSets[this.state.index].backgroundColor;
|
|
37226
|
-
return color
|
|
37473
|
+
return color
|
|
37474
|
+
? toHex(color)
|
|
37475
|
+
: getNthColor(this.state.index, getColorsPalette(this.props.definition.dataSets.length));
|
|
37227
37476
|
}
|
|
37228
|
-
|
|
37229
|
-
const
|
|
37230
|
-
|
|
37477
|
+
updateDataSeriesLabel(ev) {
|
|
37478
|
+
const label = ev.target.value;
|
|
37479
|
+
const dataSets = this.props.definition.dataSets;
|
|
37480
|
+
if (!dataSets?.[this.state.index])
|
|
37231
37481
|
return;
|
|
37232
|
-
}
|
|
37233
37482
|
dataSets[this.state.index] = {
|
|
37234
37483
|
...dataSets[this.state.index],
|
|
37235
|
-
|
|
37484
|
+
label,
|
|
37236
37485
|
};
|
|
37237
37486
|
this.props.updateChart(this.props.figureId, { dataSets });
|
|
37238
37487
|
}
|
|
37239
|
-
|
|
37488
|
+
getDataSerieLabel() {
|
|
37240
37489
|
const dataSets = this.props.definition.dataSets;
|
|
37241
|
-
|
|
37242
|
-
return "left";
|
|
37243
|
-
}
|
|
37244
|
-
return dataSets[this.state.index].yAxisId === "y1" ? "right" : "left";
|
|
37245
|
-
}
|
|
37246
|
-
get canHaveTwoVerticalAxis() {
|
|
37247
|
-
return "horizontal" in this.props.definition ? !this.props.definition.horizontal : true;
|
|
37490
|
+
return dataSets[this.state.index]?.label || this.getDataSeries()[this.state.index];
|
|
37248
37491
|
}
|
|
37249
|
-
|
|
37250
|
-
|
|
37492
|
+
}
|
|
37493
|
+
|
|
37494
|
+
class SeriesWithAxisDesignEditor extends Component {
|
|
37495
|
+
static template = "o-spreadsheet-SeriesWithAxisDesignEditor";
|
|
37496
|
+
static components = {
|
|
37497
|
+
SeriesDesignEditor,
|
|
37498
|
+
Checkbox,
|
|
37499
|
+
RadioSelection,
|
|
37500
|
+
Section,
|
|
37501
|
+
RoundColorPicker,
|
|
37502
|
+
};
|
|
37503
|
+
static props = {
|
|
37504
|
+
figureId: String,
|
|
37505
|
+
definition: Object,
|
|
37506
|
+
canUpdateChart: Function,
|
|
37507
|
+
updateChart: Function,
|
|
37508
|
+
slots: { type: Object, optional: true },
|
|
37509
|
+
};
|
|
37510
|
+
axisChoices = CHART_AXIS_CHOICES;
|
|
37511
|
+
updateDataSeriesAxis(index, axis) {
|
|
37251
37512
|
const dataSets = [...this.props.definition.dataSets];
|
|
37252
|
-
if (!dataSets?.[
|
|
37513
|
+
if (!dataSets?.[index]) {
|
|
37253
37514
|
return;
|
|
37254
37515
|
}
|
|
37255
|
-
dataSets[
|
|
37256
|
-
...dataSets[
|
|
37257
|
-
|
|
37516
|
+
dataSets[index] = {
|
|
37517
|
+
...dataSets[index],
|
|
37518
|
+
yAxisId: axis === "left" ? "y" : "y1",
|
|
37258
37519
|
};
|
|
37259
37520
|
this.props.updateChart(this.props.figureId, { dataSets });
|
|
37260
37521
|
}
|
|
37261
|
-
|
|
37522
|
+
getDataSerieAxis(index) {
|
|
37262
37523
|
const dataSets = this.props.definition.dataSets;
|
|
37263
|
-
|
|
37524
|
+
if (!dataSets?.[index]) {
|
|
37525
|
+
return "left";
|
|
37526
|
+
}
|
|
37527
|
+
return dataSets[index].yAxisId === "y1" ? "right" : "left";
|
|
37264
37528
|
}
|
|
37265
|
-
|
|
37266
|
-
this.props.
|
|
37529
|
+
get canHaveTwoVerticalAxis() {
|
|
37530
|
+
return !("horizontal" in this.props.definition && this.props.definition.horizontal);
|
|
37267
37531
|
}
|
|
37268
|
-
toggleDataTrend(display) {
|
|
37532
|
+
toggleDataTrend(index, display) {
|
|
37269
37533
|
const dataSets = [...this.props.definition.dataSets];
|
|
37270
|
-
if (!dataSets?.[
|
|
37534
|
+
if (!dataSets?.[index]) {
|
|
37271
37535
|
return;
|
|
37272
37536
|
}
|
|
37273
|
-
dataSets[
|
|
37274
|
-
...dataSets[
|
|
37537
|
+
dataSets[index] = {
|
|
37538
|
+
...dataSets[index],
|
|
37275
37539
|
trend: {
|
|
37276
37540
|
type: "polynomial",
|
|
37277
37541
|
order: 1,
|
|
37278
|
-
...dataSets[
|
|
37542
|
+
...dataSets[index].trend,
|
|
37279
37543
|
display,
|
|
37280
37544
|
},
|
|
37281
37545
|
};
|
|
37282
37546
|
this.props.updateChart(this.props.figureId, { dataSets });
|
|
37283
37547
|
}
|
|
37284
|
-
getTrendLineConfiguration() {
|
|
37548
|
+
getTrendLineConfiguration(index) {
|
|
37285
37549
|
const dataSets = this.props.definition.dataSets;
|
|
37286
|
-
return dataSets?.[
|
|
37550
|
+
return dataSets?.[index]?.trend;
|
|
37287
37551
|
}
|
|
37288
37552
|
getTrendType(config) {
|
|
37289
37553
|
if (!config) {
|
|
@@ -37291,7 +37555,7 @@ class ChartWithAxisDesignPanel extends Component {
|
|
|
37291
37555
|
}
|
|
37292
37556
|
return config.type === "polynomial" && config.order === 1 ? "linear" : config.type;
|
|
37293
37557
|
}
|
|
37294
|
-
onChangeTrendType(ev) {
|
|
37558
|
+
onChangeTrendType(index, ev) {
|
|
37295
37559
|
const type = ev.target.value;
|
|
37296
37560
|
let config;
|
|
37297
37561
|
switch (type) {
|
|
@@ -37304,37 +37568,59 @@ class ChartWithAxisDesignPanel extends Component {
|
|
|
37304
37568
|
break;
|
|
37305
37569
|
case "exponential":
|
|
37306
37570
|
case "logarithmic":
|
|
37571
|
+
case "trailingMovingAverage":
|
|
37307
37572
|
config = { type };
|
|
37308
37573
|
break;
|
|
37309
37574
|
default:
|
|
37310
37575
|
return;
|
|
37311
37576
|
}
|
|
37312
|
-
this.updateTrendLineValue(config);
|
|
37577
|
+
this.updateTrendLineValue(index, config);
|
|
37313
37578
|
}
|
|
37314
|
-
onChangePolynomialDegree(ev) {
|
|
37579
|
+
onChangePolynomialDegree(index, ev) {
|
|
37315
37580
|
const element = ev.target;
|
|
37316
37581
|
const order = parseInt(element.value || "1");
|
|
37317
37582
|
if (order < 2) {
|
|
37318
|
-
element.value = `${this.getTrendLineConfiguration()?.order ?? 2}`;
|
|
37583
|
+
element.value = `${this.getTrendLineConfiguration(index)?.order ?? 2}`;
|
|
37319
37584
|
return;
|
|
37320
37585
|
}
|
|
37321
|
-
this.updateTrendLineValue({ order });
|
|
37586
|
+
this.updateTrendLineValue(index, { order });
|
|
37322
37587
|
}
|
|
37323
|
-
|
|
37324
|
-
return
|
|
37588
|
+
get defaultWindowSize() {
|
|
37589
|
+
return DEFAULT_WINDOW_SIZE;
|
|
37325
37590
|
}
|
|
37326
|
-
|
|
37327
|
-
|
|
37591
|
+
onChangeMovingAverageWindow(index, ev) {
|
|
37592
|
+
const element = ev.target;
|
|
37593
|
+
let window = parseInt(element.value) || DEFAULT_WINDOW_SIZE;
|
|
37594
|
+
if (window <= 1) {
|
|
37595
|
+
window = DEFAULT_WINDOW_SIZE;
|
|
37596
|
+
}
|
|
37597
|
+
this.updateTrendLineValue(index, { window });
|
|
37328
37598
|
}
|
|
37329
|
-
|
|
37599
|
+
getDataSerieColor(index) {
|
|
37600
|
+
const dataSets = this.props.definition.dataSets;
|
|
37601
|
+
if (!dataSets?.[index])
|
|
37602
|
+
return "";
|
|
37603
|
+
const color = dataSets[index].backgroundColor;
|
|
37604
|
+
return color
|
|
37605
|
+
? toHex(color)
|
|
37606
|
+
: getNthColor(index, getColorsPalette(this.props.definition.dataSets.length));
|
|
37607
|
+
}
|
|
37608
|
+
getTrendLineColor(index) {
|
|
37609
|
+
return (this.getTrendLineConfiguration(index)?.color ??
|
|
37610
|
+
setColorAlpha(this.getDataSerieColor(index), 0.5));
|
|
37611
|
+
}
|
|
37612
|
+
updateTrendLineColor(index, color) {
|
|
37613
|
+
this.updateTrendLineValue(index, { color });
|
|
37614
|
+
}
|
|
37615
|
+
updateTrendLineValue(index, config) {
|
|
37330
37616
|
const dataSets = [...this.props.definition.dataSets];
|
|
37331
|
-
if (!dataSets?.[
|
|
37617
|
+
if (!dataSets?.[index]) {
|
|
37332
37618
|
return;
|
|
37333
37619
|
}
|
|
37334
|
-
dataSets[
|
|
37335
|
-
...dataSets[
|
|
37620
|
+
dataSets[index] = {
|
|
37621
|
+
...dataSets[index],
|
|
37336
37622
|
trend: {
|
|
37337
|
-
...dataSets[
|
|
37623
|
+
...dataSets[index].trend,
|
|
37338
37624
|
...config,
|
|
37339
37625
|
},
|
|
37340
37626
|
};
|
|
@@ -37342,29 +37628,67 @@ class ChartWithAxisDesignPanel extends Component {
|
|
|
37342
37628
|
}
|
|
37343
37629
|
}
|
|
37344
37630
|
|
|
37631
|
+
class ChartWithAxisDesignPanel extends Component {
|
|
37632
|
+
static template = "o-spreadsheet-ChartWithAxisDesignPanel";
|
|
37633
|
+
static components = {
|
|
37634
|
+
GeneralDesignEditor,
|
|
37635
|
+
SidePanelCollapsible,
|
|
37636
|
+
Section,
|
|
37637
|
+
AxisDesignEditor,
|
|
37638
|
+
Checkbox,
|
|
37639
|
+
SeriesWithAxisDesignEditor,
|
|
37640
|
+
};
|
|
37641
|
+
static props = {
|
|
37642
|
+
figureId: String,
|
|
37643
|
+
definition: Object,
|
|
37644
|
+
canUpdateChart: Function,
|
|
37645
|
+
updateChart: Function,
|
|
37646
|
+
};
|
|
37647
|
+
get axesList() {
|
|
37648
|
+
const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
|
|
37649
|
+
let axes = [{ id: "x", name: _t("Horizontal axis") }];
|
|
37650
|
+
if (useLeftAxis) {
|
|
37651
|
+
axes.push({ id: "y", name: useRightAxis ? _t("Left axis") : _t("Vertical axis") });
|
|
37652
|
+
}
|
|
37653
|
+
if (useRightAxis) {
|
|
37654
|
+
axes.push({ id: "y1", name: useLeftAxis ? _t("Right axis") : _t("Vertical axis") });
|
|
37655
|
+
}
|
|
37656
|
+
return axes;
|
|
37657
|
+
}
|
|
37658
|
+
updateLegendPosition(ev) {
|
|
37659
|
+
this.props.updateChart(this.props.figureId, {
|
|
37660
|
+
legendPosition: ev.target.value,
|
|
37661
|
+
});
|
|
37662
|
+
}
|
|
37663
|
+
}
|
|
37664
|
+
|
|
37345
37665
|
class ComboChartDesignPanel extends ChartWithAxisDesignPanel {
|
|
37346
37666
|
static template = "o-spreadsheet-ComboChartDesignPanel";
|
|
37667
|
+
static components = {
|
|
37668
|
+
...ChartWithAxisDesignPanel.components,
|
|
37669
|
+
RadioSelection,
|
|
37670
|
+
};
|
|
37347
37671
|
seriesTypeChoices = [
|
|
37348
37672
|
{ value: "bar", label: _t("Bar") },
|
|
37349
37673
|
{ value: "line", label: _t("Line") },
|
|
37350
37674
|
];
|
|
37351
|
-
updateDataSeriesType(type) {
|
|
37675
|
+
updateDataSeriesType(index, type) {
|
|
37352
37676
|
const dataSets = [...this.props.definition.dataSets];
|
|
37353
|
-
if (!dataSets?.[
|
|
37677
|
+
if (!dataSets?.[index]) {
|
|
37354
37678
|
return;
|
|
37355
37679
|
}
|
|
37356
|
-
dataSets[
|
|
37357
|
-
...dataSets[
|
|
37680
|
+
dataSets[index] = {
|
|
37681
|
+
...dataSets[index],
|
|
37358
37682
|
type,
|
|
37359
37683
|
};
|
|
37360
37684
|
this.props.updateChart(this.props.figureId, { dataSets });
|
|
37361
37685
|
}
|
|
37362
|
-
getDataSeriesType() {
|
|
37686
|
+
getDataSeriesType(index) {
|
|
37363
37687
|
const dataSets = this.props.definition.dataSets;
|
|
37364
|
-
if (!dataSets?.[
|
|
37688
|
+
if (!dataSets?.[index]) {
|
|
37365
37689
|
return "bar";
|
|
37366
37690
|
}
|
|
37367
|
-
return dataSets[
|
|
37691
|
+
return dataSets[index].type ?? "line";
|
|
37368
37692
|
}
|
|
37369
37693
|
}
|
|
37370
37694
|
|
|
@@ -37547,11 +37871,6 @@ class LineConfigPanel extends GenericChartConfigPanel {
|
|
|
37547
37871
|
stacked,
|
|
37548
37872
|
});
|
|
37549
37873
|
}
|
|
37550
|
-
onUpdateAggregated(aggregated) {
|
|
37551
|
-
this.props.updateChart(this.props.figureId, {
|
|
37552
|
-
aggregated,
|
|
37553
|
-
});
|
|
37554
|
-
}
|
|
37555
37874
|
onUpdateCumulative(cumulative) {
|
|
37556
37875
|
this.props.updateChart(this.props.figureId, {
|
|
37557
37876
|
cumulative,
|
|
@@ -37579,6 +37898,27 @@ class PieChartDesignPanel extends Component {
|
|
|
37579
37898
|
}
|
|
37580
37899
|
}
|
|
37581
37900
|
|
|
37901
|
+
class RadarChartDesignPanel extends Component {
|
|
37902
|
+
static template = "o-spreadsheet-RadarChartDesignPanel";
|
|
37903
|
+
static components = {
|
|
37904
|
+
GeneralDesignEditor,
|
|
37905
|
+
SeriesDesignEditor,
|
|
37906
|
+
Section,
|
|
37907
|
+
Checkbox,
|
|
37908
|
+
};
|
|
37909
|
+
static props = {
|
|
37910
|
+
figureId: String,
|
|
37911
|
+
definition: Object,
|
|
37912
|
+
canUpdateChart: Function,
|
|
37913
|
+
updateChart: Function,
|
|
37914
|
+
};
|
|
37915
|
+
updateLegendPosition(ev) {
|
|
37916
|
+
this.props.updateChart(this.props.figureId, {
|
|
37917
|
+
legendPosition: ev.target.value,
|
|
37918
|
+
});
|
|
37919
|
+
}
|
|
37920
|
+
}
|
|
37921
|
+
|
|
37582
37922
|
class ScatterConfigPanel extends GenericChartConfigPanel {
|
|
37583
37923
|
static template = "o-spreadsheet-ScatterConfigPanel";
|
|
37584
37924
|
get canTreatLabelsAsText() {
|
|
@@ -37773,9 +38113,6 @@ class WaterfallChartDesignPanel extends Component {
|
|
|
37773
38113
|
verticalAxisPosition: value,
|
|
37774
38114
|
});
|
|
37775
38115
|
}
|
|
37776
|
-
updateShowValues(showValues) {
|
|
37777
|
-
this.props.updateChart(this.props.figureId, { showValues });
|
|
37778
|
-
}
|
|
37779
38116
|
}
|
|
37780
38117
|
|
|
37781
38118
|
const chartSidePanelComponentRegistry = new Registry();
|
|
@@ -37815,6 +38152,10 @@ chartSidePanelComponentRegistry
|
|
|
37815
38152
|
.add("pyramid", {
|
|
37816
38153
|
configuration: GenericChartConfigPanel,
|
|
37817
38154
|
design: ChartWithAxisDesignPanel,
|
|
38155
|
+
})
|
|
38156
|
+
.add("radar", {
|
|
38157
|
+
configuration: GenericChartConfigPanel,
|
|
38158
|
+
design: RadarChartDesignPanel,
|
|
37818
38159
|
});
|
|
37819
38160
|
|
|
37820
38161
|
css /* scss */ `
|
|
@@ -39017,13 +39358,6 @@ class DOMDndHelper {
|
|
|
39017
39358
|
return;
|
|
39018
39359
|
this.edgeScrollIntervalId = window.setInterval(() => {
|
|
39019
39360
|
const offset = direction * 3;
|
|
39020
|
-
let newPosition = this.currentMousePosition + offset;
|
|
39021
|
-
if (newPosition < Math.min(this.container.start, this.minPosition)) {
|
|
39022
|
-
newPosition = Math.min(this.container.start, this.minPosition);
|
|
39023
|
-
}
|
|
39024
|
-
else if (newPosition > Math.max(this.container.end, this.maxPosition)) {
|
|
39025
|
-
newPosition = Math.max(this.container.end, this.maxPosition);
|
|
39026
|
-
}
|
|
39027
39361
|
this.container.scroll += offset;
|
|
39028
39362
|
}, 5);
|
|
39029
39363
|
}
|
|
@@ -39200,7 +39534,6 @@ css /* scss */ `
|
|
|
39200
39534
|
width: 142px;
|
|
39201
39535
|
.o-cf-preview-description-rule {
|
|
39202
39536
|
margin-bottom: 4px;
|
|
39203
|
-
font-weight: 600;
|
|
39204
39537
|
max-height: 2.8em;
|
|
39205
39538
|
line-height: 1.4em;
|
|
39206
39539
|
}
|
|
@@ -39672,7 +40005,7 @@ class ConditionalFormattingEditor extends Component {
|
|
|
39672
40005
|
setColorScaleColor(target, color) {
|
|
39673
40006
|
const point = this.state.rules.colorScale[target];
|
|
39674
40007
|
if (point) {
|
|
39675
|
-
point.color = Number.parseInt(color.
|
|
40008
|
+
point.color = Number.parseInt(color.slice(1), 16);
|
|
39676
40009
|
}
|
|
39677
40010
|
this.closeMenus();
|
|
39678
40011
|
}
|
|
@@ -39783,7 +40116,7 @@ class ConditionalFormattingEditor extends Component {
|
|
|
39783
40116
|
return [this.state.rules.dataBar.rangeValues || ""];
|
|
39784
40117
|
}
|
|
39785
40118
|
updateDataBarColor(color) {
|
|
39786
|
-
this.state.rules.dataBar.color = Number.parseInt(color.
|
|
40119
|
+
this.state.rules.dataBar.color = Number.parseInt(color.slice(1), 16);
|
|
39787
40120
|
}
|
|
39788
40121
|
onDataBarRangeUpdate(ranges) {
|
|
39789
40122
|
this.state.rules.dataBar.rangeValues = ranges[0];
|
|
@@ -41196,10 +41529,11 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41196
41529
|
activeSheetMatches = [];
|
|
41197
41530
|
specificRangeMatches = [];
|
|
41198
41531
|
currentSearchRegex = null;
|
|
41199
|
-
isSearchDirty = false;
|
|
41200
41532
|
initialShowFormulaState;
|
|
41201
41533
|
preserveSelectedMatchIndex = false;
|
|
41202
41534
|
irreplaceableMatchCount = 0;
|
|
41535
|
+
isSearchDirty = false;
|
|
41536
|
+
shouldFinalizeUpdateSelection = false;
|
|
41203
41537
|
notificationStore = this.get(NotificationStore);
|
|
41204
41538
|
// fixme: why do we make selectedMatchIndex on top of a selected
|
|
41205
41539
|
// property in the matches?
|
|
@@ -41245,10 +41579,13 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41245
41579
|
this.updateSearchOptions({ searchFormulas: showFormula });
|
|
41246
41580
|
}
|
|
41247
41581
|
selectPreviousMatch() {
|
|
41248
|
-
this.selectNextCell(Direction.previous
|
|
41582
|
+
this.selectNextCell(Direction.previous, {
|
|
41583
|
+
jumpToMatchSheet: true,
|
|
41584
|
+
updateSelection: true,
|
|
41585
|
+
});
|
|
41249
41586
|
}
|
|
41250
41587
|
selectNextMatch() {
|
|
41251
|
-
this.selectNextCell(Direction.next);
|
|
41588
|
+
this.selectNextCell(Direction.next, { jumpToMatchSheet: true, updateSelection: true });
|
|
41252
41589
|
}
|
|
41253
41590
|
handle(cmd) {
|
|
41254
41591
|
switch (cmd.type) {
|
|
@@ -41265,8 +41602,11 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41265
41602
|
case "ADD_COLUMNS_ROWS":
|
|
41266
41603
|
case "EVALUATE_CELLS":
|
|
41267
41604
|
case "UPDATE_CELL":
|
|
41605
|
+
this.isSearchDirty = true;
|
|
41606
|
+
break;
|
|
41268
41607
|
case "ACTIVATE_SHEET":
|
|
41269
41608
|
this.isSearchDirty = true;
|
|
41609
|
+
this.shouldFinalizeUpdateSelection = true;
|
|
41270
41610
|
break;
|
|
41271
41611
|
case "REPLACE_SEARCH":
|
|
41272
41612
|
for (const match of cmd.matches) {
|
|
@@ -41281,7 +41621,11 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41281
41621
|
}
|
|
41282
41622
|
finalize() {
|
|
41283
41623
|
if (this.isSearchDirty) {
|
|
41284
|
-
this.refreshSearch(
|
|
41624
|
+
this.refreshSearch({
|
|
41625
|
+
jumpToMatchSheet: false,
|
|
41626
|
+
updateSelection: this.shouldFinalizeUpdateSelection,
|
|
41627
|
+
});
|
|
41628
|
+
this.shouldFinalizeUpdateSelection = false;
|
|
41285
41629
|
this.isSearchDirty = false;
|
|
41286
41630
|
}
|
|
41287
41631
|
}
|
|
@@ -41308,17 +41652,17 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41308
41652
|
}
|
|
41309
41653
|
this.toSearch = toSearch;
|
|
41310
41654
|
this.currentSearchRegex = getSearchRegex(this.toSearch, this.searchOptions);
|
|
41311
|
-
this.refreshSearch();
|
|
41655
|
+
this.refreshSearch({ jumpToMatchSheet: true, updateSelection: true });
|
|
41312
41656
|
}
|
|
41313
41657
|
/**
|
|
41314
41658
|
* refresh the matches according to the current search options
|
|
41315
41659
|
*/
|
|
41316
|
-
refreshSearch(
|
|
41660
|
+
refreshSearch(options) {
|
|
41317
41661
|
if (!this.preserveSelectedMatchIndex) {
|
|
41318
41662
|
this.selectedMatchIndex = null;
|
|
41319
41663
|
}
|
|
41320
41664
|
this.findMatches();
|
|
41321
|
-
this.selectNextCell(Direction.current,
|
|
41665
|
+
this.selectNextCell(Direction.current, options);
|
|
41322
41666
|
}
|
|
41323
41667
|
getSheetsInSearchOrder() {
|
|
41324
41668
|
switch (this.searchOptions.searchScope) {
|
|
@@ -41388,7 +41732,7 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41388
41732
|
* It is also used to keep coherence between the selected searchMatch
|
|
41389
41733
|
* and selectedMatchIndex.
|
|
41390
41734
|
*/
|
|
41391
|
-
selectNextCell(indexChange,
|
|
41735
|
+
selectNextCell(indexChange, options) {
|
|
41392
41736
|
const matches = this.searchMatches;
|
|
41393
41737
|
if (!matches.length) {
|
|
41394
41738
|
this.selectedMatchIndex = null;
|
|
@@ -41414,7 +41758,7 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41414
41758
|
this.selectedMatchIndex = nextIndex;
|
|
41415
41759
|
const selectedMatch = matches[nextIndex];
|
|
41416
41760
|
// Switch to the sheet where the match is located
|
|
41417
|
-
if (jumpToMatchSheet && this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
41761
|
+
if (options.jumpToMatchSheet && this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
41418
41762
|
// We set `preserveSelectedMatchIndex` to true to avoid resetting the selected search
|
|
41419
41763
|
// index in the `refreshSearch` function when a new sheet is activated. The reason being
|
|
41420
41764
|
// that, when we automatically go back to previous sheet while performing a search, the
|
|
@@ -41430,7 +41774,9 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41430
41774
|
}
|
|
41431
41775
|
// we want grid selection to capture the selection stream
|
|
41432
41776
|
this.model.selection.getBackToDefault();
|
|
41433
|
-
|
|
41777
|
+
if (options.updateSelection) {
|
|
41778
|
+
this.model.selection.selectCell(selectedMatch.col, selectedMatch.row);
|
|
41779
|
+
}
|
|
41434
41780
|
}
|
|
41435
41781
|
/**
|
|
41436
41782
|
* Replace the value of the currently selected match
|
|
@@ -41445,7 +41791,7 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
41445
41791
|
matches: [this.searchMatches[this.selectedMatchIndex]],
|
|
41446
41792
|
searchOptions: this.searchOptions,
|
|
41447
41793
|
});
|
|
41448
|
-
this.selectNextCell(Direction.next);
|
|
41794
|
+
this.selectNextCell(Direction.next, { jumpToMatchSheet: true, updateSelection: true });
|
|
41449
41795
|
}
|
|
41450
41796
|
/**
|
|
41451
41797
|
* Apply the replace function to all the matches one time.
|
|
@@ -41627,6 +41973,14 @@ class FindAndReplacePanel extends Component {
|
|
|
41627
41973
|
onMounted(() => this.searchInput.el?.focus());
|
|
41628
41974
|
onWillUnmount(() => this.updateSearchContent.stopDebounce());
|
|
41629
41975
|
this.updateSearchContent = debounce(this.store.updateSearchContent, 200);
|
|
41976
|
+
useExternalListener(window, "keydown", (ev) => {
|
|
41977
|
+
const code = keyboardEventToShortcutString(ev);
|
|
41978
|
+
if (code === "Ctrl+F" || code === "Ctrl+H") {
|
|
41979
|
+
this.searchInput.el?.focus();
|
|
41980
|
+
ev.preventDefault();
|
|
41981
|
+
ev.stopPropagation();
|
|
41982
|
+
}
|
|
41983
|
+
}, { capture: true });
|
|
41630
41984
|
}
|
|
41631
41985
|
onFocusSearch() {
|
|
41632
41986
|
this.updateDataRange();
|
|
@@ -42202,7 +42556,6 @@ function createMeasureAutoComplete(pivot, forComputedMeasure) {
|
|
|
42202
42556
|
sequence: 0,
|
|
42203
42557
|
autoSelectFirstProposal: true,
|
|
42204
42558
|
getProposals(tokenAtCursor) {
|
|
42205
|
-
// return []
|
|
42206
42559
|
const measureProposals = pivot.measures
|
|
42207
42560
|
.filter((m) => m !== forComputedMeasure)
|
|
42208
42561
|
.map((measure) => {
|
|
@@ -43783,13 +44136,15 @@ pivotRegistry.add("SPREADSHEET", {
|
|
|
43783
44136
|
class PivotSidePanelStore extends SpreadsheetStore {
|
|
43784
44137
|
pivotId;
|
|
43785
44138
|
mutators = ["reset", "deferUpdates", "applyUpdate", "discardPendingUpdate", "update"];
|
|
43786
|
-
updatesAreDeferred
|
|
44139
|
+
updatesAreDeferred;
|
|
43787
44140
|
draft = null;
|
|
43788
44141
|
notification = this.get(NotificationStore);
|
|
43789
44142
|
alreadyNotified = false;
|
|
43790
44143
|
constructor(get, pivotId) {
|
|
43791
44144
|
super(get);
|
|
43792
44145
|
this.pivotId = pivotId;
|
|
44146
|
+
this.updatesAreDeferred =
|
|
44147
|
+
this.getters.getPivotCoreDefinition(this.pivotId).deferUpdates ?? false;
|
|
43793
44148
|
}
|
|
43794
44149
|
handle(cmd) {
|
|
43795
44150
|
switch (cmd.type) {
|
|
@@ -43877,10 +44232,14 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
43877
44232
|
this.draft = null;
|
|
43878
44233
|
}
|
|
43879
44234
|
deferUpdates(shouldDefer) {
|
|
43880
|
-
this.updatesAreDeferred = shouldDefer;
|
|
43881
44235
|
if (shouldDefer === false && this.draft) {
|
|
44236
|
+
this.draft.deferUpdates = false;
|
|
43882
44237
|
this.applyUpdate();
|
|
43883
44238
|
}
|
|
44239
|
+
else {
|
|
44240
|
+
this.update({ deferUpdates: shouldDefer });
|
|
44241
|
+
}
|
|
44242
|
+
this.updatesAreDeferred = shouldDefer;
|
|
43884
44243
|
}
|
|
43885
44244
|
applyUpdate() {
|
|
43886
44245
|
if (this.draft) {
|
|
@@ -44138,7 +44497,7 @@ class RemoveDuplicatesPanel extends Component {
|
|
|
44138
44497
|
return colLabel;
|
|
44139
44498
|
}
|
|
44140
44499
|
get isEveryColumnSelected() {
|
|
44141
|
-
return Object.values(this.state.columns).every((value) => value
|
|
44500
|
+
return Object.values(this.state.columns).every((value) => value);
|
|
44142
44501
|
}
|
|
44143
44502
|
get errorMessages() {
|
|
44144
44503
|
const cancelledReasons = this.env.model.canDispatch("REMOVE_DUPLICATES", {
|
|
@@ -44238,8 +44597,7 @@ class SettingsPanel extends Component {
|
|
|
44238
44597
|
const currentLocale = this.currentLocale;
|
|
44239
44598
|
const localeInLoadedLocales = this.loadedLocales.find((l) => l.code === currentLocale.code);
|
|
44240
44599
|
if (!localeInLoadedLocales) {
|
|
44241
|
-
|
|
44242
|
-
return locales;
|
|
44600
|
+
return [...this.loadedLocales, currentLocale].sort((a, b) => a.name.localeCompare(b.name));
|
|
44243
44601
|
}
|
|
44244
44602
|
else if (!deepEquals(currentLocale, localeInLoadedLocales)) {
|
|
44245
44603
|
const index = this.loadedLocales.indexOf(localeInLoadedLocales);
|
|
@@ -46133,10 +46491,9 @@ class GridComposer extends Component {
|
|
|
46133
46491
|
});
|
|
46134
46492
|
}
|
|
46135
46493
|
get focus() {
|
|
46136
|
-
|
|
46494
|
+
return this.composerFocusStore.activeComposer === this.composerInterface
|
|
46137
46495
|
? this.composerFocusStore.focusMode
|
|
46138
46496
|
: "inactive";
|
|
46139
|
-
return focus;
|
|
46140
46497
|
}
|
|
46141
46498
|
get composerProps() {
|
|
46142
46499
|
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
@@ -47143,6 +47500,7 @@ class PaintFormatStore extends SpreadsheetStore {
|
|
|
47143
47500
|
new CellClipboardHandler(this.getters, this.model.dispatch),
|
|
47144
47501
|
new BorderClipboardHandler(this.getters, this.model.dispatch),
|
|
47145
47502
|
new TableClipboardHandler(this.getters, this.model.dispatch),
|
|
47503
|
+
new ConditionalFormatClipboardHandler(this.getters, this.model.dispatch),
|
|
47146
47504
|
];
|
|
47147
47505
|
status = "inactive";
|
|
47148
47506
|
copiedData;
|
|
@@ -47153,6 +47511,13 @@ class PaintFormatStore extends SpreadsheetStore {
|
|
|
47153
47511
|
this.highlightStore.unRegister(this);
|
|
47154
47512
|
});
|
|
47155
47513
|
}
|
|
47514
|
+
handle(cmd) {
|
|
47515
|
+
switch (cmd.type) {
|
|
47516
|
+
case "PAINT_FORMAT":
|
|
47517
|
+
this.paintFormat(cmd.sheetId, cmd.target);
|
|
47518
|
+
break;
|
|
47519
|
+
}
|
|
47520
|
+
}
|
|
47156
47521
|
activate(args) {
|
|
47157
47522
|
this.copiedData = this.copyFormats();
|
|
47158
47523
|
this.status = args.persistent ? "persistent" : "oneOff";
|
|
@@ -47162,18 +47527,7 @@ class PaintFormatStore extends SpreadsheetStore {
|
|
|
47162
47527
|
this.copiedData = undefined;
|
|
47163
47528
|
}
|
|
47164
47529
|
pasteFormat(target) {
|
|
47165
|
-
|
|
47166
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
47167
|
-
for (const handler of this.clipboardHandlers) {
|
|
47168
|
-
handler.paste({ zones: target, sheetId }, this.copiedData, {
|
|
47169
|
-
isCutOperation: false,
|
|
47170
|
-
pasteOption: "onlyFormat",
|
|
47171
|
-
});
|
|
47172
|
-
}
|
|
47173
|
-
}
|
|
47174
|
-
if (this.status === "oneOff") {
|
|
47175
|
-
this.cancel();
|
|
47176
|
-
}
|
|
47530
|
+
this.model.dispatch("PAINT_FORMAT", { target, sheetId: this.getters.getActiveSheetId() });
|
|
47177
47531
|
}
|
|
47178
47532
|
get isActive() {
|
|
47179
47533
|
return this.status !== "inactive";
|
|
@@ -47187,6 +47541,19 @@ class PaintFormatStore extends SpreadsheetStore {
|
|
|
47187
47541
|
}
|
|
47188
47542
|
return copiedData;
|
|
47189
47543
|
}
|
|
47544
|
+
paintFormat(sheetId, target) {
|
|
47545
|
+
if (this.copiedData) {
|
|
47546
|
+
for (const handler of this.clipboardHandlers) {
|
|
47547
|
+
handler.paste({ zones: target, sheetId }, this.copiedData, {
|
|
47548
|
+
isCutOperation: false,
|
|
47549
|
+
pasteOption: "onlyFormat",
|
|
47550
|
+
});
|
|
47551
|
+
}
|
|
47552
|
+
}
|
|
47553
|
+
if (this.status === "oneOff") {
|
|
47554
|
+
this.cancel();
|
|
47555
|
+
}
|
|
47556
|
+
}
|
|
47190
47557
|
get highlights() {
|
|
47191
47558
|
const data = this.copiedData;
|
|
47192
47559
|
if (!data) {
|
|
@@ -47563,7 +47930,7 @@ class AbstractResizer extends Component {
|
|
|
47563
47930
|
if (index < 0) {
|
|
47564
47931
|
return;
|
|
47565
47932
|
}
|
|
47566
|
-
if (this.state.waitingForMove
|
|
47933
|
+
if (this.state.waitingForMove) {
|
|
47567
47934
|
if (!this.env.model.getters.isGridSelectionActive()) {
|
|
47568
47935
|
this._selectElement(index, false);
|
|
47569
47936
|
}
|
|
@@ -49122,7 +49489,7 @@ class SidePanelStore extends SpreadsheetStore {
|
|
|
49122
49489
|
}
|
|
49123
49490
|
open(componentTag, panelProps = {}) {
|
|
49124
49491
|
const state = this.computeState(componentTag, panelProps);
|
|
49125
|
-
if (state.isOpen
|
|
49492
|
+
if (!state.isOpen) {
|
|
49126
49493
|
return;
|
|
49127
49494
|
}
|
|
49128
49495
|
if (this.isOpen && componentTag !== this.componentTag) {
|
|
@@ -49461,6 +49828,8 @@ class Grid extends Component {
|
|
|
49461
49828
|
},
|
|
49462
49829
|
"Ctrl+D": async () => this.env.model.dispatch("COPY_PASTE_CELLS_ABOVE"),
|
|
49463
49830
|
"Ctrl+R": async () => this.env.model.dispatch("COPY_PASTE_CELLS_ON_LEFT"),
|
|
49831
|
+
"Ctrl+H": () => this.sidePanel.open("FindAndReplace", {}),
|
|
49832
|
+
"Ctrl+F": () => this.sidePanel.open("FindAndReplace", {}),
|
|
49464
49833
|
"Ctrl+Shift+E": () => this.setHorizontalAlign("center"),
|
|
49465
49834
|
"Ctrl+Shift+L": () => this.setHorizontalAlign("left"),
|
|
49466
49835
|
"Ctrl+Shift+R": () => this.setHorizontalAlign("right"),
|
|
@@ -49868,31 +50237,6 @@ class Grid extends Component {
|
|
|
49868
50237
|
}
|
|
49869
50238
|
}
|
|
49870
50239
|
|
|
49871
|
-
/** @odoo-module */
|
|
49872
|
-
class EditableName extends Component {
|
|
49873
|
-
static template = "o-spreadsheet-EditableName";
|
|
49874
|
-
static props = {
|
|
49875
|
-
name: String,
|
|
49876
|
-
displayName: String,
|
|
49877
|
-
onChanged: Function,
|
|
49878
|
-
};
|
|
49879
|
-
state;
|
|
49880
|
-
setup() {
|
|
49881
|
-
this.state = useState({
|
|
49882
|
-
isEditing: false,
|
|
49883
|
-
name: "",
|
|
49884
|
-
});
|
|
49885
|
-
}
|
|
49886
|
-
rename() {
|
|
49887
|
-
this.state.isEditing = true;
|
|
49888
|
-
this.state.name = this.props.name;
|
|
49889
|
-
}
|
|
49890
|
-
save() {
|
|
49891
|
-
this.props.onChanged(this.state.name.trim());
|
|
49892
|
-
this.state.isEditing = false;
|
|
49893
|
-
}
|
|
49894
|
-
}
|
|
49895
|
-
|
|
49896
50240
|
/**
|
|
49897
50241
|
* BasePlugin
|
|
49898
50242
|
*
|
|
@@ -53810,7 +54154,7 @@ class SheetPlugin extends CorePlugin {
|
|
|
53810
54154
|
this.sheetIdsMapName[sheet.name] = sheet.id;
|
|
53811
54155
|
}
|
|
53812
54156
|
for (let sheetData of data.sheets) {
|
|
53813
|
-
const name = sheetData.name ||
|
|
54157
|
+
const name = sheetData.name || "Sheet" + (Object.keys(this.sheets).length + 1);
|
|
53814
54158
|
const { colNumber, rowNumber } = this.getImportedSheetSize(sheetData);
|
|
53815
54159
|
const sheet = {
|
|
53816
54160
|
id: sheetData.id,
|
|
@@ -55429,7 +55773,7 @@ class PivotCorePlugin extends CorePlugin {
|
|
|
55429
55773
|
case "DUPLICATE_PIVOT": {
|
|
55430
55774
|
const { pivotId, newPivotId } = cmd;
|
|
55431
55775
|
const pivot = deepCopy(this.getPivotCore(pivotId).definition);
|
|
55432
|
-
pivot.name =
|
|
55776
|
+
pivot.name = cmd.duplicatedPivotName ?? pivot.name + " (copy)";
|
|
55433
55777
|
this.addPivot(newPivotId, pivot);
|
|
55434
55778
|
break;
|
|
55435
55779
|
}
|
|
@@ -55469,7 +55813,7 @@ class PivotCorePlugin extends CorePlugin {
|
|
|
55469
55813
|
return `(#${formulaId}) ${this.getPivotName(pivotId)}`;
|
|
55470
55814
|
}
|
|
55471
55815
|
getPivotName(pivotId) {
|
|
55472
|
-
return
|
|
55816
|
+
return this.getPivotCore(pivotId).definition.name;
|
|
55473
55817
|
}
|
|
55474
55818
|
/**
|
|
55475
55819
|
* Returns the pivot core definition of the pivot with the given id.
|
|
@@ -57111,7 +57455,7 @@ class Evaluator {
|
|
|
57111
57455
|
cellsToCompute.addMany(arrayFormulasPositions);
|
|
57112
57456
|
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositions));
|
|
57113
57457
|
this.evaluate(cellsToCompute);
|
|
57114
|
-
console.
|
|
57458
|
+
console.debug("evaluate Cells", performance.now() - start, "ms");
|
|
57115
57459
|
}
|
|
57116
57460
|
getArrayFormulasImpactedByChangesOf(positions) {
|
|
57117
57461
|
const impactedPositions = this.createEmptyPositionSet();
|
|
@@ -57155,7 +57499,7 @@ class Evaluator {
|
|
|
57155
57499
|
const start = performance.now();
|
|
57156
57500
|
this.evaluatedCells = new PositionMap();
|
|
57157
57501
|
this.evaluate(this.getAllCells());
|
|
57158
|
-
console.
|
|
57502
|
+
console.debug("evaluate all cells", performance.now() - start, "ms");
|
|
57159
57503
|
}
|
|
57160
57504
|
evaluateFormulaResult(sheetId, formulaString) {
|
|
57161
57505
|
const compiledFormula = compile(formulaString);
|
|
@@ -58161,8 +58505,7 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
58161
58505
|
.map((cell) => cell.value);
|
|
58162
58506
|
switch (threshold.type) {
|
|
58163
58507
|
case "value":
|
|
58164
|
-
|
|
58165
|
-
return result;
|
|
58508
|
+
return functionName === "max" ? largeMax(rangeValues) : largeMin(rangeValues);
|
|
58166
58509
|
case "number":
|
|
58167
58510
|
return Number(threshold.value);
|
|
58168
58511
|
case "percentage":
|
|
@@ -59366,8 +59709,7 @@ function withPivotPresentationLayer (PivotClass) {
|
|
|
59366
59709
|
throw new NotAvailableError();
|
|
59367
59710
|
}
|
|
59368
59711
|
const comparedValue = this._getPivotCellValueAndFormat(measure.id, comparedDomain);
|
|
59369
|
-
|
|
59370
|
-
return comparedValueNumber;
|
|
59712
|
+
return this.strictMeasureValueToNumber(comparedValue);
|
|
59371
59713
|
}
|
|
59372
59714
|
getPivotValueCells(measureId) {
|
|
59373
59715
|
return this.getTableStructure()
|
|
@@ -60901,7 +61243,7 @@ class Session extends EventBus {
|
|
|
60901
61243
|
this.onMessageReceived(message);
|
|
60902
61244
|
}
|
|
60903
61245
|
this.isReplayingInitialRevisions = false;
|
|
60904
|
-
console.
|
|
61246
|
+
console.debug("Replayed", numberOfCommands, "commands in", performance.now() - start, "ms");
|
|
60905
61247
|
}
|
|
60906
61248
|
/**
|
|
60907
61249
|
* Notify the server that the user client left the collaborative session
|
|
@@ -61073,7 +61415,6 @@ class Session extends EventBus {
|
|
|
61073
61415
|
if (this.waitingAck) {
|
|
61074
61416
|
return;
|
|
61075
61417
|
}
|
|
61076
|
-
this.waitingAck = true;
|
|
61077
61418
|
this.sendPendingMessage();
|
|
61078
61419
|
}
|
|
61079
61420
|
/**
|
|
@@ -61110,6 +61451,7 @@ class Session extends EventBus {
|
|
|
61110
61451
|
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.
|
|
61111
61452
|
${JSON.stringify(message)}`);
|
|
61112
61453
|
}
|
|
61454
|
+
this.waitingAck = true;
|
|
61113
61455
|
this.transportService.sendMessage({
|
|
61114
61456
|
...message,
|
|
61115
61457
|
serverRevisionId: this.serverRevisionId,
|
|
@@ -61269,8 +61611,7 @@ class CollaborativePlugin extends UIPlugin {
|
|
|
61269
61611
|
}
|
|
61270
61612
|
const color = client.color;
|
|
61271
61613
|
/* Cell background */
|
|
61272
|
-
|
|
61273
|
-
ctx.fillStyle = cellBackgroundColor;
|
|
61614
|
+
ctx.fillStyle = `${color}10`;
|
|
61274
61615
|
ctx.lineWidth = 4 * thinLineWidth;
|
|
61275
61616
|
ctx.strokeStyle = color;
|
|
61276
61617
|
ctx.globalCompositeOperation = "multiply";
|
|
@@ -61637,8 +61978,7 @@ class HeaderVisibilityUIPlugin extends UIPlugin {
|
|
|
61637
61978
|
exportForExcel(data) {
|
|
61638
61979
|
for (const sheetData of data.sheets) {
|
|
61639
61980
|
for (const [row, rowData] of Object.entries(sheetData.rows)) {
|
|
61640
|
-
|
|
61641
|
-
rowData.isHidden = isHidden;
|
|
61981
|
+
rowData.isHidden = this.isRowHidden(sheetData.id, Number(row));
|
|
61642
61982
|
}
|
|
61643
61983
|
}
|
|
61644
61984
|
}
|
|
@@ -61698,6 +62038,7 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
61698
62038
|
this.dispatch("DUPLICATE_PIVOT", {
|
|
61699
62039
|
pivotId,
|
|
61700
62040
|
newPivotId,
|
|
62041
|
+
duplicatedPivotName: _t("%s (copy)", this.getters.getPivotCoreDefinition(pivotId).name),
|
|
61701
62042
|
});
|
|
61702
62043
|
const activeSheetId = this.getters.getActiveSheetId();
|
|
61703
62044
|
const position = this.getters.getSheetIds().indexOf(activeSheetId) + 1;
|
|
@@ -62162,7 +62503,6 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
62162
62503
|
if (!isEqual(zone, newZone)) {
|
|
62163
62504
|
hasExpanded = true;
|
|
62164
62505
|
zone = newZone;
|
|
62165
|
-
continue;
|
|
62166
62506
|
}
|
|
62167
62507
|
} while (hasExpanded);
|
|
62168
62508
|
return zone;
|
|
@@ -63255,7 +63595,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
63255
63595
|
case "ADD_COLUMNS_ROWS": {
|
|
63256
63596
|
this.status = "invisible";
|
|
63257
63597
|
// If we add a col/row inside or before the cut area, we invalidate the clipboard
|
|
63258
|
-
if (this._isCutOperation
|
|
63598
|
+
if (!this._isCutOperation || cmd.sheetId !== this.copiedData?.sheetId) {
|
|
63259
63599
|
return;
|
|
63260
63600
|
}
|
|
63261
63601
|
const isClipboardDirty = this.isColRowDirtyingClipboard(cmd.position === "before" ? cmd.base : cmd.base + 1, cmd.dimension);
|
|
@@ -63267,7 +63607,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
63267
63607
|
case "REMOVE_COLUMNS_ROWS": {
|
|
63268
63608
|
this.status = "invisible";
|
|
63269
63609
|
// If we remove a col/row inside or before the cut area, we invalidate the clipboard
|
|
63270
|
-
if (this._isCutOperation
|
|
63610
|
+
if (!this._isCutOperation || cmd.sheetId !== this.copiedData?.sheetId) {
|
|
63271
63611
|
return;
|
|
63272
63612
|
}
|
|
63273
63613
|
for (let el of cmd.elements) {
|
|
@@ -63289,7 +63629,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
63289
63629
|
break;
|
|
63290
63630
|
}
|
|
63291
63631
|
case "DELETE_SHEET":
|
|
63292
|
-
if (this._isCutOperation
|
|
63632
|
+
if (!this._isCutOperation) {
|
|
63293
63633
|
return;
|
|
63294
63634
|
}
|
|
63295
63635
|
if (this.originSheetId === cmd.sheetId) {
|
|
@@ -64182,8 +64522,7 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
64182
64522
|
this.setSelectionMixin({ zone, cell: { col, row } }, [zone]);
|
|
64183
64523
|
}
|
|
64184
64524
|
setActiveSheet(id) {
|
|
64185
|
-
|
|
64186
|
-
this.activeSheet = sheet;
|
|
64525
|
+
this.activeSheet = this.getters.getSheet(id);
|
|
64187
64526
|
}
|
|
64188
64527
|
activateNextSheet(direction) {
|
|
64189
64528
|
const sheetIds = this.getters.getSheetIds();
|
|
@@ -64877,9 +65216,6 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
64877
65216
|
case "UNFREEZE_COLUMNS_ROWS":
|
|
64878
65217
|
this.resetViewports(this.getters.getActiveSheetId());
|
|
64879
65218
|
break;
|
|
64880
|
-
case "DELETE_SHEET":
|
|
64881
|
-
this.sheetsWithDirtyViewports.delete(cmd.sheetId);
|
|
64882
|
-
break;
|
|
64883
65219
|
case "SCROLL_TO_CELL":
|
|
64884
65220
|
this.refreshViewport(this.getters.getActiveSheetId(), { col: cmd.col, row: cmd.row });
|
|
64885
65221
|
break;
|
|
@@ -66831,10 +67167,9 @@ css /* scss */ `
|
|
|
66831
67167
|
user-select: none;
|
|
66832
67168
|
color: ${TEXT_BODY};
|
|
66833
67169
|
|
|
66834
|
-
.o-
|
|
67170
|
+
.o-sidePanelTitle {
|
|
66835
67171
|
line-height: 20px;
|
|
66836
67172
|
font-size: 16px;
|
|
66837
|
-
font-weight: 600;
|
|
66838
67173
|
}
|
|
66839
67174
|
|
|
66840
67175
|
.o-sidePanelHeader {
|
|
@@ -66919,6 +67254,10 @@ css /* scss */ `
|
|
|
66919
67254
|
}
|
|
66920
67255
|
}
|
|
66921
67256
|
}
|
|
67257
|
+
|
|
67258
|
+
.o-fw-bold {
|
|
67259
|
+
font-weight: 500;
|
|
67260
|
+
}
|
|
66922
67261
|
`;
|
|
66923
67262
|
class SidePanel extends Component {
|
|
66924
67263
|
static template = "o-spreadsheet-SidePanel";
|
|
@@ -67750,8 +68089,7 @@ class WebClipboardWrapper {
|
|
|
67750
68089
|
for (const item of clipboardItems) {
|
|
67751
68090
|
for (const type of item.types) {
|
|
67752
68091
|
const blob = await item.getType(type);
|
|
67753
|
-
|
|
67754
|
-
clipboardContent[type] = text;
|
|
68092
|
+
clipboardContent[type] = await blob.text();
|
|
67755
68093
|
}
|
|
67756
68094
|
}
|
|
67757
68095
|
return { status: "ok", content: clipboardContent };
|
|
@@ -68063,7 +68401,6 @@ class Spreadsheet extends Component {
|
|
|
68063
68401
|
spreadsheetRef = useRef("spreadsheet");
|
|
68064
68402
|
spreadsheetRect = useSpreadsheetRect();
|
|
68065
68403
|
_focusGrid;
|
|
68066
|
-
keyDownMapping;
|
|
68067
68404
|
isViewportTooSmall = false;
|
|
68068
68405
|
notificationStore;
|
|
68069
68406
|
composerFocusStore;
|
|
@@ -68087,10 +68424,6 @@ class Spreadsheet extends Component {
|
|
|
68087
68424
|
this.notificationStore = useStore(NotificationStore);
|
|
68088
68425
|
this.composerFocusStore = useStore(ComposerFocusStore);
|
|
68089
68426
|
this.sidePanel = useStore(SidePanelStore);
|
|
68090
|
-
this.keyDownMapping = {
|
|
68091
|
-
"CTRL+H": () => this.sidePanel.toggle("FindAndReplace", {}),
|
|
68092
|
-
"CTRL+F": () => this.sidePanel.toggle("FindAndReplace", {}),
|
|
68093
|
-
};
|
|
68094
68427
|
const fileStore = this.model.config.external.fileStore;
|
|
68095
68428
|
useSubEnv({
|
|
68096
68429
|
model: this.model,
|
|
@@ -68190,20 +68523,6 @@ class Spreadsheet extends Component {
|
|
|
68190
68523
|
}
|
|
68191
68524
|
this._focusGrid();
|
|
68192
68525
|
}
|
|
68193
|
-
onKeydown(ev) {
|
|
68194
|
-
let keyDownString = "";
|
|
68195
|
-
if (isCtrlKey(ev)) {
|
|
68196
|
-
keyDownString += "CTRL+";
|
|
68197
|
-
}
|
|
68198
|
-
keyDownString += ev.key.toUpperCase();
|
|
68199
|
-
let handler = this.keyDownMapping[keyDownString];
|
|
68200
|
-
if (handler) {
|
|
68201
|
-
ev.preventDefault();
|
|
68202
|
-
ev.stopPropagation();
|
|
68203
|
-
handler();
|
|
68204
|
-
return;
|
|
68205
|
-
}
|
|
68206
|
-
}
|
|
68207
68526
|
get gridHeight() {
|
|
68208
68527
|
const { height } = this.env.model.getters.getSheetViewDimension();
|
|
68209
68528
|
return height;
|
|
@@ -69618,10 +69937,10 @@ class SelectionStreamProcessorImpl {
|
|
|
69618
69937
|
getNextCellPosition(currentPosition, dimension, direction) {
|
|
69619
69938
|
const dimOfInterest = dimension === "cols" ? "col" : "row";
|
|
69620
69939
|
const startingPosition = { ...currentPosition };
|
|
69621
|
-
|
|
69622
|
-
|
|
69623
|
-
|
|
69624
|
-
|
|
69940
|
+
startingPosition[dimOfInterest] =
|
|
69941
|
+
dimension === "cols"
|
|
69942
|
+
? this.getNextAvailableCol(direction, startingPosition.col, startingPosition.row)
|
|
69943
|
+
: this.getNextAvailableRow(direction, startingPosition.col, startingPosition.row);
|
|
69625
69944
|
return { col: startingPosition.col, row: startingPosition.row };
|
|
69626
69945
|
}
|
|
69627
69946
|
getPosition() {
|
|
@@ -69745,6 +70064,8 @@ function createChart(chart, chartSheetIndex, data) {
|
|
|
69745
70064
|
case "pie":
|
|
69746
70065
|
plot = addDoughnutChart(chart.data, chartSheetIndex, data, { holeSize: 0 });
|
|
69747
70066
|
break;
|
|
70067
|
+
case "radar":
|
|
70068
|
+
plot = addRadarChart(chart.data);
|
|
69748
70069
|
}
|
|
69749
70070
|
let position = "t";
|
|
69750
70071
|
switch (chart.data.legendPosition) {
|
|
@@ -70203,6 +70524,53 @@ function addScatterChart(chart) {
|
|
|
70203
70524
|
`
|
|
70204
70525
|
: ""}`;
|
|
70205
70526
|
}
|
|
70527
|
+
function addRadarChart(chart) {
|
|
70528
|
+
const dataSetsColors = chart.dataSets.map((ds) => ds.backgroundColor ?? "");
|
|
70529
|
+
const colors = new ColorGenerator(chart.dataSets.length, dataSetsColors);
|
|
70530
|
+
const dataSetsNodes = [];
|
|
70531
|
+
for (const [dsIndex, dataset] of Object.entries(chart.dataSets)) {
|
|
70532
|
+
const color = toXlsxHexColor(colors.next());
|
|
70533
|
+
const dataShapeProperty = shapeProperty({
|
|
70534
|
+
line: {
|
|
70535
|
+
width: 2.5,
|
|
70536
|
+
style: "solid",
|
|
70537
|
+
color,
|
|
70538
|
+
},
|
|
70539
|
+
});
|
|
70540
|
+
const dataSetNode = escapeXml /*xml*/ `
|
|
70541
|
+
<c:ser>
|
|
70542
|
+
<c:idx val="${dsIndex}"/>
|
|
70543
|
+
<c:order val="${dsIndex}"/>
|
|
70544
|
+
<c:smooth val="0"/>
|
|
70545
|
+
<c:marker>
|
|
70546
|
+
<c:symbol val="circle" />
|
|
70547
|
+
<c:size val="5"/>
|
|
70548
|
+
${shapeProperty({ backgroundColor: color, line: { color } })}
|
|
70549
|
+
</c:marker>
|
|
70550
|
+
${extractDataSetLabel(dataset.label)}
|
|
70551
|
+
${dataShapeProperty}
|
|
70552
|
+
${chart.labelRange ? escapeXml `<c:cat>${stringRef(chart.labelRange)}</c:cat>` : ""} <!-- x-coordinate values -->
|
|
70553
|
+
<c:val> <!-- x-coordinate values -->
|
|
70554
|
+
${numberRef(dataset.range)}
|
|
70555
|
+
</c:val>
|
|
70556
|
+
</c:ser>
|
|
70557
|
+
`;
|
|
70558
|
+
dataSetsNodes.push(dataSetNode);
|
|
70559
|
+
}
|
|
70560
|
+
return escapeXml /*xml*/ `
|
|
70561
|
+
${escapeXml /*xml*/ `
|
|
70562
|
+
<c:radarChart>
|
|
70563
|
+
<c:radarStyle val="marker"/>
|
|
70564
|
+
<c:varyColors val="0"/>
|
|
70565
|
+
${joinXmlNodes(dataSetsNodes)}
|
|
70566
|
+
<c:axId val="${catAxId}" />
|
|
70567
|
+
<c:axId val="${valAxId}" />
|
|
70568
|
+
</c:radarChart>
|
|
70569
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor)}
|
|
70570
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
70571
|
+
`}
|
|
70572
|
+
`;
|
|
70573
|
+
}
|
|
70206
70574
|
function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
|
|
70207
70575
|
const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
|
|
70208
70576
|
const colors = new ColorGenerator(maxLength);
|
|
@@ -71310,25 +71678,23 @@ function addSheetViews(sheet) {
|
|
|
71310
71678
|
["showGridLines", sheet.areGridLinesVisible ? 1 : 0],
|
|
71311
71679
|
["workbookViewId", 0],
|
|
71312
71680
|
];
|
|
71313
|
-
|
|
71681
|
+
return escapeXml /*xml*/ `
|
|
71314
71682
|
<sheetViews>
|
|
71315
71683
|
<sheetView ${formatAttributes(sheetViewAttrs)}>
|
|
71316
71684
|
${splitPanes}
|
|
71317
71685
|
</sheetView>
|
|
71318
71686
|
</sheetViews>
|
|
71319
71687
|
`;
|
|
71320
|
-
return sheetView;
|
|
71321
71688
|
}
|
|
71322
71689
|
function addSheetProperties(sheet) {
|
|
71323
71690
|
if (!sheet.color) {
|
|
71324
71691
|
return "";
|
|
71325
71692
|
}
|
|
71326
|
-
|
|
71693
|
+
return escapeXml /*xml*/ `
|
|
71327
71694
|
<sheetPr>
|
|
71328
71695
|
<tabColor ${formatAttributes([["rgb", toXlsxHexColor(sheet.color)]])} />
|
|
71329
71696
|
</sheetPr>
|
|
71330
71697
|
`;
|
|
71331
|
-
return sheetView;
|
|
71332
71698
|
}
|
|
71333
71699
|
|
|
71334
71700
|
/**
|
|
@@ -71641,9 +72007,7 @@ var Status;
|
|
|
71641
72007
|
})(Status || (Status = {}));
|
|
71642
72008
|
class Model extends EventBus {
|
|
71643
72009
|
corePlugins = [];
|
|
71644
|
-
featurePlugins = [];
|
|
71645
72010
|
statefulUIPlugins = [];
|
|
71646
|
-
coreViewsPlugins = [];
|
|
71647
72011
|
range;
|
|
71648
72012
|
session;
|
|
71649
72013
|
/**
|
|
@@ -71688,7 +72052,7 @@ class Model extends EventBus {
|
|
|
71688
72052
|
coreHandlers = [];
|
|
71689
72053
|
constructor(data = {}, config = {}, stateUpdateMessages = [], uuidGenerator = new UuidGenerator(), verboseImport = false) {
|
|
71690
72054
|
const start = performance.now();
|
|
71691
|
-
console.
|
|
72055
|
+
console.debug("##### Model creation #####");
|
|
71692
72056
|
super();
|
|
71693
72057
|
setDefaultTranslationMethod();
|
|
71694
72058
|
stateUpdateMessages = repairInitialMessages(data, stateUpdateMessages);
|
|
@@ -71729,7 +72093,6 @@ class Model extends EventBus {
|
|
|
71729
72093
|
this.session.loadInitialMessages(stateUpdateMessages);
|
|
71730
72094
|
for (let Plugin of coreViewsPluginRegistry.getAll()) {
|
|
71731
72095
|
const plugin = this.setupUiPlugin(Plugin);
|
|
71732
|
-
this.coreViewsPlugins.push(plugin);
|
|
71733
72096
|
this.handlers.push(plugin);
|
|
71734
72097
|
this.uiHandlers.push(plugin);
|
|
71735
72098
|
this.coreHandlers.push(plugin);
|
|
@@ -71742,7 +72105,6 @@ class Model extends EventBus {
|
|
|
71742
72105
|
}
|
|
71743
72106
|
for (let Plugin of featurePluginRegistry.getAll()) {
|
|
71744
72107
|
const plugin = this.setupUiPlugin(Plugin);
|
|
71745
|
-
this.featurePlugins.push(plugin);
|
|
71746
72108
|
this.handlers.push(plugin);
|
|
71747
72109
|
this.uiHandlers.push(plugin);
|
|
71748
72110
|
}
|
|
@@ -71759,16 +72121,16 @@ class Model extends EventBus {
|
|
|
71759
72121
|
this.joinSession();
|
|
71760
72122
|
if (config.snapshotRequested) {
|
|
71761
72123
|
const startSnapshot = performance.now();
|
|
71762
|
-
console.
|
|
72124
|
+
console.debug("Snapshot requested");
|
|
71763
72125
|
this.session.snapshot(this.exportData());
|
|
71764
72126
|
this.garbageCollectExternalResources();
|
|
71765
|
-
console.
|
|
72127
|
+
console.debug("Snapshot taken in", performance.now() - startSnapshot, "ms");
|
|
71766
72128
|
}
|
|
71767
72129
|
// mark all models as "raw", so they will not be turned into reactive objects
|
|
71768
72130
|
// by owl, since we do not rely on reactivity
|
|
71769
72131
|
markRaw(this);
|
|
71770
|
-
console.
|
|
71771
|
-
console.
|
|
72132
|
+
console.debug("Model created in", performance.now() - start, "ms");
|
|
72133
|
+
console.debug("######");
|
|
71772
72134
|
}
|
|
71773
72135
|
joinSession() {
|
|
71774
72136
|
this.session.join(this.config.client);
|
|
@@ -71827,7 +72189,7 @@ class Model extends EventBus {
|
|
|
71827
72189
|
this.finalize();
|
|
71828
72190
|
}
|
|
71829
72191
|
setupSession(revisionId) {
|
|
71830
|
-
|
|
72192
|
+
return new Session(buildRevisionLog({
|
|
71831
72193
|
initialRevisionId: revisionId,
|
|
71832
72194
|
recordChanges: this.state.recordChanges.bind(this.state),
|
|
71833
72195
|
dispatch: (command) => {
|
|
@@ -71840,7 +72202,6 @@ class Model extends EventBus {
|
|
|
71840
72202
|
this.isReplayingCommand = false;
|
|
71841
72203
|
},
|
|
71842
72204
|
}), this.config.transportService, revisionId);
|
|
71843
|
-
return session;
|
|
71844
72205
|
}
|
|
71845
72206
|
setupSessionEvents() {
|
|
71846
72207
|
this.session.on("remote-revision-received", this, this.onRemoteRevisionReceived);
|
|
@@ -71933,8 +72294,7 @@ class Model extends EventBus {
|
|
|
71933
72294
|
return results;
|
|
71934
72295
|
}
|
|
71935
72296
|
checkDispatchAllowedLocalCommand(command) {
|
|
71936
|
-
|
|
71937
|
-
return results;
|
|
72297
|
+
return this.uiHandlers.map((handler) => handler.allowDispatch(command));
|
|
71938
72298
|
}
|
|
71939
72299
|
finalize() {
|
|
71940
72300
|
this.status = 3 /* Status.Finalizing */;
|
|
@@ -71991,7 +72351,7 @@ class Model extends EventBus {
|
|
|
71991
72351
|
this.finalize();
|
|
71992
72352
|
const time = performance.now() - start;
|
|
71993
72353
|
if (time > 5) {
|
|
71994
|
-
console.
|
|
72354
|
+
console.debug(type, time, "ms");
|
|
71995
72355
|
}
|
|
71996
72356
|
});
|
|
71997
72357
|
this.session.save(command, commands, changes);
|
|
@@ -72294,7 +72654,6 @@ const components = {
|
|
|
72294
72654
|
PivotDimensionOrder,
|
|
72295
72655
|
PivotDimension,
|
|
72296
72656
|
PivotLayoutConfigurator,
|
|
72297
|
-
EditableName,
|
|
72298
72657
|
PivotDeferUpdate,
|
|
72299
72658
|
PivotTitleSection,
|
|
72300
72659
|
CogWheelMenu,
|
|
@@ -72343,6 +72702,6 @@ const constants = {
|
|
|
72343
72702
|
export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
|
|
72344
72703
|
|
|
72345
72704
|
|
|
72346
|
-
__info__.version = "18.1.0-alpha.
|
|
72347
|
-
__info__.date = "2024-10-
|
|
72348
|
-
__info__.hash = "
|
|
72705
|
+
__info__.version = "18.1.0-alpha.2";
|
|
72706
|
+
__info__.date = "2024-10-24T08:53:21.828Z";
|
|
72707
|
+
__info__.hash = "2a01250";
|