@odoo/o-spreadsheet 18.1.0-alpha.6 → 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 +1606 -556
- package/dist/o-spreadsheet.d.ts +424 -302
- package/dist/o-spreadsheet.esm.js +1606 -556
- package/dist/o-spreadsheet.iife.js +1606 -556
- package/dist/o-spreadsheet.iife.min.js +512 -516
- package/dist/o_spreadsheet.xml +239 -36
- 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-
|
|
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) {
|
|
@@ -171,10 +171,13 @@
|
|
|
171
171
|
const ALERT_INFO_BORDER = "#98DBE2";
|
|
172
172
|
const ALERT_INFO_TEXT_COLOR = "#09414A";
|
|
173
173
|
const BADGE_SELECTED_COLOR = "#E6F2F3";
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
const
|
|
174
|
+
const CHART_PADDING$1 = 20;
|
|
175
|
+
const CHART_PADDING_BOTTOM = 10;
|
|
176
|
+
const CHART_PADDING_TOP = 15;
|
|
177
|
+
const CHART_TITLE_FONT_SIZE = 16;
|
|
178
|
+
const CHART_AXIS_TITLE_FONT_SIZE = 12;
|
|
179
|
+
const SCORECARD_CHART_TITLE_FONT_SIZE = 14;
|
|
180
|
+
const PIVOT_TOKEN_COLOR = "#F28C28";
|
|
178
181
|
// Color picker defaults as upper case HEX to match `toHex`helper
|
|
179
182
|
const COLOR_PICKER_DEFAULTS = [
|
|
180
183
|
"#000000",
|
|
@@ -263,7 +266,6 @@
|
|
|
263
266
|
const MIN_COL_WIDTH = 5;
|
|
264
267
|
const HEADER_HEIGHT = 26;
|
|
265
268
|
const HEADER_WIDTH = 48;
|
|
266
|
-
const TOPBAR_HEIGHT = 63;
|
|
267
269
|
const TOPBAR_TOOLBAR_HEIGHT = 34;
|
|
268
270
|
const BOTTOMBAR_HEIGHT = 36;
|
|
269
271
|
const DEFAULT_CELL_WIDTH = 96;
|
|
@@ -334,8 +336,8 @@
|
|
|
334
336
|
const DEBOUNCE_TIME = 200;
|
|
335
337
|
const MESSAGE_VERSION = 1;
|
|
336
338
|
// Sheets
|
|
337
|
-
const
|
|
338
|
-
const
|
|
339
|
+
const FORBIDDEN_SHEETNAME_CHARS = ["'", "*", "?", "/", "\\", "[", "]"];
|
|
340
|
+
const FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX = /'|\*|\?|\/|\\|\[|\]/;
|
|
339
341
|
// Cells
|
|
340
342
|
const FORMULA_REF_IDENTIFIER = "|";
|
|
341
343
|
// Components
|
|
@@ -388,6 +390,7 @@
|
|
|
388
390
|
//------------------------------------------------------------------------------
|
|
389
391
|
// Miscellaneous
|
|
390
392
|
//------------------------------------------------------------------------------
|
|
393
|
+
const sanitizeSheetNameRegex = new RegExp(FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX, "g");
|
|
391
394
|
/**
|
|
392
395
|
* Remove quotes from a quoted string
|
|
393
396
|
* ```js
|
|
@@ -483,6 +486,10 @@
|
|
|
483
486
|
}
|
|
484
487
|
return symbolName;
|
|
485
488
|
}
|
|
489
|
+
/** Replace the excel-excluded characters of a sheetName */
|
|
490
|
+
function sanitizeSheetName(sheetName, replacementChar = " ") {
|
|
491
|
+
return sheetName.replace(sanitizeSheetNameRegex, replacementChar);
|
|
492
|
+
}
|
|
486
493
|
function clip(val, min, max) {
|
|
487
494
|
return val < min ? min : val > max ? max : val;
|
|
488
495
|
}
|
|
@@ -782,6 +789,7 @@
|
|
|
782
789
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
|
|
783
790
|
*/
|
|
784
791
|
const whiteSpaceSpecialCharacters = [
|
|
792
|
+
" ",
|
|
785
793
|
"\t",
|
|
786
794
|
"\f",
|
|
787
795
|
"\v",
|
|
@@ -796,17 +804,15 @@
|
|
|
796
804
|
String.fromCharCode(parseInt("3000", 16)),
|
|
797
805
|
String.fromCharCode(parseInt("feff", 16)),
|
|
798
806
|
];
|
|
799
|
-
const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|")
|
|
807
|
+
const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|"), "g");
|
|
808
|
+
const newLineRegexp = /(\r\n|\r)/g;
|
|
800
809
|
/**
|
|
801
|
-
* Replace all
|
|
802
|
-
* different newlines types by \n.
|
|
810
|
+
* Replace all different newlines characters by \n
|
|
803
811
|
*/
|
|
804
|
-
function
|
|
812
|
+
function replaceNewLines(text) {
|
|
805
813
|
if (!text)
|
|
806
814
|
return "";
|
|
807
|
-
|
|
808
|
-
return text;
|
|
809
|
-
return text.replace(whiteSpaceRegexp, (match, newLine) => (newLine ? NEWLINE : " "));
|
|
815
|
+
return text.replace(newLineRegexp, NEWLINE);
|
|
810
816
|
}
|
|
811
817
|
/**
|
|
812
818
|
* Determine if the numbers are consecutive.
|
|
@@ -972,7 +978,7 @@
|
|
|
972
978
|
|
|
973
979
|
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
974
980
|
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
|
|
975
|
-
const colors
|
|
981
|
+
const colors = [
|
|
976
982
|
"#eb6d00",
|
|
977
983
|
"#0074d9",
|
|
978
984
|
"#ad8e00",
|
|
@@ -995,6 +1001,12 @@
|
|
|
995
1001
|
function colorNumberString(color) {
|
|
996
1002
|
return toHex(color.toString(16).padStart(6, "0"));
|
|
997
1003
|
}
|
|
1004
|
+
function colorToNumber(color) {
|
|
1005
|
+
if (typeof color === "number") {
|
|
1006
|
+
return color;
|
|
1007
|
+
}
|
|
1008
|
+
return Number.parseInt(toHex(color).slice(1), 16);
|
|
1009
|
+
}
|
|
998
1010
|
/**
|
|
999
1011
|
* Converts any CSS color value to a standardized hex6 value.
|
|
1000
1012
|
* Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
|
|
@@ -1345,9 +1357,9 @@
|
|
|
1345
1357
|
"#056BD9", // Blue #3
|
|
1346
1358
|
"#155193", // Blue #4
|
|
1347
1359
|
"#A76DBC", // Violet #1
|
|
1348
|
-
"#7F4295", // Violet #
|
|
1349
|
-
"#6D2387", // Violet #
|
|
1350
|
-
"#4F1565", // Violet #
|
|
1360
|
+
"#7F4295", // Violet #2
|
|
1361
|
+
"#6D2387", // Violet #3
|
|
1362
|
+
"#4F1565", // Violet #4
|
|
1351
1363
|
"#EA6175", // Red #1
|
|
1352
1364
|
"#CE4257", // Red #2
|
|
1353
1365
|
"#982738", // Red #3
|
|
@@ -1373,6 +1385,81 @@
|
|
|
1373
1385
|
"#C08A16", // Yellow #3
|
|
1374
1386
|
"#936A12", // Yellow #4
|
|
1375
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
|
+
];
|
|
1376
1463
|
function getNthColor(index, palette) {
|
|
1377
1464
|
return palette[index % palette.length];
|
|
1378
1465
|
}
|
|
@@ -1390,6 +1477,20 @@
|
|
|
1390
1477
|
return COLORS_XL;
|
|
1391
1478
|
}
|
|
1392
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
|
+
}
|
|
1393
1494
|
class ColorGenerator {
|
|
1394
1495
|
preferredColors;
|
|
1395
1496
|
currentColorIndex = 0;
|
|
@@ -1404,6 +1505,62 @@
|
|
|
1404
1505
|
: getNthColor(this.currentColorIndex++, this.palette);
|
|
1405
1506
|
}
|
|
1406
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
|
+
}
|
|
1407
1564
|
|
|
1408
1565
|
//------------------------------------------------------------------------------
|
|
1409
1566
|
// Coordinate
|
|
@@ -3275,6 +3432,7 @@
|
|
|
3275
3432
|
]);
|
|
3276
3433
|
const invalidateChartEvaluationCommands = new Set([
|
|
3277
3434
|
"EVALUATE_CELLS",
|
|
3435
|
+
"EVALUATE_CHARTS",
|
|
3278
3436
|
"UPDATE_CELL",
|
|
3279
3437
|
"UNHIDE_COLUMNS_ROWS",
|
|
3280
3438
|
"HIDE_COLUMNS_ROWS",
|
|
@@ -3311,6 +3469,7 @@
|
|
|
3311
3469
|
"RESIZE_SHEETVIEW",
|
|
3312
3470
|
"SET_VIEWPORT_OFFSET",
|
|
3313
3471
|
"EVALUATE_CELLS",
|
|
3472
|
+
"EVALUATE_CHARTS",
|
|
3314
3473
|
"SET_FORMULA_VISIBILITY",
|
|
3315
3474
|
"UPDATE_FILTER",
|
|
3316
3475
|
]);
|
|
@@ -6515,7 +6674,7 @@
|
|
|
6515
6674
|
const POSTFIX_UNARY_OPERATORS = ["%"];
|
|
6516
6675
|
const OPERATORS = "+,-,*,/,:,=,<>,>=,>,<=,<,^,&".split(",").concat(POSTFIX_UNARY_OPERATORS);
|
|
6517
6676
|
function tokenize(str, locale = DEFAULT_LOCALE) {
|
|
6518
|
-
str =
|
|
6677
|
+
str = replaceNewLines(str);
|
|
6519
6678
|
const chars = new TokenizingChars(str);
|
|
6520
6679
|
const result = [];
|
|
6521
6680
|
while (!chars.isOver()) {
|
|
@@ -6662,12 +6821,12 @@
|
|
|
6662
6821
|
if (length) {
|
|
6663
6822
|
return { type: "SPACE", value: NEWLINE.repeat(length) };
|
|
6664
6823
|
}
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
chars.shift();
|
|
6824
|
+
let spaces = "";
|
|
6825
|
+
while (chars.current && chars.current.match(whiteSpaceRegexp)) {
|
|
6826
|
+
spaces += chars.shift();
|
|
6668
6827
|
}
|
|
6669
|
-
if (
|
|
6670
|
-
return { type: "SPACE", value:
|
|
6828
|
+
if (spaces) {
|
|
6829
|
+
return { type: "SPACE", value: spaces };
|
|
6671
6830
|
}
|
|
6672
6831
|
return null;
|
|
6673
6832
|
}
|
|
@@ -7526,6 +7685,16 @@
|
|
|
7526
7685
|
}
|
|
7527
7686
|
return domainToString([...domain.slice(0, index), ...domain.slice(index + 1)]);
|
|
7528
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
|
+
}
|
|
7529
7698
|
|
|
7530
7699
|
const pivotTimeAdapterRegistry = new Registry();
|
|
7531
7700
|
function pivotTimeAdapter(granularity) {
|
|
@@ -8036,6 +8205,29 @@
|
|
|
8036
8205
|
format: `${" ".repeat(indent)}${format}* `,
|
|
8037
8206
|
};
|
|
8038
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
|
+
}
|
|
8039
8231
|
|
|
8040
8232
|
class CellClipboardHandler extends AbstractCellClipboardHandler {
|
|
8041
8233
|
isCutAllowed(data) {
|
|
@@ -9515,6 +9707,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9515
9707
|
}
|
|
9516
9708
|
return relativeLuminance(backgroundColor) < 0.3 ? "#FFFFFF" : "#000000";
|
|
9517
9709
|
}
|
|
9710
|
+
function chartMutedFontColor(backgroundColor) {
|
|
9711
|
+
if (!backgroundColor) {
|
|
9712
|
+
return "#666666";
|
|
9713
|
+
}
|
|
9714
|
+
return relativeLuminance(backgroundColor) < 0.3 ? "#C8C8C8" : "#666666";
|
|
9715
|
+
}
|
|
9518
9716
|
function checkDataset(definition) {
|
|
9519
9717
|
if (definition.dataSets) {
|
|
9520
9718
|
const invalidRanges = definition.dataSets.find((range) => !rangeReference.test(range.dataRange)) !== undefined;
|
|
@@ -9650,8 +9848,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9650
9848
|
const yMin = chart.chartArea.top;
|
|
9651
9849
|
const textsPositions = {};
|
|
9652
9850
|
for (const dataset of chart._metasets) {
|
|
9653
|
-
if (dataset.xAxisID === TREND_LINE_XAXIS_ID) {
|
|
9654
|
-
|
|
9851
|
+
if (dataset.xAxisID === TREND_LINE_XAXIS_ID || dataset.hidden) {
|
|
9852
|
+
continue;
|
|
9655
9853
|
}
|
|
9656
9854
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
9657
9855
|
const parsedValue = dataset._parsed[i];
|
|
@@ -10098,7 +10296,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
10098
10296
|
function drawScoreChart(structure, canvas) {
|
|
10099
10297
|
const ctx = canvas.getContext("2d");
|
|
10100
10298
|
canvas.width = structure.canvas.width;
|
|
10101
|
-
const availableWidth = canvas.width -
|
|
10299
|
+
const availableWidth = canvas.width - CHART_PADDING$1 * 2;
|
|
10102
10300
|
canvas.height = structure.canvas.height;
|
|
10103
10301
|
ctx.fillStyle = structure.canvas.backgroundColor;
|
|
10104
10302
|
ctx.fillRect(0, 0, structure.canvas.width, structure.canvas.height);
|
|
@@ -10233,10 +10431,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
10233
10431
|
}
|
|
10234
10432
|
|
|
10235
10433
|
/* Padding at the border of the chart */
|
|
10236
|
-
const CHART_PADDING =
|
|
10434
|
+
const CHART_PADDING = 10;
|
|
10237
10435
|
const BOTTOM_PADDING_RATIO = 0.05;
|
|
10238
10436
|
/* Maximum font sizes of each element */
|
|
10239
|
-
const CHART_TITLE_FONT_SIZE = SCORECARD_GAUGE_CHART_FONT_SIZE;
|
|
10240
10437
|
const KEY_VALUE_FONT_SIZE = 32;
|
|
10241
10438
|
const BASELINE_MAX_FONT_SIZE = 16;
|
|
10242
10439
|
function formatBaselineDescr(baselineDescr, baseline) {
|
|
@@ -10308,7 +10505,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
10308
10505
|
: this.height - (this.height - titleHeight - baselineHeight) / 2 - CHART_PADDING,
|
|
10309
10506
|
},
|
|
10310
10507
|
};
|
|
10311
|
-
const minimalBaselinePosition = baselineArrowSize +
|
|
10508
|
+
const minimalBaselinePosition = baselineArrowSize + CHART_PADDING * 2;
|
|
10312
10509
|
if (structure.baseline.position.x < minimalBaselinePosition) {
|
|
10313
10510
|
structure.baseline.position.x = minimalBaselinePosition;
|
|
10314
10511
|
}
|
|
@@ -10388,7 +10585,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
10388
10585
|
return this.runtime.background;
|
|
10389
10586
|
}
|
|
10390
10587
|
get secondaryFontColor() {
|
|
10391
|
-
return
|
|
10588
|
+
return chartMutedFontColor(this.backgroundColor);
|
|
10392
10589
|
}
|
|
10393
10590
|
getTextDimensions(text, font) {
|
|
10394
10591
|
this.context.font = font;
|
|
@@ -10414,7 +10611,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
10414
10611
|
}
|
|
10415
10612
|
return {
|
|
10416
10613
|
title: {
|
|
10417
|
-
font: getDefaultContextFont(
|
|
10614
|
+
font: getDefaultContextFont(this.runtime.title.fontSize ?? SCORECARD_CHART_TITLE_FONT_SIZE, this.runtime.title.bold, this.runtime.title.italic),
|
|
10418
10615
|
color: this.runtime.title.color ?? this.secondaryFontColor,
|
|
10419
10616
|
},
|
|
10420
10617
|
keyValue: {
|
|
@@ -14639,7 +14836,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
14639
14836
|
CellValueType.boolean,
|
|
14640
14837
|
];
|
|
14641
14838
|
function cellsSortingCriterion(sortingOrder) {
|
|
14642
|
-
const inverse = sortingOrder === "
|
|
14839
|
+
const inverse = sortingOrder === "asc" ? 1 : -1;
|
|
14643
14840
|
return (left, right) => {
|
|
14644
14841
|
if (left.type === CellValueType.empty) {
|
|
14645
14842
|
return right.type === CellValueType.empty ? 0 : 1;
|
|
@@ -14731,7 +14928,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
14731
14928
|
const sortColumns = [];
|
|
14732
14929
|
const nRows = matrix.length;
|
|
14733
14930
|
for (let i = 0; i < criteria.length; i += 2) {
|
|
14734
|
-
sortingOrders.push(toBoolean(toScalar(criteria[i + 1])?.value) ? "
|
|
14931
|
+
sortingOrders.push(toBoolean(toScalar(criteria[i + 1])?.value) ? "asc" : "desc");
|
|
14735
14932
|
const sortColumn = criteria[i];
|
|
14736
14933
|
if (isMatrix(sortColumn) && (sortColumn.length > 1 || sortColumn[0].length > 1)) {
|
|
14737
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));
|
|
@@ -14748,12 +14945,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
14748
14945
|
if (sortColumns.length === 0) {
|
|
14749
14946
|
for (let i = 0; i < matrix[0].length; i++) {
|
|
14750
14947
|
sortColumns.push(matrix.map((row) => row[i].value));
|
|
14751
|
-
sortingOrders.push("
|
|
14948
|
+
sortingOrders.push("asc");
|
|
14752
14949
|
}
|
|
14753
14950
|
}
|
|
14754
14951
|
const sortingCriteria = {
|
|
14755
|
-
|
|
14756
|
-
|
|
14952
|
+
desc: cellsSortingCriterion("desc"),
|
|
14953
|
+
asc: cellsSortingCriterion("asc"),
|
|
14757
14954
|
};
|
|
14758
14955
|
const indexes = range(0, matrix.length);
|
|
14759
14956
|
indexes.sort((a, b) => {
|
|
@@ -20477,20 +20674,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20477
20674
|
replaceSelectedRange(zone) {
|
|
20478
20675
|
const ref = this.getZoneReference(zone);
|
|
20479
20676
|
const currentToken = this.tokenAtCursor;
|
|
20480
|
-
|
|
20481
|
-
|
|
20482
|
-
replaceStart = currentToken.start;
|
|
20483
|
-
}
|
|
20484
|
-
else if (currentToken?.type === "RIGHT_PAREN") {
|
|
20485
|
-
// match left parenthesis
|
|
20486
|
-
const leftParenthesisIndex = this.currentTokens.findIndex((token) => token.type === "LEFT_PAREN" && token.parenthesesCode === currentToken.parenthesesCode);
|
|
20487
|
-
const functionToken = this.currentTokens[leftParenthesisIndex - 1];
|
|
20488
|
-
if (functionToken === undefined) {
|
|
20489
|
-
return;
|
|
20490
|
-
}
|
|
20491
|
-
replaceStart = functionToken.start;
|
|
20492
|
-
}
|
|
20493
|
-
this.replaceText(ref, replaceStart, this.selectionEnd);
|
|
20677
|
+
const start = currentToken?.type === "REFERENCE" ? currentToken.start : this.selectionStart;
|
|
20678
|
+
this.replaceText(ref, start, this.selectionEnd);
|
|
20494
20679
|
}
|
|
20495
20680
|
/**
|
|
20496
20681
|
* Replace the reference of the old zone by the new one.
|
|
@@ -20523,17 +20708,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20523
20708
|
getZoneReference(zone) {
|
|
20524
20709
|
const inputSheetId = this.sheetId;
|
|
20525
20710
|
const sheetId = this.getters.getActiveSheetId();
|
|
20526
|
-
if (zone.top === zone.bottom && zone.left === zone.right) {
|
|
20527
|
-
const position = { sheetId, col: zone.left, row: zone.top };
|
|
20528
|
-
const pivotId = this.getters.getPivotIdFromPosition(position);
|
|
20529
|
-
const pivotCell = this.getters.getPivotCellFromPosition(position);
|
|
20530
|
-
const cell = this.getters.getCell(position);
|
|
20531
|
-
if (pivotId && pivotCell.type !== "EMPTY" && !cell?.isFormula) {
|
|
20532
|
-
const formulaPivotId = this.getters.getPivotFormulaId(pivotId);
|
|
20533
|
-
const formula = createPivotFormula(formulaPivotId, pivotCell);
|
|
20534
|
-
return localizeFormula(formula, this.getters.getLocale()).slice(1); // strip leading =
|
|
20535
|
-
}
|
|
20536
|
-
}
|
|
20537
20711
|
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
20538
20712
|
return this.getters.getSelectionRangeString(range, inputSheetId);
|
|
20539
20713
|
}
|
|
@@ -20704,37 +20878,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20704
20878
|
const editionSheetId = this.sheetId;
|
|
20705
20879
|
const rangeColor = (rangeString) => {
|
|
20706
20880
|
const colorIndex = this.colorIndexByRange[rangeString];
|
|
20707
|
-
return colors
|
|
20881
|
+
return colors[colorIndex % colors.length];
|
|
20708
20882
|
};
|
|
20709
|
-
|
|
20710
|
-
for (const range of this.getReferencedRanges()) {
|
|
20883
|
+
return this.getReferencedRanges().map((range) => {
|
|
20711
20884
|
const rangeString = this.getters.getRangeString(range, editionSheetId);
|
|
20712
20885
|
const { numberOfRows, numberOfCols } = zoneToDimension(range.zone);
|
|
20713
20886
|
const zone = numberOfRows * numberOfCols === 1
|
|
20714
20887
|
? this.getters.expandZone(range.sheetId, range.zone)
|
|
20715
20888
|
: range.zone;
|
|
20716
|
-
|
|
20889
|
+
return {
|
|
20717
20890
|
zone,
|
|
20718
20891
|
color: rangeColor(rangeString),
|
|
20719
20892
|
sheetId: range.sheetId,
|
|
20720
20893
|
interactive: true,
|
|
20721
|
-
}
|
|
20722
|
-
}
|
|
20723
|
-
const activeSheetId = this.getters.getActiveSheetId();
|
|
20724
|
-
const selectionZone = this.model.selection.getAnchor().zone;
|
|
20725
|
-
const isSelectionHightlighted = highlights.find((highlight) => highlight.sheetId === activeSheetId && isEqual(highlight.zone, selectionZone));
|
|
20726
|
-
if (this.editionMode === "selecting" && !isSelectionHightlighted) {
|
|
20727
|
-
highlights.push({
|
|
20728
|
-
zone: selectionZone,
|
|
20729
|
-
color: "#445566",
|
|
20730
|
-
sheetId: activeSheetId,
|
|
20731
|
-
dashed: true,
|
|
20732
|
-
interactive: false,
|
|
20733
|
-
noFill: true,
|
|
20734
|
-
thinLine: true,
|
|
20735
|
-
});
|
|
20736
|
-
}
|
|
20737
|
-
return highlights;
|
|
20894
|
+
};
|
|
20895
|
+
});
|
|
20738
20896
|
}
|
|
20739
20897
|
/**
|
|
20740
20898
|
* Return ranges currently referenced in the composer
|
|
@@ -20962,6 +21120,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20962
21120
|
return error;
|
|
20963
21121
|
},
|
|
20964
21122
|
isBadExpression: true,
|
|
21123
|
+
normalizedFormula: tokens.map((t) => t.value).join(""),
|
|
20965
21124
|
};
|
|
20966
21125
|
}
|
|
20967
21126
|
}
|
|
@@ -21089,6 +21248,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21089
21248
|
symbols,
|
|
21090
21249
|
tokens,
|
|
21091
21250
|
isBadExpression: false,
|
|
21251
|
+
normalizedFormula: cacheKey,
|
|
21092
21252
|
};
|
|
21093
21253
|
return compiledFormula;
|
|
21094
21254
|
}
|
|
@@ -21235,7 +21395,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21235
21395
|
|
|
21236
21396
|
const PIVOT_FUNCTIONS = ["PIVOT.VALUE", "PIVOT.HEADER", "PIVOT"];
|
|
21237
21397
|
/**
|
|
21238
|
-
* Create a proposal entry for the
|
|
21398
|
+
* Create a proposal entry for the composer autocomplete
|
|
21239
21399
|
* to insert a field name string in a formula.
|
|
21240
21400
|
*/
|
|
21241
21401
|
function makeFieldProposal(field, granularity) {
|
|
@@ -21353,6 +21513,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21353
21513
|
description: definition.name,
|
|
21354
21514
|
htmlContent: [{ value: str, color: tokenColors.NUMBER }],
|
|
21355
21515
|
fuzzySearchKey: str + definition.name,
|
|
21516
|
+
alwaysExpanded: true,
|
|
21356
21517
|
};
|
|
21357
21518
|
})
|
|
21358
21519
|
.filter(isDefined);
|
|
@@ -22018,14 +22179,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
22018
22179
|
const GAUGE_LABELS_FONT_SIZE = 12;
|
|
22019
22180
|
const GAUGE_DEFAULT_VALUE_FONT_SIZE = 80;
|
|
22020
22181
|
const GAUGE_BACKGROUND_COLOR = "#F3F2F1";
|
|
22021
|
-
const GAUGE_TEXT_COLOR = "#666666";
|
|
22022
|
-
const GAUGE_TEXT_COLOR_HIGH_CONTRAST = "#C8C8C8";
|
|
22023
|
-
const GAUGE_INFLECTION_MARKER_COLOR = "#666666aa";
|
|
22024
22182
|
const GAUGE_INFLECTION_LABEL_BOTTOM_MARGIN = 6;
|
|
22025
22183
|
const GAUGE_TITLE_SECTION_HEIGHT = 25;
|
|
22026
|
-
const GAUGE_TITLE_FONT_SIZE = SCORECARD_GAUGE_CHART_FONT_SIZE;
|
|
22027
|
-
const GAUGE_TITLE_PADDING_LEFT = SCORECARD_GAUGE_CHART_PADDING;
|
|
22028
|
-
const GAUGE_TITLE_PADDING_TOP = SCORECARD_GAUGE_CHART_PADDING;
|
|
22029
22184
|
function drawGaugeChart(canvas, runtime) {
|
|
22030
22185
|
const canvasBoundingRect = canvas.getBoundingClientRect();
|
|
22031
22186
|
canvas.width = canvasBoundingRect.width;
|
|
@@ -22084,7 +22239,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
22084
22239
|
ctx.translate(rectX + width / 2 - 0.5, rectY + height - 0.5); // -0.5 for sharper lines. see RendererPlugin.drawBorders comment
|
|
22085
22240
|
ctx.rotate(Math.PI / 2 - inflectionValue.rotation);
|
|
22086
22241
|
ctx.lineWidth = 2;
|
|
22087
|
-
ctx.strokeStyle =
|
|
22242
|
+
ctx.strokeStyle = chartMutedFontColor(config.backgroundColor) + "aa";
|
|
22088
22243
|
ctx.beginPath();
|
|
22089
22244
|
ctx.moveTo(0, -(height - config.gauge.arcWidth));
|
|
22090
22245
|
ctx.lineTo(0, -height - 3);
|
|
@@ -22138,22 +22293,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
22138
22293
|
x: gaugeRect.x + gaugeRect.width - gaugeArcWidth / 2,
|
|
22139
22294
|
y: gaugeRect.y + gaugeRect.height + GAUGE_LABELS_FONT_SIZE,
|
|
22140
22295
|
};
|
|
22141
|
-
const textColor =
|
|
22296
|
+
const textColor = chartMutedFontColor(runtime.background);
|
|
22142
22297
|
const inflectionValues = getInflectionValues(runtime, gaugeRect, textColor, ctx);
|
|
22143
22298
|
let x = 0, titleWidth = 0, titleHeight = 0;
|
|
22144
22299
|
if (runtime.title.text) {
|
|
22145
|
-
({ width: titleWidth, height: titleHeight } = computeTextDimension(ctx, runtime.title.text, { ...runtime.title
|
|
22300
|
+
({ width: titleWidth, height: titleHeight } = computeTextDimension(ctx, runtime.title.text, { fontSize: CHART_TITLE_FONT_SIZE, ...runtime.title }, "px"));
|
|
22146
22301
|
}
|
|
22147
22302
|
switch (runtime.title.align) {
|
|
22148
22303
|
case "right":
|
|
22149
|
-
x = boundingRect.width - titleWidth -
|
|
22304
|
+
x = boundingRect.width - titleWidth - CHART_PADDING$1;
|
|
22150
22305
|
break;
|
|
22151
22306
|
case "center":
|
|
22152
22307
|
x = (boundingRect.width - titleWidth) / 2;
|
|
22153
22308
|
break;
|
|
22154
22309
|
case "left":
|
|
22155
22310
|
default:
|
|
22156
|
-
x =
|
|
22311
|
+
x = CHART_PADDING$1;
|
|
22157
22312
|
break;
|
|
22158
22313
|
}
|
|
22159
22314
|
return {
|
|
@@ -22161,10 +22316,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
22161
22316
|
height: boundingRect.height,
|
|
22162
22317
|
title: {
|
|
22163
22318
|
label: runtime.title.text ?? "",
|
|
22164
|
-
fontSize:
|
|
22319
|
+
fontSize: runtime.title.fontSize ?? CHART_TITLE_FONT_SIZE,
|
|
22165
22320
|
textPosition: {
|
|
22166
22321
|
x,
|
|
22167
|
-
y:
|
|
22322
|
+
y: CHART_PADDING_TOP + titleHeight / 2,
|
|
22168
22323
|
},
|
|
22169
22324
|
color: runtime.title.color ?? textColor,
|
|
22170
22325
|
bold: runtime.title.bold,
|
|
@@ -22281,11 +22436,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
22281
22436
|
}
|
|
22282
22437
|
return runtime.colors.at(-1);
|
|
22283
22438
|
}
|
|
22284
|
-
function getContrastedTextColor(backgroundColor) {
|
|
22285
|
-
return relativeLuminance(backgroundColor) > 0.3
|
|
22286
|
-
? GAUGE_TEXT_COLOR
|
|
22287
|
-
: GAUGE_TEXT_COLOR_HIGH_CONTRAST;
|
|
22288
|
-
}
|
|
22289
22439
|
function getSegmentsOfRectangle(rectangle) {
|
|
22290
22440
|
return [
|
|
22291
22441
|
{ start: rectangle.topLeft, end: rectangle.topRight },
|
|
@@ -26999,13 +27149,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
26999
27149
|
versionFrom: "7",
|
|
27000
27150
|
migrate(data) {
|
|
27001
27151
|
const namesTaken = [];
|
|
27002
|
-
const globalForbiddenInExcel = new RegExp(FORBIDDEN_IN_EXCEL_REGEX, "g");
|
|
27003
27152
|
for (let sheet of data.sheets || []) {
|
|
27004
27153
|
if (!sheet.name) {
|
|
27005
27154
|
continue;
|
|
27006
27155
|
}
|
|
27007
27156
|
const oldName = sheet.name;
|
|
27008
|
-
const escapedName = oldName
|
|
27157
|
+
const escapedName = sanitizeSheetName(oldName, "_");
|
|
27009
27158
|
let i = 1;
|
|
27010
27159
|
let newName = escapedName;
|
|
27011
27160
|
while (namesTaken.includes(newName)) {
|
|
@@ -27758,6 +27907,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27758
27907
|
["GaugeLowerInflectionPointNaN" /* CommandResult.GaugeLowerInflectionPointNaN */]: _t("The lower inflection point value must be a number"),
|
|
27759
27908
|
["GaugeUpperInflectionPointNaN" /* CommandResult.GaugeUpperInflectionPointNaN */]: _t("The upper inflection point value must be a number"),
|
|
27760
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
|
+
},
|
|
27761
27923
|
};
|
|
27762
27924
|
const CustomCurrencyTerms = {
|
|
27763
27925
|
Custom: _t("Custom"),
|
|
@@ -28161,6 +28323,26 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28161
28323
|
locale: getters.getLocale(),
|
|
28162
28324
|
};
|
|
28163
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
|
+
}
|
|
28164
28346
|
function getTrendDatasetForBarChart(config, data) {
|
|
28165
28347
|
const filteredValues = [];
|
|
28166
28348
|
const filteredLabels = [];
|
|
@@ -28241,37 +28423,45 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28241
28423
|
const labelRange = labelMax - labelMin;
|
|
28242
28424
|
const normalizedLabels = labels.map((v) => (v - labelMin) / labelRange);
|
|
28243
28425
|
const normalizedNewLabels = newLabels.map((v) => (v - labelMin) / labelRange);
|
|
28244
|
-
|
|
28245
|
-
|
|
28246
|
-
|
|
28247
|
-
|
|
28248
|
-
|
|
28249
|
-
|
|
28250
|
-
|
|
28251
|
-
|
|
28252
|
-
|
|
28253
|
-
|
|
28254
|
-
|
|
28255
|
-
|
|
28256
|
-
|
|
28257
|
-
|
|
28258
|
-
|
|
28259
|
-
|
|
28426
|
+
try {
|
|
28427
|
+
switch (config.type) {
|
|
28428
|
+
case "polynomial": {
|
|
28429
|
+
const order = config.order;
|
|
28430
|
+
if (!order) {
|
|
28431
|
+
return Array.from({ length: newLabels.length }, () => NaN);
|
|
28432
|
+
}
|
|
28433
|
+
if (order === 1) {
|
|
28434
|
+
return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0];
|
|
28435
|
+
}
|
|
28436
|
+
const coeffs = polynomialRegression(values, normalizedLabels, order, true).flat();
|
|
28437
|
+
return normalizedNewLabels.map((v) => evaluatePolynomial(coeffs, v, order));
|
|
28438
|
+
}
|
|
28439
|
+
case "exponential": {
|
|
28440
|
+
const positiveLogValues = [];
|
|
28441
|
+
const filteredLabels = [];
|
|
28442
|
+
for (let i = 0; i < values.length; i++) {
|
|
28443
|
+
if (values[i] > 0) {
|
|
28444
|
+
positiveLogValues.push(Math.log(values[i]));
|
|
28445
|
+
filteredLabels.push(normalizedLabels[i]);
|
|
28446
|
+
}
|
|
28447
|
+
}
|
|
28448
|
+
if (!filteredLabels.length) {
|
|
28449
|
+
return Array.from({ length: newLabels.length }, () => NaN);
|
|
28260
28450
|
}
|
|
28451
|
+
return expM(predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true))[0];
|
|
28261
28452
|
}
|
|
28262
|
-
|
|
28263
|
-
return [];
|
|
28453
|
+
case "logarithmic": {
|
|
28454
|
+
return predictLinearValues([values], logM([normalizedLabels]), logM([normalizedNewLabels]), true)[0];
|
|
28264
28455
|
}
|
|
28265
|
-
|
|
28266
|
-
|
|
28267
|
-
|
|
28268
|
-
|
|
28269
|
-
|
|
28270
|
-
case "trailingMovingAverage": {
|
|
28271
|
-
return getMovingAverageValues(values, config.window);
|
|
28456
|
+
case "trailingMovingAverage": {
|
|
28457
|
+
return getMovingAverageValues(values, config.window);
|
|
28458
|
+
}
|
|
28459
|
+
default:
|
|
28460
|
+
return Array.from({ length: newLabels.length }, () => NaN);
|
|
28272
28461
|
}
|
|
28273
|
-
|
|
28274
|
-
|
|
28462
|
+
}
|
|
28463
|
+
catch (e) {
|
|
28464
|
+
return Array.from({ length: newLabels.length }, () => NaN);
|
|
28275
28465
|
}
|
|
28276
28466
|
}
|
|
28277
28467
|
function getChartAxisType(chart, labelRange, getters) {
|
|
@@ -28705,6 +28895,43 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28705
28895
|
}
|
|
28706
28896
|
return datasets;
|
|
28707
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
|
+
}
|
|
28708
28935
|
function getTrendingLineDataSet(dataset, config, data) {
|
|
28709
28936
|
const defaultBorderColor = colorToRGBA(dataset.backgroundColor);
|
|
28710
28937
|
defaultBorderColor.a = 1;
|
|
@@ -28742,54 +28969,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28742
28969
|
return new ColorGenerator(dataSetsSize, definition.dataSets?.map((ds) => ds.backgroundColor) || []);
|
|
28743
28970
|
}
|
|
28744
28971
|
|
|
28745
|
-
function
|
|
28746
|
-
// TODO FIXME: this is unused ATM. All the charts should probably use this instead oh whatever padding they are using now
|
|
28747
|
-
// also look into how DEFAULT_CHART_PADDING is used in scorecards, it look strange
|
|
28972
|
+
function getChartLayout(definition) {
|
|
28748
28973
|
return {
|
|
28749
28974
|
padding: {
|
|
28750
|
-
left:
|
|
28751
|
-
right:
|
|
28752
|
-
top:
|
|
28753
|
-
bottom:
|
|
28975
|
+
left: CHART_PADDING$1,
|
|
28976
|
+
right: CHART_PADDING$1,
|
|
28977
|
+
top: CHART_PADDING_TOP,
|
|
28978
|
+
bottom: CHART_PADDING_BOTTOM,
|
|
28754
28979
|
},
|
|
28755
28980
|
};
|
|
28756
28981
|
}
|
|
28757
|
-
function getBarChartLayout(definition) {
|
|
28758
|
-
return {
|
|
28759
|
-
padding: computeChartPadding({
|
|
28760
|
-
displayTitle: !!definition.title?.text,
|
|
28761
|
-
displayLegend: definition.legendPosition === "top",
|
|
28762
|
-
}),
|
|
28763
|
-
};
|
|
28764
|
-
}
|
|
28765
|
-
function getLineChartLayout(definition) {
|
|
28766
|
-
return {
|
|
28767
|
-
padding: computeChartPadding({
|
|
28768
|
-
displayTitle: !!definition.title?.text,
|
|
28769
|
-
displayLegend: definition.legendPosition === "top",
|
|
28770
|
-
}),
|
|
28771
|
-
};
|
|
28772
|
-
}
|
|
28773
|
-
function getPieChartLayout(definition) {
|
|
28774
|
-
return {
|
|
28775
|
-
padding: { left: 20, right: 20, top: definition.title ? 10 : 25, bottom: 10 },
|
|
28776
|
-
};
|
|
28777
|
-
}
|
|
28778
|
-
function getWaterfallChartLayout(definition) {
|
|
28779
|
-
return {
|
|
28780
|
-
padding: { left: 20, right: 20, top: definition.title ? 10 : 25, bottom: 10 },
|
|
28781
|
-
};
|
|
28782
|
-
}
|
|
28783
|
-
function computeChartPadding({ displayTitle, displayLegend, }) {
|
|
28784
|
-
let top = 25;
|
|
28785
|
-
if (displayTitle) {
|
|
28786
|
-
top = 0;
|
|
28787
|
-
}
|
|
28788
|
-
else if (displayLegend) {
|
|
28789
|
-
top = 10;
|
|
28790
|
-
}
|
|
28791
|
-
return { left: 20, right: 20, top, bottom: 10 };
|
|
28792
|
-
}
|
|
28793
28982
|
|
|
28794
28983
|
function getLegendDisplayOptions(definition, args) {
|
|
28795
28984
|
return {
|
|
@@ -28847,11 +29036,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28847
29036
|
return {
|
|
28848
29037
|
...INTERACTIVE_LEGEND_CONFIG,
|
|
28849
29038
|
...getLegendDisplayOptions(definition),
|
|
28850
|
-
|
|
28851
|
-
|
|
28852
|
-
|
|
28853
|
-
|
|
28854
|
-
|
|
29039
|
+
...getCustomLegendLabels(chartFontColor(definition.background), {
|
|
29040
|
+
pointStyle: "circle",
|
|
29041
|
+
// the stroke is the border around the circle, so increasing its size with the chart's color reduce the size of the circle
|
|
29042
|
+
strokeStyle: definition.background || "#ffffff",
|
|
29043
|
+
lineWidth: 8,
|
|
29044
|
+
}),
|
|
28855
29045
|
};
|
|
28856
29046
|
}
|
|
28857
29047
|
function getComboChartLegend(definition, args) {
|
|
@@ -28940,10 +29130,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28940
29130
|
target.style.cursor = "default";
|
|
28941
29131
|
},
|
|
28942
29132
|
onClick: (event, legendItem, legend) => {
|
|
28943
|
-
|
|
29133
|
+
const index = legendItem.datasetIndex;
|
|
29134
|
+
if (!legend.legendItems || index === undefined) {
|
|
28944
29135
|
return;
|
|
28945
29136
|
}
|
|
28946
|
-
const index = legend.legendItems.indexOf(legendItem);
|
|
28947
29137
|
if (legend.chart.isDatasetVisible(index)) {
|
|
28948
29138
|
legend.chart.hide(index);
|
|
28949
29139
|
}
|
|
@@ -28959,15 +29149,29 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28959
29149
|
labels: {
|
|
28960
29150
|
color: fontColor,
|
|
28961
29151
|
usePointStyle: true,
|
|
28962
|
-
generateLabels: (chart) => chart.data.datasets.map((dataset, index) =>
|
|
28963
|
-
|
|
28964
|
-
|
|
28965
|
-
|
|
28966
|
-
|
|
28967
|
-
|
|
28968
|
-
|
|
28969
|
-
|
|
28970
|
-
|
|
29152
|
+
generateLabels: (chart) => chart.data.datasets.map((dataset, index) => {
|
|
29153
|
+
if (dataset["xAxisID"] === TREND_LINE_XAXIS_ID) {
|
|
29154
|
+
return {
|
|
29155
|
+
text: dataset.label ?? "",
|
|
29156
|
+
fontColor,
|
|
29157
|
+
strokeStyle: dataset.borderColor,
|
|
29158
|
+
hidden: !chart.isDatasetVisible(index),
|
|
29159
|
+
pointStyle: "line",
|
|
29160
|
+
datasetIndex: index,
|
|
29161
|
+
lineWidth: 3,
|
|
29162
|
+
};
|
|
29163
|
+
}
|
|
29164
|
+
return {
|
|
29165
|
+
text: dataset.label ?? "",
|
|
29166
|
+
fontColor,
|
|
29167
|
+
strokeStyle: dataset.borderColor,
|
|
29168
|
+
fillStyle: dataset.backgroundColor,
|
|
29169
|
+
hidden: !chart.isDatasetVisible(index),
|
|
29170
|
+
pointStyle: dataset.type === "line" ? "line" : "rect",
|
|
29171
|
+
datasetIndex: index,
|
|
29172
|
+
...legendLabelConfig,
|
|
29173
|
+
};
|
|
29174
|
+
}),
|
|
28971
29175
|
},
|
|
28972
29176
|
};
|
|
28973
29177
|
}
|
|
@@ -29105,6 +29309,44 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29105
29309
|
},
|
|
29106
29310
|
};
|
|
29107
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
|
+
}
|
|
29108
29350
|
function getChartAxisTitleRuntime(design) {
|
|
29109
29351
|
if (design?.title?.text) {
|
|
29110
29352
|
const { text, color, align, italic, bold } = design.title;
|
|
@@ -29115,6 +29357,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29115
29357
|
font: {
|
|
29116
29358
|
style: italic ? "italic" : "normal",
|
|
29117
29359
|
weight: bold ? "bold" : "normal",
|
|
29360
|
+
size: design.title.fontSize ?? CHART_AXIS_TITLE_FONT_SIZE,
|
|
29118
29361
|
},
|
|
29119
29362
|
align: align === "left" ? "start" : align === "right" ? "end" : "center",
|
|
29120
29363
|
};
|
|
@@ -29167,6 +29410,44 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29167
29410
|
};
|
|
29168
29411
|
}
|
|
29169
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
|
+
}
|
|
29170
29451
|
|
|
29171
29452
|
function getChartShowValues(definition, args) {
|
|
29172
29453
|
const { axisFormats, locale } = args;
|
|
@@ -29180,17 +29461,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29180
29461
|
|
|
29181
29462
|
function getChartTitle(definition) {
|
|
29182
29463
|
const chartTitle = definition.title;
|
|
29183
|
-
const fontColor =
|
|
29464
|
+
const fontColor = chartMutedFontColor(definition.background);
|
|
29184
29465
|
return {
|
|
29185
29466
|
display: !!chartTitle.text,
|
|
29186
29467
|
text: _t(chartTitle.text),
|
|
29187
29468
|
color: chartTitle?.color ?? fontColor,
|
|
29188
29469
|
align: chartTitle.align === "center" ? "center" : chartTitle.align === "right" ? "end" : "start",
|
|
29189
29470
|
font: {
|
|
29190
|
-
size:
|
|
29471
|
+
size: definition.title.fontSize ?? CHART_TITLE_FONT_SIZE,
|
|
29191
29472
|
weight: chartTitle.bold ? "bold" : "normal",
|
|
29192
29473
|
style: chartTitle.italic ? "italic" : "normal",
|
|
29193
29474
|
},
|
|
29475
|
+
padding: {
|
|
29476
|
+
// Disable title top/left/right padding to use the chart padding instead.
|
|
29477
|
+
// The legend already has a top padding, so bottom padding is useless for the title there.
|
|
29478
|
+
bottom: definition.legendPosition === "top" ? 0 : CHART_PADDING$1,
|
|
29479
|
+
},
|
|
29194
29480
|
};
|
|
29195
29481
|
}
|
|
29196
29482
|
|
|
@@ -29321,6 +29607,25 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29321
29607
|
},
|
|
29322
29608
|
};
|
|
29323
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
|
+
}
|
|
29324
29629
|
function calculatePercentage(dataset, dataIndex) {
|
|
29325
29630
|
const numericData = dataset.filter((value) => typeof value === "number");
|
|
29326
29631
|
const total = numericData.reduce((sum, value) => sum + value, 0);
|
|
@@ -29337,26 +29642,27 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29337
29642
|
canChartParseLabels: canChartParseLabels,
|
|
29338
29643
|
getBarChartData: getBarChartData,
|
|
29339
29644
|
getBarChartDatasets: getBarChartDatasets,
|
|
29340
|
-
getBarChartLayout: getBarChartLayout,
|
|
29341
29645
|
getBarChartLegend: getBarChartLegend,
|
|
29342
29646
|
getBarChartScales: getBarChartScales,
|
|
29343
29647
|
getBarChartTooltip: getBarChartTooltip,
|
|
29344
29648
|
getChartLabelFormat: getChartLabelFormat,
|
|
29649
|
+
getChartLayout: getChartLayout,
|
|
29345
29650
|
getChartShowValues: getChartShowValues,
|
|
29346
29651
|
getChartTitle: getChartTitle,
|
|
29347
29652
|
getComboChartDatasets: getComboChartDatasets,
|
|
29348
29653
|
getComboChartLegend: getComboChartLegend,
|
|
29349
|
-
getCommonChartLayout: getCommonChartLayout,
|
|
29350
29654
|
getData: getData,
|
|
29655
|
+
getGeoChartData: getGeoChartData,
|
|
29656
|
+
getGeoChartDatasets: getGeoChartDatasets,
|
|
29657
|
+
getGeoChartScales: getGeoChartScales,
|
|
29658
|
+
getGeoChartTooltip: getGeoChartTooltip,
|
|
29351
29659
|
getLineChartData: getLineChartData,
|
|
29352
29660
|
getLineChartDatasets: getLineChartDatasets,
|
|
29353
|
-
getLineChartLayout: getLineChartLayout,
|
|
29354
29661
|
getLineChartLegend: getLineChartLegend,
|
|
29355
29662
|
getLineChartScales: getLineChartScales,
|
|
29356
29663
|
getLineChartTooltip: getLineChartTooltip,
|
|
29357
29664
|
getPieChartData: getPieChartData,
|
|
29358
29665
|
getPieChartDatasets: getPieChartDatasets,
|
|
29359
|
-
getPieChartLayout: getPieChartLayout,
|
|
29360
29666
|
getPieChartLegend: getPieChartLegend,
|
|
29361
29667
|
getPieChartTooltip: getPieChartTooltip,
|
|
29362
29668
|
getPyramidChartData: getPyramidChartData,
|
|
@@ -29372,7 +29678,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29372
29678
|
getScatterChartScales: getScatterChartScales,
|
|
29373
29679
|
getTrendDatasetForBarChart: getTrendDatasetForBarChart,
|
|
29374
29680
|
getTrendDatasetForLineChart: getTrendDatasetForLineChart,
|
|
29375
|
-
getWaterfallChartLayout: getWaterfallChartLayout,
|
|
29376
29681
|
getWaterfallChartLegend: getWaterfallChartLegend,
|
|
29377
29682
|
getWaterfallChartScales: getWaterfallChartScales,
|
|
29378
29683
|
getWaterfallChartTooltip: getWaterfallChartTooltip,
|
|
@@ -29520,7 +29825,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29520
29825
|
options: {
|
|
29521
29826
|
...CHART_COMMON_OPTIONS,
|
|
29522
29827
|
indexAxis: chart.horizontal ? "y" : "x",
|
|
29523
|
-
layout:
|
|
29828
|
+
layout: getChartLayout(),
|
|
29524
29829
|
scales: getBarChartScales(definition, chartData),
|
|
29525
29830
|
plugins: {
|
|
29526
29831
|
title: getChartTitle(definition),
|
|
@@ -29672,7 +29977,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29672
29977
|
},
|
|
29673
29978
|
options: {
|
|
29674
29979
|
...CHART_COMMON_OPTIONS,
|
|
29675
|
-
layout:
|
|
29980
|
+
layout: getChartLayout(),
|
|
29676
29981
|
scales: getBarChartScales(definition, chartData),
|
|
29677
29982
|
plugins: {
|
|
29678
29983
|
title: getChartTitle(definition),
|
|
@@ -29924,6 +30229,133 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29924
30229
|
return clip(value, minValue, maxValue);
|
|
29925
30230
|
}
|
|
29926
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
|
+
|
|
29927
30359
|
class LineChart extends AbstractChart {
|
|
29928
30360
|
dataSets;
|
|
29929
30361
|
labelRange;
|
|
@@ -30073,7 +30505,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30073
30505
|
},
|
|
30074
30506
|
options: {
|
|
30075
30507
|
...CHART_COMMON_OPTIONS,
|
|
30076
|
-
layout:
|
|
30508
|
+
layout: getChartLayout(),
|
|
30077
30509
|
scales: getLineChartScales(definition, chartData),
|
|
30078
30510
|
plugins: {
|
|
30079
30511
|
title: getChartTitle(definition),
|
|
@@ -30208,7 +30640,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30208
30640
|
},
|
|
30209
30641
|
options: {
|
|
30210
30642
|
...CHART_COMMON_OPTIONS,
|
|
30211
|
-
layout:
|
|
30643
|
+
layout: getChartLayout(),
|
|
30212
30644
|
plugins: {
|
|
30213
30645
|
title: getChartTitle(definition),
|
|
30214
30646
|
legend: getPieChartLegend(definition, chartData),
|
|
@@ -30345,7 +30777,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30345
30777
|
options: {
|
|
30346
30778
|
...CHART_COMMON_OPTIONS,
|
|
30347
30779
|
indexAxis: "y",
|
|
30348
|
-
layout:
|
|
30780
|
+
layout: getChartLayout(),
|
|
30349
30781
|
scales: getPyramidChartScales(definition, chartData),
|
|
30350
30782
|
plugins: {
|
|
30351
30783
|
title: getChartTitle(definition),
|
|
@@ -30494,7 +30926,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30494
30926
|
},
|
|
30495
30927
|
options: {
|
|
30496
30928
|
...CHART_COMMON_OPTIONS,
|
|
30497
|
-
layout:
|
|
30929
|
+
layout: getChartLayout(),
|
|
30498
30930
|
scales: getRadarChartScales(definition, chartData),
|
|
30499
30931
|
plugins: {
|
|
30500
30932
|
title: getChartTitle(definition),
|
|
@@ -30647,7 +31079,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30647
31079
|
},
|
|
30648
31080
|
options: {
|
|
30649
31081
|
...CHART_COMMON_OPTIONS,
|
|
30650
|
-
layout:
|
|
31082
|
+
layout: getChartLayout(),
|
|
30651
31083
|
scales: getScatterChartScales(definition, chartData),
|
|
30652
31084
|
plugins: {
|
|
30653
31085
|
title: getChartTitle(definition),
|
|
@@ -30808,7 +31240,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30808
31240
|
},
|
|
30809
31241
|
options: {
|
|
30810
31242
|
...CHART_COMMON_OPTIONS,
|
|
30811
|
-
layout:
|
|
31243
|
+
layout: getChartLayout(),
|
|
30812
31244
|
scales: getWaterfallChartScales(definition, chartData),
|
|
30813
31245
|
plugins: {
|
|
30814
31246
|
title: getChartTitle(definition),
|
|
@@ -30917,6 +31349,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30917
31349
|
getChartDefinitionFromContextCreation: RadarChart.getDefinitionFromContextCreation,
|
|
30918
31350
|
sequence: 80,
|
|
30919
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
|
+
});
|
|
30920
31361
|
const chartComponentRegistry = new Registry();
|
|
30921
31362
|
chartComponentRegistry.add("line", ChartJsComponent);
|
|
30922
31363
|
chartComponentRegistry.add("bar", ChartJsComponent);
|
|
@@ -30928,6 +31369,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30928
31369
|
chartComponentRegistry.add("waterfall", ChartJsComponent);
|
|
30929
31370
|
chartComponentRegistry.add("pyramid", ChartJsComponent);
|
|
30930
31371
|
chartComponentRegistry.add("radar", ChartJsComponent);
|
|
31372
|
+
chartComponentRegistry.add("geo", ChartJsComponent);
|
|
30931
31373
|
const chartCategories = {
|
|
30932
31374
|
line: _t("Line"),
|
|
30933
31375
|
column: _t("Column"),
|
|
@@ -31087,6 +31529,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31087
31529
|
subtypeDefinition: { fillArea: true },
|
|
31088
31530
|
category: "misc",
|
|
31089
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",
|
|
31090
31539
|
});
|
|
31091
31540
|
|
|
31092
31541
|
/**
|
|
@@ -31937,18 +32386,66 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31937
32386
|
},
|
|
31938
32387
|
};
|
|
31939
32388
|
|
|
31940
|
-
|
|
31941
|
-
|
|
31942
|
-
|
|
31943
|
-
|
|
31944
|
-
|
|
31945
|
-
|
|
31946
|
-
|
|
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
|
+
}
|
|
31947
32425
|
}
|
|
31948
32426
|
}
|
|
31949
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
|
+
|
|
31950
32446
|
class FilterMenuValueItem extends owl.Component {
|
|
31951
32447
|
static template = "o-spreadsheet-FilterMenuValueItem";
|
|
32448
|
+
static components = { Checkbox };
|
|
31952
32449
|
static props = {
|
|
31953
32450
|
value: String,
|
|
31954
32451
|
isChecked: Boolean,
|
|
@@ -31986,8 +32483,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31986
32483
|
.o-filter-menu-item {
|
|
31987
32484
|
display: flex;
|
|
31988
32485
|
box-sizing: border-box;
|
|
31989
|
-
height: ${MENU_ITEM_HEIGHT}px;
|
|
31990
|
-
padding: 4px 4px 4px 0px;
|
|
31991
32486
|
cursor: pointer;
|
|
31992
32487
|
user-select: none;
|
|
31993
32488
|
|
|
@@ -31996,14 +32491,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31996
32491
|
}
|
|
31997
32492
|
}
|
|
31998
32493
|
|
|
31999
|
-
input {
|
|
32000
|
-
box-sizing: border-box;
|
|
32001
|
-
margin-bottom: 5px;
|
|
32002
|
-
border: 1px solid #949494;
|
|
32003
|
-
height: 24px;
|
|
32004
|
-
padding-right: 28px;
|
|
32005
|
-
}
|
|
32006
|
-
|
|
32007
32494
|
.o-search-icon {
|
|
32008
32495
|
right: 5px;
|
|
32009
32496
|
top: 3px;
|
|
@@ -32020,19 +32507,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32020
32507
|
display: flex;
|
|
32021
32508
|
flex-direction: row;
|
|
32022
32509
|
margin-bottom: 4px;
|
|
32023
|
-
|
|
32024
|
-
.o-filter-menu-action-text {
|
|
32025
|
-
cursor: pointer;
|
|
32026
|
-
margin-right: 10px;
|
|
32027
|
-
color: blue;
|
|
32028
|
-
text-decoration: underline;
|
|
32029
|
-
}
|
|
32030
32510
|
}
|
|
32031
32511
|
|
|
32032
32512
|
.o-filter-menu-list {
|
|
32033
32513
|
flex: auto;
|
|
32034
32514
|
overflow-y: auto;
|
|
32035
|
-
border: 1px solid
|
|
32515
|
+
border: 1px solid ${GRAY_300};
|
|
32036
32516
|
|
|
32037
32517
|
.o-filter-menu-no-values {
|
|
32038
32518
|
color: #949494;
|
|
@@ -33118,6 +33598,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
33118
33598
|
adaptChartRange: adaptChartRange,
|
|
33119
33599
|
chartFactory: chartFactory,
|
|
33120
33600
|
chartFontColor: chartFontColor,
|
|
33601
|
+
chartMutedFontColor: chartMutedFontColor,
|
|
33121
33602
|
chartRuntimeFactory: chartRuntimeFactory,
|
|
33122
33603
|
chartToImage: chartToImage,
|
|
33123
33604
|
checkDataset: checkDataset,
|
|
@@ -34223,6 +34704,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34223
34704
|
isReadonlyAllowed: true,
|
|
34224
34705
|
icon: "o-spreadsheet-Icon.PIVOT",
|
|
34225
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
|
+
};
|
|
34226
34722
|
const FIX_FORMULAS = {
|
|
34227
34723
|
name: _t("Convert to individual formulas"),
|
|
34228
34724
|
execute(env) {
|
|
@@ -34259,6 +34755,66 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34259
34755
|
},
|
|
34260
34756
|
icon: "o-spreadsheet-Icon.PIVOT",
|
|
34261
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
|
+
}
|
|
34262
34818
|
|
|
34263
34819
|
//------------------------------------------------------------------------------
|
|
34264
34820
|
// Context Menu Registry
|
|
@@ -34357,14 +34913,33 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34357
34913
|
name: INSERT_LINK_NAME,
|
|
34358
34914
|
sequence: 150,
|
|
34359
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,
|
|
34360
34922
|
})
|
|
34361
34923
|
.add("pivot_fix_formulas", {
|
|
34362
34924
|
...FIX_FORMULAS,
|
|
34363
|
-
sequence:
|
|
34925
|
+
sequence: 160,
|
|
34364
34926
|
})
|
|
34365
34927
|
.add("pivot_properties", {
|
|
34366
34928
|
...pivotProperties,
|
|
34367
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,
|
|
34368
34943
|
});
|
|
34369
34944
|
|
|
34370
34945
|
const sortRange = {
|
|
@@ -34377,7 +34952,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34377
34952
|
execute: (env) => {
|
|
34378
34953
|
const { anchor, zones } = env.model.getters.getSelection();
|
|
34379
34954
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
34380
|
-
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "
|
|
34955
|
+
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "asc");
|
|
34381
34956
|
},
|
|
34382
34957
|
icon: "o-spreadsheet-Icon.SORT_ASCENDING",
|
|
34383
34958
|
};
|
|
@@ -34405,7 +34980,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34405
34980
|
execute: (env) => {
|
|
34406
34981
|
const { anchor, zones } = env.model.getters.getSelection();
|
|
34407
34982
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
34408
|
-
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "
|
|
34983
|
+
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "desc");
|
|
34409
34984
|
},
|
|
34410
34985
|
icon: "o-spreadsheet-Icon.SORT_DESCENDING",
|
|
34411
34986
|
};
|
|
@@ -34888,6 +35463,227 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34888
35463
|
}
|
|
34889
35464
|
}
|
|
34890
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
|
+
|
|
34891
35687
|
const hideCols = {
|
|
34892
35688
|
name: HIDE_COLUMNS_NAME,
|
|
34893
35689
|
execute: (env) => {
|
|
@@ -35059,6 +35855,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35059
35855
|
return env.model.getters.getGridLinesVisibility(sheetId);
|
|
35060
35856
|
},
|
|
35061
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
|
+
};
|
|
35062
35871
|
const viewFormulas = {
|
|
35063
35872
|
name: _t("Formulas"),
|
|
35064
35873
|
isActive: (env) => env.model.getters.shouldShowFormulas(),
|
|
@@ -35676,6 +36485,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35676
36485
|
.addChild("view_formulas", ["view", "show"], {
|
|
35677
36486
|
...viewFormulas,
|
|
35678
36487
|
sequence: 10,
|
|
36488
|
+
})
|
|
36489
|
+
.addChild("view_irregularity_map", ["view"], {
|
|
36490
|
+
...irregularityMap,
|
|
36491
|
+
sequence: 40,
|
|
36492
|
+
separator: true,
|
|
35679
36493
|
})
|
|
35680
36494
|
// ---------------------------------------------------------------------
|
|
35681
36495
|
// INSERT MENU ITEMS
|
|
@@ -35978,62 +36792,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35978
36792
|
}
|
|
35979
36793
|
const otRegistry = new OTRegistry();
|
|
35980
36794
|
|
|
35981
|
-
const CHECK_SVG = /*xml*/ `
|
|
35982
|
-
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'>
|
|
35983
|
-
<path fill='none' stroke='#FFF' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/>
|
|
35984
|
-
</svg>
|
|
35985
|
-
`;
|
|
35986
|
-
const CHECKBOX_WIDTH = 14;
|
|
35987
|
-
css /* scss */ `
|
|
35988
|
-
label.o-checkbox {
|
|
35989
|
-
input {
|
|
35990
|
-
appearance: none;
|
|
35991
|
-
-webkit-appearance: none;
|
|
35992
|
-
-moz-appearance: none;
|
|
35993
|
-
border-radius: 0;
|
|
35994
|
-
width: ${CHECKBOX_WIDTH}px;
|
|
35995
|
-
height: ${CHECKBOX_WIDTH}px;
|
|
35996
|
-
vertical-align: top;
|
|
35997
|
-
box-sizing: border-box;
|
|
35998
|
-
outline: none;
|
|
35999
|
-
border: 1px solid ${GRAY_300};
|
|
36000
|
-
|
|
36001
|
-
&:hover {
|
|
36002
|
-
border-color: ${ACTION_COLOR};
|
|
36003
|
-
}
|
|
36004
|
-
|
|
36005
|
-
&:checked {
|
|
36006
|
-
background: url("data:image/svg+xml,${encodeURIComponent(CHECK_SVG)}");
|
|
36007
|
-
background-color: ${ACTION_COLOR};
|
|
36008
|
-
border-color: ${ACTION_COLOR};
|
|
36009
|
-
}
|
|
36010
|
-
|
|
36011
|
-
&:focus {
|
|
36012
|
-
outline: none;
|
|
36013
|
-
box-shadow: 0 0 0 0.25rem rgba(113, 75, 103, 0.25);
|
|
36014
|
-
border-color: ${ACTION_COLOR};
|
|
36015
|
-
}
|
|
36016
|
-
}
|
|
36017
|
-
}
|
|
36018
|
-
`;
|
|
36019
|
-
class Checkbox extends owl.Component {
|
|
36020
|
-
static template = "o-spreadsheet.Checkbox";
|
|
36021
|
-
static props = {
|
|
36022
|
-
label: { type: String, optional: true },
|
|
36023
|
-
value: { type: Boolean, optional: true },
|
|
36024
|
-
className: { type: String, optional: true },
|
|
36025
|
-
name: { type: String, optional: true },
|
|
36026
|
-
title: { type: String, optional: true },
|
|
36027
|
-
disabled: { type: Boolean, optional: true },
|
|
36028
|
-
onChange: Function,
|
|
36029
|
-
};
|
|
36030
|
-
static defaultProps = { value: false };
|
|
36031
|
-
onChange(ev) {
|
|
36032
|
-
const value = ev.target.checked;
|
|
36033
|
-
this.props.onChange(value);
|
|
36034
|
-
}
|
|
36035
|
-
}
|
|
36036
|
-
|
|
36037
36795
|
class Section extends owl.Component {
|
|
36038
36796
|
static template = "o_spreadsheet.Section";
|
|
36039
36797
|
static props = {
|
|
@@ -37410,6 +38168,95 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37410
38168
|
}
|
|
37411
38169
|
}
|
|
37412
38170
|
|
|
38171
|
+
css /* scss */ `
|
|
38172
|
+
.o-font-size-editor {
|
|
38173
|
+
height: calc(100% - 4px);
|
|
38174
|
+
input.o-font-size {
|
|
38175
|
+
outline-color: ${SELECTION_BORDER_COLOR};
|
|
38176
|
+
height: 20px;
|
|
38177
|
+
width: 23px;
|
|
38178
|
+
}
|
|
38179
|
+
}
|
|
38180
|
+
.o-text-options > div {
|
|
38181
|
+
cursor: pointer;
|
|
38182
|
+
line-height: 26px;
|
|
38183
|
+
padding: 3px 12px;
|
|
38184
|
+
&:hover {
|
|
38185
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
38186
|
+
}
|
|
38187
|
+
}
|
|
38188
|
+
`;
|
|
38189
|
+
class FontSizeEditor extends owl.Component {
|
|
38190
|
+
static template = "o-spreadsheet-FontSizeEditor";
|
|
38191
|
+
static props = {
|
|
38192
|
+
currentFontSize: Number,
|
|
38193
|
+
onFontSizeChanged: Function,
|
|
38194
|
+
onToggle: { type: Function, optional: true },
|
|
38195
|
+
class: String,
|
|
38196
|
+
};
|
|
38197
|
+
static components = { Popover };
|
|
38198
|
+
fontSizes = FONT_SIZES;
|
|
38199
|
+
dropdown = owl.useState({ isOpen: false });
|
|
38200
|
+
inputRef = owl.useRef("inputFontSize");
|
|
38201
|
+
rootEditorRef = owl.useRef("FontSizeEditor");
|
|
38202
|
+
fontSizeListRef = owl.useRef("fontSizeList");
|
|
38203
|
+
setup() {
|
|
38204
|
+
owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
|
|
38205
|
+
}
|
|
38206
|
+
get popoverProps() {
|
|
38207
|
+
const { x, y, width, height } = this.rootEditorRef.el.getBoundingClientRect();
|
|
38208
|
+
return {
|
|
38209
|
+
anchorRect: { x, y, width, height },
|
|
38210
|
+
positioning: "BottomLeft",
|
|
38211
|
+
verticalOffset: 0,
|
|
38212
|
+
};
|
|
38213
|
+
}
|
|
38214
|
+
onExternalClick(ev) {
|
|
38215
|
+
if (!isChildEvent(this.fontSizeListRef.el, ev) && !isChildEvent(this.rootEditorRef.el, ev)) {
|
|
38216
|
+
this.closeFontList();
|
|
38217
|
+
}
|
|
38218
|
+
}
|
|
38219
|
+
toggleFontList() {
|
|
38220
|
+
const isOpen = this.dropdown.isOpen;
|
|
38221
|
+
if (!isOpen) {
|
|
38222
|
+
this.props.onToggle?.();
|
|
38223
|
+
this.inputRef.el.focus();
|
|
38224
|
+
}
|
|
38225
|
+
else {
|
|
38226
|
+
this.closeFontList();
|
|
38227
|
+
}
|
|
38228
|
+
}
|
|
38229
|
+
closeFontList() {
|
|
38230
|
+
this.dropdown.isOpen = false;
|
|
38231
|
+
}
|
|
38232
|
+
setSize(fontSizeStr) {
|
|
38233
|
+
const fontSize = clip(Math.floor(parseFloat(fontSizeStr)), 1, 400);
|
|
38234
|
+
this.props.onFontSizeChanged(fontSize);
|
|
38235
|
+
this.closeFontList();
|
|
38236
|
+
}
|
|
38237
|
+
setSizeFromInput(ev) {
|
|
38238
|
+
this.setSize(ev.target.value);
|
|
38239
|
+
}
|
|
38240
|
+
setSizeFromList(fontSizeStr) {
|
|
38241
|
+
this.setSize(fontSizeStr);
|
|
38242
|
+
}
|
|
38243
|
+
onInputFocused(ev) {
|
|
38244
|
+
this.dropdown.isOpen = true;
|
|
38245
|
+
ev.target.select();
|
|
38246
|
+
}
|
|
38247
|
+
onInputKeydown(ev) {
|
|
38248
|
+
if (ev.key === "Enter" || ev.key === "Escape") {
|
|
38249
|
+
this.closeFontList();
|
|
38250
|
+
const target = ev.target;
|
|
38251
|
+
// In the case of a ESCAPE key, we get the previous font size back
|
|
38252
|
+
if (ev.key === "Escape") {
|
|
38253
|
+
target.value = `${this.props.currentFontSize}`;
|
|
38254
|
+
}
|
|
38255
|
+
this.props.onToggle?.();
|
|
38256
|
+
}
|
|
38257
|
+
}
|
|
38258
|
+
}
|
|
38259
|
+
|
|
37413
38260
|
css /* scss */ `
|
|
37414
38261
|
.o-chart-title-designer {
|
|
37415
38262
|
> span {
|
|
@@ -37444,7 +38291,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37444
38291
|
`;
|
|
37445
38292
|
class ChartTitle extends owl.Component {
|
|
37446
38293
|
static template = "o-spreadsheet.ChartTitle";
|
|
37447
|
-
static components = { Section, ColorPickerWidget };
|
|
38294
|
+
static components = { Section, ColorPickerWidget, FontSizeEditor };
|
|
37448
38295
|
static props = {
|
|
37449
38296
|
title: { type: String, optional: true },
|
|
37450
38297
|
updateTitle: Function,
|
|
@@ -37453,7 +38300,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37453
38300
|
toggleBold: { type: Function, optional: true },
|
|
37454
38301
|
updateAlignment: { type: Function, optional: true },
|
|
37455
38302
|
updateColor: { type: Function, optional: true },
|
|
37456
|
-
style:
|
|
38303
|
+
style: Object,
|
|
38304
|
+
onFontSizeChanged: Function,
|
|
37457
38305
|
};
|
|
37458
38306
|
static defaultProps = {
|
|
37459
38307
|
title: "",
|
|
@@ -37468,6 +38316,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37468
38316
|
updateTitle(ev) {
|
|
37469
38317
|
this.props.updateTitle(ev.target.value);
|
|
37470
38318
|
}
|
|
38319
|
+
updateFontSize(fontSize) {
|
|
38320
|
+
this.props.onFontSizeChanged(fontSize);
|
|
38321
|
+
}
|
|
37471
38322
|
toggleDropdownTool(tool, ev) {
|
|
37472
38323
|
const isOpen = this.state.activeTool === tool;
|
|
37473
38324
|
this.closeMenus();
|
|
@@ -37510,6 +38361,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37510
38361
|
return {
|
|
37511
38362
|
color: "",
|
|
37512
38363
|
align: "center",
|
|
38364
|
+
fontSize: CHART_AXIS_TITLE_FONT_SIZE,
|
|
37513
38365
|
...axisDesign.title,
|
|
37514
38366
|
};
|
|
37515
38367
|
}
|
|
@@ -37527,6 +38379,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37527
38379
|
};
|
|
37528
38380
|
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
37529
38381
|
}
|
|
38382
|
+
updateAxisTitleFontSize(fontSize) {
|
|
38383
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
38384
|
+
axesDesign[this.state.currentAxis] = {
|
|
38385
|
+
...axesDesign[this.state.currentAxis],
|
|
38386
|
+
title: {
|
|
38387
|
+
...(axesDesign[this.state.currentAxis]?.title ?? {}),
|
|
38388
|
+
fontSize,
|
|
38389
|
+
},
|
|
38390
|
+
};
|
|
38391
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
38392
|
+
}
|
|
37530
38393
|
toggleBoldAxisTitle() {
|
|
37531
38394
|
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
37532
38395
|
const title = axesDesign[this.state.currentAxis]?.title ?? {};
|
|
@@ -37646,8 +38509,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37646
38509
|
figureId: String,
|
|
37647
38510
|
definition: Object,
|
|
37648
38511
|
updateChart: Function,
|
|
38512
|
+
defaultChartTitleFontSize: { type: Number, optional: true },
|
|
37649
38513
|
slots: { type: Object, optional: true },
|
|
37650
38514
|
};
|
|
38515
|
+
static defaultProps = {
|
|
38516
|
+
defaultChartTitleFontSize: CHART_TITLE_FONT_SIZE,
|
|
38517
|
+
};
|
|
37651
38518
|
state;
|
|
37652
38519
|
setup() {
|
|
37653
38520
|
this.state = owl.useState({
|
|
@@ -37673,6 +38540,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37673
38540
|
get titleStyle() {
|
|
37674
38541
|
return {
|
|
37675
38542
|
align: "left",
|
|
38543
|
+
fontSize: this.props.defaultChartTitleFontSize,
|
|
37676
38544
|
...this.title,
|
|
37677
38545
|
};
|
|
37678
38546
|
}
|
|
@@ -37681,6 +38549,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37681
38549
|
this.props.updateChart(this.props.figureId, { title });
|
|
37682
38550
|
this.state.activeTool = "";
|
|
37683
38551
|
}
|
|
38552
|
+
updateChartTitleFontSize(fontSize) {
|
|
38553
|
+
const title = { ...this.title, fontSize };
|
|
38554
|
+
this.props.updateChart(this.props.figureId, { title });
|
|
38555
|
+
}
|
|
37684
38556
|
toggleBoldChartTitle() {
|
|
37685
38557
|
let title = this.title;
|
|
37686
38558
|
title = { ...title, bold: !title.bold };
|
|
@@ -37888,7 +38760,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
37888
38760
|
case "polynomial":
|
|
37889
38761
|
config = {
|
|
37890
38762
|
type: "polynomial",
|
|
37891
|
-
order: type === "linear" ? 1 :
|
|
38763
|
+
order: type === "linear" ? 1 : this.getMaxPolynomialDegree(index),
|
|
37892
38764
|
};
|
|
37893
38765
|
break;
|
|
37894
38766
|
case "exponential":
|
|
@@ -38159,6 +39031,104 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38159
39031
|
}
|
|
38160
39032
|
}
|
|
38161
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
|
+
|
|
38162
39132
|
class LineConfigPanel extends GenericChartConfigPanel {
|
|
38163
39133
|
static template = "o-spreadsheet-LineConfigPanel";
|
|
38164
39134
|
get canTreatLabelsAsText() {
|
|
@@ -38348,6 +39318,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38348
39318
|
get humanizeNumbersLabel() {
|
|
38349
39319
|
return _t("Humanize numbers");
|
|
38350
39320
|
}
|
|
39321
|
+
get defaultScorecardTitleFontSize() {
|
|
39322
|
+
return SCORECARD_CHART_TITLE_FONT_SIZE;
|
|
39323
|
+
}
|
|
38351
39324
|
updateHumanizeNumbers(humanize) {
|
|
38352
39325
|
this.props.updateChart(this.props.figureId, { humanize });
|
|
38353
39326
|
}
|
|
@@ -38469,6 +39442,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38469
39442
|
.add("radar", {
|
|
38470
39443
|
configuration: GenericChartConfigPanel,
|
|
38471
39444
|
design: RadarChartDesignPanel,
|
|
39445
|
+
})
|
|
39446
|
+
.add("geo", {
|
|
39447
|
+
configuration: GeoChartConfigPanel,
|
|
39448
|
+
design: GeoChartDesignPanel,
|
|
38472
39449
|
});
|
|
38473
39450
|
|
|
38474
39451
|
css /* scss */ `
|
|
@@ -39811,6 +40788,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
39811
40788
|
confirmEdition(content) {
|
|
39812
40789
|
this.args().onConfirm(content);
|
|
39813
40790
|
}
|
|
40791
|
+
getTokenColor(token) {
|
|
40792
|
+
if (token.type === "SYMBOL") {
|
|
40793
|
+
const matchedColor = this.args().getContextualColoredSymbolToken?.(token);
|
|
40794
|
+
if (matchedColor) {
|
|
40795
|
+
return matchedColor;
|
|
40796
|
+
}
|
|
40797
|
+
}
|
|
40798
|
+
return super.getTokenColor(token);
|
|
40799
|
+
}
|
|
39814
40800
|
}
|
|
39815
40801
|
|
|
39816
40802
|
css /* scss */ `
|
|
@@ -39823,7 +40809,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
39823
40809
|
border-color: ${GRAY_300};
|
|
39824
40810
|
|
|
39825
40811
|
&.active {
|
|
39826
|
-
border-color: ${
|
|
40812
|
+
border-color: ${ACTION_COLOR};
|
|
39827
40813
|
}
|
|
39828
40814
|
|
|
39829
40815
|
&.o-invalid {
|
|
@@ -39848,6 +40834,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
39848
40834
|
placeholder: { type: String, optional: true },
|
|
39849
40835
|
class: { type: String, optional: true },
|
|
39850
40836
|
invalid: { type: Boolean, optional: true },
|
|
40837
|
+
getContextualColoredSymbolToken: { type: Function, optional: true },
|
|
39851
40838
|
};
|
|
39852
40839
|
static components = { Composer };
|
|
39853
40840
|
static defaultProps = {
|
|
@@ -39864,6 +40851,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
39864
40851
|
content: this.props.composerContent,
|
|
39865
40852
|
contextualAutocomplete: this.props.contextualAutocomplete,
|
|
39866
40853
|
defaultRangeSheetId: this.props.defaultRangeSheetId,
|
|
40854
|
+
getContextualColoredSymbolToken: this.props.getContextualColoredSymbolToken,
|
|
39867
40855
|
}));
|
|
39868
40856
|
this.standaloneComposerStore = standaloneComposerStore;
|
|
39869
40857
|
this.composerInterface = {
|
|
@@ -40779,7 +41767,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40779
41767
|
}
|
|
40780
41768
|
const point = this.state.rules.colorScale[target];
|
|
40781
41769
|
if (point) {
|
|
40782
|
-
point.color =
|
|
41770
|
+
point.color = colorToNumber(color);
|
|
40783
41771
|
}
|
|
40784
41772
|
this.updateConditionalFormat({ rule: this.state.rules.colorScale });
|
|
40785
41773
|
this.closeMenus();
|
|
@@ -40924,6 +41912,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40924
41912
|
return [this.state.rules.dataBar.rangeValues || ""];
|
|
40925
41913
|
}
|
|
40926
41914
|
updateDataBarColor(color) {
|
|
41915
|
+
if (!isColorValid(color)) {
|
|
41916
|
+
return;
|
|
41917
|
+
}
|
|
40927
41918
|
this.state.rules.dataBar.color = Number.parseInt(color.slice(1), 16);
|
|
40928
41919
|
this.updateConditionalFormat({ rule: this.state.rules.dataBar });
|
|
40929
41920
|
}
|
|
@@ -43424,7 +44415,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43424
44415
|
return {
|
|
43425
44416
|
text: text,
|
|
43426
44417
|
description: measure.displayName,
|
|
43427
|
-
htmlContent: [{ value: text, color:
|
|
44418
|
+
htmlContent: [{ value: text, color: PIVOT_TOKEN_COLOR }],
|
|
43428
44419
|
fuzzySearchKey: measure.displayName + text + measure.fieldName,
|
|
43429
44420
|
};
|
|
43430
44421
|
});
|
|
@@ -43433,7 +44424,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43433
44424
|
return {
|
|
43434
44425
|
text: text,
|
|
43435
44426
|
description: dimension.displayName,
|
|
43436
|
-
htmlContent: [{ value: text, color:
|
|
44427
|
+
htmlContent: [{ value: text, color: PIVOT_TOKEN_COLOR }],
|
|
43437
44428
|
fuzzySearchKey: dimension.displayName + text + dimension.fieldName,
|
|
43438
44429
|
};
|
|
43439
44430
|
});
|
|
@@ -43513,6 +44504,76 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43513
44504
|
measure: this.props.measure,
|
|
43514
44505
|
});
|
|
43515
44506
|
}
|
|
44507
|
+
getColoredSymbolToken(token) {
|
|
44508
|
+
if (token.type !== "SYMBOL") {
|
|
44509
|
+
return undefined;
|
|
44510
|
+
}
|
|
44511
|
+
const tokenValue = unquote(token.value, "'");
|
|
44512
|
+
if (this.props.definition.columns.some((col) => col.nameWithGranularity === tokenValue) ||
|
|
44513
|
+
this.props.definition.rows.some((row) => row.nameWithGranularity === tokenValue) ||
|
|
44514
|
+
this.props.definition.measures.some((measure) => measure.id === tokenValue && measure.id !== this.props.measure.id)) {
|
|
44515
|
+
return PIVOT_TOKEN_COLOR;
|
|
44516
|
+
}
|
|
44517
|
+
return undefined;
|
|
44518
|
+
}
|
|
44519
|
+
}
|
|
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
|
+
}
|
|
43516
44577
|
}
|
|
43517
44578
|
|
|
43518
44579
|
css /* scss */ `
|
|
@@ -43528,6 +44589,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43528
44589
|
PivotDimensionOrder,
|
|
43529
44590
|
PivotDimensionGranularity,
|
|
43530
44591
|
PivotMeasureEditor,
|
|
44592
|
+
PivotSortSection,
|
|
43531
44593
|
};
|
|
43532
44594
|
static props = {
|
|
43533
44595
|
definition: Object,
|
|
@@ -43684,9 +44746,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43684
44746
|
}
|
|
43685
44747
|
updateMeasure(measure, newMeasure) {
|
|
43686
44748
|
const { measures } = this.props.definition;
|
|
43687
|
-
|
|
44749
|
+
const update = {
|
|
43688
44750
|
measures: measures.map((m) => (m.id === measure.id ? newMeasure : m)),
|
|
43689
|
-
}
|
|
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);
|
|
43690
44756
|
}
|
|
43691
44757
|
getMeasureId(fieldName, aggregator) {
|
|
43692
44758
|
const baseId = fieldName + (aggregator ? `:${aggregator}` : "");
|
|
@@ -43842,10 +44908,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43842
44908
|
measures;
|
|
43843
44909
|
columns;
|
|
43844
44910
|
rows;
|
|
44911
|
+
sortedColumn;
|
|
43845
44912
|
constructor(definition, fields) {
|
|
43846
44913
|
this.measures = definition.measures.map((measure) => createMeasure(fields, measure));
|
|
43847
44914
|
this.columns = definition.columns.map((dimension) => createPivotDimension(fields, dimension));
|
|
43848
44915
|
this.rows = definition.rows.map((dimension) => createPivotDimension(fields, dimension));
|
|
44916
|
+
this.sortedColumn = definition.sortedColumn;
|
|
43849
44917
|
}
|
|
43850
44918
|
getDimension(nameWithGranularity) {
|
|
43851
44919
|
const dimension = this.columns.find((d) => d.nameWithGranularity === nameWithGranularity) ||
|
|
@@ -43999,6 +45067,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43999
45067
|
pivotCells = {};
|
|
44000
45068
|
rowTree;
|
|
44001
45069
|
colTree;
|
|
45070
|
+
isSorted = false;
|
|
44002
45071
|
constructor(columns, rows, measures, fieldsType) {
|
|
44003
45072
|
this.columns = columns.map((row) => {
|
|
44004
45073
|
// offset in the pivot table
|
|
@@ -44172,6 +45241,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44172
45241
|
value,
|
|
44173
45242
|
field: row.fields[rowDepth],
|
|
44174
45243
|
children: [],
|
|
45244
|
+
type: this.fieldsType[fieldName] || "char",
|
|
44175
45245
|
width: 0, // not used
|
|
44176
45246
|
};
|
|
44177
45247
|
treesAtDepth[depth].push(node);
|
|
@@ -44194,6 +45264,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44194
45264
|
field: leaf.fields[depth],
|
|
44195
45265
|
children: [],
|
|
44196
45266
|
width: leaf.width,
|
|
45267
|
+
type: this.fieldsType[fieldName] || "char",
|
|
44197
45268
|
};
|
|
44198
45269
|
if (treesAtDepth[depth]?.at(-1)?.value !== value) {
|
|
44199
45270
|
treesAtDepth[depth + 1] = [];
|
|
@@ -44212,6 +45283,35 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44212
45283
|
fieldsType: this.fieldsType,
|
|
44213
45284
|
};
|
|
44214
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
|
+
}
|
|
44215
45315
|
}
|
|
44216
45316
|
const EMPTY_PIVOT_CELL = { type: "EMPTY" };
|
|
44217
45317
|
|
|
@@ -44289,6 +45389,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44289
45389
|
value: groups[key]?.[0]?.[column.nameWithGranularity]?.value ?? null,
|
|
44290
45390
|
field: colName,
|
|
44291
45391
|
children: dataEntriesToColumnsTree(groups[key] || [], columns, index + 1),
|
|
45392
|
+
type: column.type,
|
|
44292
45393
|
width: 0,
|
|
44293
45394
|
};
|
|
44294
45395
|
});
|
|
@@ -45154,6 +46255,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45154
46255
|
format: measure.format,
|
|
45155
46256
|
display: measure.display,
|
|
45156
46257
|
})),
|
|
46258
|
+
sortedColumn: this.shouldKeepSortedColumn(definition) ? definition.sortedColumn : undefined,
|
|
45157
46259
|
};
|
|
45158
46260
|
if (!this.draft && deepEquals(coreDefinition, cleanedDefinition)) {
|
|
45159
46261
|
return;
|
|
@@ -45212,6 +46314,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45212
46314
|
}
|
|
45213
46315
|
return granularitiesPerFields;
|
|
45214
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
|
+
}
|
|
45215
46330
|
}
|
|
45216
46331
|
|
|
45217
46332
|
class PivotSpreadsheetSidePanel extends owl.Component {
|
|
@@ -46313,6 +47428,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46313
47428
|
}
|
|
46314
47429
|
}
|
|
46315
47430
|
`;
|
|
47431
|
+
const DEFAULT_TABLE_STYLE_COLOR = "#3C78D8";
|
|
46316
47432
|
class TableStyleEditorPanel extends owl.Component {
|
|
46317
47433
|
static template = "o-spreadsheet-TableStyleEditorPanel";
|
|
46318
47434
|
static components = { Section, RoundColorPicker, TableStylePreview };
|
|
@@ -46331,7 +47447,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46331
47447
|
: null;
|
|
46332
47448
|
return {
|
|
46333
47449
|
pickerOpened: false,
|
|
46334
|
-
primaryColor: editedStyle?.primaryColor ||
|
|
47450
|
+
primaryColor: editedStyle?.primaryColor || DEFAULT_TABLE_STYLE_COLOR,
|
|
46335
47451
|
selectedTemplateName: editedStyle?.templateName || "lightColoredText",
|
|
46336
47452
|
styleName: editedStyle?.displayName || this.env.model.getters.getNewCustomTableStyleName(),
|
|
46337
47453
|
};
|
|
@@ -46340,7 +47456,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46340
47456
|
this.state.pickerOpened = !this.state.pickerOpened;
|
|
46341
47457
|
}
|
|
46342
47458
|
onColorPicked(color) {
|
|
46343
|
-
this.state.primaryColor = color;
|
|
47459
|
+
this.state.primaryColor = isColorValid(color) ? color : DEFAULT_TABLE_STYLE_COLOR;
|
|
46344
47460
|
this.state.pickerOpened = false;
|
|
46345
47461
|
}
|
|
46346
47462
|
onTemplatePicked(templateName) {
|
|
@@ -47956,6 +49072,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47956
49072
|
draggedFigure: undefined,
|
|
47957
49073
|
horizontalSnap: undefined,
|
|
47958
49074
|
verticalSnap: undefined,
|
|
49075
|
+
cancelDnd: undefined,
|
|
47959
49076
|
});
|
|
47960
49077
|
setup() {
|
|
47961
49078
|
owl.onMounted(() => {
|
|
@@ -47968,12 +49085,28 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47968
49085
|
// new rendering
|
|
47969
49086
|
this.render();
|
|
47970
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
|
+
});
|
|
47971
49101
|
}
|
|
47972
49102
|
getVisibleFigures() {
|
|
47973
49103
|
const visibleFigures = this.env.model.getters.getVisibleFigures();
|
|
47974
49104
|
if (this.dnd.draggedFigure &&
|
|
47975
49105
|
!visibleFigures.some((figure) => figure.id === this.dnd.draggedFigure?.id)) {
|
|
47976
|
-
|
|
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
|
+
}
|
|
47977
49110
|
}
|
|
47978
49111
|
return visibleFigures;
|
|
47979
49112
|
}
|
|
@@ -48092,7 +49225,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48092
49225
|
this.dnd.verticalSnap = undefined;
|
|
48093
49226
|
this.env.model.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x, y });
|
|
48094
49227
|
};
|
|
48095
|
-
startDnd(onMouseMove, onMouseUp);
|
|
49228
|
+
this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
|
|
48096
49229
|
}
|
|
48097
49230
|
/**
|
|
48098
49231
|
* Initialize the resize of a figure with mouse movements
|
|
@@ -48140,7 +49273,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48140
49273
|
this.dnd.horizontalSnap = undefined;
|
|
48141
49274
|
this.dnd.verticalSnap = undefined;
|
|
48142
49275
|
};
|
|
48143
|
-
startDnd(onMouseMove, onMouseUp);
|
|
49276
|
+
this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
|
|
48144
49277
|
}
|
|
48145
49278
|
getOtherFigures(figId) {
|
|
48146
49279
|
return this.getVisibleFigures().filter((f) => f.id !== figId);
|
|
@@ -49247,9 +50380,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49247
50380
|
class GridRenderer {
|
|
49248
50381
|
getters;
|
|
49249
50382
|
renderer;
|
|
50383
|
+
fingerprints;
|
|
49250
50384
|
constructor(get) {
|
|
49251
50385
|
this.getters = get(ModelStore).getters;
|
|
49252
50386
|
this.renderer = get(RendererStore);
|
|
50387
|
+
this.fingerprints = get(FormulaFingerprintStore);
|
|
49253
50388
|
this.renderer.register(this);
|
|
49254
50389
|
}
|
|
49255
50390
|
get renderingLayers() {
|
|
@@ -49727,14 +50862,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49727
50862
|
const showFormula = this.getters.shouldShowFormulas();
|
|
49728
50863
|
const { x, y, width, height } = this.getters.getVisibleRect(zone);
|
|
49729
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);
|
|
49730
50873
|
const box = {
|
|
49731
50874
|
x,
|
|
49732
50875
|
y,
|
|
49733
50876
|
width,
|
|
49734
50877
|
height,
|
|
49735
50878
|
border: this.getters.getCellComputedBorder(position) || undefined,
|
|
49736
|
-
style
|
|
49737
|
-
dataBarFill
|
|
50879
|
+
style,
|
|
50880
|
+
dataBarFill,
|
|
49738
50881
|
verticalAlign,
|
|
49739
50882
|
isError: (cell.type === CellValueType.error && !!cell.message) ||
|
|
49740
50883
|
this.getters.isDataValidationInvalid(position),
|
|
@@ -49759,7 +50902,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49759
50902
|
box.hasIcon = this.getters.doesCellHaveGridIcon(position);
|
|
49760
50903
|
const headerIconWidth = box.hasIcon ? GRID_ICON_EDGE_LENGTH + GRID_ICON_MARGIN : 0;
|
|
49761
50904
|
/** Content */
|
|
49762
|
-
const style = this.getters.getCellComputedStyle(position);
|
|
49763
50905
|
const wrapping = style.wrapping || "overflow";
|
|
49764
50906
|
const wrapText = wrapping === "wrap" && !showFormula;
|
|
49765
50907
|
const maxWidth = width - 2 * MIN_CELL_TEXT_MARGIN;
|
|
@@ -51737,62 +52879,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51737
52879
|
}
|
|
51738
52880
|
}
|
|
51739
52881
|
|
|
51740
|
-
class PositionMap {
|
|
51741
|
-
map = {};
|
|
51742
|
-
constructor(entries = []) {
|
|
51743
|
-
for (const [position, value] of entries) {
|
|
51744
|
-
this.set(position, value);
|
|
51745
|
-
}
|
|
51746
|
-
}
|
|
51747
|
-
set({ sheetId, col, row }, value) {
|
|
51748
|
-
const map = this.map;
|
|
51749
|
-
if (!map[sheetId]) {
|
|
51750
|
-
map[sheetId] = {};
|
|
51751
|
-
}
|
|
51752
|
-
if (!map[sheetId][col]) {
|
|
51753
|
-
map[sheetId][col] = {};
|
|
51754
|
-
}
|
|
51755
|
-
map[sheetId][col][row] = value;
|
|
51756
|
-
}
|
|
51757
|
-
get({ sheetId, col, row }) {
|
|
51758
|
-
return this.map[sheetId]?.[col]?.[row];
|
|
51759
|
-
}
|
|
51760
|
-
getSheet(sheetId) {
|
|
51761
|
-
return this.map[sheetId];
|
|
51762
|
-
}
|
|
51763
|
-
has({ sheetId, col, row }) {
|
|
51764
|
-
return this.map[sheetId]?.[col]?.[row] !== undefined;
|
|
51765
|
-
}
|
|
51766
|
-
delete({ sheetId, col, row }) {
|
|
51767
|
-
delete this.map[sheetId]?.[col]?.[row];
|
|
51768
|
-
}
|
|
51769
|
-
keys() {
|
|
51770
|
-
const map = this.map;
|
|
51771
|
-
const keys = [];
|
|
51772
|
-
for (const sheetId in map) {
|
|
51773
|
-
for (const col in map[sheetId]) {
|
|
51774
|
-
for (const row in map[sheetId][col]) {
|
|
51775
|
-
keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
|
|
51776
|
-
}
|
|
51777
|
-
}
|
|
51778
|
-
}
|
|
51779
|
-
return keys;
|
|
51780
|
-
}
|
|
51781
|
-
keysForSheet(sheetId) {
|
|
51782
|
-
const map = this.map[sheetId];
|
|
51783
|
-
if (!map) {
|
|
51784
|
-
return [];
|
|
51785
|
-
}
|
|
51786
|
-
const keys = [];
|
|
51787
|
-
for (const col in map) {
|
|
51788
|
-
for (const row in map[col]) {
|
|
51789
|
-
keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
|
|
51790
|
-
}
|
|
51791
|
-
}
|
|
51792
|
-
return keys;
|
|
51793
|
-
}
|
|
51794
|
-
}
|
|
51795
|
-
|
|
51796
52882
|
/**
|
|
51797
52883
|
* Core Plugin
|
|
51798
52884
|
*
|
|
@@ -51887,7 +52973,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51887
52973
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
51888
52974
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
51889
52975
|
const cell = this.getters.getCell({ sheetId, col, row });
|
|
51890
|
-
if (cell) {
|
|
52976
|
+
if (cell?.isFormula || cell?.content) {
|
|
51891
52977
|
this.dispatch("UPDATE_CELL", {
|
|
51892
52978
|
sheetId: sheetId,
|
|
51893
52979
|
content: "",
|
|
@@ -51923,7 +53009,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51923
53009
|
for (let zone of recomputeZones(zones)) {
|
|
51924
53010
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
51925
53011
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
51926
|
-
// commandHelpers.updateCell(sheetId, col, row, { style: undefined});
|
|
51927
53012
|
this.dispatch("UPDATE_CELL", {
|
|
51928
53013
|
sheetId,
|
|
51929
53014
|
col,
|
|
@@ -52232,7 +53317,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52232
53317
|
const before = this.getters.getCell({ sheetId, col, row });
|
|
52233
53318
|
const hasContent = "content" in after || "formula" in after;
|
|
52234
53319
|
// Compute the new cell properties
|
|
52235
|
-
const afterContent = hasContent ?
|
|
53320
|
+
const afterContent = hasContent ? replaceNewLines(after?.content) : before?.content || "";
|
|
52236
53321
|
let style;
|
|
52237
53322
|
if (after.style !== undefined) {
|
|
52238
53323
|
style = after.style || undefined;
|
|
@@ -55177,6 +56262,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55177
56262
|
};
|
|
55178
56263
|
}
|
|
55179
56264
|
getUnboundedZone(sheetId, zone) {
|
|
56265
|
+
if (zone.bottom === undefined || zone.right === undefined) {
|
|
56266
|
+
return zone;
|
|
56267
|
+
}
|
|
55180
56268
|
const isFullRow = zone.left === 0 && zone.right === this.getNumberCols(sheetId) - 1;
|
|
55181
56269
|
const isFullCol = zone.top === 0 && zone.bottom === this.getNumberRows(sheetId) - 1;
|
|
55182
56270
|
return {
|
|
@@ -55342,7 +56430,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55342
56430
|
if (orderedSheetIds.find((id) => sheets[id]?.name.toLowerCase() === name && id !== cmd.sheetId)) {
|
|
55343
56431
|
return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
|
|
55344
56432
|
}
|
|
55345
|
-
if (
|
|
56433
|
+
if (FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX.test(name)) {
|
|
55346
56434
|
return "ForbiddenCharactersInSheetName" /* CommandResult.ForbiddenCharactersInSheetName */;
|
|
55347
56435
|
}
|
|
55348
56436
|
return "Success" /* CommandResult.Success */;
|
|
@@ -59460,66 +60548,25 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
59460
60548
|
return;
|
|
59461
60549
|
}
|
|
59462
60550
|
const zone = this.getters.getRangeFromSheetXC(sheetId, range).zone;
|
|
59463
|
-
const
|
|
60551
|
+
const colorThresholds = [{ value: minValue, color: rule.minimum.color }];
|
|
59464
60552
|
if (rule.midpoint && midValue) {
|
|
59465
|
-
|
|
59466
|
-
minValue,
|
|
59467
|
-
minColor: rule.minimum.color,
|
|
59468
|
-
colorDiffUnit: this.computeColorDiffUnits(minValue, midValue, rule.minimum.color, rule.midpoint.color),
|
|
59469
|
-
});
|
|
59470
|
-
colorCellArgs.push({
|
|
59471
|
-
minValue: midValue,
|
|
59472
|
-
minColor: rule.midpoint.color,
|
|
59473
|
-
colorDiffUnit: this.computeColorDiffUnits(midValue, maxValue, rule.midpoint.color, rule.maximum.color),
|
|
59474
|
-
});
|
|
59475
|
-
}
|
|
59476
|
-
else {
|
|
59477
|
-
colorCellArgs.push({
|
|
59478
|
-
minValue,
|
|
59479
|
-
minColor: rule.minimum.color,
|
|
59480
|
-
colorDiffUnit: this.computeColorDiffUnits(minValue, maxValue, rule.minimum.color, rule.maximum.color),
|
|
59481
|
-
});
|
|
60553
|
+
colorThresholds.push({ value: midValue, color: rule.midpoint.color });
|
|
59482
60554
|
}
|
|
60555
|
+
colorThresholds.push({ value: maxValue, color: rule.maximum.color });
|
|
60556
|
+
const colorScale = getColorScale(colorThresholds);
|
|
59483
60557
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
59484
60558
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
59485
60559
|
const cell = this.getters.getEvaluatedCell({ sheetId, col, row });
|
|
59486
60560
|
if (cell.type === CellValueType.number) {
|
|
59487
60561
|
const value = clip(cell.value, minValue, maxValue);
|
|
59488
|
-
let color;
|
|
59489
|
-
if (colorCellArgs.length === 2 && midValue) {
|
|
59490
|
-
color =
|
|
59491
|
-
value <= midValue
|
|
59492
|
-
? this.colorCell(value, colorCellArgs[0].minValue, colorCellArgs[0].minColor, colorCellArgs[0].colorDiffUnit)
|
|
59493
|
-
: this.colorCell(value, colorCellArgs[1].minValue, colorCellArgs[1].minColor, colorCellArgs[1].colorDiffUnit);
|
|
59494
|
-
}
|
|
59495
|
-
else {
|
|
59496
|
-
color = this.colorCell(value, colorCellArgs[0].minValue, colorCellArgs[0].minColor, colorCellArgs[0].colorDiffUnit);
|
|
59497
|
-
}
|
|
59498
60562
|
if (!computedStyle[col])
|
|
59499
60563
|
computedStyle[col] = [];
|
|
59500
60564
|
computedStyle[col][row] = computedStyle[col]?.[row] || {};
|
|
59501
|
-
computedStyle[col][row].fillColor =
|
|
60565
|
+
computedStyle[col][row].fillColor = colorScale(value);
|
|
59502
60566
|
}
|
|
59503
60567
|
}
|
|
59504
60568
|
}
|
|
59505
60569
|
}
|
|
59506
|
-
computeColorDiffUnits(minValue, maxValue, minColor, maxColor) {
|
|
59507
|
-
const deltaValue = maxValue - minValue;
|
|
59508
|
-
const deltaColorR = ((minColor >> 16) % 256) - ((maxColor >> 16) % 256);
|
|
59509
|
-
const deltaColorG = ((minColor >> 8) % 256) - ((maxColor >> 8) % 256);
|
|
59510
|
-
const deltaColorB = (minColor % 256) - (maxColor % 256);
|
|
59511
|
-
const colorDiffUnitR = deltaColorR / deltaValue;
|
|
59512
|
-
const colorDiffUnitG = deltaColorG / deltaValue;
|
|
59513
|
-
const colorDiffUnitB = deltaColorB / deltaValue;
|
|
59514
|
-
return [colorDiffUnitR, colorDiffUnitG, colorDiffUnitB];
|
|
59515
|
-
}
|
|
59516
|
-
colorCell(value, minValue, minColor, colorDiffUnit) {
|
|
59517
|
-
const [colorDiffUnitR, colorDiffUnitG, colorDiffUnitB] = colorDiffUnit;
|
|
59518
|
-
const r = Math.round(((minColor >> 16) % 256) - colorDiffUnitR * (value - minValue));
|
|
59519
|
-
const g = Math.round(((minColor >> 8) % 256) - colorDiffUnitG * (value - minValue));
|
|
59520
|
-
const b = Math.round((minColor % 256) - colorDiffUnitB * (value - minValue));
|
|
59521
|
-
return (r << 16) | (g << 8) | b;
|
|
59522
|
-
}
|
|
59523
60570
|
/**
|
|
59524
60571
|
* Execute the predicate to know if a conditional formatting rule should be applied to a cell
|
|
59525
60572
|
*/
|
|
@@ -60145,7 +61192,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60145
61192
|
}
|
|
60146
61193
|
getValuesToAggregate(measure, domain) {
|
|
60147
61194
|
const { rowDomain, colDomain } = domainToColRowDomain(this, domain);
|
|
60148
|
-
const table =
|
|
61195
|
+
const table = super.getTableStructure();
|
|
60149
61196
|
const values = [];
|
|
60150
61197
|
if (colDomain.length === 0 &&
|
|
60151
61198
|
rowDomain.length < this.definition.rows.length &&
|
|
@@ -60579,6 +61626,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60579
61626
|
}
|
|
60580
61627
|
throw new Error(`Value ${result.value} is not a number`);
|
|
60581
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
|
+
}
|
|
60582
61644
|
}
|
|
60583
61645
|
return PivotPresentationLayer;
|
|
60584
61646
|
}
|
|
@@ -60750,11 +61812,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60750
61812
|
return EMPTY_PIVOT_CELL;
|
|
60751
61813
|
}
|
|
60752
61814
|
if (functionName === "PIVOT") {
|
|
60753
|
-
const includeTotal = args[2]
|
|
60754
|
-
const
|
|
61815
|
+
const includeTotal = toScalar(args[2]);
|
|
61816
|
+
const shouldIncludeTotal = includeTotal === undefined ? true : toBoolean(includeTotal);
|
|
61817
|
+
const includeColumnHeaders = toScalar(args[3]);
|
|
61818
|
+
const shouldIncludeColumnHeaders = includeColumnHeaders === undefined ? true : toBoolean(includeColumnHeaders);
|
|
60755
61819
|
const pivotCells = pivot
|
|
60756
61820
|
.getTableStructure()
|
|
60757
|
-
.getPivotCells(
|
|
61821
|
+
.getPivotCells(shouldIncludeTotal, shouldIncludeColumnHeaders);
|
|
60758
61822
|
const pivotCol = position.col - mainPosition.col;
|
|
60759
61823
|
const pivotRow = position.row - mainPosition.row;
|
|
60760
61824
|
return pivotCells[pivotCol][pivotRow];
|
|
@@ -62352,23 +63416,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62352
63416
|
}
|
|
62353
63417
|
}
|
|
62354
63418
|
|
|
62355
|
-
function randomChoice(arr) {
|
|
62356
|
-
return arr[Math.floor(Math.random() * arr.length)];
|
|
62357
|
-
}
|
|
62358
|
-
const colors = [
|
|
62359
|
-
"#ff851b",
|
|
62360
|
-
"#0074d9",
|
|
62361
|
-
"#7fdbff",
|
|
62362
|
-
"#b10dc9",
|
|
62363
|
-
"#39cccc",
|
|
62364
|
-
"#f012be",
|
|
62365
|
-
"#3d9970",
|
|
62366
|
-
"#111111",
|
|
62367
|
-
"#ff4136",
|
|
62368
|
-
"#aaaaaa",
|
|
62369
|
-
"#85144b",
|
|
62370
|
-
"#001f3f",
|
|
62371
|
-
];
|
|
62372
63419
|
class CollaborativePlugin extends UIPlugin {
|
|
62373
63420
|
static getters = [
|
|
62374
63421
|
"getClientsToDisplay",
|
|
@@ -62377,7 +63424,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62377
63424
|
"isFullySynchronized",
|
|
62378
63425
|
];
|
|
62379
63426
|
static layers = ["Selection"];
|
|
62380
|
-
availableColors = new
|
|
63427
|
+
availableColors = new AlternatingColorGenerator(12);
|
|
62381
63428
|
colors = {};
|
|
62382
63429
|
session;
|
|
62383
63430
|
constructor(config) {
|
|
@@ -62388,14 +63435,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62388
63435
|
return (position.row < this.getters.getNumberRows(position.sheetId) &&
|
|
62389
63436
|
position.col < this.getters.getNumberCols(position.sheetId));
|
|
62390
63437
|
}
|
|
62391
|
-
chooseNewColor() {
|
|
62392
|
-
if (this.availableColors.size === 0) {
|
|
62393
|
-
this.availableColors = new Set(colors);
|
|
62394
|
-
}
|
|
62395
|
-
const color = randomChoice([...this.availableColors.values()]);
|
|
62396
|
-
this.availableColors.delete(color);
|
|
62397
|
-
return color;
|
|
62398
|
-
}
|
|
62399
63438
|
getClient() {
|
|
62400
63439
|
return this.session.getClient();
|
|
62401
63440
|
}
|
|
@@ -62430,7 +63469,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62430
63469
|
this.isPositionValid(client.position)) {
|
|
62431
63470
|
const position = client.position;
|
|
62432
63471
|
if (!this.colors[client.id]) {
|
|
62433
|
-
this.colors[client.id] = this.
|
|
63472
|
+
this.colors[client.id] = this.availableColors.next();
|
|
62434
63473
|
}
|
|
62435
63474
|
const color = this.colors[client.id];
|
|
62436
63475
|
clients.push({ ...client, position, color });
|
|
@@ -62667,7 +63706,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62667
63706
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
62668
63707
|
const position = { sheetId, col, row };
|
|
62669
63708
|
const pivotCell = this.getters.getPivotCellFromPosition(position);
|
|
62670
|
-
if (
|
|
63709
|
+
if (this.isSpilledPivotValueFormula(position, pivotCell)) {
|
|
62671
63710
|
measurePositions.push(position);
|
|
62672
63711
|
const pivotId = this.getters.getPivotIdFromPosition(position) || "";
|
|
62673
63712
|
measuresByPivotId[pivotId] ??= new Set();
|
|
@@ -62704,6 +63743,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62704
63743
|
format,
|
|
62705
63744
|
});
|
|
62706
63745
|
}
|
|
63746
|
+
isSpilledPivotValueFormula(position, pivotCell) {
|
|
63747
|
+
const cell = this.getters.getCell(position);
|
|
63748
|
+
return pivotCell.type === "VALUE" && !cell?.isFormula;
|
|
63749
|
+
}
|
|
62707
63750
|
/**
|
|
62708
63751
|
* This function allows to adjust the quantity of decimal places after a decimal
|
|
62709
63752
|
* point on cells containing number value. It does this by changing the cells
|
|
@@ -62754,6 +63797,69 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62754
63797
|
}
|
|
62755
63798
|
}
|
|
62756
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
|
+
|
|
62757
63863
|
class HeaderVisibilityUIPlugin extends UIPlugin {
|
|
62758
63864
|
static getters = [
|
|
62759
63865
|
"getNextVisibleCellPosition",
|
|
@@ -62908,7 +64014,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62908
64014
|
getPivotDuplicateSheetName(pivotName) {
|
|
62909
64015
|
let i = 1;
|
|
62910
64016
|
const names = this.getters.getSheetIds().map((id) => this.getters.getSheetName(id));
|
|
62911
|
-
const sanitizedName = pivotName
|
|
64017
|
+
const sanitizedName = sanitizeSheetName(pivotName);
|
|
62912
64018
|
let name = sanitizedName;
|
|
62913
64019
|
while (names.includes(name)) {
|
|
62914
64020
|
name = `${sanitizedName} (${i})`;
|
|
@@ -64291,10 +65397,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
64291
65397
|
case "RESIZE_TABLE": {
|
|
64292
65398
|
const table = this.getters.getCoreTableMatchingTopLeft(cmd.sheetId, cmd.zone);
|
|
64293
65399
|
this.dispatch("UPDATE_TABLE", { ...cmd });
|
|
64294
|
-
if (!table
|
|
65400
|
+
if (!table)
|
|
64295
65401
|
return;
|
|
64296
|
-
const oldTableZone = table.range.zone;
|
|
64297
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;
|
|
64298
65407
|
if (newTableZone.bottom >= oldTableZone.bottom) {
|
|
64299
65408
|
for (let col = newTableZone.left; col <= newTableZone.right; col++) {
|
|
64300
65409
|
const autofillSource = { col, row: oldTableZone.bottom, sheetId: cmd.sheetId };
|
|
@@ -65500,15 +66609,23 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
65500
66609
|
handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
|
|
65501
66610
|
const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
|
|
65502
66611
|
let currentIndex = cmd.base;
|
|
66612
|
+
const resizingGroups = {};
|
|
65503
66613
|
for (const element of toRemove) {
|
|
65504
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) {
|
|
65505
66623
|
this.dispatch("RESIZE_COLUMNS_ROWS", {
|
|
65506
66624
|
dimension: cmd.dimension,
|
|
65507
66625
|
sheetId: cmd.sheetId,
|
|
65508
|
-
size,
|
|
65509
|
-
elements: [
|
|
66626
|
+
size: parseInt(size, 10),
|
|
66627
|
+
elements: resizingGroups[size],
|
|
65510
66628
|
});
|
|
65511
|
-
currentIndex += 1;
|
|
65512
66629
|
}
|
|
65513
66630
|
this.dispatch("REMOVE_COLUMNS_ROWS", {
|
|
65514
66631
|
dimension: cmd.dimension,
|
|
@@ -66090,6 +67207,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66090
67207
|
break;
|
|
66091
67208
|
case "DELETE_SHEET":
|
|
66092
67209
|
this.cleanViewports();
|
|
67210
|
+
this.sheetsWithDirtyViewports.delete(cmd.sheetId);
|
|
66093
67211
|
break;
|
|
66094
67212
|
case "ACTIVATE_SHEET":
|
|
66095
67213
|
this.sheetsWithDirtyViewports.add(cmd.sheetIdTo);
|
|
@@ -66740,7 +67858,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66740
67858
|
.add("data_cleanup", DataCleanupPlugin)
|
|
66741
67859
|
.add("table_autofill", TableAutofillPlugin)
|
|
66742
67860
|
.add("table_ui_resize", TableResizeUI)
|
|
66743
|
-
.add("datavalidation_insert", DataValidationInsertionPlugin)
|
|
67861
|
+
.add("datavalidation_insert", DataValidationInsertionPlugin)
|
|
67862
|
+
.add("geo_features", GeoFeaturePlugin);
|
|
66744
67863
|
// Plugins which have a state, but which should not be shared in collaborative
|
|
66745
67864
|
const statefulUIPluginRegistry = new Registry()
|
|
66746
67865
|
.add("selection", GridSelectionPlugin)
|
|
@@ -66984,7 +68103,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66984
68103
|
env.raiseError(_t("A sheet with the name %s already exists. Please select another name.", name), errorCallback);
|
|
66985
68104
|
}
|
|
66986
68105
|
else if (result.reasons.includes("ForbiddenCharactersInSheetName" /* CommandResult.ForbiddenCharactersInSheetName */)) {
|
|
66987
|
-
env.raiseError(_t("Some used characters are not allowed in a sheet name (Forbidden characters are %s).",
|
|
68106
|
+
env.raiseError(_t("Some used characters are not allowed in a sheet name (Forbidden characters are %s).", FORBIDDEN_SHEETNAME_CHARS.join(" ")), errorCallback);
|
|
66988
68107
|
}
|
|
66989
68108
|
}
|
|
66990
68109
|
|
|
@@ -68214,7 +69333,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68214
69333
|
setup() {
|
|
68215
69334
|
owl.onWillUpdateProps((nextProps) => {
|
|
68216
69335
|
if (nextProps.action !== this.props.action) {
|
|
68217
|
-
this.actionButton = createAction(
|
|
69336
|
+
this.actionButton = createAction(nextProps.action);
|
|
68218
69337
|
}
|
|
68219
69338
|
});
|
|
68220
69339
|
}
|
|
@@ -68484,8 +69603,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68484
69603
|
.o-topbar-composer {
|
|
68485
69604
|
height: fit-content;
|
|
68486
69605
|
margin-top: -1px;
|
|
69606
|
+
margin-bottom: -1px;
|
|
68487
69607
|
border: 1px solid;
|
|
68488
|
-
z-index: ${ComponentsImportance.TopBarComposer};
|
|
68489
69608
|
font-family: ${DEFAULT_FONT};
|
|
68490
69609
|
|
|
68491
69610
|
.o-composer:empty:not(:focus):not(.active)::before {
|
|
@@ -68543,6 +69662,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68543
69662
|
}
|
|
68544
69663
|
return cssPropertiesToCss({
|
|
68545
69664
|
"border-color": SELECTION_BORDER_COLOR,
|
|
69665
|
+
"z-index": String(ComponentsImportance.TopBarComposer),
|
|
68546
69666
|
});
|
|
68547
69667
|
}
|
|
68548
69668
|
onFocus(selection) {
|
|
@@ -68550,88 +69670,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68550
69670
|
}
|
|
68551
69671
|
}
|
|
68552
69672
|
|
|
68553
|
-
css /* scss */ `
|
|
68554
|
-
.o-font-size-editor {
|
|
68555
|
-
height: calc(100% - 4px);
|
|
68556
|
-
input.o-font-size {
|
|
68557
|
-
outline-color: ${SELECTION_BORDER_COLOR};
|
|
68558
|
-
height: 20px;
|
|
68559
|
-
width: 23px;
|
|
68560
|
-
}
|
|
68561
|
-
}
|
|
68562
|
-
.o-text-options > div {
|
|
68563
|
-
cursor: pointer;
|
|
68564
|
-
line-height: 26px;
|
|
68565
|
-
padding: 3px 12px;
|
|
68566
|
-
&:hover {
|
|
68567
|
-
background-color: rgba(0, 0, 0, 0.08);
|
|
68568
|
-
}
|
|
68569
|
-
}
|
|
68570
|
-
`;
|
|
68571
|
-
class FontSizeEditor extends owl.Component {
|
|
68572
|
-
static template = "o-spreadsheet-FontSizeEditor";
|
|
68573
|
-
static props = {
|
|
68574
|
-
onToggle: Function,
|
|
68575
|
-
dropdownStyle: String,
|
|
68576
|
-
class: String,
|
|
68577
|
-
};
|
|
68578
|
-
static components = {};
|
|
68579
|
-
fontSizes = FONT_SIZES;
|
|
68580
|
-
dropdown = owl.useState({ isOpen: false });
|
|
68581
|
-
inputRef = owl.useRef("inputFontSize");
|
|
68582
|
-
rootEditorRef = owl.useRef("FontSizeEditor");
|
|
68583
|
-
setup() {
|
|
68584
|
-
owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
|
|
68585
|
-
}
|
|
68586
|
-
onExternalClick(ev) {
|
|
68587
|
-
if (!isChildEvent(this.rootEditorRef.el, ev)) {
|
|
68588
|
-
this.closeFontList();
|
|
68589
|
-
}
|
|
68590
|
-
}
|
|
68591
|
-
get currentFontSize() {
|
|
68592
|
-
return this.env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
|
|
68593
|
-
}
|
|
68594
|
-
toggleFontList() {
|
|
68595
|
-
const isOpen = this.dropdown.isOpen;
|
|
68596
|
-
if (!isOpen) {
|
|
68597
|
-
this.props.onToggle();
|
|
68598
|
-
this.inputRef.el.focus();
|
|
68599
|
-
}
|
|
68600
|
-
else {
|
|
68601
|
-
this.closeFontList();
|
|
68602
|
-
}
|
|
68603
|
-
}
|
|
68604
|
-
closeFontList() {
|
|
68605
|
-
this.dropdown.isOpen = false;
|
|
68606
|
-
}
|
|
68607
|
-
setSize(fontSizeStr) {
|
|
68608
|
-
const fontSize = clip(Math.floor(parseFloat(fontSizeStr)), 1, 400);
|
|
68609
|
-
setStyle(this.env, { fontSize });
|
|
68610
|
-
this.closeFontList();
|
|
68611
|
-
}
|
|
68612
|
-
setSizeFromInput(ev) {
|
|
68613
|
-
this.setSize(ev.target.value);
|
|
68614
|
-
}
|
|
68615
|
-
setSizeFromList(fontSizeStr) {
|
|
68616
|
-
this.setSize(fontSizeStr);
|
|
68617
|
-
}
|
|
68618
|
-
onInputFocused(ev) {
|
|
68619
|
-
this.dropdown.isOpen = true;
|
|
68620
|
-
ev.target.select();
|
|
68621
|
-
}
|
|
68622
|
-
onInputKeydown(ev) {
|
|
68623
|
-
if (ev.key === "Enter" || ev.key === "Escape") {
|
|
68624
|
-
this.closeFontList();
|
|
68625
|
-
const target = ev.target;
|
|
68626
|
-
// In the case of a ESCAPE key, we get the previous font size back
|
|
68627
|
-
if (ev.key === "Escape") {
|
|
68628
|
-
target.value = `${this.currentFontSize}`;
|
|
68629
|
-
}
|
|
68630
|
-
this.props.onToggle();
|
|
68631
|
-
}
|
|
68632
|
-
}
|
|
68633
|
-
}
|
|
68634
|
-
|
|
68635
69673
|
class TableDropdownButton extends owl.Component {
|
|
68636
69674
|
static template = "o-spreadsheet-TableDropdownButton";
|
|
68637
69675
|
static components = { TableStylesPopover, ActionButton };
|
|
@@ -68733,6 +69771,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68733
69771
|
}
|
|
68734
69772
|
}
|
|
68735
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
|
+
|
|
68736
69783
|
.o-topbar-composer {
|
|
68737
69784
|
flex-grow: 1;
|
|
68738
69785
|
}
|
|
@@ -68800,9 +69847,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68800
69847
|
onClick: Function,
|
|
68801
69848
|
dropdownMaxHeight: Number,
|
|
68802
69849
|
};
|
|
68803
|
-
get dropdownStyle() {
|
|
68804
|
-
return `max-height:${this.props.dropdownMaxHeight}px`;
|
|
68805
|
-
}
|
|
68806
69850
|
static components = {
|
|
68807
69851
|
ColorPickerWidget,
|
|
68808
69852
|
ColorPicker,
|
|
@@ -68829,8 +69873,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68829
69873
|
formatNumberMenuItemSpec = formatNumberMenuItemSpec;
|
|
68830
69874
|
isntToolbarMenu = false;
|
|
68831
69875
|
composerFocusStore;
|
|
69876
|
+
fingerprints;
|
|
68832
69877
|
setup() {
|
|
68833
69878
|
this.composerFocusStore = useStore(ComposerFocusStore);
|
|
69879
|
+
this.fingerprints = useStore(FormulaFingerprintStore);
|
|
68834
69880
|
owl.useExternalListener(window, "click", this.onExternalClick);
|
|
68835
69881
|
owl.onWillStart(() => this.updateCellState());
|
|
68836
69882
|
owl.onWillUpdateProps(() => this.updateCellState());
|
|
@@ -68840,6 +69886,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68840
69886
|
.getAllOrdered()
|
|
68841
69887
|
.filter((item) => !item.isVisible || item.isVisible(this.env));
|
|
68842
69888
|
}
|
|
69889
|
+
get currentFontSize() {
|
|
69890
|
+
return this.env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
|
|
69891
|
+
}
|
|
68843
69892
|
onExternalClick(ev) {
|
|
68844
69893
|
// TODO : manage click events better. We need this piece of code
|
|
68845
69894
|
// otherwise the event opening the menu would close it on the same frame.
|
|
@@ -68918,6 +69967,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68918
69967
|
setStyle(this.env, { [target]: color });
|
|
68919
69968
|
this.onClick();
|
|
68920
69969
|
}
|
|
69970
|
+
setFontSize(fontSize) {
|
|
69971
|
+
setStyle(this.env, { fontSize });
|
|
69972
|
+
}
|
|
68921
69973
|
}
|
|
68922
69974
|
|
|
68923
69975
|
function instantiateClipboard() {
|
|
@@ -69295,7 +70347,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
69295
70347
|
properties["grid-template-rows"] = `auto`;
|
|
69296
70348
|
}
|
|
69297
70349
|
else {
|
|
69298
|
-
properties["grid-template-rows"] =
|
|
70350
|
+
properties["grid-template-rows"] = `max-content auto ${BOTTOMBAR_HEIGHT + 1}px`;
|
|
69299
70351
|
}
|
|
69300
70352
|
properties["grid-template-columns"] = `auto ${this.sidePanel.panelSize}px`;
|
|
69301
70353
|
return cssPropertiesToCss(properties);
|
|
@@ -70373,9 +71425,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
70373
71425
|
getBackToDefault() {
|
|
70374
71426
|
this.stream.getBackToDefault();
|
|
70375
71427
|
}
|
|
70376
|
-
getAnchor() {
|
|
70377
|
-
return this.anchor;
|
|
70378
|
-
}
|
|
70379
71428
|
modifyAnchor(anchor, mode, options) {
|
|
70380
71429
|
const sheetId = this.getters.getActiveSheetId();
|
|
70381
71430
|
anchor = {
|
|
@@ -70918,12 +71967,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
70918
71967
|
// <manualLayout/> to manually position the chart in the figure container
|
|
70919
71968
|
let title = escapeXml ``;
|
|
70920
71969
|
if (chart.data.title?.text) {
|
|
70921
|
-
const
|
|
70922
|
-
|
|
70923
|
-
: chart.data.fontColor;
|
|
71970
|
+
const titleColor = toXlsxHexColor(chartMutedFontColor(chart.data.backgroundColor));
|
|
71971
|
+
const fontSize = chart.data.title.fontSize ?? CHART_TITLE_FONT_SIZE;
|
|
70924
71972
|
title = escapeXml /*xml*/ `
|
|
70925
71973
|
<c:title>
|
|
70926
|
-
${insertText(chart.data.title.text,
|
|
71974
|
+
${insertText(chart.data.title.text, titleColor, fontSize, chart.data.title)}
|
|
70927
71975
|
<c:overlay val="0" />
|
|
70928
71976
|
</c:title>
|
|
70929
71977
|
`;
|
|
@@ -71013,7 +72061,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
71013
72061
|
</a:ln>
|
|
71014
72062
|
`;
|
|
71015
72063
|
}
|
|
71016
|
-
function insertText(text, fontColor = "000000", fontsize =
|
|
72064
|
+
function insertText(text, fontColor = "000000", fontsize = CHART_TITLE_FONT_SIZE, style = {}) {
|
|
71017
72065
|
return escapeXml /*xml*/ `
|
|
71018
72066
|
<c:tx>
|
|
71019
72067
|
<c:rich>
|
|
@@ -71514,6 +72562,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
71514
72562
|
// Each Axis present inside a graph needs to be identified by an unsigned integer in order to be referenced by its crossAxis.
|
|
71515
72563
|
// I.e. x-axis, will reference y-axis and vice-versa.
|
|
71516
72564
|
const color = title?.color ? toXlsxHexColor(title.color) : defaultFontColor;
|
|
72565
|
+
const fontSize = title?.fontSize ?? CHART_AXIS_TITLE_FONT_SIZE;
|
|
71517
72566
|
return escapeXml /*xml*/ `
|
|
71518
72567
|
<${axisName}>
|
|
71519
72568
|
<c:axId val="${axId}"/>
|
|
@@ -71529,7 +72578,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
71529
72578
|
<c:minorTickMark val="none" />
|
|
71530
72579
|
<c:numFmt formatCode="General" sourceLinked="1" />
|
|
71531
72580
|
<c:title>
|
|
71532
|
-
${insertText(title?.text ?? "", color,
|
|
72581
|
+
${insertText(title?.text ?? "", color, fontSize, title)}
|
|
71533
72582
|
</c:title>
|
|
71534
72583
|
${insertTextProperties(10, defaultFontColor)}
|
|
71535
72584
|
</${axisName}>
|
|
@@ -73307,6 +74356,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73307
74356
|
session: this.session,
|
|
73308
74357
|
defaultCurrency: this.config.defaultCurrency,
|
|
73309
74358
|
customColors: this.config.customColors || [],
|
|
74359
|
+
external: this.config.external,
|
|
73310
74360
|
};
|
|
73311
74361
|
}
|
|
73312
74362
|
// ---------------------------------------------------------------------------
|
|
@@ -73538,7 +74588,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73538
74588
|
MIN_COL_WIDTH,
|
|
73539
74589
|
HEADER_HEIGHT,
|
|
73540
74590
|
HEADER_WIDTH,
|
|
73541
|
-
TOPBAR_HEIGHT,
|
|
73542
74591
|
BOTTOMBAR_HEIGHT,
|
|
73543
74592
|
DEFAULT_CELL_WIDTH,
|
|
73544
74593
|
DEFAULT_CELL_HEIGHT,
|
|
@@ -73640,6 +74689,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73640
74689
|
createPivotFormula,
|
|
73641
74690
|
areDomainArgsFieldsValid,
|
|
73642
74691
|
splitReference,
|
|
74692
|
+
sanitizeSheetName,
|
|
73643
74693
|
};
|
|
73644
74694
|
const links = {
|
|
73645
74695
|
isMarkdownLink,
|
|
@@ -73778,9 +74828,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73778
74828
|
exports.tokenize = tokenize;
|
|
73779
74829
|
|
|
73780
74830
|
|
|
73781
|
-
__info__.version = "18.1.0-alpha.
|
|
73782
|
-
__info__.date = "2024-
|
|
73783
|
-
__info__.hash = "
|
|
74831
|
+
__info__.version = "18.1.0-alpha.8";
|
|
74832
|
+
__info__.date = "2024-12-19T07:49:54.421Z";
|
|
74833
|
+
__info__.hash = "87a1567";
|
|
73784
74834
|
|
|
73785
74835
|
|
|
73786
74836
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|