@odoo/o-spreadsheet 18.1.0-alpha.7 → 18.1.0
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 +1317 -315
- package/dist/o-spreadsheet.d.ts +398 -292
- package/dist/o-spreadsheet.esm.js +1317 -315
- package/dist/o-spreadsheet.iife.js +1317 -315
- package/dist/o-spreadsheet.iife.min.js +515 -515
- package/dist/o_spreadsheet.xml +217 -23
- package/package.json +4 -3
|
@@ -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
|
|
6
|
-
* @date 2024-12-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.1.0
|
|
6
|
+
* @date 2024-12-26T06:37:07.879Z
|
|
7
|
+
* @hash c520e89
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -266,7 +266,6 @@
|
|
|
266
266
|
const MIN_COL_WIDTH = 5;
|
|
267
267
|
const HEADER_HEIGHT = 26;
|
|
268
268
|
const HEADER_WIDTH = 48;
|
|
269
|
-
const TOPBAR_HEIGHT = 63;
|
|
270
269
|
const TOPBAR_TOOLBAR_HEIGHT = 34;
|
|
271
270
|
const BOTTOMBAR_HEIGHT = 36;
|
|
272
271
|
const DEFAULT_CELL_WIDTH = 96;
|
|
@@ -790,6 +789,7 @@
|
|
|
790
789
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
|
|
791
790
|
*/
|
|
792
791
|
const whiteSpaceSpecialCharacters = [
|
|
792
|
+
" ",
|
|
793
793
|
"\t",
|
|
794
794
|
"\f",
|
|
795
795
|
"\v",
|
|
@@ -804,17 +804,15 @@
|
|
|
804
804
|
String.fromCharCode(parseInt("3000", 16)),
|
|
805
805
|
String.fromCharCode(parseInt("feff", 16)),
|
|
806
806
|
];
|
|
807
|
-
const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|")
|
|
807
|
+
const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|"), "g");
|
|
808
|
+
const newLineRegexp = /(\r\n|\r)/g;
|
|
808
809
|
/**
|
|
809
|
-
* Replace all
|
|
810
|
-
* different newlines types by \n.
|
|
810
|
+
* Replace all different newlines characters by \n
|
|
811
811
|
*/
|
|
812
|
-
function
|
|
812
|
+
function replaceNewLines(text) {
|
|
813
813
|
if (!text)
|
|
814
814
|
return "";
|
|
815
|
-
|
|
816
|
-
return text;
|
|
817
|
-
return text.replace(whiteSpaceRegexp, (match, newLine) => (newLine ? NEWLINE : " "));
|
|
815
|
+
return text.replace(newLineRegexp, NEWLINE);
|
|
818
816
|
}
|
|
819
817
|
/**
|
|
820
818
|
* Determine if the numbers are consecutive.
|
|
@@ -980,7 +978,7 @@
|
|
|
980
978
|
|
|
981
979
|
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
982
980
|
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
|
|
983
|
-
const colors
|
|
981
|
+
const colors = [
|
|
984
982
|
"#eb6d00",
|
|
985
983
|
"#0074d9",
|
|
986
984
|
"#ad8e00",
|
|
@@ -1003,6 +1001,12 @@
|
|
|
1003
1001
|
function colorNumberString(color) {
|
|
1004
1002
|
return toHex(color.toString(16).padStart(6, "0"));
|
|
1005
1003
|
}
|
|
1004
|
+
function colorToNumber(color) {
|
|
1005
|
+
if (typeof color === "number") {
|
|
1006
|
+
return color;
|
|
1007
|
+
}
|
|
1008
|
+
return Number.parseInt(toHex(color).slice(1), 16);
|
|
1009
|
+
}
|
|
1006
1010
|
/**
|
|
1007
1011
|
* Converts any CSS color value to a standardized hex6 value.
|
|
1008
1012
|
* Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
|
|
@@ -1353,9 +1357,9 @@
|
|
|
1353
1357
|
"#056BD9", // Blue #3
|
|
1354
1358
|
"#155193", // Blue #4
|
|
1355
1359
|
"#A76DBC", // Violet #1
|
|
1356
|
-
"#7F4295", // Violet #
|
|
1357
|
-
"#6D2387", // Violet #
|
|
1358
|
-
"#4F1565", // Violet #
|
|
1360
|
+
"#7F4295", // Violet #2
|
|
1361
|
+
"#6D2387", // Violet #3
|
|
1362
|
+
"#4F1565", // Violet #4
|
|
1359
1363
|
"#EA6175", // Red #1
|
|
1360
1364
|
"#CE4257", // Red #2
|
|
1361
1365
|
"#982738", // Red #3
|
|
@@ -1381,6 +1385,81 @@
|
|
|
1381
1385
|
"#C08A16", // Yellow #3
|
|
1382
1386
|
"#936A12", // Yellow #4
|
|
1383
1387
|
];
|
|
1388
|
+
// Same as above but with alternating colors
|
|
1389
|
+
const ALTERNATING_COLORS_MD = [
|
|
1390
|
+
"#4EA7F2", // Blue #1
|
|
1391
|
+
"#43C5B1", // Teal #1
|
|
1392
|
+
"#EA6175", // Red #1
|
|
1393
|
+
"#F4A261", // Orange #1
|
|
1394
|
+
"#8481DD", // Purple #1
|
|
1395
|
+
"#FFD86D", // Yellow #1
|
|
1396
|
+
"#3188E6", // Blue #2
|
|
1397
|
+
"#00A78D", // Teal #2
|
|
1398
|
+
"#CE4257", // Red #2
|
|
1399
|
+
"#F48935", // Orange #2
|
|
1400
|
+
"#5752D1", // Purple #2
|
|
1401
|
+
"#FFBC2C", // Yellow #2
|
|
1402
|
+
];
|
|
1403
|
+
const ALTERNATING_COLORS_LG = [
|
|
1404
|
+
"#4EA7F2", // Blue #1
|
|
1405
|
+
"#A76DBC", // Violet #1
|
|
1406
|
+
"#EA6175", // Red #1
|
|
1407
|
+
"#43C5B1", // Teal #1
|
|
1408
|
+
"#F4A261", // Orange #1
|
|
1409
|
+
"#8481DD", // Purple #1
|
|
1410
|
+
"#A4A8B6", // Gray #1
|
|
1411
|
+
"#FFD86D", // Yellow #1
|
|
1412
|
+
"#3188E6", // Blue #2
|
|
1413
|
+
"#7F4295", // Violet #2
|
|
1414
|
+
"#CE4257", // Red #2
|
|
1415
|
+
"#00A78D", // Teal #2
|
|
1416
|
+
"#F48935", // Orange #2
|
|
1417
|
+
"#5752D1", // Purple #2
|
|
1418
|
+
"#7E8290", // Gray #2
|
|
1419
|
+
"#FFBC2C", // Yellow #2
|
|
1420
|
+
"#056BD9", // Blue #3
|
|
1421
|
+
"#6D2387", // Violet #3
|
|
1422
|
+
"#982738", // Red #3
|
|
1423
|
+
"#0E8270", // Teal #3
|
|
1424
|
+
"#BE5D10", // Orange #3
|
|
1425
|
+
"#3A3580", // Purple #3
|
|
1426
|
+
"#545B70", // Gray #3
|
|
1427
|
+
"#C08A16", // Yellow #3
|
|
1428
|
+
];
|
|
1429
|
+
const ALTERNATING_COLORS_XL = [
|
|
1430
|
+
"#4EA7F2", // Blue #1
|
|
1431
|
+
"#A76DBC", // Violet #1
|
|
1432
|
+
"#EA6175", // Red #1
|
|
1433
|
+
"#43C5B1", // Teal #1
|
|
1434
|
+
"#F4A261", // Orange #1
|
|
1435
|
+
"#8481DD", // Purple #1
|
|
1436
|
+
"#A4A8B6", // Grey #1
|
|
1437
|
+
"#FFD86D", // Yellow #1
|
|
1438
|
+
"#3188E6", // Blue #2
|
|
1439
|
+
"#7F4295", // Violet #2
|
|
1440
|
+
"#CE4257", // Red #2
|
|
1441
|
+
"#00A78D", // Teal #2
|
|
1442
|
+
"#F48935", // Orange #2
|
|
1443
|
+
"#5752D1", // Purple #2
|
|
1444
|
+
"#7E8290", // Grey #2
|
|
1445
|
+
"#FFBC2C", // Yellow #2
|
|
1446
|
+
"#056BD9", // Blue #3
|
|
1447
|
+
"#6D2387", // Violet #3
|
|
1448
|
+
"#982738", // Red #3
|
|
1449
|
+
"#0E8270", // Teal #3
|
|
1450
|
+
"#BE5D10", // Orange #3
|
|
1451
|
+
"#3A3580", // Purple #3
|
|
1452
|
+
"#545B70", // Grey #3
|
|
1453
|
+
"#C08A16", // Yellow #3
|
|
1454
|
+
"#155193", // Blue #4
|
|
1455
|
+
"#4F1565", // Violet #4
|
|
1456
|
+
"#791B29", // Red #4
|
|
1457
|
+
"#105F53", // Teal #4
|
|
1458
|
+
"#7D380D", // Orange #4
|
|
1459
|
+
"#26235F", // Purple #4
|
|
1460
|
+
"#3F4250", // Grey #4
|
|
1461
|
+
"#936A12", // Yellow #4
|
|
1462
|
+
];
|
|
1384
1463
|
function getNthColor(index, palette) {
|
|
1385
1464
|
return palette[index % palette.length];
|
|
1386
1465
|
}
|
|
@@ -1398,6 +1477,20 @@
|
|
|
1398
1477
|
return COLORS_XL;
|
|
1399
1478
|
}
|
|
1400
1479
|
}
|
|
1480
|
+
function getAlternatingColorsPalette(quantity) {
|
|
1481
|
+
if (quantity <= 6) {
|
|
1482
|
+
return COLORS_SM;
|
|
1483
|
+
}
|
|
1484
|
+
else if (quantity <= 12) {
|
|
1485
|
+
return ALTERNATING_COLORS_MD;
|
|
1486
|
+
}
|
|
1487
|
+
else if (quantity <= 24) {
|
|
1488
|
+
return ALTERNATING_COLORS_LG;
|
|
1489
|
+
}
|
|
1490
|
+
else {
|
|
1491
|
+
return ALTERNATING_COLORS_XL;
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1401
1494
|
class ColorGenerator {
|
|
1402
1495
|
preferredColors;
|
|
1403
1496
|
currentColorIndex = 0;
|
|
@@ -1412,6 +1505,62 @@
|
|
|
1412
1505
|
: getNthColor(this.currentColorIndex++, this.palette);
|
|
1413
1506
|
}
|
|
1414
1507
|
}
|
|
1508
|
+
class AlternatingColorGenerator extends ColorGenerator {
|
|
1509
|
+
constructor(paletteSize, preferredColors = []) {
|
|
1510
|
+
super(paletteSize, preferredColors);
|
|
1511
|
+
this.palette = getAlternatingColorsPalette(paletteSize).filter((c) => !preferredColors.includes(c));
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
/**
|
|
1515
|
+
* Returns a function that maps a value to a color using a color scale defined by the given
|
|
1516
|
+
* color/threshold values pairs.
|
|
1517
|
+
*/
|
|
1518
|
+
function getColorScale(colorScalePoints) {
|
|
1519
|
+
if (colorScalePoints.length < 2) {
|
|
1520
|
+
throw new Error("Color scale must have at least 2 points");
|
|
1521
|
+
}
|
|
1522
|
+
const sortedColorScalePoints = [...colorScalePoints.sort((a, b) => a.value - b.value)];
|
|
1523
|
+
const thresholds = [];
|
|
1524
|
+
for (let i = 1; i < sortedColorScalePoints.length; i++) {
|
|
1525
|
+
const minColor = colorToNumber(sortedColorScalePoints[i - 1].color);
|
|
1526
|
+
const maxColor = colorToNumber(sortedColorScalePoints[i].color);
|
|
1527
|
+
thresholds.push({
|
|
1528
|
+
min: sortedColorScalePoints[i - 1].value,
|
|
1529
|
+
max: sortedColorScalePoints[i].value,
|
|
1530
|
+
minColor,
|
|
1531
|
+
maxColor,
|
|
1532
|
+
colorDiff: computeColorDiffUnits(sortedColorScalePoints[i - 1].value, sortedColorScalePoints[i].value, minColor, maxColor),
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
return (value) => {
|
|
1536
|
+
if (value < thresholds[0].min) {
|
|
1537
|
+
return colorNumberString(thresholds[0].minColor);
|
|
1538
|
+
}
|
|
1539
|
+
for (const threshold of thresholds) {
|
|
1540
|
+
if (value >= threshold.min && value <= threshold.max) {
|
|
1541
|
+
return colorNumberString(colorCell(value, threshold.min, threshold.minColor, threshold.colorDiff));
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
return colorNumberString(thresholds[thresholds.length - 1].maxColor);
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
function computeColorDiffUnits(minValue, maxValue, minColor, maxColor) {
|
|
1548
|
+
const deltaValue = maxValue - minValue;
|
|
1549
|
+
const deltaColorR = ((minColor >> 16) % 256) - ((maxColor >> 16) % 256);
|
|
1550
|
+
const deltaColorG = ((minColor >> 8) % 256) - ((maxColor >> 8) % 256);
|
|
1551
|
+
const deltaColorB = (minColor % 256) - (maxColor % 256);
|
|
1552
|
+
const colorDiffUnitR = deltaColorR / deltaValue;
|
|
1553
|
+
const colorDiffUnitG = deltaColorG / deltaValue;
|
|
1554
|
+
const colorDiffUnitB = deltaColorB / deltaValue;
|
|
1555
|
+
return [colorDiffUnitR, colorDiffUnitG, colorDiffUnitB];
|
|
1556
|
+
}
|
|
1557
|
+
function colorCell(value, minValue, minColor, colorDiffUnit) {
|
|
1558
|
+
const [colorDiffUnitR, colorDiffUnitG, colorDiffUnitB] = colorDiffUnit;
|
|
1559
|
+
const r = Math.round(((minColor >> 16) % 256) - colorDiffUnitR * (value - minValue));
|
|
1560
|
+
const g = Math.round(((minColor >> 8) % 256) - colorDiffUnitG * (value - minValue));
|
|
1561
|
+
const b = Math.round((minColor % 256) - colorDiffUnitB * (value - minValue));
|
|
1562
|
+
return (r << 16) | (g << 8) | b;
|
|
1563
|
+
}
|
|
1415
1564
|
|
|
1416
1565
|
//------------------------------------------------------------------------------
|
|
1417
1566
|
// Coordinate
|
|
@@ -3283,6 +3432,7 @@
|
|
|
3283
3432
|
]);
|
|
3284
3433
|
const invalidateChartEvaluationCommands = new Set([
|
|
3285
3434
|
"EVALUATE_CELLS",
|
|
3435
|
+
"EVALUATE_CHARTS",
|
|
3286
3436
|
"UPDATE_CELL",
|
|
3287
3437
|
"UNHIDE_COLUMNS_ROWS",
|
|
3288
3438
|
"HIDE_COLUMNS_ROWS",
|
|
@@ -3319,6 +3469,7 @@
|
|
|
3319
3469
|
"RESIZE_SHEETVIEW",
|
|
3320
3470
|
"SET_VIEWPORT_OFFSET",
|
|
3321
3471
|
"EVALUATE_CELLS",
|
|
3472
|
+
"EVALUATE_CHARTS",
|
|
3322
3473
|
"SET_FORMULA_VISIBILITY",
|
|
3323
3474
|
"UPDATE_FILTER",
|
|
3324
3475
|
]);
|
|
@@ -6523,7 +6674,7 @@
|
|
|
6523
6674
|
const POSTFIX_UNARY_OPERATORS = ["%"];
|
|
6524
6675
|
const OPERATORS = "+,-,*,/,:,=,<>,>=,>,<=,<,^,&".split(",").concat(POSTFIX_UNARY_OPERATORS);
|
|
6525
6676
|
function tokenize(str, locale = DEFAULT_LOCALE) {
|
|
6526
|
-
str =
|
|
6677
|
+
str = replaceNewLines(str);
|
|
6527
6678
|
const chars = new TokenizingChars(str);
|
|
6528
6679
|
const result = [];
|
|
6529
6680
|
while (!chars.isOver()) {
|
|
@@ -6670,12 +6821,12 @@
|
|
|
6670
6821
|
if (length) {
|
|
6671
6822
|
return { type: "SPACE", value: NEWLINE.repeat(length) };
|
|
6672
6823
|
}
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
chars.shift();
|
|
6824
|
+
let spaces = "";
|
|
6825
|
+
while (chars.current && chars.current.match(whiteSpaceRegexp)) {
|
|
6826
|
+
spaces += chars.shift();
|
|
6676
6827
|
}
|
|
6677
|
-
if (
|
|
6678
|
-
return { type: "SPACE", value:
|
|
6828
|
+
if (spaces) {
|
|
6829
|
+
return { type: "SPACE", value: spaces };
|
|
6679
6830
|
}
|
|
6680
6831
|
return null;
|
|
6681
6832
|
}
|
|
@@ -7534,6 +7685,16 @@
|
|
|
7534
7685
|
}
|
|
7535
7686
|
return domainToString([...domain.slice(0, index), ...domain.slice(index + 1)]);
|
|
7536
7687
|
}
|
|
7688
|
+
function sortPivotTree(tree, baseDomain, sortFn) {
|
|
7689
|
+
const sortedTree = [...tree];
|
|
7690
|
+
const domain = [...baseDomain];
|
|
7691
|
+
sortedTree.sort((node1, node2) => sortFn([...domain, node1], [...domain, node2]));
|
|
7692
|
+
for (const node of tree) {
|
|
7693
|
+
const children = sortPivotTree(node.children, [...domain, node], sortFn);
|
|
7694
|
+
node.children = children;
|
|
7695
|
+
}
|
|
7696
|
+
return sortedTree;
|
|
7697
|
+
}
|
|
7537
7698
|
|
|
7538
7699
|
const pivotTimeAdapterRegistry = new Registry();
|
|
7539
7700
|
function pivotTimeAdapter(granularity) {
|
|
@@ -8044,6 +8205,29 @@
|
|
|
8044
8205
|
format: `${" ".repeat(indent)}${format}* `,
|
|
8045
8206
|
};
|
|
8046
8207
|
}
|
|
8208
|
+
function isSortedColumnValid(sortedColumn, pivot) {
|
|
8209
|
+
try {
|
|
8210
|
+
if (!pivot.getMeasure(sortedColumn.measure)) {
|
|
8211
|
+
return false;
|
|
8212
|
+
}
|
|
8213
|
+
const columns = pivot.definition.columns;
|
|
8214
|
+
for (let i = 0; i < sortedColumn.domain.length; i++) {
|
|
8215
|
+
if (columns[i].nameWithGranularity !== sortedColumn.domain[i].field) {
|
|
8216
|
+
return false;
|
|
8217
|
+
}
|
|
8218
|
+
const possibleValues = pivot
|
|
8219
|
+
.getPossibleFieldValues(columns[i])
|
|
8220
|
+
.map((v) => v.value);
|
|
8221
|
+
if (!possibleValues.includes(sortedColumn.domain[i].value)) {
|
|
8222
|
+
return false;
|
|
8223
|
+
}
|
|
8224
|
+
}
|
|
8225
|
+
return true;
|
|
8226
|
+
}
|
|
8227
|
+
catch (e) {
|
|
8228
|
+
return false;
|
|
8229
|
+
}
|
|
8230
|
+
}
|
|
8047
8231
|
|
|
8048
8232
|
class CellClipboardHandler extends AbstractCellClipboardHandler {
|
|
8049
8233
|
isCutAllowed(data) {
|
|
@@ -14652,7 +14836,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
14652
14836
|
CellValueType.boolean,
|
|
14653
14837
|
];
|
|
14654
14838
|
function cellsSortingCriterion(sortingOrder) {
|
|
14655
|
-
const inverse = sortingOrder === "
|
|
14839
|
+
const inverse = sortingOrder === "asc" ? 1 : -1;
|
|
14656
14840
|
return (left, right) => {
|
|
14657
14841
|
if (left.type === CellValueType.empty) {
|
|
14658
14842
|
return right.type === CellValueType.empty ? 0 : 1;
|
|
@@ -14744,7 +14928,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
14744
14928
|
const sortColumns = [];
|
|
14745
14929
|
const nRows = matrix.length;
|
|
14746
14930
|
for (let i = 0; i < criteria.length; i += 2) {
|
|
14747
|
-
sortingOrders.push(toBoolean(toScalar(criteria[i + 1])?.value) ? "
|
|
14931
|
+
sortingOrders.push(toBoolean(toScalar(criteria[i + 1])?.value) ? "asc" : "desc");
|
|
14748
14932
|
const sortColumn = criteria[i];
|
|
14749
14933
|
if (isMatrix(sortColumn) && (sortColumn.length > 1 || sortColumn[0].length > 1)) {
|
|
14750
14934
|
assert(() => sortColumn.length === 1 && sortColumn[0].length === nRows, _t("Wrong size for %s. Expected a range of size 1x%s. Got %sx%s.", `sort_column${i + 1}`, nRows, sortColumn.length, sortColumn[0].length));
|
|
@@ -14761,12 +14945,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
14761
14945
|
if (sortColumns.length === 0) {
|
|
14762
14946
|
for (let i = 0; i < matrix[0].length; i++) {
|
|
14763
14947
|
sortColumns.push(matrix.map((row) => row[i].value));
|
|
14764
|
-
sortingOrders.push("
|
|
14948
|
+
sortingOrders.push("asc");
|
|
14765
14949
|
}
|
|
14766
14950
|
}
|
|
14767
14951
|
const sortingCriteria = {
|
|
14768
|
-
|
|
14769
|
-
|
|
14952
|
+
desc: cellsSortingCriterion("desc"),
|
|
14953
|
+
asc: cellsSortingCriterion("asc"),
|
|
14770
14954
|
};
|
|
14771
14955
|
const indexes = range(0, matrix.length);
|
|
14772
14956
|
indexes.sort((a, b) => {
|
|
@@ -20490,20 +20674,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20490
20674
|
replaceSelectedRange(zone) {
|
|
20491
20675
|
const ref = this.getZoneReference(zone);
|
|
20492
20676
|
const currentToken = this.tokenAtCursor;
|
|
20493
|
-
|
|
20494
|
-
|
|
20495
|
-
replaceStart = currentToken.start;
|
|
20496
|
-
}
|
|
20497
|
-
else if (currentToken?.type === "RIGHT_PAREN") {
|
|
20498
|
-
// match left parenthesis
|
|
20499
|
-
const leftParenthesisIndex = this.currentTokens.findIndex((token) => token.type === "LEFT_PAREN" && token.parenthesesCode === currentToken.parenthesesCode);
|
|
20500
|
-
const functionToken = this.currentTokens[leftParenthesisIndex - 1];
|
|
20501
|
-
if (functionToken === undefined) {
|
|
20502
|
-
return;
|
|
20503
|
-
}
|
|
20504
|
-
replaceStart = functionToken.start;
|
|
20505
|
-
}
|
|
20506
|
-
this.replaceText(ref, replaceStart, this.selectionEnd);
|
|
20677
|
+
const start = currentToken?.type === "REFERENCE" ? currentToken.start : this.selectionStart;
|
|
20678
|
+
this.replaceText(ref, start, this.selectionEnd);
|
|
20507
20679
|
}
|
|
20508
20680
|
/**
|
|
20509
20681
|
* Replace the reference of the old zone by the new one.
|
|
@@ -20536,17 +20708,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20536
20708
|
getZoneReference(zone) {
|
|
20537
20709
|
const inputSheetId = this.sheetId;
|
|
20538
20710
|
const sheetId = this.getters.getActiveSheetId();
|
|
20539
|
-
if (zone.top === zone.bottom && zone.left === zone.right) {
|
|
20540
|
-
const position = { sheetId, col: zone.left, row: zone.top };
|
|
20541
|
-
const pivotId = this.getters.getPivotIdFromPosition(position);
|
|
20542
|
-
const pivotCell = this.getters.getPivotCellFromPosition(position);
|
|
20543
|
-
const cell = this.getters.getCell(position);
|
|
20544
|
-
if (pivotId && pivotCell.type !== "EMPTY" && !cell?.isFormula) {
|
|
20545
|
-
const formulaPivotId = this.getters.getPivotFormulaId(pivotId);
|
|
20546
|
-
const formula = createPivotFormula(formulaPivotId, pivotCell);
|
|
20547
|
-
return localizeFormula(formula, this.getters.getLocale()).slice(1); // strip leading =
|
|
20548
|
-
}
|
|
20549
|
-
}
|
|
20550
20711
|
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
20551
20712
|
return this.getters.getSelectionRangeString(range, inputSheetId);
|
|
20552
20713
|
}
|
|
@@ -20717,37 +20878,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20717
20878
|
const editionSheetId = this.sheetId;
|
|
20718
20879
|
const rangeColor = (rangeString) => {
|
|
20719
20880
|
const colorIndex = this.colorIndexByRange[rangeString];
|
|
20720
|
-
return colors
|
|
20881
|
+
return colors[colorIndex % colors.length];
|
|
20721
20882
|
};
|
|
20722
|
-
|
|
20723
|
-
for (const range of this.getReferencedRanges()) {
|
|
20883
|
+
return this.getReferencedRanges().map((range) => {
|
|
20724
20884
|
const rangeString = this.getters.getRangeString(range, editionSheetId);
|
|
20725
20885
|
const { numberOfRows, numberOfCols } = zoneToDimension(range.zone);
|
|
20726
20886
|
const zone = numberOfRows * numberOfCols === 1
|
|
20727
20887
|
? this.getters.expandZone(range.sheetId, range.zone)
|
|
20728
20888
|
: range.zone;
|
|
20729
|
-
|
|
20889
|
+
return {
|
|
20730
20890
|
zone,
|
|
20731
20891
|
color: rangeColor(rangeString),
|
|
20732
20892
|
sheetId: range.sheetId,
|
|
20733
20893
|
interactive: true,
|
|
20734
|
-
}
|
|
20735
|
-
}
|
|
20736
|
-
const activeSheetId = this.getters.getActiveSheetId();
|
|
20737
|
-
const selectionZone = this.model.selection.getAnchor().zone;
|
|
20738
|
-
const isSelectionHightlighted = highlights.find((highlight) => highlight.sheetId === activeSheetId && isEqual(highlight.zone, selectionZone));
|
|
20739
|
-
if (this.editionMode === "selecting" && !isSelectionHightlighted) {
|
|
20740
|
-
highlights.push({
|
|
20741
|
-
zone: selectionZone,
|
|
20742
|
-
color: "#445566",
|
|
20743
|
-
sheetId: activeSheetId,
|
|
20744
|
-
dashed: true,
|
|
20745
|
-
interactive: false,
|
|
20746
|
-
noFill: true,
|
|
20747
|
-
thinLine: true,
|
|
20748
|
-
});
|
|
20749
|
-
}
|
|
20750
|
-
return highlights;
|
|
20894
|
+
};
|
|
20895
|
+
});
|
|
20751
20896
|
}
|
|
20752
20897
|
/**
|
|
20753
20898
|
* Return ranges currently referenced in the composer
|
|
@@ -20975,6 +21120,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20975
21120
|
return error;
|
|
20976
21121
|
},
|
|
20977
21122
|
isBadExpression: true,
|
|
21123
|
+
normalizedFormula: tokens.map((t) => t.value).join(""),
|
|
20978
21124
|
};
|
|
20979
21125
|
}
|
|
20980
21126
|
}
|
|
@@ -21102,6 +21248,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21102
21248
|
symbols,
|
|
21103
21249
|
tokens,
|
|
21104
21250
|
isBadExpression: false,
|
|
21251
|
+
normalizedFormula: cacheKey,
|
|
21105
21252
|
};
|
|
21106
21253
|
return compiledFormula;
|
|
21107
21254
|
}
|
|
@@ -21366,6 +21513,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21366
21513
|
description: definition.name,
|
|
21367
21514
|
htmlContent: [{ value: str, color: tokenColors.NUMBER }],
|
|
21368
21515
|
fuzzySearchKey: str + definition.name,
|
|
21516
|
+
alwaysExpanded: true,
|
|
21369
21517
|
};
|
|
21370
21518
|
})
|
|
21371
21519
|
.filter(isDefined);
|
|
@@ -27759,6 +27907,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27759
27907
|
["GaugeLowerInflectionPointNaN" /* CommandResult.GaugeLowerInflectionPointNaN */]: _t("The lower inflection point value must be a number"),
|
|
27760
27908
|
["GaugeUpperInflectionPointNaN" /* CommandResult.GaugeUpperInflectionPointNaN */]: _t("The upper inflection point value must be a number"),
|
|
27761
27909
|
},
|
|
27910
|
+
GeoChart: {
|
|
27911
|
+
ColorScales: {
|
|
27912
|
+
blues: _t("Blues"),
|
|
27913
|
+
cividis: _t("Cividis"),
|
|
27914
|
+
greens: _t("Greens"),
|
|
27915
|
+
greys: _t("Greys"),
|
|
27916
|
+
oranges: _t("Oranges"),
|
|
27917
|
+
purples: _t("Purples"),
|
|
27918
|
+
rainbow: _t("Rainbow"),
|
|
27919
|
+
reds: _t("Reds"),
|
|
27920
|
+
viridis: _t("Viridis"),
|
|
27921
|
+
},
|
|
27922
|
+
},
|
|
27762
27923
|
};
|
|
27763
27924
|
const CustomCurrencyTerms = {
|
|
27764
27925
|
Custom: _t("Custom"),
|
|
@@ -28162,6 +28323,26 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28162
28323
|
locale: getters.getLocale(),
|
|
28163
28324
|
};
|
|
28164
28325
|
}
|
|
28326
|
+
function getGeoChartData(definition, dataSets, labelRange, getters) {
|
|
28327
|
+
const labelValues = getChartLabelValues(getters, dataSets, labelRange);
|
|
28328
|
+
let labels = labelValues.formattedValues;
|
|
28329
|
+
if (definition.dataSetsHaveTitle) {
|
|
28330
|
+
labels.shift();
|
|
28331
|
+
}
|
|
28332
|
+
let dataSetsValues = getChartDatasetValues(getters, dataSets);
|
|
28333
|
+
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
28334
|
+
const format = getChartDatasetFormat(getters, dataSets, "left") ||
|
|
28335
|
+
getChartDatasetFormat(getters, dataSets, "right");
|
|
28336
|
+
return {
|
|
28337
|
+
dataSetsValues,
|
|
28338
|
+
axisFormats: { y: format },
|
|
28339
|
+
labels,
|
|
28340
|
+
locale: getters.getLocale(),
|
|
28341
|
+
availableRegions: getters.getGeoChartAvailableRegions(),
|
|
28342
|
+
geoFeatureNameToId: getters.geoFeatureNameToId,
|
|
28343
|
+
getGeoJsonFeatures: getters.getGeoJsonFeatures,
|
|
28344
|
+
};
|
|
28345
|
+
}
|
|
28165
28346
|
function getTrendDatasetForBarChart(config, data) {
|
|
28166
28347
|
const filteredValues = [];
|
|
28167
28348
|
const filteredLabels = [];
|
|
@@ -28714,6 +28895,43 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28714
28895
|
}
|
|
28715
28896
|
return datasets;
|
|
28716
28897
|
}
|
|
28898
|
+
function getGeoChartDatasets(definition, args) {
|
|
28899
|
+
const { availableRegions, dataSetsValues, labels } = args;
|
|
28900
|
+
const regionName = definition.region || availableRegions[0]?.id;
|
|
28901
|
+
const features = regionName ? args.getGeoJsonFeatures(regionName) : undefined;
|
|
28902
|
+
const dataset = {
|
|
28903
|
+
outline: features,
|
|
28904
|
+
showOutline: !!features,
|
|
28905
|
+
data: [],
|
|
28906
|
+
};
|
|
28907
|
+
if (features && regionName) {
|
|
28908
|
+
const labelsAndValues = {};
|
|
28909
|
+
if (dataSetsValues[0]) {
|
|
28910
|
+
for (let i = 0; i < dataSetsValues[0].data.length; i++) {
|
|
28911
|
+
if (!labels[i] || dataSetsValues[0].data[i] === undefined) {
|
|
28912
|
+
continue;
|
|
28913
|
+
}
|
|
28914
|
+
const featureId = args.geoFeatureNameToId(regionName, labels[i]);
|
|
28915
|
+
if (featureId) {
|
|
28916
|
+
labelsAndValues[featureId] = { value: dataSetsValues[0].data[i], label: labels[i] };
|
|
28917
|
+
}
|
|
28918
|
+
}
|
|
28919
|
+
}
|
|
28920
|
+
for (const feature of features) {
|
|
28921
|
+
if (!feature.id) {
|
|
28922
|
+
continue;
|
|
28923
|
+
}
|
|
28924
|
+
dataset.data.push({
|
|
28925
|
+
feature: {
|
|
28926
|
+
...feature,
|
|
28927
|
+
properties: { name: labelsAndValues[feature.id]?.label },
|
|
28928
|
+
},
|
|
28929
|
+
value: labelsAndValues[feature.id]?.value,
|
|
28930
|
+
});
|
|
28931
|
+
}
|
|
28932
|
+
}
|
|
28933
|
+
return [dataset];
|
|
28934
|
+
}
|
|
28717
28935
|
function getTrendingLineDataSet(dataset, config, data) {
|
|
28718
28936
|
const defaultBorderColor = colorToRGBA(dataset.backgroundColor);
|
|
28719
28937
|
defaultBorderColor.a = 1;
|
|
@@ -29091,6 +29309,44 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29091
29309
|
},
|
|
29092
29310
|
};
|
|
29093
29311
|
}
|
|
29312
|
+
function getGeoChartScales(definition, args) {
|
|
29313
|
+
const { locale, axisFormats, availableRegions } = args;
|
|
29314
|
+
const geoLegendPosition = legendPositionToGeoLegendPosition(definition.legendPosition);
|
|
29315
|
+
const region = definition.region
|
|
29316
|
+
? availableRegions.find((r) => r.id === definition.region)
|
|
29317
|
+
: availableRegions[0];
|
|
29318
|
+
const format = axisFormats?.y || axisFormats?.y1;
|
|
29319
|
+
return {
|
|
29320
|
+
projection: {
|
|
29321
|
+
// projection: region?.defaultProjection,
|
|
29322
|
+
projection: getGeoChartProjection(region?.defaultProjection || "mercator"),
|
|
29323
|
+
axis: "x",
|
|
29324
|
+
},
|
|
29325
|
+
color: {
|
|
29326
|
+
axis: "x",
|
|
29327
|
+
display: definition.legendPosition !== "none",
|
|
29328
|
+
border: { color: GRAY_300 },
|
|
29329
|
+
grid: { color: GRAY_300 },
|
|
29330
|
+
ticks: {
|
|
29331
|
+
color: chartFontColor(definition.background),
|
|
29332
|
+
callback: formatTickValue({ locale, format }),
|
|
29333
|
+
},
|
|
29334
|
+
legend: {
|
|
29335
|
+
position: geoLegendPosition,
|
|
29336
|
+
align: geoLegendPosition.includes("right") ? "left" : "right",
|
|
29337
|
+
margin: getLegendMargin(definition),
|
|
29338
|
+
},
|
|
29339
|
+
interpolate: getRuntimeColorScale(definition),
|
|
29340
|
+
missing: definition.missingValueColor || "#ffffff",
|
|
29341
|
+
},
|
|
29342
|
+
};
|
|
29343
|
+
}
|
|
29344
|
+
function getGeoChartProjection(projection) {
|
|
29345
|
+
if (projection === "conicConformal") {
|
|
29346
|
+
return window.ChartGeo.geoConicConformal().rotate([100, 0]); // Centered on the US
|
|
29347
|
+
}
|
|
29348
|
+
return projection;
|
|
29349
|
+
}
|
|
29094
29350
|
function getChartAxisTitleRuntime(design) {
|
|
29095
29351
|
if (design?.title?.text) {
|
|
29096
29352
|
const { text, color, align, italic, bold } = design.title;
|
|
@@ -29154,6 +29410,44 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29154
29410
|
};
|
|
29155
29411
|
}
|
|
29156
29412
|
}
|
|
29413
|
+
function getRuntimeColorScale(definition) {
|
|
29414
|
+
if (!definition.colorScale || typeof definition.colorScale === "string") {
|
|
29415
|
+
return definition.colorScale || "oranges";
|
|
29416
|
+
}
|
|
29417
|
+
const scaleColors = [{ value: 0, color: definition.colorScale.minColor }];
|
|
29418
|
+
if (definition.colorScale.midColor) {
|
|
29419
|
+
scaleColors.push({ value: 0.5, color: definition.colorScale.midColor });
|
|
29420
|
+
}
|
|
29421
|
+
scaleColors.push({ value: 1, color: definition.colorScale.maxColor });
|
|
29422
|
+
return getColorScale(scaleColors);
|
|
29423
|
+
}
|
|
29424
|
+
function getLegendMargin(definition) {
|
|
29425
|
+
switch (definition.legendPosition) {
|
|
29426
|
+
case "top":
|
|
29427
|
+
case "right":
|
|
29428
|
+
const hasTitle = !!definition.title.text;
|
|
29429
|
+
const topMargin = hasTitle ? CHART_PADDING_TOP + 30 : CHART_PADDING_TOP;
|
|
29430
|
+
return { top: topMargin, left: CHART_PADDING$1, right: CHART_PADDING$1 };
|
|
29431
|
+
case "bottom":
|
|
29432
|
+
case "left":
|
|
29433
|
+
case "none":
|
|
29434
|
+
return { left: CHART_PADDING$1, right: CHART_PADDING$1, bottom: CHART_PADDING_BOTTOM };
|
|
29435
|
+
}
|
|
29436
|
+
}
|
|
29437
|
+
function legendPositionToGeoLegendPosition(position) {
|
|
29438
|
+
switch (position) {
|
|
29439
|
+
case "top":
|
|
29440
|
+
return "top-left";
|
|
29441
|
+
case "right":
|
|
29442
|
+
return "top-right";
|
|
29443
|
+
case "bottom":
|
|
29444
|
+
return "bottom-right";
|
|
29445
|
+
case "left":
|
|
29446
|
+
return "bottom-left";
|
|
29447
|
+
case "none":
|
|
29448
|
+
return "bottom-left";
|
|
29449
|
+
}
|
|
29450
|
+
}
|
|
29157
29451
|
|
|
29158
29452
|
function getChartShowValues(definition, args) {
|
|
29159
29453
|
const { axisFormats, locale } = args;
|
|
@@ -29313,6 +29607,25 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29313
29607
|
},
|
|
29314
29608
|
};
|
|
29315
29609
|
}
|
|
29610
|
+
function getGeoChartTooltip(definition, args) {
|
|
29611
|
+
const { locale, axisFormats } = args;
|
|
29612
|
+
const format = axisFormats?.y || axisFormats?.y1;
|
|
29613
|
+
return {
|
|
29614
|
+
filter: function (tooltipItem) {
|
|
29615
|
+
return tooltipItem.raw.value !== undefined;
|
|
29616
|
+
},
|
|
29617
|
+
callbacks: {
|
|
29618
|
+
label: function (tooltipItem) {
|
|
29619
|
+
const rawItem = tooltipItem.raw;
|
|
29620
|
+
const xLabel = rawItem.feature.properties.name;
|
|
29621
|
+
const yLabel = rawItem.value;
|
|
29622
|
+
const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
|
|
29623
|
+
const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
|
|
29624
|
+
return xLabel ? `${xLabel}: ${yLabelStr}` : yLabelStr;
|
|
29625
|
+
},
|
|
29626
|
+
},
|
|
29627
|
+
};
|
|
29628
|
+
}
|
|
29316
29629
|
function calculatePercentage(dataset, dataIndex) {
|
|
29317
29630
|
const numericData = dataset.filter((value) => typeof value === "number");
|
|
29318
29631
|
const total = numericData.reduce((sum, value) => sum + value, 0);
|
|
@@ -29339,6 +29652,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29339
29652
|
getComboChartDatasets: getComboChartDatasets,
|
|
29340
29653
|
getComboChartLegend: getComboChartLegend,
|
|
29341
29654
|
getData: getData,
|
|
29655
|
+
getGeoChartData: getGeoChartData,
|
|
29656
|
+
getGeoChartDatasets: getGeoChartDatasets,
|
|
29657
|
+
getGeoChartScales: getGeoChartScales,
|
|
29658
|
+
getGeoChartTooltip: getGeoChartTooltip,
|
|
29342
29659
|
getLineChartData: getLineChartData,
|
|
29343
29660
|
getLineChartDatasets: getLineChartDatasets,
|
|
29344
29661
|
getLineChartLegend: getLineChartLegend,
|
|
@@ -29912,6 +30229,133 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29912
30229
|
return clip(value, minValue, maxValue);
|
|
29913
30230
|
}
|
|
29914
30231
|
|
|
30232
|
+
class GeoChart extends AbstractChart {
|
|
30233
|
+
dataSets;
|
|
30234
|
+
labelRange;
|
|
30235
|
+
background;
|
|
30236
|
+
legendPosition;
|
|
30237
|
+
type = "geo";
|
|
30238
|
+
dataSetsHaveTitle;
|
|
30239
|
+
dataSetDesign;
|
|
30240
|
+
colorScale;
|
|
30241
|
+
missingValueColor;
|
|
30242
|
+
region;
|
|
30243
|
+
constructor(definition, sheetId, getters) {
|
|
30244
|
+
super(definition, sheetId, getters);
|
|
30245
|
+
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
30246
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
30247
|
+
this.background = definition.background;
|
|
30248
|
+
this.legendPosition = definition.legendPosition;
|
|
30249
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
30250
|
+
this.dataSetDesign = definition.dataSets;
|
|
30251
|
+
this.colorScale = definition.colorScale;
|
|
30252
|
+
this.missingValueColor = definition.missingValueColor;
|
|
30253
|
+
this.region = definition.region;
|
|
30254
|
+
}
|
|
30255
|
+
static transformDefinition(definition, executed) {
|
|
30256
|
+
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
30257
|
+
}
|
|
30258
|
+
static validateChartDefinition(validator, definition) {
|
|
30259
|
+
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
30260
|
+
}
|
|
30261
|
+
static getDefinitionFromContextCreation(context) {
|
|
30262
|
+
return {
|
|
30263
|
+
background: context.background,
|
|
30264
|
+
dataSets: context.range ?? [],
|
|
30265
|
+
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
30266
|
+
legendPosition: context.legendPosition ?? "top",
|
|
30267
|
+
title: context.title || { text: "" },
|
|
30268
|
+
type: "geo",
|
|
30269
|
+
labelRange: context.auxiliaryRange || undefined,
|
|
30270
|
+
aggregated: context.aggregated,
|
|
30271
|
+
};
|
|
30272
|
+
}
|
|
30273
|
+
getContextCreation() {
|
|
30274
|
+
const range = [];
|
|
30275
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
30276
|
+
range.push({
|
|
30277
|
+
...this.dataSetDesign?.[i],
|
|
30278
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
30279
|
+
});
|
|
30280
|
+
}
|
|
30281
|
+
return {
|
|
30282
|
+
...this,
|
|
30283
|
+
range,
|
|
30284
|
+
auxiliaryRange: this.labelRange
|
|
30285
|
+
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
30286
|
+
: undefined,
|
|
30287
|
+
};
|
|
30288
|
+
}
|
|
30289
|
+
copyForSheetId(sheetId) {
|
|
30290
|
+
const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
|
|
30291
|
+
const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
|
|
30292
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
|
|
30293
|
+
return new GeoChart(definition, sheetId, this.getters);
|
|
30294
|
+
}
|
|
30295
|
+
copyInSheetId(sheetId) {
|
|
30296
|
+
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
30297
|
+
return new GeoChart(definition, sheetId, this.getters);
|
|
30298
|
+
}
|
|
30299
|
+
getDefinition() {
|
|
30300
|
+
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
30301
|
+
}
|
|
30302
|
+
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
30303
|
+
const ranges = [];
|
|
30304
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
30305
|
+
ranges.push({
|
|
30306
|
+
...this.dataSetDesign?.[i],
|
|
30307
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
30308
|
+
});
|
|
30309
|
+
}
|
|
30310
|
+
return {
|
|
30311
|
+
type: "geo",
|
|
30312
|
+
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
30313
|
+
background: this.background,
|
|
30314
|
+
dataSets: ranges,
|
|
30315
|
+
legendPosition: this.legendPosition,
|
|
30316
|
+
labelRange: labelRange
|
|
30317
|
+
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
30318
|
+
: undefined,
|
|
30319
|
+
title: this.title,
|
|
30320
|
+
colorScale: this.colorScale,
|
|
30321
|
+
missingValueColor: this.missingValueColor,
|
|
30322
|
+
region: this.region,
|
|
30323
|
+
};
|
|
30324
|
+
}
|
|
30325
|
+
getDefinitionForExcel() {
|
|
30326
|
+
return undefined;
|
|
30327
|
+
}
|
|
30328
|
+
updateRanges(applyChange) {
|
|
30329
|
+
const { dataSets, labelRange, isStale } = updateChartRangesWithDataSets(this.getters, applyChange, this.dataSets, this.labelRange);
|
|
30330
|
+
if (!isStale) {
|
|
30331
|
+
return this;
|
|
30332
|
+
}
|
|
30333
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange);
|
|
30334
|
+
return new GeoChart(definition, this.sheetId, this.getters);
|
|
30335
|
+
}
|
|
30336
|
+
}
|
|
30337
|
+
function createGeoChartRuntime(chart, getters) {
|
|
30338
|
+
const definition = chart.getDefinition();
|
|
30339
|
+
const chartData = getGeoChartData(definition, chart.dataSets, chart.labelRange, getters);
|
|
30340
|
+
const config = {
|
|
30341
|
+
type: "choropleth",
|
|
30342
|
+
data: {
|
|
30343
|
+
datasets: getGeoChartDatasets(definition, chartData),
|
|
30344
|
+
},
|
|
30345
|
+
options: {
|
|
30346
|
+
...CHART_COMMON_OPTIONS,
|
|
30347
|
+
layout: getChartLayout(),
|
|
30348
|
+
scales: getGeoChartScales(definition, chartData),
|
|
30349
|
+
plugins: {
|
|
30350
|
+
title: getChartTitle(definition),
|
|
30351
|
+
tooltip: getGeoChartTooltip(definition, chartData),
|
|
30352
|
+
legend: { display: false },
|
|
30353
|
+
},
|
|
30354
|
+
},
|
|
30355
|
+
};
|
|
30356
|
+
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
30357
|
+
}
|
|
30358
|
+
|
|
29915
30359
|
class LineChart extends AbstractChart {
|
|
29916
30360
|
dataSets;
|
|
29917
30361
|
labelRange;
|
|
@@ -30905,6 +31349,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30905
31349
|
getChartDefinitionFromContextCreation: RadarChart.getDefinitionFromContextCreation,
|
|
30906
31350
|
sequence: 80,
|
|
30907
31351
|
});
|
|
31352
|
+
chartRegistry.add("geo", {
|
|
31353
|
+
match: (type) => type === "geo",
|
|
31354
|
+
createChart: (definition, sheetId, getters) => new GeoChart(definition, sheetId, getters),
|
|
31355
|
+
getChartRuntime: createGeoChartRuntime,
|
|
31356
|
+
validateChartDefinition: GeoChart.validateChartDefinition,
|
|
31357
|
+
transformDefinition: GeoChart.transformDefinition,
|
|
31358
|
+
getChartDefinitionFromContextCreation: GeoChart.getDefinitionFromContextCreation,
|
|
31359
|
+
sequence: 90,
|
|
31360
|
+
});
|
|
30908
31361
|
const chartComponentRegistry = new Registry();
|
|
30909
31362
|
chartComponentRegistry.add("line", ChartJsComponent);
|
|
30910
31363
|
chartComponentRegistry.add("bar", ChartJsComponent);
|
|
@@ -30916,6 +31369,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30916
31369
|
chartComponentRegistry.add("waterfall", ChartJsComponent);
|
|
30917
31370
|
chartComponentRegistry.add("pyramid", ChartJsComponent);
|
|
30918
31371
|
chartComponentRegistry.add("radar", ChartJsComponent);
|
|
31372
|
+
chartComponentRegistry.add("geo", ChartJsComponent);
|
|
30919
31373
|
const chartCategories = {
|
|
30920
31374
|
line: _t("Line"),
|
|
30921
31375
|
column: _t("Column"),
|
|
@@ -31075,6 +31529,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31075
31529
|
subtypeDefinition: { fillArea: true },
|
|
31076
31530
|
category: "misc",
|
|
31077
31531
|
preview: "o-spreadsheet-ChartPreview.FILLED_RADAR_CHART",
|
|
31532
|
+
})
|
|
31533
|
+
.add("geo", {
|
|
31534
|
+
displayName: _t("Geo Chart"),
|
|
31535
|
+
chartSubtype: "geo",
|
|
31536
|
+
chartType: "geo",
|
|
31537
|
+
category: "misc",
|
|
31538
|
+
preview: "o-spreadsheet-ChartPreview.GEO_CHART",
|
|
31078
31539
|
});
|
|
31079
31540
|
|
|
31080
31541
|
/**
|
|
@@ -31925,18 +32386,66 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31925
32386
|
},
|
|
31926
32387
|
};
|
|
31927
32388
|
|
|
31928
|
-
|
|
31929
|
-
|
|
31930
|
-
|
|
31931
|
-
|
|
31932
|
-
|
|
31933
|
-
|
|
31934
|
-
|
|
32389
|
+
const CHECK_SVG = /*xml*/ `
|
|
32390
|
+
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'>
|
|
32391
|
+
<path fill='none' stroke='#FFF' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/>
|
|
32392
|
+
</svg>
|
|
32393
|
+
`;
|
|
32394
|
+
const CHECKBOX_WIDTH = 14;
|
|
32395
|
+
css /* scss */ `
|
|
32396
|
+
label.o-checkbox {
|
|
32397
|
+
input {
|
|
32398
|
+
appearance: none;
|
|
32399
|
+
-webkit-appearance: none;
|
|
32400
|
+
-moz-appearance: none;
|
|
32401
|
+
border-radius: 0;
|
|
32402
|
+
width: ${CHECKBOX_WIDTH}px;
|
|
32403
|
+
height: ${CHECKBOX_WIDTH}px;
|
|
32404
|
+
vertical-align: top;
|
|
32405
|
+
box-sizing: border-box;
|
|
32406
|
+
outline: none;
|
|
32407
|
+
border: 1px solid ${GRAY_300};
|
|
32408
|
+
cursor: pointer;
|
|
32409
|
+
|
|
32410
|
+
&:hover {
|
|
32411
|
+
border-color: ${ACTION_COLOR};
|
|
32412
|
+
}
|
|
32413
|
+
|
|
32414
|
+
&:checked {
|
|
32415
|
+
background: url("data:image/svg+xml,${encodeURIComponent(CHECK_SVG)}");
|
|
32416
|
+
background-color: ${ACTION_COLOR};
|
|
32417
|
+
border-color: ${ACTION_COLOR};
|
|
32418
|
+
}
|
|
32419
|
+
|
|
32420
|
+
&:focus {
|
|
32421
|
+
outline: none;
|
|
32422
|
+
box-shadow: 0 0 0 0.25rem rgba(113, 75, 103, 0.25);
|
|
32423
|
+
border-color: ${ACTION_COLOR};
|
|
32424
|
+
}
|
|
31935
32425
|
}
|
|
31936
32426
|
}
|
|
31937
32427
|
`;
|
|
32428
|
+
class Checkbox extends owl.Component {
|
|
32429
|
+
static template = "o-spreadsheet.Checkbox";
|
|
32430
|
+
static props = {
|
|
32431
|
+
label: { type: String, optional: true },
|
|
32432
|
+
value: { type: Boolean, optional: true },
|
|
32433
|
+
className: { type: String, optional: true },
|
|
32434
|
+
name: { type: String, optional: true },
|
|
32435
|
+
title: { type: String, optional: true },
|
|
32436
|
+
disabled: { type: Boolean, optional: true },
|
|
32437
|
+
onChange: Function,
|
|
32438
|
+
};
|
|
32439
|
+
static defaultProps = { value: false };
|
|
32440
|
+
onChange(ev) {
|
|
32441
|
+
const value = ev.target.checked;
|
|
32442
|
+
this.props.onChange(value);
|
|
32443
|
+
}
|
|
32444
|
+
}
|
|
32445
|
+
|
|
31938
32446
|
class FilterMenuValueItem extends owl.Component {
|
|
31939
32447
|
static template = "o-spreadsheet-FilterMenuValueItem";
|
|
32448
|
+
static components = { Checkbox };
|
|
31940
32449
|
static props = {
|
|
31941
32450
|
value: String,
|
|
31942
32451
|
isChecked: Boolean,
|
|
@@ -31974,8 +32483,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31974
32483
|
.o-filter-menu-item {
|
|
31975
32484
|
display: flex;
|
|
31976
32485
|
box-sizing: border-box;
|
|
31977
|
-
height: ${MENU_ITEM_HEIGHT}px;
|
|
31978
|
-
padding: 4px 4px 4px 0px;
|
|
31979
32486
|
cursor: pointer;
|
|
31980
32487
|
user-select: none;
|
|
31981
32488
|
|
|
@@ -31984,14 +32491,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31984
32491
|
}
|
|
31985
32492
|
}
|
|
31986
32493
|
|
|
31987
|
-
input {
|
|
31988
|
-
box-sizing: border-box;
|
|
31989
|
-
margin-bottom: 5px;
|
|
31990
|
-
border: 1px solid #949494;
|
|
31991
|
-
height: 24px;
|
|
31992
|
-
padding-right: 28px;
|
|
31993
|
-
}
|
|
31994
|
-
|
|
31995
32494
|
.o-search-icon {
|
|
31996
32495
|
right: 5px;
|
|
31997
32496
|
top: 3px;
|
|
@@ -32008,19 +32507,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32008
32507
|
display: flex;
|
|
32009
32508
|
flex-direction: row;
|
|
32010
32509
|
margin-bottom: 4px;
|
|
32011
|
-
|
|
32012
|
-
.o-filter-menu-action-text {
|
|
32013
|
-
cursor: pointer;
|
|
32014
|
-
margin-right: 10px;
|
|
32015
|
-
color: blue;
|
|
32016
|
-
text-decoration: underline;
|
|
32017
|
-
}
|
|
32018
32510
|
}
|
|
32019
32511
|
|
|
32020
32512
|
.o-filter-menu-list {
|
|
32021
32513
|
flex: auto;
|
|
32022
32514
|
overflow-y: auto;
|
|
32023
|
-
border: 1px solid
|
|
32515
|
+
border: 1px solid ${GRAY_300};
|
|
32024
32516
|
|
|
32025
32517
|
.o-filter-menu-no-values {
|
|
32026
32518
|
color: #949494;
|
|
@@ -34212,6 +34704,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34212
34704
|
isReadonlyAllowed: true,
|
|
34213
34705
|
icon: "o-spreadsheet-Icon.PIVOT",
|
|
34214
34706
|
};
|
|
34707
|
+
const pivotSortingAsc = {
|
|
34708
|
+
name: _t("Ascending"),
|
|
34709
|
+
execute: (env) => sortPivot(env, "asc"),
|
|
34710
|
+
isActive: (env) => isPivotSortMenuItemActive(env, "asc"),
|
|
34711
|
+
};
|
|
34712
|
+
const pivotSortingDesc = {
|
|
34713
|
+
name: _t("Descending"),
|
|
34714
|
+
execute: (env) => sortPivot(env, "desc"),
|
|
34715
|
+
isActive: (env) => isPivotSortMenuItemActive(env, "desc"),
|
|
34716
|
+
};
|
|
34717
|
+
const noPivotSorting = {
|
|
34718
|
+
name: _t("No sorting"),
|
|
34719
|
+
execute: (env) => sortPivot(env, "none"),
|
|
34720
|
+
isActive: (env) => isPivotSortMenuItemActive(env, "none"),
|
|
34721
|
+
};
|
|
34215
34722
|
const FIX_FORMULAS = {
|
|
34216
34723
|
name: _t("Convert to individual formulas"),
|
|
34217
34724
|
execute(env) {
|
|
@@ -34248,6 +34755,66 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34248
34755
|
},
|
|
34249
34756
|
icon: "o-spreadsheet-Icon.PIVOT",
|
|
34250
34757
|
};
|
|
34758
|
+
function canSortPivot(env) {
|
|
34759
|
+
const position = env.model.getters.getActivePosition();
|
|
34760
|
+
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
34761
|
+
if (!pivotId ||
|
|
34762
|
+
!env.model.getters.isExistingPivot(pivotId) ||
|
|
34763
|
+
!env.model.getters.isSpillPivotFormula(position)) {
|
|
34764
|
+
return false;
|
|
34765
|
+
}
|
|
34766
|
+
const pivot = env.model.getters.getPivot(pivotId);
|
|
34767
|
+
if (!pivot.isValid()) {
|
|
34768
|
+
return false;
|
|
34769
|
+
}
|
|
34770
|
+
const pivotCell = env.model.getters.getPivotCellFromPosition(position);
|
|
34771
|
+
return pivotCell.type === "VALUE" || pivotCell.type === "MEASURE_HEADER";
|
|
34772
|
+
}
|
|
34773
|
+
function sortPivot(env, order) {
|
|
34774
|
+
const position = env.model.getters.getActivePosition();
|
|
34775
|
+
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
34776
|
+
const pivotCell = env.model.getters.getPivotCellFromPosition(position);
|
|
34777
|
+
if (pivotCell.type === "EMPTY" || pivotCell.type === "HEADER" || !pivotId) {
|
|
34778
|
+
return;
|
|
34779
|
+
}
|
|
34780
|
+
if (order === "none") {
|
|
34781
|
+
env.model.dispatch("UPDATE_PIVOT", {
|
|
34782
|
+
pivotId: pivotId,
|
|
34783
|
+
pivot: {
|
|
34784
|
+
...env.model.getters.getPivotCoreDefinition(pivotId),
|
|
34785
|
+
sortedColumn: undefined,
|
|
34786
|
+
},
|
|
34787
|
+
});
|
|
34788
|
+
return;
|
|
34789
|
+
}
|
|
34790
|
+
const pivot = env.model.getters.getPivot(pivotId);
|
|
34791
|
+
const colDomain = domainToColRowDomain(pivot, pivotCell.domain).colDomain;
|
|
34792
|
+
env.model.dispatch("UPDATE_PIVOT", {
|
|
34793
|
+
pivotId: pivotId,
|
|
34794
|
+
pivot: {
|
|
34795
|
+
...env.model.getters.getPivotCoreDefinition(pivotId),
|
|
34796
|
+
sortedColumn: { domain: colDomain, order, measure: pivotCell.measure },
|
|
34797
|
+
},
|
|
34798
|
+
});
|
|
34799
|
+
}
|
|
34800
|
+
function isPivotSortMenuItemActive(env, order) {
|
|
34801
|
+
const position = env.model.getters.getActivePosition();
|
|
34802
|
+
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
34803
|
+
const pivotCell = env.model.getters.getPivotCellFromPosition(position);
|
|
34804
|
+
if (pivotCell.type === "EMPTY" || pivotCell.type === "HEADER" || !pivotId) {
|
|
34805
|
+
return false;
|
|
34806
|
+
}
|
|
34807
|
+
const pivot = env.model.getters.getPivot(pivotId);
|
|
34808
|
+
const colDomain = domainToColRowDomain(pivot, pivotCell.domain).colDomain;
|
|
34809
|
+
const sortedColumn = pivot.definition.sortedColumn;
|
|
34810
|
+
if (order === "none") {
|
|
34811
|
+
return !sortedColumn;
|
|
34812
|
+
}
|
|
34813
|
+
if (!sortedColumn || sortedColumn.order !== order) {
|
|
34814
|
+
return false;
|
|
34815
|
+
}
|
|
34816
|
+
return sortedColumn.measure === pivotCell.measure && deepEquals(sortedColumn.domain, colDomain);
|
|
34817
|
+
}
|
|
34251
34818
|
|
|
34252
34819
|
//------------------------------------------------------------------------------
|
|
34253
34820
|
// Context Menu Registry
|
|
@@ -34346,14 +34913,33 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34346
34913
|
name: INSERT_LINK_NAME,
|
|
34347
34914
|
sequence: 150,
|
|
34348
34915
|
separator: true,
|
|
34916
|
+
})
|
|
34917
|
+
.add("pivot_sorting", {
|
|
34918
|
+
name: _t("Sort pivot"),
|
|
34919
|
+
sequence: 155,
|
|
34920
|
+
icon: "o-spreadsheet-Icon.SORT_RANGE",
|
|
34921
|
+
isVisible: canSortPivot,
|
|
34349
34922
|
})
|
|
34350
34923
|
.add("pivot_fix_formulas", {
|
|
34351
34924
|
...FIX_FORMULAS,
|
|
34352
|
-
sequence:
|
|
34925
|
+
sequence: 160,
|
|
34353
34926
|
})
|
|
34354
34927
|
.add("pivot_properties", {
|
|
34355
34928
|
...pivotProperties,
|
|
34356
34929
|
sequence: 170,
|
|
34930
|
+
separator: true,
|
|
34931
|
+
})
|
|
34932
|
+
.addChild("pivot_sorting_asc", ["pivot_sorting"], {
|
|
34933
|
+
...pivotSortingAsc,
|
|
34934
|
+
sequence: 10,
|
|
34935
|
+
})
|
|
34936
|
+
.addChild("pivot_sorting_desc", ["pivot_sorting"], {
|
|
34937
|
+
...pivotSortingDesc,
|
|
34938
|
+
sequence: 20,
|
|
34939
|
+
})
|
|
34940
|
+
.addChild("pivot_sorting_none", ["pivot_sorting"], {
|
|
34941
|
+
...noPivotSorting,
|
|
34942
|
+
sequence: 30,
|
|
34357
34943
|
});
|
|
34358
34944
|
|
|
34359
34945
|
const sortRange = {
|
|
@@ -34366,7 +34952,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34366
34952
|
execute: (env) => {
|
|
34367
34953
|
const { anchor, zones } = env.model.getters.getSelection();
|
|
34368
34954
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
34369
|
-
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "
|
|
34955
|
+
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "asc");
|
|
34370
34956
|
},
|
|
34371
34957
|
icon: "o-spreadsheet-Icon.SORT_ASCENDING",
|
|
34372
34958
|
};
|
|
@@ -34394,7 +34980,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34394
34980
|
execute: (env) => {
|
|
34395
34981
|
const { anchor, zones } = env.model.getters.getSelection();
|
|
34396
34982
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
34397
|
-
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "
|
|
34983
|
+
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "desc");
|
|
34398
34984
|
},
|
|
34399
34985
|
icon: "o-spreadsheet-Icon.SORT_DESCENDING",
|
|
34400
34986
|
};
|
|
@@ -34877,6 +35463,227 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34877
35463
|
}
|
|
34878
35464
|
}
|
|
34879
35465
|
|
|
35466
|
+
class PositionMap {
|
|
35467
|
+
map = {};
|
|
35468
|
+
constructor(entries = []) {
|
|
35469
|
+
for (const [position, value] of entries) {
|
|
35470
|
+
this.set(position, value);
|
|
35471
|
+
}
|
|
35472
|
+
}
|
|
35473
|
+
set({ sheetId, col, row }, value) {
|
|
35474
|
+
const map = this.map;
|
|
35475
|
+
if (!map[sheetId]) {
|
|
35476
|
+
map[sheetId] = {};
|
|
35477
|
+
}
|
|
35478
|
+
if (!map[sheetId][col]) {
|
|
35479
|
+
map[sheetId][col] = {};
|
|
35480
|
+
}
|
|
35481
|
+
map[sheetId][col][row] = value;
|
|
35482
|
+
}
|
|
35483
|
+
get({ sheetId, col, row }) {
|
|
35484
|
+
return this.map[sheetId]?.[col]?.[row];
|
|
35485
|
+
}
|
|
35486
|
+
getSheet(sheetId) {
|
|
35487
|
+
return this.map[sheetId];
|
|
35488
|
+
}
|
|
35489
|
+
has({ sheetId, col, row }) {
|
|
35490
|
+
return this.map[sheetId]?.[col]?.[row] !== undefined;
|
|
35491
|
+
}
|
|
35492
|
+
delete({ sheetId, col, row }) {
|
|
35493
|
+
delete this.map[sheetId]?.[col]?.[row];
|
|
35494
|
+
}
|
|
35495
|
+
keys() {
|
|
35496
|
+
const map = this.map;
|
|
35497
|
+
const keys = [];
|
|
35498
|
+
for (const sheetId in map) {
|
|
35499
|
+
for (const col in map[sheetId]) {
|
|
35500
|
+
for (const row in map[sheetId][col]) {
|
|
35501
|
+
keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
|
|
35502
|
+
}
|
|
35503
|
+
}
|
|
35504
|
+
}
|
|
35505
|
+
return keys;
|
|
35506
|
+
}
|
|
35507
|
+
keysForSheet(sheetId) {
|
|
35508
|
+
const map = this.map[sheetId];
|
|
35509
|
+
if (!map) {
|
|
35510
|
+
return [];
|
|
35511
|
+
}
|
|
35512
|
+
const keys = [];
|
|
35513
|
+
for (const col in map) {
|
|
35514
|
+
for (const row in map[col]) {
|
|
35515
|
+
keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
|
|
35516
|
+
}
|
|
35517
|
+
}
|
|
35518
|
+
return keys;
|
|
35519
|
+
}
|
|
35520
|
+
*entries() {
|
|
35521
|
+
const map = this.map;
|
|
35522
|
+
for (const position of this.keys()) {
|
|
35523
|
+
const { sheetId, col, row } = position;
|
|
35524
|
+
yield [position, map[sheetId][col][row]];
|
|
35525
|
+
}
|
|
35526
|
+
}
|
|
35527
|
+
}
|
|
35528
|
+
|
|
35529
|
+
class FormulaFingerprintStore extends SpreadsheetStore {
|
|
35530
|
+
mutators = ["enable", "disable"];
|
|
35531
|
+
isInvalidated = false;
|
|
35532
|
+
fingerprintColors = {
|
|
35533
|
+
[DATA_FINGERPRINT]: "#D9D9D9",
|
|
35534
|
+
};
|
|
35535
|
+
isEnabled = false;
|
|
35536
|
+
colors = new PositionMap();
|
|
35537
|
+
handle(cmd) {
|
|
35538
|
+
if (isCoreCommand(cmd) && this.isEnabled) {
|
|
35539
|
+
this.isInvalidated = true;
|
|
35540
|
+
}
|
|
35541
|
+
switch (cmd.type) {
|
|
35542
|
+
case "UNDO":
|
|
35543
|
+
case "REDO":
|
|
35544
|
+
case "ACTIVATE_SHEET":
|
|
35545
|
+
if (this.isEnabled) {
|
|
35546
|
+
this.isInvalidated = true;
|
|
35547
|
+
}
|
|
35548
|
+
break;
|
|
35549
|
+
}
|
|
35550
|
+
}
|
|
35551
|
+
finalize() {
|
|
35552
|
+
if (this.isInvalidated) {
|
|
35553
|
+
this.isInvalidated = false;
|
|
35554
|
+
this.computeFingerprints();
|
|
35555
|
+
}
|
|
35556
|
+
}
|
|
35557
|
+
enable() {
|
|
35558
|
+
this.isEnabled = true;
|
|
35559
|
+
this.computeFingerprints();
|
|
35560
|
+
}
|
|
35561
|
+
disable() {
|
|
35562
|
+
this.isEnabled = false;
|
|
35563
|
+
this.colors = new PositionMap();
|
|
35564
|
+
}
|
|
35565
|
+
computeFingerprints() {
|
|
35566
|
+
this.colors = new PositionMap();
|
|
35567
|
+
const fingerprints = new PositionMap();
|
|
35568
|
+
const allFingerprints = new Set();
|
|
35569
|
+
const activeSheetId = this.getters.getActiveSheetId();
|
|
35570
|
+
const cells = this.getters.getCells(activeSheetId);
|
|
35571
|
+
for (const cellId in cells) {
|
|
35572
|
+
const fingerprint = this.computeFingerprint(cells[cellId]);
|
|
35573
|
+
if (!fingerprint) {
|
|
35574
|
+
continue;
|
|
35575
|
+
}
|
|
35576
|
+
allFingerprints.add(fingerprint);
|
|
35577
|
+
const position = this.getters.getCellPosition(cellId);
|
|
35578
|
+
fingerprints.set(position, fingerprint);
|
|
35579
|
+
}
|
|
35580
|
+
this.assignColors(allFingerprints);
|
|
35581
|
+
for (const [position, fingerprint] of fingerprints.entries()) {
|
|
35582
|
+
const color = this.fingerprintColors[fingerprint];
|
|
35583
|
+
this.colors.set(position, color);
|
|
35584
|
+
this.colorSpreadZone(position, color);
|
|
35585
|
+
}
|
|
35586
|
+
}
|
|
35587
|
+
colorSpreadZone(position, fingerprintColor) {
|
|
35588
|
+
const spreadZone = this.getters.getSpreadZone(position);
|
|
35589
|
+
if (!spreadZone) {
|
|
35590
|
+
return;
|
|
35591
|
+
}
|
|
35592
|
+
const sheetId = position.sheetId;
|
|
35593
|
+
for (let row = spreadZone.top; row <= spreadZone.bottom; row++) {
|
|
35594
|
+
for (let col = spreadZone.left; col <= spreadZone.right; col++) {
|
|
35595
|
+
const spreadPosition = { sheetId, col, row };
|
|
35596
|
+
this.colors.set(spreadPosition, fingerprintColor);
|
|
35597
|
+
}
|
|
35598
|
+
}
|
|
35599
|
+
}
|
|
35600
|
+
assignColors(fingerprints) {
|
|
35601
|
+
const colors = new AlternatingColorGenerator(fingerprints.size);
|
|
35602
|
+
Object.keys(this.fingerprintColors).forEach(() => colors.next());
|
|
35603
|
+
for (const fingerprint of fingerprints) {
|
|
35604
|
+
if (!this.fingerprintColors[fingerprint]) {
|
|
35605
|
+
this.fingerprintColors[fingerprint] = setColorAlpha(colors.next(), 0.8);
|
|
35606
|
+
}
|
|
35607
|
+
}
|
|
35608
|
+
}
|
|
35609
|
+
computeFingerprint(cell) {
|
|
35610
|
+
const position = this.getters.getCellPosition(cell.id);
|
|
35611
|
+
if (cell.isFormula) {
|
|
35612
|
+
return this.computeFormulaFingerprint(position, cell);
|
|
35613
|
+
}
|
|
35614
|
+
else {
|
|
35615
|
+
return this.getLiteralFingerprint(position);
|
|
35616
|
+
}
|
|
35617
|
+
}
|
|
35618
|
+
computeFormulaFingerprint(position, cell) {
|
|
35619
|
+
const dependencies = cell.compiledFormula.dependencies;
|
|
35620
|
+
const colCellOffset = position.col;
|
|
35621
|
+
const rowCellOffset = position.row;
|
|
35622
|
+
const positionSheetIndex = this.getters.getSheetIds().indexOf(position.sheetId);
|
|
35623
|
+
// As an optimization, we do not build each reference vector individually
|
|
35624
|
+
// to sum them up, but instead we directly add each component to the resulting
|
|
35625
|
+
// vector. This is equivalent to summing up all reference vectors.
|
|
35626
|
+
const fingerprintVector = {
|
|
35627
|
+
dx: 0,
|
|
35628
|
+
dy: 0,
|
|
35629
|
+
dSheet: 0,
|
|
35630
|
+
};
|
|
35631
|
+
for (const range of dependencies) {
|
|
35632
|
+
const zone = range.zone;
|
|
35633
|
+
const [left, right] = range.parts;
|
|
35634
|
+
const rangeSheetIndex = this.getters.getSheetIds().indexOf(range.sheetId);
|
|
35635
|
+
fingerprintVector.dSheet = rangeSheetIndex - positionSheetIndex;
|
|
35636
|
+
// in relative mode, we offset the col and row by the cell's position
|
|
35637
|
+
// in absolute mode, we offset the col and row relative to the sheet
|
|
35638
|
+
const isLeftUnbounded = range.isFullRow && !range.unboundedZone.hasHeader;
|
|
35639
|
+
const isTopUnbounded = range.isFullCol && !range.unboundedZone.hasHeader;
|
|
35640
|
+
const leftOffset = isLeftUnbounded || left?.colFixed ? 0 : colCellOffset;
|
|
35641
|
+
const topOffset = isTopUnbounded || left?.rowFixed ? 0 : rowCellOffset;
|
|
35642
|
+
const isRightFixed = (!right && left?.colFixed) || right?.colFixed;
|
|
35643
|
+
const isBottomFixed = (!right && left.rowFixed) || right?.rowFixed;
|
|
35644
|
+
const isRightUnbounded = range.unboundedZone.right === undefined;
|
|
35645
|
+
const isBottomUnbounded = range.unboundedZone.bottom === undefined;
|
|
35646
|
+
const rightOffset = isRightUnbounded || isRightFixed ? 0 : colCellOffset;
|
|
35647
|
+
const bottomOffset = isBottomUnbounded || isBottomFixed ? 0 : rowCellOffset;
|
|
35648
|
+
const referenceZone = reorderZone({
|
|
35649
|
+
top: zone.top - topOffset,
|
|
35650
|
+
left: zone.left - leftOffset,
|
|
35651
|
+
right: zone.right - rightOffset,
|
|
35652
|
+
bottom: zone.bottom - bottomOffset,
|
|
35653
|
+
});
|
|
35654
|
+
for (let dy = referenceZone.top; dy <= referenceZone.bottom; dy++) {
|
|
35655
|
+
for (let dx = referenceZone.left; dx <= referenceZone.right; dx++) {
|
|
35656
|
+
fingerprintVector.dx += dx;
|
|
35657
|
+
fingerprintVector.dy += dy;
|
|
35658
|
+
}
|
|
35659
|
+
}
|
|
35660
|
+
}
|
|
35661
|
+
// removes the index placeholders from the normalized formula
|
|
35662
|
+
// =|N0|+|N1|+|N0| -> =|N|+|N|+|N|
|
|
35663
|
+
const normalizedFormula = cell.compiledFormula.normalizedFormula.replace(/(|\w)(\d)(|)/g, "$1$3");
|
|
35664
|
+
return hash(fingerprintVector) + normalizedFormula;
|
|
35665
|
+
}
|
|
35666
|
+
getLiteralFingerprint(position) {
|
|
35667
|
+
const evaluatedCell = this.getters.getEvaluatedCell(position);
|
|
35668
|
+
switch (evaluatedCell.type) {
|
|
35669
|
+
case CellValueType.number:
|
|
35670
|
+
case CellValueType.boolean:
|
|
35671
|
+
return DATA_FINGERPRINT;
|
|
35672
|
+
case CellValueType.text:
|
|
35673
|
+
case CellValueType.empty:
|
|
35674
|
+
case CellValueType.error:
|
|
35675
|
+
return undefined;
|
|
35676
|
+
}
|
|
35677
|
+
}
|
|
35678
|
+
}
|
|
35679
|
+
function hash(vector) {
|
|
35680
|
+
return Object.entries(vector)
|
|
35681
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
35682
|
+
.map(([_, value]) => value)
|
|
35683
|
+
.join(",");
|
|
35684
|
+
}
|
|
35685
|
+
const DATA_FINGERPRINT = "DATA_FINGERPRINT";
|
|
35686
|
+
|
|
34880
35687
|
const hideCols = {
|
|
34881
35688
|
name: HIDE_COLUMNS_NAME,
|
|
34882
35689
|
execute: (env) => {
|
|
@@ -35048,6 +35855,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35048
35855
|
return env.model.getters.getGridLinesVisibility(sheetId);
|
|
35049
35856
|
},
|
|
35050
35857
|
};
|
|
35858
|
+
const irregularityMap = {
|
|
35859
|
+
name: _t("Irregularity map"),
|
|
35860
|
+
execute: (env) => {
|
|
35861
|
+
const fingerprintStore = env.getStore(FormulaFingerprintStore);
|
|
35862
|
+
if (fingerprintStore.isEnabled) {
|
|
35863
|
+
fingerprintStore.disable();
|
|
35864
|
+
}
|
|
35865
|
+
else {
|
|
35866
|
+
fingerprintStore.enable();
|
|
35867
|
+
}
|
|
35868
|
+
},
|
|
35869
|
+
icon: "o-spreadsheet-Icon.IRREGULARITY_MAP",
|
|
35870
|
+
};
|
|
35051
35871
|
const viewFormulas = {
|
|
35052
35872
|
name: _t("Formulas"),
|
|
35053
35873
|
isActive: (env) => env.model.getters.shouldShowFormulas(),
|
|
@@ -35665,6 +36485,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35665
36485
|
.addChild("view_formulas", ["view", "show"], {
|
|
35666
36486
|
...viewFormulas,
|
|
35667
36487
|
sequence: 10,
|
|
36488
|
+
})
|
|
36489
|
+
.addChild("view_irregularity_map", ["view"], {
|
|
36490
|
+
...irregularityMap,
|
|
36491
|
+
sequence: 40,
|
|
36492
|
+
separator: true,
|
|
35668
36493
|
})
|
|
35669
36494
|
// ---------------------------------------------------------------------
|
|
35670
36495
|
// INSERT MENU ITEMS
|
|
@@ -35967,62 +36792,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35967
36792
|
}
|
|
35968
36793
|
const otRegistry = new OTRegistry();
|
|
35969
36794
|
|
|
35970
|
-
const CHECK_SVG = /*xml*/ `
|
|
35971
|
-
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'>
|
|
35972
|
-
<path fill='none' stroke='#FFF' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/>
|
|
35973
|
-
</svg>
|
|
35974
|
-
`;
|
|
35975
|
-
const CHECKBOX_WIDTH = 14;
|
|
35976
|
-
css /* scss */ `
|
|
35977
|
-
label.o-checkbox {
|
|
35978
|
-
input {
|
|
35979
|
-
appearance: none;
|
|
35980
|
-
-webkit-appearance: none;
|
|
35981
|
-
-moz-appearance: none;
|
|
35982
|
-
border-radius: 0;
|
|
35983
|
-
width: ${CHECKBOX_WIDTH}px;
|
|
35984
|
-
height: ${CHECKBOX_WIDTH}px;
|
|
35985
|
-
vertical-align: top;
|
|
35986
|
-
box-sizing: border-box;
|
|
35987
|
-
outline: none;
|
|
35988
|
-
border: 1px solid ${GRAY_300};
|
|
35989
|
-
|
|
35990
|
-
&:hover {
|
|
35991
|
-
border-color: ${ACTION_COLOR};
|
|
35992
|
-
}
|
|
35993
|
-
|
|
35994
|
-
&:checked {
|
|
35995
|
-
background: url("data:image/svg+xml,${encodeURIComponent(CHECK_SVG)}");
|
|
35996
|
-
background-color: ${ACTION_COLOR};
|
|
35997
|
-
border-color: ${ACTION_COLOR};
|
|
35998
|
-
}
|
|
35999
|
-
|
|
36000
|
-
&:focus {
|
|
36001
|
-
outline: none;
|
|
36002
|
-
box-shadow: 0 0 0 0.25rem rgba(113, 75, 103, 0.25);
|
|
36003
|
-
border-color: ${ACTION_COLOR};
|
|
36004
|
-
}
|
|
36005
|
-
}
|
|
36006
|
-
}
|
|
36007
|
-
`;
|
|
36008
|
-
class Checkbox extends owl.Component {
|
|
36009
|
-
static template = "o-spreadsheet.Checkbox";
|
|
36010
|
-
static props = {
|
|
36011
|
-
label: { type: String, optional: true },
|
|
36012
|
-
value: { type: Boolean, optional: true },
|
|
36013
|
-
className: { type: String, optional: true },
|
|
36014
|
-
name: { type: String, optional: true },
|
|
36015
|
-
title: { type: String, optional: true },
|
|
36016
|
-
disabled: { type: Boolean, optional: true },
|
|
36017
|
-
onChange: Function,
|
|
36018
|
-
};
|
|
36019
|
-
static defaultProps = { value: false };
|
|
36020
|
-
onChange(ev) {
|
|
36021
|
-
const value = ev.target.checked;
|
|
36022
|
-
this.props.onChange(value);
|
|
36023
|
-
}
|
|
36024
|
-
}
|
|
36025
|
-
|
|
36026
36795
|
class Section extends owl.Component {
|
|
36027
36796
|
static template = "o_spreadsheet.Section";
|
|
36028
36797
|
static props = {
|
|
@@ -38262,6 +39031,104 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38262
39031
|
}
|
|
38263
39032
|
}
|
|
38264
39033
|
|
|
39034
|
+
class GeoChartRegionSelectSection extends owl.Component {
|
|
39035
|
+
static template = "o-spreadsheet-GeoChartRegionSelectSection";
|
|
39036
|
+
static components = { Section };
|
|
39037
|
+
static props = {
|
|
39038
|
+
figureId: String,
|
|
39039
|
+
definition: Object,
|
|
39040
|
+
updateChart: Function,
|
|
39041
|
+
};
|
|
39042
|
+
updateSelectedRegion(ev) {
|
|
39043
|
+
const value = ev.target.value;
|
|
39044
|
+
this.props.updateChart(this.props.figureId, { region: value });
|
|
39045
|
+
}
|
|
39046
|
+
get availableRegions() {
|
|
39047
|
+
return this.env.model.getters.getGeoChartAvailableRegions();
|
|
39048
|
+
}
|
|
39049
|
+
get selectedRegion() {
|
|
39050
|
+
return this.props.definition.region || this.availableRegions[0]?.id;
|
|
39051
|
+
}
|
|
39052
|
+
}
|
|
39053
|
+
|
|
39054
|
+
class GeoChartConfigPanel extends GenericChartConfigPanel {
|
|
39055
|
+
static template = "o-spreadsheet-GeoChartConfigPanel";
|
|
39056
|
+
static components = { ...GenericChartConfigPanel.components, GeoChartRegionSelectSection };
|
|
39057
|
+
get dataRanges() {
|
|
39058
|
+
return this.getDataSeriesRanges().slice(0, 1);
|
|
39059
|
+
}
|
|
39060
|
+
onDataSeriesConfirmed() {
|
|
39061
|
+
this.dataSeriesRanges = spreadRange(this.env.model.getters, this.dataSeriesRanges).slice(0, 1);
|
|
39062
|
+
this.state.datasetDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
39063
|
+
dataSets: this.dataSeriesRanges,
|
|
39064
|
+
});
|
|
39065
|
+
}
|
|
39066
|
+
getLabelRangeOptions() {
|
|
39067
|
+
return [
|
|
39068
|
+
{
|
|
39069
|
+
name: "dataSetsHaveTitle",
|
|
39070
|
+
label: this.dataSetsHaveTitleLabel,
|
|
39071
|
+
value: this.props.definition.dataSetsHaveTitle,
|
|
39072
|
+
onChange: this.onUpdateDataSetsHaveTitle.bind(this),
|
|
39073
|
+
},
|
|
39074
|
+
];
|
|
39075
|
+
}
|
|
39076
|
+
}
|
|
39077
|
+
|
|
39078
|
+
const DEFAULT_CUSTOM_COLOR_SCALE = {
|
|
39079
|
+
minColor: "#FFF5EB",
|
|
39080
|
+
midColor: "#FD8D3C",
|
|
39081
|
+
maxColor: "#7F2704",
|
|
39082
|
+
};
|
|
39083
|
+
class GeoChartDesignPanel extends ChartWithAxisDesignPanel {
|
|
39084
|
+
static template = "o-spreadsheet-GeoChartDesignPanel";
|
|
39085
|
+
static components = { ...ChartWithAxisDesignPanel.components, RoundColorPicker };
|
|
39086
|
+
colorScalesChoices = ChartTerms.GeoChart.ColorScales;
|
|
39087
|
+
updateColorScaleType(ev) {
|
|
39088
|
+
const value = ev.target.value;
|
|
39089
|
+
value === "custom"
|
|
39090
|
+
? this.updateColorScale(DEFAULT_CUSTOM_COLOR_SCALE)
|
|
39091
|
+
: this.updateColorScale(value);
|
|
39092
|
+
}
|
|
39093
|
+
updateColorScale(colorScale) {
|
|
39094
|
+
this.props.updateChart(this.props.figureId, { colorScale });
|
|
39095
|
+
}
|
|
39096
|
+
updateMissingValueColor(color) {
|
|
39097
|
+
this.props.updateChart(this.props.figureId, { missingValueColor: color });
|
|
39098
|
+
}
|
|
39099
|
+
updateLegendPosition(ev) {
|
|
39100
|
+
const value = ev.target.value;
|
|
39101
|
+
this.props.updateChart(this.props.figureId, { legendPosition: value });
|
|
39102
|
+
}
|
|
39103
|
+
get selectedColorScale() {
|
|
39104
|
+
return typeof this.props.definition.colorScale === "object"
|
|
39105
|
+
? "custom"
|
|
39106
|
+
: this.props.definition.colorScale || "oranges";
|
|
39107
|
+
}
|
|
39108
|
+
get selectedMissingValueColor() {
|
|
39109
|
+
return this.props.definition.missingValueColor || "#ffffff";
|
|
39110
|
+
}
|
|
39111
|
+
get customColorScale() {
|
|
39112
|
+
if (typeof this.props.definition.colorScale === "object") {
|
|
39113
|
+
return this.props.definition.colorScale;
|
|
39114
|
+
}
|
|
39115
|
+
return undefined;
|
|
39116
|
+
}
|
|
39117
|
+
getCustomColorScaleColor(color) {
|
|
39118
|
+
return this.customColorScale?.[color] ?? "";
|
|
39119
|
+
}
|
|
39120
|
+
setCustomColorScaleColor(colorType, color) {
|
|
39121
|
+
if (!color && colorType !== "midColor") {
|
|
39122
|
+
color = "#fff";
|
|
39123
|
+
}
|
|
39124
|
+
const customColorScale = this.customColorScale;
|
|
39125
|
+
if (!customColorScale) {
|
|
39126
|
+
return;
|
|
39127
|
+
}
|
|
39128
|
+
this.updateColorScale({ ...customColorScale, [colorType]: color });
|
|
39129
|
+
}
|
|
39130
|
+
}
|
|
39131
|
+
|
|
38265
39132
|
class LineConfigPanel extends GenericChartConfigPanel {
|
|
38266
39133
|
static template = "o-spreadsheet-LineConfigPanel";
|
|
38267
39134
|
get canTreatLabelsAsText() {
|
|
@@ -38575,6 +39442,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38575
39442
|
.add("radar", {
|
|
38576
39443
|
configuration: GenericChartConfigPanel,
|
|
38577
39444
|
design: RadarChartDesignPanel,
|
|
39445
|
+
})
|
|
39446
|
+
.add("geo", {
|
|
39447
|
+
configuration: GeoChartConfigPanel,
|
|
39448
|
+
design: GeoChartDesignPanel,
|
|
38578
39449
|
});
|
|
38579
39450
|
|
|
38580
39451
|
css /* scss */ `
|
|
@@ -39938,7 +40809,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
39938
40809
|
border-color: ${GRAY_300};
|
|
39939
40810
|
|
|
39940
40811
|
&.active {
|
|
39941
|
-
border-color: ${
|
|
40812
|
+
border-color: ${ACTION_COLOR};
|
|
39942
40813
|
}
|
|
39943
40814
|
|
|
39944
40815
|
&.o-invalid {
|
|
@@ -40896,7 +41767,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40896
41767
|
}
|
|
40897
41768
|
const point = this.state.rules.colorScale[target];
|
|
40898
41769
|
if (point) {
|
|
40899
|
-
point.color =
|
|
41770
|
+
point.color = colorToNumber(color);
|
|
40900
41771
|
}
|
|
40901
41772
|
this.updateConditionalFormat({ rule: this.state.rules.colorScale });
|
|
40902
41773
|
this.closeMenus();
|
|
@@ -41041,6 +41912,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
41041
41912
|
return [this.state.rules.dataBar.rangeValues || ""];
|
|
41042
41913
|
}
|
|
41043
41914
|
updateDataBarColor(color) {
|
|
41915
|
+
if (!isColorValid(color)) {
|
|
41916
|
+
return;
|
|
41917
|
+
}
|
|
41044
41918
|
this.state.rules.dataBar.color = Number.parseInt(color.slice(1), 16);
|
|
41045
41919
|
this.updateConditionalFormat({ rule: this.state.rules.dataBar });
|
|
41046
41920
|
}
|
|
@@ -41171,6 +42045,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
41171
42045
|
border: 1px solid #d8dadd;
|
|
41172
42046
|
color: #374151;
|
|
41173
42047
|
}
|
|
42048
|
+
|
|
42049
|
+
table {
|
|
42050
|
+
table-layout: fixed;
|
|
42051
|
+
}
|
|
41174
42052
|
}
|
|
41175
42053
|
`;
|
|
41176
42054
|
class CustomCurrencyPanel extends owl.Component {
|
|
@@ -43644,6 +44522,64 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43644
44522
|
}
|
|
43645
44523
|
}
|
|
43646
44524
|
|
|
44525
|
+
css /* scss */ `
|
|
44526
|
+
.o-pivot-sort {
|
|
44527
|
+
.o-sort-card {
|
|
44528
|
+
width: fit-content;
|
|
44529
|
+
background-color: ${GRAY_100};
|
|
44530
|
+
border: 1px solid ${GRAY_300};
|
|
44531
|
+
|
|
44532
|
+
.o-sort-value {
|
|
44533
|
+
color: ${PRIMARY_BUTTON_BG};
|
|
44534
|
+
}
|
|
44535
|
+
}
|
|
44536
|
+
}
|
|
44537
|
+
`;
|
|
44538
|
+
class PivotSortSection extends owl.Component {
|
|
44539
|
+
static template = "o-spreadsheet-PivotSortSection";
|
|
44540
|
+
static components = {
|
|
44541
|
+
Section,
|
|
44542
|
+
};
|
|
44543
|
+
static props = {
|
|
44544
|
+
definition: Object,
|
|
44545
|
+
pivotId: String,
|
|
44546
|
+
};
|
|
44547
|
+
get hasValidSort() {
|
|
44548
|
+
const pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
44549
|
+
return (!!this.props.definition.sortedColumn &&
|
|
44550
|
+
isSortedColumnValid(this.props.definition.sortedColumn, pivot));
|
|
44551
|
+
}
|
|
44552
|
+
get sortDescription() {
|
|
44553
|
+
const sortOrder = this.props.definition.sortedColumn?.order === "asc" ? _t("ascending") : _t("descending");
|
|
44554
|
+
return _t("Sorted on column (%(ascOrDesc)s):", {
|
|
44555
|
+
ascOrDesc: sortOrder,
|
|
44556
|
+
});
|
|
44557
|
+
}
|
|
44558
|
+
get sortValuesAndFields() {
|
|
44559
|
+
const sortedColumn = this.props.definition.sortedColumn;
|
|
44560
|
+
if (!sortedColumn) {
|
|
44561
|
+
return [];
|
|
44562
|
+
}
|
|
44563
|
+
const pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
44564
|
+
const locale = this.env.model.getters.getLocale();
|
|
44565
|
+
const currentDomain = [];
|
|
44566
|
+
const sortValues = [];
|
|
44567
|
+
for (const domainItem of sortedColumn.domain) {
|
|
44568
|
+
currentDomain.push(domainItem);
|
|
44569
|
+
const { value, format } = pivot.getPivotHeaderValueAndFormat(currentDomain);
|
|
44570
|
+
const label = formatValue(value, { format, locale });
|
|
44571
|
+
const field = pivot.definition.getDimension(domainItem.field);
|
|
44572
|
+
sortValues.push({ field: getFieldDisplayName(field), value: label });
|
|
44573
|
+
}
|
|
44574
|
+
if (sortedColumn.domain.length === 0) {
|
|
44575
|
+
sortValues.push({ value: _t("Total") });
|
|
44576
|
+
}
|
|
44577
|
+
const measureLabel = pivot.getMeasure(sortedColumn.measure).displayName;
|
|
44578
|
+
sortValues.push({ value: measureLabel, field: _t("Measure") });
|
|
44579
|
+
return sortValues;
|
|
44580
|
+
}
|
|
44581
|
+
}
|
|
44582
|
+
|
|
43647
44583
|
css /* scss */ `
|
|
43648
44584
|
.add-calculated-measure {
|
|
43649
44585
|
cursor: pointer;
|
|
@@ -43657,6 +44593,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43657
44593
|
PivotDimensionOrder,
|
|
43658
44594
|
PivotDimensionGranularity,
|
|
43659
44595
|
PivotMeasureEditor,
|
|
44596
|
+
PivotSortSection,
|
|
43660
44597
|
};
|
|
43661
44598
|
static props = {
|
|
43662
44599
|
definition: Object,
|
|
@@ -43813,9 +44750,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43813
44750
|
}
|
|
43814
44751
|
updateMeasure(measure, newMeasure) {
|
|
43815
44752
|
const { measures } = this.props.definition;
|
|
43816
|
-
|
|
44753
|
+
const update = {
|
|
43817
44754
|
measures: measures.map((m) => (m.id === measure.id ? newMeasure : m)),
|
|
43818
|
-
}
|
|
44755
|
+
};
|
|
44756
|
+
if (this.props.definition.sortedColumn?.measure === measure.id) {
|
|
44757
|
+
update.sortedColumn = { ...this.props.definition.sortedColumn, measure: newMeasure.id };
|
|
44758
|
+
}
|
|
44759
|
+
this.props.onDimensionsUpdated(update);
|
|
43819
44760
|
}
|
|
43820
44761
|
getMeasureId(fieldName, aggregator) {
|
|
43821
44762
|
const baseId = fieldName + (aggregator ? `:${aggregator}` : "");
|
|
@@ -43971,10 +44912,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43971
44912
|
measures;
|
|
43972
44913
|
columns;
|
|
43973
44914
|
rows;
|
|
44915
|
+
sortedColumn;
|
|
43974
44916
|
constructor(definition, fields) {
|
|
43975
44917
|
this.measures = definition.measures.map((measure) => createMeasure(fields, measure));
|
|
43976
44918
|
this.columns = definition.columns.map((dimension) => createPivotDimension(fields, dimension));
|
|
43977
44919
|
this.rows = definition.rows.map((dimension) => createPivotDimension(fields, dimension));
|
|
44920
|
+
this.sortedColumn = definition.sortedColumn;
|
|
43978
44921
|
}
|
|
43979
44922
|
getDimension(nameWithGranularity) {
|
|
43980
44923
|
const dimension = this.columns.find((d) => d.nameWithGranularity === nameWithGranularity) ||
|
|
@@ -44128,6 +45071,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44128
45071
|
pivotCells = {};
|
|
44129
45072
|
rowTree;
|
|
44130
45073
|
colTree;
|
|
45074
|
+
isSorted = false;
|
|
44131
45075
|
constructor(columns, rows, measures, fieldsType) {
|
|
44132
45076
|
this.columns = columns.map((row) => {
|
|
44133
45077
|
// offset in the pivot table
|
|
@@ -44301,6 +45245,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44301
45245
|
value,
|
|
44302
45246
|
field: row.fields[rowDepth],
|
|
44303
45247
|
children: [],
|
|
45248
|
+
type: this.fieldsType[fieldName] || "char",
|
|
44304
45249
|
width: 0, // not used
|
|
44305
45250
|
};
|
|
44306
45251
|
treesAtDepth[depth].push(node);
|
|
@@ -44323,6 +45268,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44323
45268
|
field: leaf.fields[depth],
|
|
44324
45269
|
children: [],
|
|
44325
45270
|
width: leaf.width,
|
|
45271
|
+
type: this.fieldsType[fieldName] || "char",
|
|
44326
45272
|
};
|
|
44327
45273
|
if (treesAtDepth[depth]?.at(-1)?.value !== value) {
|
|
44328
45274
|
treesAtDepth[depth + 1] = [];
|
|
@@ -44341,6 +45287,35 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44341
45287
|
fieldsType: this.fieldsType,
|
|
44342
45288
|
};
|
|
44343
45289
|
}
|
|
45290
|
+
sort(measure, sortedColumn, getValue) {
|
|
45291
|
+
if (this.isSorted) {
|
|
45292
|
+
return;
|
|
45293
|
+
}
|
|
45294
|
+
const getSortValue = (measure, domain) => {
|
|
45295
|
+
const rawValue = getValue(measure, domain).value;
|
|
45296
|
+
return typeof rawValue === "number" ? rawValue : -Infinity;
|
|
45297
|
+
};
|
|
45298
|
+
const sortColDomain = sortedColumn.domain;
|
|
45299
|
+
const sortFn = (rowDomain1, rowDomain2) => {
|
|
45300
|
+
const value1 = getSortValue(measure, [...rowDomain1, ...sortColDomain]);
|
|
45301
|
+
const value2 = getSortValue(measure, [...rowDomain2, ...sortColDomain]);
|
|
45302
|
+
return sortedColumn.order === "asc" ? value1 - value2 : value2 - value1;
|
|
45303
|
+
};
|
|
45304
|
+
const sortedRowTree = sortPivotTree(this.rowTree(), [], sortFn);
|
|
45305
|
+
this.rowTree = lazy(sortedRowTree);
|
|
45306
|
+
this.rows = [...this.rowTreeToRows(sortedRowTree), this.rows[this.rows.length - 1]];
|
|
45307
|
+
this.isSorted = true;
|
|
45308
|
+
}
|
|
45309
|
+
rowTreeToRows(tree, parentRow) {
|
|
45310
|
+
return tree.flatMap((node) => {
|
|
45311
|
+
const row = {
|
|
45312
|
+
indent: parentRow ? parentRow.indent + 1 : 0,
|
|
45313
|
+
fields: [...(parentRow?.fields || []), node.field],
|
|
45314
|
+
values: [...(parentRow?.values || []), node.value],
|
|
45315
|
+
};
|
|
45316
|
+
return [row, ...this.rowTreeToRows(node.children, row)];
|
|
45317
|
+
});
|
|
45318
|
+
}
|
|
44344
45319
|
}
|
|
44345
45320
|
const EMPTY_PIVOT_CELL = { type: "EMPTY" };
|
|
44346
45321
|
|
|
@@ -44418,6 +45393,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44418
45393
|
value: groups[key]?.[0]?.[column.nameWithGranularity]?.value ?? null,
|
|
44419
45394
|
field: colName,
|
|
44420
45395
|
children: dataEntriesToColumnsTree(groups[key] || [], columns, index + 1),
|
|
45396
|
+
type: column.type,
|
|
44421
45397
|
width: 0,
|
|
44422
45398
|
};
|
|
44423
45399
|
});
|
|
@@ -45283,6 +46259,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45283
46259
|
format: measure.format,
|
|
45284
46260
|
display: measure.display,
|
|
45285
46261
|
})),
|
|
46262
|
+
sortedColumn: this.shouldKeepSortedColumn(definition) ? definition.sortedColumn : undefined,
|
|
45286
46263
|
};
|
|
45287
46264
|
if (!this.draft && deepEquals(coreDefinition, cleanedDefinition)) {
|
|
45288
46265
|
return;
|
|
@@ -45341,6 +46318,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45341
46318
|
}
|
|
45342
46319
|
return granularitiesPerFields;
|
|
45343
46320
|
}
|
|
46321
|
+
/**
|
|
46322
|
+
* Check if we want to keep the sorted column when updating the pivot definition. We should remove it if either
|
|
46323
|
+
* the measure is not in the new definition or the columns have changed.
|
|
46324
|
+
*/
|
|
46325
|
+
shouldKeepSortedColumn(newDefinition) {
|
|
46326
|
+
const { sortedColumn } = newDefinition;
|
|
46327
|
+
if (!sortedColumn) {
|
|
46328
|
+
return true;
|
|
46329
|
+
}
|
|
46330
|
+
const oldDefinition = this.getters.getPivotCoreDefinition(this.pivotId);
|
|
46331
|
+
return (newDefinition.measures.find((measure) => measure.id === sortedColumn.measure) &&
|
|
46332
|
+
deepEquals(oldDefinition.columns, newDefinition.columns));
|
|
46333
|
+
}
|
|
45344
46334
|
}
|
|
45345
46335
|
|
|
45346
46336
|
class PivotSpreadsheetSidePanel extends owl.Component {
|
|
@@ -46442,6 +47432,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46442
47432
|
}
|
|
46443
47433
|
}
|
|
46444
47434
|
`;
|
|
47435
|
+
const DEFAULT_TABLE_STYLE_COLOR = "#3C78D8";
|
|
46445
47436
|
class TableStyleEditorPanel extends owl.Component {
|
|
46446
47437
|
static template = "o-spreadsheet-TableStyleEditorPanel";
|
|
46447
47438
|
static components = { Section, RoundColorPicker, TableStylePreview };
|
|
@@ -46460,7 +47451,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46460
47451
|
: null;
|
|
46461
47452
|
return {
|
|
46462
47453
|
pickerOpened: false,
|
|
46463
|
-
primaryColor: editedStyle?.primaryColor ||
|
|
47454
|
+
primaryColor: editedStyle?.primaryColor || DEFAULT_TABLE_STYLE_COLOR,
|
|
46464
47455
|
selectedTemplateName: editedStyle?.templateName || "lightColoredText",
|
|
46465
47456
|
styleName: editedStyle?.displayName || this.env.model.getters.getNewCustomTableStyleName(),
|
|
46466
47457
|
};
|
|
@@ -46469,7 +47460,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46469
47460
|
this.state.pickerOpened = !this.state.pickerOpened;
|
|
46470
47461
|
}
|
|
46471
47462
|
onColorPicked(color) {
|
|
46472
|
-
this.state.primaryColor = color;
|
|
47463
|
+
this.state.primaryColor = isColorValid(color) ? color : DEFAULT_TABLE_STYLE_COLOR;
|
|
46473
47464
|
this.state.pickerOpened = false;
|
|
46474
47465
|
}
|
|
46475
47466
|
onTemplatePicked(templateName) {
|
|
@@ -48085,6 +49076,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48085
49076
|
draggedFigure: undefined,
|
|
48086
49077
|
horizontalSnap: undefined,
|
|
48087
49078
|
verticalSnap: undefined,
|
|
49079
|
+
cancelDnd: undefined,
|
|
48088
49080
|
});
|
|
48089
49081
|
setup() {
|
|
48090
49082
|
owl.onMounted(() => {
|
|
@@ -48097,12 +49089,28 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48097
49089
|
// new rendering
|
|
48098
49090
|
this.render();
|
|
48099
49091
|
});
|
|
49092
|
+
owl.onWillUpdateProps(() => {
|
|
49093
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
49094
|
+
const draggedFigureId = this.dnd.draggedFigure?.id;
|
|
49095
|
+
if (draggedFigureId && !this.env.model.getters.getFigure(sheetId, draggedFigureId)) {
|
|
49096
|
+
if (this.dnd.cancelDnd) {
|
|
49097
|
+
this.dnd.cancelDnd();
|
|
49098
|
+
}
|
|
49099
|
+
this.dnd.draggedFigure = undefined;
|
|
49100
|
+
this.dnd.horizontalSnap = undefined;
|
|
49101
|
+
this.dnd.verticalSnap = undefined;
|
|
49102
|
+
this.dnd.cancelDnd = undefined;
|
|
49103
|
+
}
|
|
49104
|
+
});
|
|
48100
49105
|
}
|
|
48101
49106
|
getVisibleFigures() {
|
|
48102
49107
|
const visibleFigures = this.env.model.getters.getVisibleFigures();
|
|
48103
49108
|
if (this.dnd.draggedFigure &&
|
|
48104
49109
|
!visibleFigures.some((figure) => figure.id === this.dnd.draggedFigure?.id)) {
|
|
48105
|
-
|
|
49110
|
+
const draggedFigure = this.env.model.getters.getFigure(this.env.model.getters.getActiveSheetId(), this.dnd.draggedFigure?.id);
|
|
49111
|
+
if (draggedFigure) {
|
|
49112
|
+
visibleFigures.push(draggedFigure);
|
|
49113
|
+
}
|
|
48106
49114
|
}
|
|
48107
49115
|
return visibleFigures;
|
|
48108
49116
|
}
|
|
@@ -48221,7 +49229,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48221
49229
|
this.dnd.verticalSnap = undefined;
|
|
48222
49230
|
this.env.model.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x, y });
|
|
48223
49231
|
};
|
|
48224
|
-
startDnd(onMouseMove, onMouseUp);
|
|
49232
|
+
this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
|
|
48225
49233
|
}
|
|
48226
49234
|
/**
|
|
48227
49235
|
* Initialize the resize of a figure with mouse movements
|
|
@@ -48269,7 +49277,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48269
49277
|
this.dnd.horizontalSnap = undefined;
|
|
48270
49278
|
this.dnd.verticalSnap = undefined;
|
|
48271
49279
|
};
|
|
48272
|
-
startDnd(onMouseMove, onMouseUp);
|
|
49280
|
+
this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
|
|
48273
49281
|
}
|
|
48274
49282
|
getOtherFigures(figId) {
|
|
48275
49283
|
return this.getVisibleFigures().filter((f) => f.id !== figId);
|
|
@@ -49376,9 +50384,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49376
50384
|
class GridRenderer {
|
|
49377
50385
|
getters;
|
|
49378
50386
|
renderer;
|
|
50387
|
+
fingerprints;
|
|
49379
50388
|
constructor(get) {
|
|
49380
50389
|
this.getters = get(ModelStore).getters;
|
|
49381
50390
|
this.renderer = get(RendererStore);
|
|
50391
|
+
this.fingerprints = get(FormulaFingerprintStore);
|
|
49382
50392
|
this.renderer.register(this);
|
|
49383
50393
|
}
|
|
49384
50394
|
get renderingLayers() {
|
|
@@ -49856,14 +50866,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49856
50866
|
const showFormula = this.getters.shouldShowFormulas();
|
|
49857
50867
|
const { x, y, width, height } = this.getters.getVisibleRect(zone);
|
|
49858
50868
|
const { verticalAlign } = this.getters.getCellStyle(position);
|
|
50869
|
+
let style = this.getters.getCellComputedStyle(position);
|
|
50870
|
+
if (this.fingerprints.isEnabled) {
|
|
50871
|
+
const fingerprintColor = this.fingerprints.colors.get(position);
|
|
50872
|
+
style = { ...style, fillColor: fingerprintColor };
|
|
50873
|
+
}
|
|
50874
|
+
const dataBarFill = this.fingerprints.isEnabled
|
|
50875
|
+
? undefined
|
|
50876
|
+
: this.getters.getConditionalDataBar(position);
|
|
49859
50877
|
const box = {
|
|
49860
50878
|
x,
|
|
49861
50879
|
y,
|
|
49862
50880
|
width,
|
|
49863
50881
|
height,
|
|
49864
50882
|
border: this.getters.getCellComputedBorder(position) || undefined,
|
|
49865
|
-
style
|
|
49866
|
-
dataBarFill
|
|
50883
|
+
style,
|
|
50884
|
+
dataBarFill,
|
|
49867
50885
|
verticalAlign,
|
|
49868
50886
|
isError: (cell.type === CellValueType.error && !!cell.message) ||
|
|
49869
50887
|
this.getters.isDataValidationInvalid(position),
|
|
@@ -49888,7 +50906,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49888
50906
|
box.hasIcon = this.getters.doesCellHaveGridIcon(position);
|
|
49889
50907
|
const headerIconWidth = box.hasIcon ? GRID_ICON_EDGE_LENGTH + GRID_ICON_MARGIN : 0;
|
|
49890
50908
|
/** Content */
|
|
49891
|
-
const style = this.getters.getCellComputedStyle(position);
|
|
49892
50909
|
const wrapping = style.wrapping || "overflow";
|
|
49893
50910
|
const wrapText = wrapping === "wrap" && !showFormula;
|
|
49894
50911
|
const maxWidth = width - 2 * MIN_CELL_TEXT_MARGIN;
|
|
@@ -51866,62 +52883,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51866
52883
|
}
|
|
51867
52884
|
}
|
|
51868
52885
|
|
|
51869
|
-
class PositionMap {
|
|
51870
|
-
map = {};
|
|
51871
|
-
constructor(entries = []) {
|
|
51872
|
-
for (const [position, value] of entries) {
|
|
51873
|
-
this.set(position, value);
|
|
51874
|
-
}
|
|
51875
|
-
}
|
|
51876
|
-
set({ sheetId, col, row }, value) {
|
|
51877
|
-
const map = this.map;
|
|
51878
|
-
if (!map[sheetId]) {
|
|
51879
|
-
map[sheetId] = {};
|
|
51880
|
-
}
|
|
51881
|
-
if (!map[sheetId][col]) {
|
|
51882
|
-
map[sheetId][col] = {};
|
|
51883
|
-
}
|
|
51884
|
-
map[sheetId][col][row] = value;
|
|
51885
|
-
}
|
|
51886
|
-
get({ sheetId, col, row }) {
|
|
51887
|
-
return this.map[sheetId]?.[col]?.[row];
|
|
51888
|
-
}
|
|
51889
|
-
getSheet(sheetId) {
|
|
51890
|
-
return this.map[sheetId];
|
|
51891
|
-
}
|
|
51892
|
-
has({ sheetId, col, row }) {
|
|
51893
|
-
return this.map[sheetId]?.[col]?.[row] !== undefined;
|
|
51894
|
-
}
|
|
51895
|
-
delete({ sheetId, col, row }) {
|
|
51896
|
-
delete this.map[sheetId]?.[col]?.[row];
|
|
51897
|
-
}
|
|
51898
|
-
keys() {
|
|
51899
|
-
const map = this.map;
|
|
51900
|
-
const keys = [];
|
|
51901
|
-
for (const sheetId in map) {
|
|
51902
|
-
for (const col in map[sheetId]) {
|
|
51903
|
-
for (const row in map[sheetId][col]) {
|
|
51904
|
-
keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
|
|
51905
|
-
}
|
|
51906
|
-
}
|
|
51907
|
-
}
|
|
51908
|
-
return keys;
|
|
51909
|
-
}
|
|
51910
|
-
keysForSheet(sheetId) {
|
|
51911
|
-
const map = this.map[sheetId];
|
|
51912
|
-
if (!map) {
|
|
51913
|
-
return [];
|
|
51914
|
-
}
|
|
51915
|
-
const keys = [];
|
|
51916
|
-
for (const col in map) {
|
|
51917
|
-
for (const row in map[col]) {
|
|
51918
|
-
keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
|
|
51919
|
-
}
|
|
51920
|
-
}
|
|
51921
|
-
return keys;
|
|
51922
|
-
}
|
|
51923
|
-
}
|
|
51924
|
-
|
|
51925
52886
|
/**
|
|
51926
52887
|
* Core Plugin
|
|
51927
52888
|
*
|
|
@@ -52360,7 +53321,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52360
53321
|
const before = this.getters.getCell({ sheetId, col, row });
|
|
52361
53322
|
const hasContent = "content" in after || "formula" in after;
|
|
52362
53323
|
// Compute the new cell properties
|
|
52363
|
-
const afterContent = hasContent ?
|
|
53324
|
+
const afterContent = hasContent ? replaceNewLines(after?.content) : before?.content || "";
|
|
52364
53325
|
let style;
|
|
52365
53326
|
if (after.style !== undefined) {
|
|
52366
53327
|
style = after.style || undefined;
|
|
@@ -55305,6 +56266,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55305
56266
|
};
|
|
55306
56267
|
}
|
|
55307
56268
|
getUnboundedZone(sheetId, zone) {
|
|
56269
|
+
if (zone.bottom === undefined || zone.right === undefined) {
|
|
56270
|
+
return zone;
|
|
56271
|
+
}
|
|
55308
56272
|
const isFullRow = zone.left === 0 && zone.right === this.getNumberCols(sheetId) - 1;
|
|
55309
56273
|
const isFullCol = zone.top === 0 && zone.bottom === this.getNumberRows(sheetId) - 1;
|
|
55310
56274
|
return {
|
|
@@ -59588,66 +60552,25 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
59588
60552
|
return;
|
|
59589
60553
|
}
|
|
59590
60554
|
const zone = this.getters.getRangeFromSheetXC(sheetId, range).zone;
|
|
59591
|
-
const
|
|
60555
|
+
const colorThresholds = [{ value: minValue, color: rule.minimum.color }];
|
|
59592
60556
|
if (rule.midpoint && midValue) {
|
|
59593
|
-
|
|
59594
|
-
minValue,
|
|
59595
|
-
minColor: rule.minimum.color,
|
|
59596
|
-
colorDiffUnit: this.computeColorDiffUnits(minValue, midValue, rule.minimum.color, rule.midpoint.color),
|
|
59597
|
-
});
|
|
59598
|
-
colorCellArgs.push({
|
|
59599
|
-
minValue: midValue,
|
|
59600
|
-
minColor: rule.midpoint.color,
|
|
59601
|
-
colorDiffUnit: this.computeColorDiffUnits(midValue, maxValue, rule.midpoint.color, rule.maximum.color),
|
|
59602
|
-
});
|
|
59603
|
-
}
|
|
59604
|
-
else {
|
|
59605
|
-
colorCellArgs.push({
|
|
59606
|
-
minValue,
|
|
59607
|
-
minColor: rule.minimum.color,
|
|
59608
|
-
colorDiffUnit: this.computeColorDiffUnits(minValue, maxValue, rule.minimum.color, rule.maximum.color),
|
|
59609
|
-
});
|
|
60557
|
+
colorThresholds.push({ value: midValue, color: rule.midpoint.color });
|
|
59610
60558
|
}
|
|
60559
|
+
colorThresholds.push({ value: maxValue, color: rule.maximum.color });
|
|
60560
|
+
const colorScale = getColorScale(colorThresholds);
|
|
59611
60561
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
59612
60562
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
59613
60563
|
const cell = this.getters.getEvaluatedCell({ sheetId, col, row });
|
|
59614
60564
|
if (cell.type === CellValueType.number) {
|
|
59615
60565
|
const value = clip(cell.value, minValue, maxValue);
|
|
59616
|
-
let color;
|
|
59617
|
-
if (colorCellArgs.length === 2 && midValue) {
|
|
59618
|
-
color =
|
|
59619
|
-
value <= midValue
|
|
59620
|
-
? this.colorCell(value, colorCellArgs[0].minValue, colorCellArgs[0].minColor, colorCellArgs[0].colorDiffUnit)
|
|
59621
|
-
: this.colorCell(value, colorCellArgs[1].minValue, colorCellArgs[1].minColor, colorCellArgs[1].colorDiffUnit);
|
|
59622
|
-
}
|
|
59623
|
-
else {
|
|
59624
|
-
color = this.colorCell(value, colorCellArgs[0].minValue, colorCellArgs[0].minColor, colorCellArgs[0].colorDiffUnit);
|
|
59625
|
-
}
|
|
59626
60566
|
if (!computedStyle[col])
|
|
59627
60567
|
computedStyle[col] = [];
|
|
59628
60568
|
computedStyle[col][row] = computedStyle[col]?.[row] || {};
|
|
59629
|
-
computedStyle[col][row].fillColor =
|
|
60569
|
+
computedStyle[col][row].fillColor = colorScale(value);
|
|
59630
60570
|
}
|
|
59631
60571
|
}
|
|
59632
60572
|
}
|
|
59633
60573
|
}
|
|
59634
|
-
computeColorDiffUnits(minValue, maxValue, minColor, maxColor) {
|
|
59635
|
-
const deltaValue = maxValue - minValue;
|
|
59636
|
-
const deltaColorR = ((minColor >> 16) % 256) - ((maxColor >> 16) % 256);
|
|
59637
|
-
const deltaColorG = ((minColor >> 8) % 256) - ((maxColor >> 8) % 256);
|
|
59638
|
-
const deltaColorB = (minColor % 256) - (maxColor % 256);
|
|
59639
|
-
const colorDiffUnitR = deltaColorR / deltaValue;
|
|
59640
|
-
const colorDiffUnitG = deltaColorG / deltaValue;
|
|
59641
|
-
const colorDiffUnitB = deltaColorB / deltaValue;
|
|
59642
|
-
return [colorDiffUnitR, colorDiffUnitG, colorDiffUnitB];
|
|
59643
|
-
}
|
|
59644
|
-
colorCell(value, minValue, minColor, colorDiffUnit) {
|
|
59645
|
-
const [colorDiffUnitR, colorDiffUnitG, colorDiffUnitB] = colorDiffUnit;
|
|
59646
|
-
const r = Math.round(((minColor >> 16) % 256) - colorDiffUnitR * (value - minValue));
|
|
59647
|
-
const g = Math.round(((minColor >> 8) % 256) - colorDiffUnitG * (value - minValue));
|
|
59648
|
-
const b = Math.round((minColor % 256) - colorDiffUnitB * (value - minValue));
|
|
59649
|
-
return (r << 16) | (g << 8) | b;
|
|
59650
|
-
}
|
|
59651
60574
|
/**
|
|
59652
60575
|
* Execute the predicate to know if a conditional formatting rule should be applied to a cell
|
|
59653
60576
|
*/
|
|
@@ -60273,7 +61196,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60273
61196
|
}
|
|
60274
61197
|
getValuesToAggregate(measure, domain) {
|
|
60275
61198
|
const { rowDomain, colDomain } = domainToColRowDomain(this, domain);
|
|
60276
|
-
const table =
|
|
61199
|
+
const table = super.getTableStructure();
|
|
60277
61200
|
const values = [];
|
|
60278
61201
|
if (colDomain.length === 0 &&
|
|
60279
61202
|
rowDomain.length < this.definition.rows.length &&
|
|
@@ -60707,6 +61630,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60707
61630
|
}
|
|
60708
61631
|
throw new Error(`Value ${result.value} is not a number`);
|
|
60709
61632
|
}
|
|
61633
|
+
getTableStructure() {
|
|
61634
|
+
const table = super.getTableStructure();
|
|
61635
|
+
this.sortTableStructure(table);
|
|
61636
|
+
return table;
|
|
61637
|
+
}
|
|
61638
|
+
sortTableStructure(table) {
|
|
61639
|
+
if (!this.definition.sortedColumn || table.isSorted) {
|
|
61640
|
+
return;
|
|
61641
|
+
}
|
|
61642
|
+
const measure = this.definition.sortedColumn.measure;
|
|
61643
|
+
const isSortValid = isSortedColumnValid(this.definition.sortedColumn, this);
|
|
61644
|
+
if (isSortValid) {
|
|
61645
|
+
table.sort(measure, this.definition.sortedColumn, (measure, domain) => this._getPivotCellValueAndFormat(measure, domain));
|
|
61646
|
+
}
|
|
61647
|
+
}
|
|
60710
61648
|
}
|
|
60711
61649
|
return PivotPresentationLayer;
|
|
60712
61650
|
}
|
|
@@ -62482,23 +63420,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62482
63420
|
}
|
|
62483
63421
|
}
|
|
62484
63422
|
|
|
62485
|
-
function randomChoice(arr) {
|
|
62486
|
-
return arr[Math.floor(Math.random() * arr.length)];
|
|
62487
|
-
}
|
|
62488
|
-
const colors = [
|
|
62489
|
-
"#ff851b",
|
|
62490
|
-
"#0074d9",
|
|
62491
|
-
"#7fdbff",
|
|
62492
|
-
"#b10dc9",
|
|
62493
|
-
"#39cccc",
|
|
62494
|
-
"#f012be",
|
|
62495
|
-
"#3d9970",
|
|
62496
|
-
"#111111",
|
|
62497
|
-
"#ff4136",
|
|
62498
|
-
"#aaaaaa",
|
|
62499
|
-
"#85144b",
|
|
62500
|
-
"#001f3f",
|
|
62501
|
-
];
|
|
62502
63423
|
class CollaborativePlugin extends UIPlugin {
|
|
62503
63424
|
static getters = [
|
|
62504
63425
|
"getClientsToDisplay",
|
|
@@ -62507,7 +63428,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62507
63428
|
"isFullySynchronized",
|
|
62508
63429
|
];
|
|
62509
63430
|
static layers = ["Selection"];
|
|
62510
|
-
availableColors = new
|
|
63431
|
+
availableColors = new AlternatingColorGenerator(12);
|
|
62511
63432
|
colors = {};
|
|
62512
63433
|
session;
|
|
62513
63434
|
constructor(config) {
|
|
@@ -62518,14 +63439,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62518
63439
|
return (position.row < this.getters.getNumberRows(position.sheetId) &&
|
|
62519
63440
|
position.col < this.getters.getNumberCols(position.sheetId));
|
|
62520
63441
|
}
|
|
62521
|
-
chooseNewColor() {
|
|
62522
|
-
if (this.availableColors.size === 0) {
|
|
62523
|
-
this.availableColors = new Set(colors);
|
|
62524
|
-
}
|
|
62525
|
-
const color = randomChoice([...this.availableColors.values()]);
|
|
62526
|
-
this.availableColors.delete(color);
|
|
62527
|
-
return color;
|
|
62528
|
-
}
|
|
62529
63442
|
getClient() {
|
|
62530
63443
|
return this.session.getClient();
|
|
62531
63444
|
}
|
|
@@ -62560,7 +63473,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62560
63473
|
this.isPositionValid(client.position)) {
|
|
62561
63474
|
const position = client.position;
|
|
62562
63475
|
if (!this.colors[client.id]) {
|
|
62563
|
-
this.colors[client.id] = this.
|
|
63476
|
+
this.colors[client.id] = this.availableColors.next();
|
|
62564
63477
|
}
|
|
62565
63478
|
const color = this.colors[client.id];
|
|
62566
63479
|
clients.push({ ...client, position, color });
|
|
@@ -62797,7 +63710,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62797
63710
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
62798
63711
|
const position = { sheetId, col, row };
|
|
62799
63712
|
const pivotCell = this.getters.getPivotCellFromPosition(position);
|
|
62800
|
-
if (
|
|
63713
|
+
if (this.isSpilledPivotValueFormula(position, pivotCell)) {
|
|
62801
63714
|
measurePositions.push(position);
|
|
62802
63715
|
const pivotId = this.getters.getPivotIdFromPosition(position) || "";
|
|
62803
63716
|
measuresByPivotId[pivotId] ??= new Set();
|
|
@@ -62834,6 +63747,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62834
63747
|
format,
|
|
62835
63748
|
});
|
|
62836
63749
|
}
|
|
63750
|
+
isSpilledPivotValueFormula(position, pivotCell) {
|
|
63751
|
+
const cell = this.getters.getCell(position);
|
|
63752
|
+
return pivotCell.type === "VALUE" && !cell?.isFormula;
|
|
63753
|
+
}
|
|
62837
63754
|
/**
|
|
62838
63755
|
* This function allows to adjust the quantity of decimal places after a decimal
|
|
62839
63756
|
* point on cells containing number value. It does this by changing the cells
|
|
@@ -62884,6 +63801,69 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62884
63801
|
}
|
|
62885
63802
|
}
|
|
62886
63803
|
|
|
63804
|
+
class GeoFeaturePlugin extends UIPlugin {
|
|
63805
|
+
static getters = [
|
|
63806
|
+
"getGeoJsonFeatures",
|
|
63807
|
+
"geoFeatureNameToId",
|
|
63808
|
+
"getGeoChartAvailableRegions",
|
|
63809
|
+
];
|
|
63810
|
+
geoJsonService;
|
|
63811
|
+
geoJsonCache = {};
|
|
63812
|
+
constructor(config) {
|
|
63813
|
+
super(config);
|
|
63814
|
+
this.geoJsonService = config.external.geoJsonService;
|
|
63815
|
+
}
|
|
63816
|
+
getGeoChartAvailableRegions() {
|
|
63817
|
+
if (!this.geoJsonService) {
|
|
63818
|
+
console.error("No geoJsonService provided to the model");
|
|
63819
|
+
return [];
|
|
63820
|
+
}
|
|
63821
|
+
return this.geoJsonService.getAvailableRegions() || [];
|
|
63822
|
+
}
|
|
63823
|
+
getGeoJsonFeatures(region) {
|
|
63824
|
+
if (!this.geoJsonService) {
|
|
63825
|
+
console.error("No geoJsonService provided to the model");
|
|
63826
|
+
return;
|
|
63827
|
+
}
|
|
63828
|
+
const cachedGeoJson = this.geoJsonCache[region];
|
|
63829
|
+
if (cachedGeoJson instanceof Promise) {
|
|
63830
|
+
return undefined;
|
|
63831
|
+
}
|
|
63832
|
+
if (cachedGeoJson !== undefined) {
|
|
63833
|
+
return cachedGeoJson ?? undefined;
|
|
63834
|
+
}
|
|
63835
|
+
this.geoJsonCache[region] = new Promise(async (resolve) => {
|
|
63836
|
+
const json = await this.geoJsonService?.getTopoJson(region);
|
|
63837
|
+
this.geoJsonCache[region] = this.convertToGeoJson(json);
|
|
63838
|
+
this.dispatch("EVALUATE_CHARTS");
|
|
63839
|
+
resolve();
|
|
63840
|
+
});
|
|
63841
|
+
return undefined;
|
|
63842
|
+
}
|
|
63843
|
+
geoFeatureNameToId(region, featureName) {
|
|
63844
|
+
if (!this.geoJsonService) {
|
|
63845
|
+
console.error("No geoJsonService provided to the model");
|
|
63846
|
+
return;
|
|
63847
|
+
}
|
|
63848
|
+
return this.geoJsonService.geoFeatureNameToId(region, featureName);
|
|
63849
|
+
}
|
|
63850
|
+
convertToGeoJson(json) {
|
|
63851
|
+
if (!json) {
|
|
63852
|
+
return null;
|
|
63853
|
+
}
|
|
63854
|
+
// TopoJSON
|
|
63855
|
+
if (json.type === "Topology") {
|
|
63856
|
+
const features = window.ChartGeo.topojson.feature(json, Object.values(json.objects)[0]);
|
|
63857
|
+
return features.type === "FeatureCollection" ? features.features : [features];
|
|
63858
|
+
}
|
|
63859
|
+
// GeoJSON
|
|
63860
|
+
else if (json.type === "FeatureCollection") {
|
|
63861
|
+
return json.features;
|
|
63862
|
+
}
|
|
63863
|
+
throw new Error("Invalid TopoJSON");
|
|
63864
|
+
}
|
|
63865
|
+
}
|
|
63866
|
+
|
|
62887
63867
|
class HeaderVisibilityUIPlugin extends UIPlugin {
|
|
62888
63868
|
static getters = [
|
|
62889
63869
|
"getNextVisibleCellPosition",
|
|
@@ -64421,10 +65401,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
64421
65401
|
case "RESIZE_TABLE": {
|
|
64422
65402
|
const table = this.getters.getCoreTableMatchingTopLeft(cmd.sheetId, cmd.zone);
|
|
64423
65403
|
this.dispatch("UPDATE_TABLE", { ...cmd });
|
|
64424
|
-
if (!table
|
|
65404
|
+
if (!table)
|
|
64425
65405
|
return;
|
|
64426
|
-
const oldTableZone = table.range.zone;
|
|
64427
65406
|
const newTableZone = this.getters.getRangeFromRangeData(cmd.newTableRange).zone;
|
|
65407
|
+
this.selection.selectCell(newTableZone.right, newTableZone.bottom);
|
|
65408
|
+
if (!table.config.automaticAutofill)
|
|
65409
|
+
return;
|
|
65410
|
+
const oldTableZone = table.range.zone;
|
|
64428
65411
|
if (newTableZone.bottom >= oldTableZone.bottom) {
|
|
64429
65412
|
for (let col = newTableZone.left; col <= newTableZone.right; col++) {
|
|
64430
65413
|
const autofillSource = { col, row: oldTableZone.bottom, sheetId: cmd.sheetId };
|
|
@@ -65630,15 +66613,23 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
65630
66613
|
handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
|
|
65631
66614
|
const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
|
|
65632
66615
|
let currentIndex = cmd.base;
|
|
66616
|
+
const resizingGroups = {};
|
|
65633
66617
|
for (const element of toRemove) {
|
|
65634
66618
|
const size = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, element);
|
|
66619
|
+
const currentSize = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, currentIndex);
|
|
66620
|
+
if (size != currentSize) {
|
|
66621
|
+
resizingGroups[size] ??= [];
|
|
66622
|
+
resizingGroups[size].push(currentIndex);
|
|
66623
|
+
currentIndex += 1;
|
|
66624
|
+
}
|
|
66625
|
+
}
|
|
66626
|
+
for (const size in resizingGroups) {
|
|
65635
66627
|
this.dispatch("RESIZE_COLUMNS_ROWS", {
|
|
65636
66628
|
dimension: cmd.dimension,
|
|
65637
66629
|
sheetId: cmd.sheetId,
|
|
65638
|
-
size,
|
|
65639
|
-
elements: [
|
|
66630
|
+
size: parseInt(size, 10),
|
|
66631
|
+
elements: resizingGroups[size],
|
|
65640
66632
|
});
|
|
65641
|
-
currentIndex += 1;
|
|
65642
66633
|
}
|
|
65643
66634
|
this.dispatch("REMOVE_COLUMNS_ROWS", {
|
|
65644
66635
|
dimension: cmd.dimension,
|
|
@@ -66220,6 +67211,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66220
67211
|
break;
|
|
66221
67212
|
case "DELETE_SHEET":
|
|
66222
67213
|
this.cleanViewports();
|
|
67214
|
+
this.sheetsWithDirtyViewports.delete(cmd.sheetId);
|
|
66223
67215
|
break;
|
|
66224
67216
|
case "ACTIVATE_SHEET":
|
|
66225
67217
|
this.sheetsWithDirtyViewports.add(cmd.sheetIdTo);
|
|
@@ -66870,7 +67862,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66870
67862
|
.add("data_cleanup", DataCleanupPlugin)
|
|
66871
67863
|
.add("table_autofill", TableAutofillPlugin)
|
|
66872
67864
|
.add("table_ui_resize", TableResizeUI)
|
|
66873
|
-
.add("datavalidation_insert", DataValidationInsertionPlugin)
|
|
67865
|
+
.add("datavalidation_insert", DataValidationInsertionPlugin)
|
|
67866
|
+
.add("geo_features", GeoFeaturePlugin);
|
|
66874
67867
|
// Plugins which have a state, but which should not be shared in collaborative
|
|
66875
67868
|
const statefulUIPluginRegistry = new Registry()
|
|
66876
67869
|
.add("selection", GridSelectionPlugin)
|
|
@@ -68614,8 +69607,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68614
69607
|
.o-topbar-composer {
|
|
68615
69608
|
height: fit-content;
|
|
68616
69609
|
margin-top: -1px;
|
|
69610
|
+
margin-bottom: -1px;
|
|
68617
69611
|
border: 1px solid;
|
|
68618
|
-
z-index: ${ComponentsImportance.TopBarComposer};
|
|
68619
69612
|
font-family: ${DEFAULT_FONT};
|
|
68620
69613
|
|
|
68621
69614
|
.o-composer:empty:not(:focus):not(.active)::before {
|
|
@@ -68673,6 +69666,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68673
69666
|
}
|
|
68674
69667
|
return cssPropertiesToCss({
|
|
68675
69668
|
"border-color": SELECTION_BORDER_COLOR,
|
|
69669
|
+
"z-index": String(ComponentsImportance.TopBarComposer),
|
|
68676
69670
|
});
|
|
68677
69671
|
}
|
|
68678
69672
|
onFocus(selection) {
|
|
@@ -68781,6 +69775,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68781
69775
|
}
|
|
68782
69776
|
}
|
|
68783
69777
|
|
|
69778
|
+
.irregularity-map {
|
|
69779
|
+
border-top: 1px solid ${SEPARATOR_COLOR};
|
|
69780
|
+
height: ${TOPBAR_TOOLBAR_HEIGHT}px;
|
|
69781
|
+
|
|
69782
|
+
.alert-info {
|
|
69783
|
+
border-left: 3px solid ${ALERT_INFO_BORDER};
|
|
69784
|
+
}
|
|
69785
|
+
}
|
|
69786
|
+
|
|
68784
69787
|
.o-topbar-composer {
|
|
68785
69788
|
flex-grow: 1;
|
|
68786
69789
|
}
|
|
@@ -68874,8 +69877,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68874
69877
|
formatNumberMenuItemSpec = formatNumberMenuItemSpec;
|
|
68875
69878
|
isntToolbarMenu = false;
|
|
68876
69879
|
composerFocusStore;
|
|
69880
|
+
fingerprints;
|
|
68877
69881
|
setup() {
|
|
68878
69882
|
this.composerFocusStore = useStore(ComposerFocusStore);
|
|
69883
|
+
this.fingerprints = useStore(FormulaFingerprintStore);
|
|
68879
69884
|
owl.useExternalListener(window, "click", this.onExternalClick);
|
|
68880
69885
|
owl.onWillStart(() => this.updateCellState());
|
|
68881
69886
|
owl.onWillUpdateProps(() => this.updateCellState());
|
|
@@ -69346,7 +70351,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
69346
70351
|
properties["grid-template-rows"] = `auto`;
|
|
69347
70352
|
}
|
|
69348
70353
|
else {
|
|
69349
|
-
properties["grid-template-rows"] =
|
|
70354
|
+
properties["grid-template-rows"] = `max-content auto ${BOTTOMBAR_HEIGHT + 1}px`;
|
|
69350
70355
|
}
|
|
69351
70356
|
properties["grid-template-columns"] = `auto ${this.sidePanel.panelSize}px`;
|
|
69352
70357
|
return cssPropertiesToCss(properties);
|
|
@@ -70424,9 +71429,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
70424
71429
|
getBackToDefault() {
|
|
70425
71430
|
this.stream.getBackToDefault();
|
|
70426
71431
|
}
|
|
70427
|
-
getAnchor() {
|
|
70428
|
-
return this.anchor;
|
|
70429
|
-
}
|
|
70430
71432
|
modifyAnchor(anchor, mode, options) {
|
|
70431
71433
|
const sheetId = this.getters.getActiveSheetId();
|
|
70432
71434
|
anchor = {
|
|
@@ -73358,6 +74360,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73358
74360
|
session: this.session,
|
|
73359
74361
|
defaultCurrency: this.config.defaultCurrency,
|
|
73360
74362
|
customColors: this.config.customColors || [],
|
|
74363
|
+
external: this.config.external,
|
|
73361
74364
|
};
|
|
73362
74365
|
}
|
|
73363
74366
|
// ---------------------------------------------------------------------------
|
|
@@ -73589,7 +74592,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73589
74592
|
MIN_COL_WIDTH,
|
|
73590
74593
|
HEADER_HEIGHT,
|
|
73591
74594
|
HEADER_WIDTH,
|
|
73592
|
-
TOPBAR_HEIGHT,
|
|
73593
74595
|
BOTTOMBAR_HEIGHT,
|
|
73594
74596
|
DEFAULT_CELL_WIDTH,
|
|
73595
74597
|
DEFAULT_CELL_HEIGHT,
|
|
@@ -73830,9 +74832,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73830
74832
|
exports.tokenize = tokenize;
|
|
73831
74833
|
|
|
73832
74834
|
|
|
73833
|
-
__info__.version = "18.1.0
|
|
73834
|
-
__info__.date = "2024-12-
|
|
73835
|
-
__info__.hash = "
|
|
74835
|
+
__info__.version = "18.1.0";
|
|
74836
|
+
__info__.date = "2024-12-26T06:37:07.879Z";
|
|
74837
|
+
__info__.hash = "c520e89";
|
|
73836
74838
|
|
|
73837
74839
|
|
|
73838
74840
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|