@odoo/o-spreadsheet 18.1.0-alpha.7 → 18.1.0-alpha.8
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 +1313 -315
- package/dist/o-spreadsheet.d.ts +398 -292
- package/dist/o-spreadsheet.esm.js +1313 -315
- package/dist/o-spreadsheet.iife.js +1313 -315
- package/dist/o-spreadsheet.iife.min.js +511 -515
- package/dist/o_spreadsheet.xml +214 -20
- package/package.json +3 -2
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 18.1.0-alpha.
|
|
6
|
-
* @date 2024-12-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.1.0-alpha.8
|
|
6
|
+
* @date 2024-12-19T07:49:54.421Z
|
|
7
|
+
* @hash 87a1567
|
|
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
|
}
|
|
@@ -43644,6 +44518,64 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43644
44518
|
}
|
|
43645
44519
|
}
|
|
43646
44520
|
|
|
44521
|
+
css /* scss */ `
|
|
44522
|
+
.o-pivot-sort {
|
|
44523
|
+
.o-sort-card {
|
|
44524
|
+
width: fit-content;
|
|
44525
|
+
background-color: ${GRAY_100};
|
|
44526
|
+
border: 1px solid ${GRAY_300};
|
|
44527
|
+
|
|
44528
|
+
.o-sort-value {
|
|
44529
|
+
color: ${PRIMARY_BUTTON_BG};
|
|
44530
|
+
}
|
|
44531
|
+
}
|
|
44532
|
+
}
|
|
44533
|
+
`;
|
|
44534
|
+
class PivotSortSection extends owl.Component {
|
|
44535
|
+
static template = "o-spreadsheet-PivotSortSection";
|
|
44536
|
+
static components = {
|
|
44537
|
+
Section,
|
|
44538
|
+
};
|
|
44539
|
+
static props = {
|
|
44540
|
+
definition: Object,
|
|
44541
|
+
pivotId: String,
|
|
44542
|
+
};
|
|
44543
|
+
get hasValidSort() {
|
|
44544
|
+
const pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
44545
|
+
return (!!this.props.definition.sortedColumn &&
|
|
44546
|
+
isSortedColumnValid(this.props.definition.sortedColumn, pivot));
|
|
44547
|
+
}
|
|
44548
|
+
get sortDescription() {
|
|
44549
|
+
const sortOrder = this.props.definition.sortedColumn?.order === "asc" ? _t("ascending") : _t("descending");
|
|
44550
|
+
return _t("Sorted on column (%(ascOrDesc)s):", {
|
|
44551
|
+
ascOrDesc: sortOrder,
|
|
44552
|
+
});
|
|
44553
|
+
}
|
|
44554
|
+
get sortValuesAndFields() {
|
|
44555
|
+
const sortedColumn = this.props.definition.sortedColumn;
|
|
44556
|
+
if (!sortedColumn) {
|
|
44557
|
+
return [];
|
|
44558
|
+
}
|
|
44559
|
+
const pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
44560
|
+
const locale = this.env.model.getters.getLocale();
|
|
44561
|
+
const currentDomain = [];
|
|
44562
|
+
const sortValues = [];
|
|
44563
|
+
for (const domainItem of sortedColumn.domain) {
|
|
44564
|
+
currentDomain.push(domainItem);
|
|
44565
|
+
const { value, format } = pivot.getPivotHeaderValueAndFormat(currentDomain);
|
|
44566
|
+
const label = formatValue(value, { format, locale });
|
|
44567
|
+
const field = pivot.definition.getDimension(domainItem.field);
|
|
44568
|
+
sortValues.push({ field: getFieldDisplayName(field), value: label });
|
|
44569
|
+
}
|
|
44570
|
+
if (sortedColumn.domain.length === 0) {
|
|
44571
|
+
sortValues.push({ value: _t("Total") });
|
|
44572
|
+
}
|
|
44573
|
+
const measureLabel = pivot.getMeasure(sortedColumn.measure).displayName;
|
|
44574
|
+
sortValues.push({ value: measureLabel, field: _t("Measure") });
|
|
44575
|
+
return sortValues;
|
|
44576
|
+
}
|
|
44577
|
+
}
|
|
44578
|
+
|
|
43647
44579
|
css /* scss */ `
|
|
43648
44580
|
.add-calculated-measure {
|
|
43649
44581
|
cursor: pointer;
|
|
@@ -43657,6 +44589,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43657
44589
|
PivotDimensionOrder,
|
|
43658
44590
|
PivotDimensionGranularity,
|
|
43659
44591
|
PivotMeasureEditor,
|
|
44592
|
+
PivotSortSection,
|
|
43660
44593
|
};
|
|
43661
44594
|
static props = {
|
|
43662
44595
|
definition: Object,
|
|
@@ -43813,9 +44746,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43813
44746
|
}
|
|
43814
44747
|
updateMeasure(measure, newMeasure) {
|
|
43815
44748
|
const { measures } = this.props.definition;
|
|
43816
|
-
|
|
44749
|
+
const update = {
|
|
43817
44750
|
measures: measures.map((m) => (m.id === measure.id ? newMeasure : m)),
|
|
43818
|
-
}
|
|
44751
|
+
};
|
|
44752
|
+
if (this.props.definition.sortedColumn?.measure === measure.id) {
|
|
44753
|
+
update.sortedColumn = { ...this.props.definition.sortedColumn, measure: newMeasure.id };
|
|
44754
|
+
}
|
|
44755
|
+
this.props.onDimensionsUpdated(update);
|
|
43819
44756
|
}
|
|
43820
44757
|
getMeasureId(fieldName, aggregator) {
|
|
43821
44758
|
const baseId = fieldName + (aggregator ? `:${aggregator}` : "");
|
|
@@ -43971,10 +44908,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43971
44908
|
measures;
|
|
43972
44909
|
columns;
|
|
43973
44910
|
rows;
|
|
44911
|
+
sortedColumn;
|
|
43974
44912
|
constructor(definition, fields) {
|
|
43975
44913
|
this.measures = definition.measures.map((measure) => createMeasure(fields, measure));
|
|
43976
44914
|
this.columns = definition.columns.map((dimension) => createPivotDimension(fields, dimension));
|
|
43977
44915
|
this.rows = definition.rows.map((dimension) => createPivotDimension(fields, dimension));
|
|
44916
|
+
this.sortedColumn = definition.sortedColumn;
|
|
43978
44917
|
}
|
|
43979
44918
|
getDimension(nameWithGranularity) {
|
|
43980
44919
|
const dimension = this.columns.find((d) => d.nameWithGranularity === nameWithGranularity) ||
|
|
@@ -44128,6 +45067,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44128
45067
|
pivotCells = {};
|
|
44129
45068
|
rowTree;
|
|
44130
45069
|
colTree;
|
|
45070
|
+
isSorted = false;
|
|
44131
45071
|
constructor(columns, rows, measures, fieldsType) {
|
|
44132
45072
|
this.columns = columns.map((row) => {
|
|
44133
45073
|
// offset in the pivot table
|
|
@@ -44301,6 +45241,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44301
45241
|
value,
|
|
44302
45242
|
field: row.fields[rowDepth],
|
|
44303
45243
|
children: [],
|
|
45244
|
+
type: this.fieldsType[fieldName] || "char",
|
|
44304
45245
|
width: 0, // not used
|
|
44305
45246
|
};
|
|
44306
45247
|
treesAtDepth[depth].push(node);
|
|
@@ -44323,6 +45264,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44323
45264
|
field: leaf.fields[depth],
|
|
44324
45265
|
children: [],
|
|
44325
45266
|
width: leaf.width,
|
|
45267
|
+
type: this.fieldsType[fieldName] || "char",
|
|
44326
45268
|
};
|
|
44327
45269
|
if (treesAtDepth[depth]?.at(-1)?.value !== value) {
|
|
44328
45270
|
treesAtDepth[depth + 1] = [];
|
|
@@ -44341,6 +45283,35 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44341
45283
|
fieldsType: this.fieldsType,
|
|
44342
45284
|
};
|
|
44343
45285
|
}
|
|
45286
|
+
sort(measure, sortedColumn, getValue) {
|
|
45287
|
+
if (this.isSorted) {
|
|
45288
|
+
return;
|
|
45289
|
+
}
|
|
45290
|
+
const getSortValue = (measure, domain) => {
|
|
45291
|
+
const rawValue = getValue(measure, domain).value;
|
|
45292
|
+
return typeof rawValue === "number" ? rawValue : -Infinity;
|
|
45293
|
+
};
|
|
45294
|
+
const sortColDomain = sortedColumn.domain;
|
|
45295
|
+
const sortFn = (rowDomain1, rowDomain2) => {
|
|
45296
|
+
const value1 = getSortValue(measure, [...rowDomain1, ...sortColDomain]);
|
|
45297
|
+
const value2 = getSortValue(measure, [...rowDomain2, ...sortColDomain]);
|
|
45298
|
+
return sortedColumn.order === "asc" ? value1 - value2 : value2 - value1;
|
|
45299
|
+
};
|
|
45300
|
+
const sortedRowTree = sortPivotTree(this.rowTree(), [], sortFn);
|
|
45301
|
+
this.rowTree = lazy(sortedRowTree);
|
|
45302
|
+
this.rows = [...this.rowTreeToRows(sortedRowTree), this.rows[this.rows.length - 1]];
|
|
45303
|
+
this.isSorted = true;
|
|
45304
|
+
}
|
|
45305
|
+
rowTreeToRows(tree, parentRow) {
|
|
45306
|
+
return tree.flatMap((node) => {
|
|
45307
|
+
const row = {
|
|
45308
|
+
indent: parentRow ? parentRow.indent + 1 : 0,
|
|
45309
|
+
fields: [...(parentRow?.fields || []), node.field],
|
|
45310
|
+
values: [...(parentRow?.values || []), node.value],
|
|
45311
|
+
};
|
|
45312
|
+
return [row, ...this.rowTreeToRows(node.children, row)];
|
|
45313
|
+
});
|
|
45314
|
+
}
|
|
44344
45315
|
}
|
|
44345
45316
|
const EMPTY_PIVOT_CELL = { type: "EMPTY" };
|
|
44346
45317
|
|
|
@@ -44418,6 +45389,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44418
45389
|
value: groups[key]?.[0]?.[column.nameWithGranularity]?.value ?? null,
|
|
44419
45390
|
field: colName,
|
|
44420
45391
|
children: dataEntriesToColumnsTree(groups[key] || [], columns, index + 1),
|
|
45392
|
+
type: column.type,
|
|
44421
45393
|
width: 0,
|
|
44422
45394
|
};
|
|
44423
45395
|
});
|
|
@@ -45283,6 +46255,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45283
46255
|
format: measure.format,
|
|
45284
46256
|
display: measure.display,
|
|
45285
46257
|
})),
|
|
46258
|
+
sortedColumn: this.shouldKeepSortedColumn(definition) ? definition.sortedColumn : undefined,
|
|
45286
46259
|
};
|
|
45287
46260
|
if (!this.draft && deepEquals(coreDefinition, cleanedDefinition)) {
|
|
45288
46261
|
return;
|
|
@@ -45341,6 +46314,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45341
46314
|
}
|
|
45342
46315
|
return granularitiesPerFields;
|
|
45343
46316
|
}
|
|
46317
|
+
/**
|
|
46318
|
+
* Check if we want to keep the sorted column when updating the pivot definition. We should remove it if either
|
|
46319
|
+
* the measure is not in the new definition or the columns have changed.
|
|
46320
|
+
*/
|
|
46321
|
+
shouldKeepSortedColumn(newDefinition) {
|
|
46322
|
+
const { sortedColumn } = newDefinition;
|
|
46323
|
+
if (!sortedColumn) {
|
|
46324
|
+
return true;
|
|
46325
|
+
}
|
|
46326
|
+
const oldDefinition = this.getters.getPivotCoreDefinition(this.pivotId);
|
|
46327
|
+
return (newDefinition.measures.find((measure) => measure.id === sortedColumn.measure) &&
|
|
46328
|
+
deepEquals(oldDefinition.columns, newDefinition.columns));
|
|
46329
|
+
}
|
|
45344
46330
|
}
|
|
45345
46331
|
|
|
45346
46332
|
class PivotSpreadsheetSidePanel extends owl.Component {
|
|
@@ -46442,6 +47428,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46442
47428
|
}
|
|
46443
47429
|
}
|
|
46444
47430
|
`;
|
|
47431
|
+
const DEFAULT_TABLE_STYLE_COLOR = "#3C78D8";
|
|
46445
47432
|
class TableStyleEditorPanel extends owl.Component {
|
|
46446
47433
|
static template = "o-spreadsheet-TableStyleEditorPanel";
|
|
46447
47434
|
static components = { Section, RoundColorPicker, TableStylePreview };
|
|
@@ -46460,7 +47447,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46460
47447
|
: null;
|
|
46461
47448
|
return {
|
|
46462
47449
|
pickerOpened: false,
|
|
46463
|
-
primaryColor: editedStyle?.primaryColor ||
|
|
47450
|
+
primaryColor: editedStyle?.primaryColor || DEFAULT_TABLE_STYLE_COLOR,
|
|
46464
47451
|
selectedTemplateName: editedStyle?.templateName || "lightColoredText",
|
|
46465
47452
|
styleName: editedStyle?.displayName || this.env.model.getters.getNewCustomTableStyleName(),
|
|
46466
47453
|
};
|
|
@@ -46469,7 +47456,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46469
47456
|
this.state.pickerOpened = !this.state.pickerOpened;
|
|
46470
47457
|
}
|
|
46471
47458
|
onColorPicked(color) {
|
|
46472
|
-
this.state.primaryColor = color;
|
|
47459
|
+
this.state.primaryColor = isColorValid(color) ? color : DEFAULT_TABLE_STYLE_COLOR;
|
|
46473
47460
|
this.state.pickerOpened = false;
|
|
46474
47461
|
}
|
|
46475
47462
|
onTemplatePicked(templateName) {
|
|
@@ -48085,6 +49072,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48085
49072
|
draggedFigure: undefined,
|
|
48086
49073
|
horizontalSnap: undefined,
|
|
48087
49074
|
verticalSnap: undefined,
|
|
49075
|
+
cancelDnd: undefined,
|
|
48088
49076
|
});
|
|
48089
49077
|
setup() {
|
|
48090
49078
|
owl.onMounted(() => {
|
|
@@ -48097,12 +49085,28 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48097
49085
|
// new rendering
|
|
48098
49086
|
this.render();
|
|
48099
49087
|
});
|
|
49088
|
+
owl.onWillUpdateProps(() => {
|
|
49089
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
49090
|
+
const draggedFigureId = this.dnd.draggedFigure?.id;
|
|
49091
|
+
if (draggedFigureId && !this.env.model.getters.getFigure(sheetId, draggedFigureId)) {
|
|
49092
|
+
if (this.dnd.cancelDnd) {
|
|
49093
|
+
this.dnd.cancelDnd();
|
|
49094
|
+
}
|
|
49095
|
+
this.dnd.draggedFigure = undefined;
|
|
49096
|
+
this.dnd.horizontalSnap = undefined;
|
|
49097
|
+
this.dnd.verticalSnap = undefined;
|
|
49098
|
+
this.dnd.cancelDnd = undefined;
|
|
49099
|
+
}
|
|
49100
|
+
});
|
|
48100
49101
|
}
|
|
48101
49102
|
getVisibleFigures() {
|
|
48102
49103
|
const visibleFigures = this.env.model.getters.getVisibleFigures();
|
|
48103
49104
|
if (this.dnd.draggedFigure &&
|
|
48104
49105
|
!visibleFigures.some((figure) => figure.id === this.dnd.draggedFigure?.id)) {
|
|
48105
|
-
|
|
49106
|
+
const draggedFigure = this.env.model.getters.getFigure(this.env.model.getters.getActiveSheetId(), this.dnd.draggedFigure?.id);
|
|
49107
|
+
if (draggedFigure) {
|
|
49108
|
+
visibleFigures.push(draggedFigure);
|
|
49109
|
+
}
|
|
48106
49110
|
}
|
|
48107
49111
|
return visibleFigures;
|
|
48108
49112
|
}
|
|
@@ -48221,7 +49225,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48221
49225
|
this.dnd.verticalSnap = undefined;
|
|
48222
49226
|
this.env.model.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x, y });
|
|
48223
49227
|
};
|
|
48224
|
-
startDnd(onMouseMove, onMouseUp);
|
|
49228
|
+
this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
|
|
48225
49229
|
}
|
|
48226
49230
|
/**
|
|
48227
49231
|
* Initialize the resize of a figure with mouse movements
|
|
@@ -48269,7 +49273,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48269
49273
|
this.dnd.horizontalSnap = undefined;
|
|
48270
49274
|
this.dnd.verticalSnap = undefined;
|
|
48271
49275
|
};
|
|
48272
|
-
startDnd(onMouseMove, onMouseUp);
|
|
49276
|
+
this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
|
|
48273
49277
|
}
|
|
48274
49278
|
getOtherFigures(figId) {
|
|
48275
49279
|
return this.getVisibleFigures().filter((f) => f.id !== figId);
|
|
@@ -49376,9 +50380,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49376
50380
|
class GridRenderer {
|
|
49377
50381
|
getters;
|
|
49378
50382
|
renderer;
|
|
50383
|
+
fingerprints;
|
|
49379
50384
|
constructor(get) {
|
|
49380
50385
|
this.getters = get(ModelStore).getters;
|
|
49381
50386
|
this.renderer = get(RendererStore);
|
|
50387
|
+
this.fingerprints = get(FormulaFingerprintStore);
|
|
49382
50388
|
this.renderer.register(this);
|
|
49383
50389
|
}
|
|
49384
50390
|
get renderingLayers() {
|
|
@@ -49856,14 +50862,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49856
50862
|
const showFormula = this.getters.shouldShowFormulas();
|
|
49857
50863
|
const { x, y, width, height } = this.getters.getVisibleRect(zone);
|
|
49858
50864
|
const { verticalAlign } = this.getters.getCellStyle(position);
|
|
50865
|
+
let style = this.getters.getCellComputedStyle(position);
|
|
50866
|
+
if (this.fingerprints.isEnabled) {
|
|
50867
|
+
const fingerprintColor = this.fingerprints.colors.get(position);
|
|
50868
|
+
style = { ...style, fillColor: fingerprintColor };
|
|
50869
|
+
}
|
|
50870
|
+
const dataBarFill = this.fingerprints.isEnabled
|
|
50871
|
+
? undefined
|
|
50872
|
+
: this.getters.getConditionalDataBar(position);
|
|
49859
50873
|
const box = {
|
|
49860
50874
|
x,
|
|
49861
50875
|
y,
|
|
49862
50876
|
width,
|
|
49863
50877
|
height,
|
|
49864
50878
|
border: this.getters.getCellComputedBorder(position) || undefined,
|
|
49865
|
-
style
|
|
49866
|
-
dataBarFill
|
|
50879
|
+
style,
|
|
50880
|
+
dataBarFill,
|
|
49867
50881
|
verticalAlign,
|
|
49868
50882
|
isError: (cell.type === CellValueType.error && !!cell.message) ||
|
|
49869
50883
|
this.getters.isDataValidationInvalid(position),
|
|
@@ -49888,7 +50902,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49888
50902
|
box.hasIcon = this.getters.doesCellHaveGridIcon(position);
|
|
49889
50903
|
const headerIconWidth = box.hasIcon ? GRID_ICON_EDGE_LENGTH + GRID_ICON_MARGIN : 0;
|
|
49890
50904
|
/** Content */
|
|
49891
|
-
const style = this.getters.getCellComputedStyle(position);
|
|
49892
50905
|
const wrapping = style.wrapping || "overflow";
|
|
49893
50906
|
const wrapText = wrapping === "wrap" && !showFormula;
|
|
49894
50907
|
const maxWidth = width - 2 * MIN_CELL_TEXT_MARGIN;
|
|
@@ -51866,62 +52879,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51866
52879
|
}
|
|
51867
52880
|
}
|
|
51868
52881
|
|
|
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
52882
|
/**
|
|
51926
52883
|
* Core Plugin
|
|
51927
52884
|
*
|
|
@@ -52360,7 +53317,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52360
53317
|
const before = this.getters.getCell({ sheetId, col, row });
|
|
52361
53318
|
const hasContent = "content" in after || "formula" in after;
|
|
52362
53319
|
// Compute the new cell properties
|
|
52363
|
-
const afterContent = hasContent ?
|
|
53320
|
+
const afterContent = hasContent ? replaceNewLines(after?.content) : before?.content || "";
|
|
52364
53321
|
let style;
|
|
52365
53322
|
if (after.style !== undefined) {
|
|
52366
53323
|
style = after.style || undefined;
|
|
@@ -55305,6 +56262,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55305
56262
|
};
|
|
55306
56263
|
}
|
|
55307
56264
|
getUnboundedZone(sheetId, zone) {
|
|
56265
|
+
if (zone.bottom === undefined || zone.right === undefined) {
|
|
56266
|
+
return zone;
|
|
56267
|
+
}
|
|
55308
56268
|
const isFullRow = zone.left === 0 && zone.right === this.getNumberCols(sheetId) - 1;
|
|
55309
56269
|
const isFullCol = zone.top === 0 && zone.bottom === this.getNumberRows(sheetId) - 1;
|
|
55310
56270
|
return {
|
|
@@ -59588,66 +60548,25 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
59588
60548
|
return;
|
|
59589
60549
|
}
|
|
59590
60550
|
const zone = this.getters.getRangeFromSheetXC(sheetId, range).zone;
|
|
59591
|
-
const
|
|
60551
|
+
const colorThresholds = [{ value: minValue, color: rule.minimum.color }];
|
|
59592
60552
|
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
|
-
});
|
|
60553
|
+
colorThresholds.push({ value: midValue, color: rule.midpoint.color });
|
|
59610
60554
|
}
|
|
60555
|
+
colorThresholds.push({ value: maxValue, color: rule.maximum.color });
|
|
60556
|
+
const colorScale = getColorScale(colorThresholds);
|
|
59611
60557
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
59612
60558
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
59613
60559
|
const cell = this.getters.getEvaluatedCell({ sheetId, col, row });
|
|
59614
60560
|
if (cell.type === CellValueType.number) {
|
|
59615
60561
|
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
60562
|
if (!computedStyle[col])
|
|
59627
60563
|
computedStyle[col] = [];
|
|
59628
60564
|
computedStyle[col][row] = computedStyle[col]?.[row] || {};
|
|
59629
|
-
computedStyle[col][row].fillColor =
|
|
60565
|
+
computedStyle[col][row].fillColor = colorScale(value);
|
|
59630
60566
|
}
|
|
59631
60567
|
}
|
|
59632
60568
|
}
|
|
59633
60569
|
}
|
|
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
60570
|
/**
|
|
59652
60571
|
* Execute the predicate to know if a conditional formatting rule should be applied to a cell
|
|
59653
60572
|
*/
|
|
@@ -60273,7 +61192,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60273
61192
|
}
|
|
60274
61193
|
getValuesToAggregate(measure, domain) {
|
|
60275
61194
|
const { rowDomain, colDomain } = domainToColRowDomain(this, domain);
|
|
60276
|
-
const table =
|
|
61195
|
+
const table = super.getTableStructure();
|
|
60277
61196
|
const values = [];
|
|
60278
61197
|
if (colDomain.length === 0 &&
|
|
60279
61198
|
rowDomain.length < this.definition.rows.length &&
|
|
@@ -60707,6 +61626,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60707
61626
|
}
|
|
60708
61627
|
throw new Error(`Value ${result.value} is not a number`);
|
|
60709
61628
|
}
|
|
61629
|
+
getTableStructure() {
|
|
61630
|
+
const table = super.getTableStructure();
|
|
61631
|
+
this.sortTableStructure(table);
|
|
61632
|
+
return table;
|
|
61633
|
+
}
|
|
61634
|
+
sortTableStructure(table) {
|
|
61635
|
+
if (!this.definition.sortedColumn || table.isSorted) {
|
|
61636
|
+
return;
|
|
61637
|
+
}
|
|
61638
|
+
const measure = this.definition.sortedColumn.measure;
|
|
61639
|
+
const isSortValid = isSortedColumnValid(this.definition.sortedColumn, this);
|
|
61640
|
+
if (isSortValid) {
|
|
61641
|
+
table.sort(measure, this.definition.sortedColumn, (measure, domain) => this._getPivotCellValueAndFormat(measure, domain));
|
|
61642
|
+
}
|
|
61643
|
+
}
|
|
60710
61644
|
}
|
|
60711
61645
|
return PivotPresentationLayer;
|
|
60712
61646
|
}
|
|
@@ -62482,23 +63416,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62482
63416
|
}
|
|
62483
63417
|
}
|
|
62484
63418
|
|
|
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
63419
|
class CollaborativePlugin extends UIPlugin {
|
|
62503
63420
|
static getters = [
|
|
62504
63421
|
"getClientsToDisplay",
|
|
@@ -62507,7 +63424,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62507
63424
|
"isFullySynchronized",
|
|
62508
63425
|
];
|
|
62509
63426
|
static layers = ["Selection"];
|
|
62510
|
-
availableColors = new
|
|
63427
|
+
availableColors = new AlternatingColorGenerator(12);
|
|
62511
63428
|
colors = {};
|
|
62512
63429
|
session;
|
|
62513
63430
|
constructor(config) {
|
|
@@ -62518,14 +63435,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62518
63435
|
return (position.row < this.getters.getNumberRows(position.sheetId) &&
|
|
62519
63436
|
position.col < this.getters.getNumberCols(position.sheetId));
|
|
62520
63437
|
}
|
|
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
63438
|
getClient() {
|
|
62530
63439
|
return this.session.getClient();
|
|
62531
63440
|
}
|
|
@@ -62560,7 +63469,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62560
63469
|
this.isPositionValid(client.position)) {
|
|
62561
63470
|
const position = client.position;
|
|
62562
63471
|
if (!this.colors[client.id]) {
|
|
62563
|
-
this.colors[client.id] = this.
|
|
63472
|
+
this.colors[client.id] = this.availableColors.next();
|
|
62564
63473
|
}
|
|
62565
63474
|
const color = this.colors[client.id];
|
|
62566
63475
|
clients.push({ ...client, position, color });
|
|
@@ -62797,7 +63706,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62797
63706
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
62798
63707
|
const position = { sheetId, col, row };
|
|
62799
63708
|
const pivotCell = this.getters.getPivotCellFromPosition(position);
|
|
62800
|
-
if (
|
|
63709
|
+
if (this.isSpilledPivotValueFormula(position, pivotCell)) {
|
|
62801
63710
|
measurePositions.push(position);
|
|
62802
63711
|
const pivotId = this.getters.getPivotIdFromPosition(position) || "";
|
|
62803
63712
|
measuresByPivotId[pivotId] ??= new Set();
|
|
@@ -62834,6 +63743,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62834
63743
|
format,
|
|
62835
63744
|
});
|
|
62836
63745
|
}
|
|
63746
|
+
isSpilledPivotValueFormula(position, pivotCell) {
|
|
63747
|
+
const cell = this.getters.getCell(position);
|
|
63748
|
+
return pivotCell.type === "VALUE" && !cell?.isFormula;
|
|
63749
|
+
}
|
|
62837
63750
|
/**
|
|
62838
63751
|
* This function allows to adjust the quantity of decimal places after a decimal
|
|
62839
63752
|
* point on cells containing number value. It does this by changing the cells
|
|
@@ -62884,6 +63797,69 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62884
63797
|
}
|
|
62885
63798
|
}
|
|
62886
63799
|
|
|
63800
|
+
class GeoFeaturePlugin extends UIPlugin {
|
|
63801
|
+
static getters = [
|
|
63802
|
+
"getGeoJsonFeatures",
|
|
63803
|
+
"geoFeatureNameToId",
|
|
63804
|
+
"getGeoChartAvailableRegions",
|
|
63805
|
+
];
|
|
63806
|
+
geoJsonService;
|
|
63807
|
+
geoJsonCache = {};
|
|
63808
|
+
constructor(config) {
|
|
63809
|
+
super(config);
|
|
63810
|
+
this.geoJsonService = config.external.geoJsonService;
|
|
63811
|
+
}
|
|
63812
|
+
getGeoChartAvailableRegions() {
|
|
63813
|
+
if (!this.geoJsonService) {
|
|
63814
|
+
console.error("No geoJsonService provided to the model");
|
|
63815
|
+
return [];
|
|
63816
|
+
}
|
|
63817
|
+
return this.geoJsonService.getAvailableRegions() || [];
|
|
63818
|
+
}
|
|
63819
|
+
getGeoJsonFeatures(region) {
|
|
63820
|
+
if (!this.geoJsonService) {
|
|
63821
|
+
console.error("No geoJsonService provided to the model");
|
|
63822
|
+
return;
|
|
63823
|
+
}
|
|
63824
|
+
const cachedGeoJson = this.geoJsonCache[region];
|
|
63825
|
+
if (cachedGeoJson instanceof Promise) {
|
|
63826
|
+
return undefined;
|
|
63827
|
+
}
|
|
63828
|
+
if (cachedGeoJson !== undefined) {
|
|
63829
|
+
return cachedGeoJson ?? undefined;
|
|
63830
|
+
}
|
|
63831
|
+
this.geoJsonCache[region] = new Promise(async (resolve) => {
|
|
63832
|
+
const json = await this.geoJsonService?.getTopoJson(region);
|
|
63833
|
+
this.geoJsonCache[region] = this.convertToGeoJson(json);
|
|
63834
|
+
this.dispatch("EVALUATE_CHARTS");
|
|
63835
|
+
resolve();
|
|
63836
|
+
});
|
|
63837
|
+
return undefined;
|
|
63838
|
+
}
|
|
63839
|
+
geoFeatureNameToId(region, featureName) {
|
|
63840
|
+
if (!this.geoJsonService) {
|
|
63841
|
+
console.error("No geoJsonService provided to the model");
|
|
63842
|
+
return;
|
|
63843
|
+
}
|
|
63844
|
+
return this.geoJsonService.geoFeatureNameToId(region, featureName);
|
|
63845
|
+
}
|
|
63846
|
+
convertToGeoJson(json) {
|
|
63847
|
+
if (!json) {
|
|
63848
|
+
return null;
|
|
63849
|
+
}
|
|
63850
|
+
// TopoJSON
|
|
63851
|
+
if (json.type === "Topology") {
|
|
63852
|
+
const features = window.ChartGeo.topojson.feature(json, Object.values(json.objects)[0]);
|
|
63853
|
+
return features.type === "FeatureCollection" ? features.features : [features];
|
|
63854
|
+
}
|
|
63855
|
+
// GeoJSON
|
|
63856
|
+
else if (json.type === "FeatureCollection") {
|
|
63857
|
+
return json.features;
|
|
63858
|
+
}
|
|
63859
|
+
throw new Error("Invalid TopoJSON");
|
|
63860
|
+
}
|
|
63861
|
+
}
|
|
63862
|
+
|
|
62887
63863
|
class HeaderVisibilityUIPlugin extends UIPlugin {
|
|
62888
63864
|
static getters = [
|
|
62889
63865
|
"getNextVisibleCellPosition",
|
|
@@ -64421,10 +65397,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
64421
65397
|
case "RESIZE_TABLE": {
|
|
64422
65398
|
const table = this.getters.getCoreTableMatchingTopLeft(cmd.sheetId, cmd.zone);
|
|
64423
65399
|
this.dispatch("UPDATE_TABLE", { ...cmd });
|
|
64424
|
-
if (!table
|
|
65400
|
+
if (!table)
|
|
64425
65401
|
return;
|
|
64426
|
-
const oldTableZone = table.range.zone;
|
|
64427
65402
|
const newTableZone = this.getters.getRangeFromRangeData(cmd.newTableRange).zone;
|
|
65403
|
+
this.selection.selectCell(newTableZone.right, newTableZone.bottom);
|
|
65404
|
+
if (!table.config.automaticAutofill)
|
|
65405
|
+
return;
|
|
65406
|
+
const oldTableZone = table.range.zone;
|
|
64428
65407
|
if (newTableZone.bottom >= oldTableZone.bottom) {
|
|
64429
65408
|
for (let col = newTableZone.left; col <= newTableZone.right; col++) {
|
|
64430
65409
|
const autofillSource = { col, row: oldTableZone.bottom, sheetId: cmd.sheetId };
|
|
@@ -65630,15 +66609,23 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
65630
66609
|
handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
|
|
65631
66610
|
const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
|
|
65632
66611
|
let currentIndex = cmd.base;
|
|
66612
|
+
const resizingGroups = {};
|
|
65633
66613
|
for (const element of toRemove) {
|
|
65634
66614
|
const size = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, element);
|
|
66615
|
+
const currentSize = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, currentIndex);
|
|
66616
|
+
if (size != currentSize) {
|
|
66617
|
+
resizingGroups[size] ??= [];
|
|
66618
|
+
resizingGroups[size].push(currentIndex);
|
|
66619
|
+
currentIndex += 1;
|
|
66620
|
+
}
|
|
66621
|
+
}
|
|
66622
|
+
for (const size in resizingGroups) {
|
|
65635
66623
|
this.dispatch("RESIZE_COLUMNS_ROWS", {
|
|
65636
66624
|
dimension: cmd.dimension,
|
|
65637
66625
|
sheetId: cmd.sheetId,
|
|
65638
|
-
size,
|
|
65639
|
-
elements: [
|
|
66626
|
+
size: parseInt(size, 10),
|
|
66627
|
+
elements: resizingGroups[size],
|
|
65640
66628
|
});
|
|
65641
|
-
currentIndex += 1;
|
|
65642
66629
|
}
|
|
65643
66630
|
this.dispatch("REMOVE_COLUMNS_ROWS", {
|
|
65644
66631
|
dimension: cmd.dimension,
|
|
@@ -66220,6 +67207,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66220
67207
|
break;
|
|
66221
67208
|
case "DELETE_SHEET":
|
|
66222
67209
|
this.cleanViewports();
|
|
67210
|
+
this.sheetsWithDirtyViewports.delete(cmd.sheetId);
|
|
66223
67211
|
break;
|
|
66224
67212
|
case "ACTIVATE_SHEET":
|
|
66225
67213
|
this.sheetsWithDirtyViewports.add(cmd.sheetIdTo);
|
|
@@ -66870,7 +67858,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66870
67858
|
.add("data_cleanup", DataCleanupPlugin)
|
|
66871
67859
|
.add("table_autofill", TableAutofillPlugin)
|
|
66872
67860
|
.add("table_ui_resize", TableResizeUI)
|
|
66873
|
-
.add("datavalidation_insert", DataValidationInsertionPlugin)
|
|
67861
|
+
.add("datavalidation_insert", DataValidationInsertionPlugin)
|
|
67862
|
+
.add("geo_features", GeoFeaturePlugin);
|
|
66874
67863
|
// Plugins which have a state, but which should not be shared in collaborative
|
|
66875
67864
|
const statefulUIPluginRegistry = new Registry()
|
|
66876
67865
|
.add("selection", GridSelectionPlugin)
|
|
@@ -68614,8 +69603,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68614
69603
|
.o-topbar-composer {
|
|
68615
69604
|
height: fit-content;
|
|
68616
69605
|
margin-top: -1px;
|
|
69606
|
+
margin-bottom: -1px;
|
|
68617
69607
|
border: 1px solid;
|
|
68618
|
-
z-index: ${ComponentsImportance.TopBarComposer};
|
|
68619
69608
|
font-family: ${DEFAULT_FONT};
|
|
68620
69609
|
|
|
68621
69610
|
.o-composer:empty:not(:focus):not(.active)::before {
|
|
@@ -68673,6 +69662,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68673
69662
|
}
|
|
68674
69663
|
return cssPropertiesToCss({
|
|
68675
69664
|
"border-color": SELECTION_BORDER_COLOR,
|
|
69665
|
+
"z-index": String(ComponentsImportance.TopBarComposer),
|
|
68676
69666
|
});
|
|
68677
69667
|
}
|
|
68678
69668
|
onFocus(selection) {
|
|
@@ -68781,6 +69771,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68781
69771
|
}
|
|
68782
69772
|
}
|
|
68783
69773
|
|
|
69774
|
+
.irregularity-map {
|
|
69775
|
+
border-top: 1px solid ${SEPARATOR_COLOR};
|
|
69776
|
+
height: ${TOPBAR_TOOLBAR_HEIGHT}px;
|
|
69777
|
+
|
|
69778
|
+
.alert-info {
|
|
69779
|
+
border-left: 3px solid ${ALERT_INFO_BORDER};
|
|
69780
|
+
}
|
|
69781
|
+
}
|
|
69782
|
+
|
|
68784
69783
|
.o-topbar-composer {
|
|
68785
69784
|
flex-grow: 1;
|
|
68786
69785
|
}
|
|
@@ -68874,8 +69873,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68874
69873
|
formatNumberMenuItemSpec = formatNumberMenuItemSpec;
|
|
68875
69874
|
isntToolbarMenu = false;
|
|
68876
69875
|
composerFocusStore;
|
|
69876
|
+
fingerprints;
|
|
68877
69877
|
setup() {
|
|
68878
69878
|
this.composerFocusStore = useStore(ComposerFocusStore);
|
|
69879
|
+
this.fingerprints = useStore(FormulaFingerprintStore);
|
|
68879
69880
|
owl.useExternalListener(window, "click", this.onExternalClick);
|
|
68880
69881
|
owl.onWillStart(() => this.updateCellState());
|
|
68881
69882
|
owl.onWillUpdateProps(() => this.updateCellState());
|
|
@@ -69346,7 +70347,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
69346
70347
|
properties["grid-template-rows"] = `auto`;
|
|
69347
70348
|
}
|
|
69348
70349
|
else {
|
|
69349
|
-
properties["grid-template-rows"] =
|
|
70350
|
+
properties["grid-template-rows"] = `max-content auto ${BOTTOMBAR_HEIGHT + 1}px`;
|
|
69350
70351
|
}
|
|
69351
70352
|
properties["grid-template-columns"] = `auto ${this.sidePanel.panelSize}px`;
|
|
69352
70353
|
return cssPropertiesToCss(properties);
|
|
@@ -70424,9 +71425,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
70424
71425
|
getBackToDefault() {
|
|
70425
71426
|
this.stream.getBackToDefault();
|
|
70426
71427
|
}
|
|
70427
|
-
getAnchor() {
|
|
70428
|
-
return this.anchor;
|
|
70429
|
-
}
|
|
70430
71428
|
modifyAnchor(anchor, mode, options) {
|
|
70431
71429
|
const sheetId = this.getters.getActiveSheetId();
|
|
70432
71430
|
anchor = {
|
|
@@ -73358,6 +74356,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73358
74356
|
session: this.session,
|
|
73359
74357
|
defaultCurrency: this.config.defaultCurrency,
|
|
73360
74358
|
customColors: this.config.customColors || [],
|
|
74359
|
+
external: this.config.external,
|
|
73361
74360
|
};
|
|
73362
74361
|
}
|
|
73363
74362
|
// ---------------------------------------------------------------------------
|
|
@@ -73589,7 +74588,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73589
74588
|
MIN_COL_WIDTH,
|
|
73590
74589
|
HEADER_HEIGHT,
|
|
73591
74590
|
HEADER_WIDTH,
|
|
73592
|
-
TOPBAR_HEIGHT,
|
|
73593
74591
|
BOTTOMBAR_HEIGHT,
|
|
73594
74592
|
DEFAULT_CELL_WIDTH,
|
|
73595
74593
|
DEFAULT_CELL_HEIGHT,
|
|
@@ -73830,9 +74828,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73830
74828
|
exports.tokenize = tokenize;
|
|
73831
74829
|
|
|
73832
74830
|
|
|
73833
|
-
__info__.version = "18.1.0-alpha.
|
|
73834
|
-
__info__.date = "2024-12-
|
|
73835
|
-
__info__.hash = "
|
|
74831
|
+
__info__.version = "18.1.0-alpha.8";
|
|
74832
|
+
__info__.date = "2024-12-19T07:49:54.421Z";
|
|
74833
|
+
__info__.hash = "87a1567";
|
|
73836
74834
|
|
|
73837
74835
|
|
|
73838
74836
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|