@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
|
'use strict';
|
|
@@ -172,10 +172,13 @@ const ALERT_INFO_BG = "#CDEDF1";
|
|
|
172
172
|
const ALERT_INFO_BORDER = "#98DBE2";
|
|
173
173
|
const ALERT_INFO_TEXT_COLOR = "#09414A";
|
|
174
174
|
const BADGE_SELECTED_COLOR = "#E6F2F3";
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
const
|
|
175
|
+
const CHART_PADDING$1 = 20;
|
|
176
|
+
const CHART_PADDING_BOTTOM = 10;
|
|
177
|
+
const CHART_PADDING_TOP = 15;
|
|
178
|
+
const CHART_TITLE_FONT_SIZE = 16;
|
|
179
|
+
const CHART_AXIS_TITLE_FONT_SIZE = 12;
|
|
180
|
+
const SCORECARD_CHART_TITLE_FONT_SIZE = 14;
|
|
181
|
+
const PIVOT_TOKEN_COLOR = "#F28C28";
|
|
179
182
|
// Color picker defaults as upper case HEX to match `toHex`helper
|
|
180
183
|
const COLOR_PICKER_DEFAULTS = [
|
|
181
184
|
"#000000",
|
|
@@ -264,7 +267,6 @@ const MIN_ROW_HEIGHT = 10;
|
|
|
264
267
|
const MIN_COL_WIDTH = 5;
|
|
265
268
|
const HEADER_HEIGHT = 26;
|
|
266
269
|
const HEADER_WIDTH = 48;
|
|
267
|
-
const TOPBAR_HEIGHT = 63;
|
|
268
270
|
const TOPBAR_TOOLBAR_HEIGHT = 34;
|
|
269
271
|
const BOTTOMBAR_HEIGHT = 36;
|
|
270
272
|
const DEFAULT_CELL_WIDTH = 96;
|
|
@@ -335,8 +337,8 @@ const DEFAULT_WINDOW_SIZE = 2;
|
|
|
335
337
|
const DEBOUNCE_TIME = 200;
|
|
336
338
|
const MESSAGE_VERSION = 1;
|
|
337
339
|
// Sheets
|
|
338
|
-
const
|
|
339
|
-
const
|
|
340
|
+
const FORBIDDEN_SHEETNAME_CHARS = ["'", "*", "?", "/", "\\", "[", "]"];
|
|
341
|
+
const FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX = /'|\*|\?|\/|\\|\[|\]/;
|
|
340
342
|
// Cells
|
|
341
343
|
const FORMULA_REF_IDENTIFIER = "|";
|
|
342
344
|
// Components
|
|
@@ -389,6 +391,7 @@ const DEFAULT_CURRENCY = {
|
|
|
389
391
|
//------------------------------------------------------------------------------
|
|
390
392
|
// Miscellaneous
|
|
391
393
|
//------------------------------------------------------------------------------
|
|
394
|
+
const sanitizeSheetNameRegex = new RegExp(FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX, "g");
|
|
392
395
|
/**
|
|
393
396
|
* Remove quotes from a quoted string
|
|
394
397
|
* ```js
|
|
@@ -484,6 +487,10 @@ function getCanonicalSymbolName(symbolName) {
|
|
|
484
487
|
}
|
|
485
488
|
return symbolName;
|
|
486
489
|
}
|
|
490
|
+
/** Replace the excel-excluded characters of a sheetName */
|
|
491
|
+
function sanitizeSheetName(sheetName, replacementChar = " ") {
|
|
492
|
+
return sheetName.replace(sanitizeSheetNameRegex, replacementChar);
|
|
493
|
+
}
|
|
487
494
|
function clip(val, min, max) {
|
|
488
495
|
return val < min ? min : val > max ? max : val;
|
|
489
496
|
}
|
|
@@ -783,6 +790,7 @@ function removeFalsyAttributes(obj) {
|
|
|
783
790
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
|
|
784
791
|
*/
|
|
785
792
|
const whiteSpaceSpecialCharacters = [
|
|
793
|
+
" ",
|
|
786
794
|
"\t",
|
|
787
795
|
"\f",
|
|
788
796
|
"\v",
|
|
@@ -797,17 +805,15 @@ const whiteSpaceSpecialCharacters = [
|
|
|
797
805
|
String.fromCharCode(parseInt("3000", 16)),
|
|
798
806
|
String.fromCharCode(parseInt("feff", 16)),
|
|
799
807
|
];
|
|
800
|
-
const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|")
|
|
808
|
+
const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|"), "g");
|
|
809
|
+
const newLineRegexp = /(\r\n|\r)/g;
|
|
801
810
|
/**
|
|
802
|
-
* Replace all
|
|
803
|
-
* different newlines types by \n.
|
|
811
|
+
* Replace all different newlines characters by \n
|
|
804
812
|
*/
|
|
805
|
-
function
|
|
813
|
+
function replaceNewLines(text) {
|
|
806
814
|
if (!text)
|
|
807
815
|
return "";
|
|
808
|
-
|
|
809
|
-
return text;
|
|
810
|
-
return text.replace(whiteSpaceRegexp, (match, newLine) => (newLine ? NEWLINE : " "));
|
|
816
|
+
return text.replace(newLineRegexp, NEWLINE);
|
|
811
817
|
}
|
|
812
818
|
/**
|
|
813
819
|
* Determine if the numbers are consecutive.
|
|
@@ -973,7 +979,7 @@ function transpose2dPOJO(pojo) {
|
|
|
973
979
|
|
|
974
980
|
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
975
981
|
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
|
|
976
|
-
const colors
|
|
982
|
+
const colors = [
|
|
977
983
|
"#eb6d00",
|
|
978
984
|
"#0074d9",
|
|
979
985
|
"#ad8e00",
|
|
@@ -996,6 +1002,12 @@ const colors$1 = [
|
|
|
996
1002
|
function colorNumberString(color) {
|
|
997
1003
|
return toHex(color.toString(16).padStart(6, "0"));
|
|
998
1004
|
}
|
|
1005
|
+
function colorToNumber(color) {
|
|
1006
|
+
if (typeof color === "number") {
|
|
1007
|
+
return color;
|
|
1008
|
+
}
|
|
1009
|
+
return Number.parseInt(toHex(color).slice(1), 16);
|
|
1010
|
+
}
|
|
999
1011
|
/**
|
|
1000
1012
|
* Converts any CSS color value to a standardized hex6 value.
|
|
1001
1013
|
* Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
|
|
@@ -1346,9 +1358,9 @@ const COLORS_XL = [
|
|
|
1346
1358
|
"#056BD9", // Blue #3
|
|
1347
1359
|
"#155193", // Blue #4
|
|
1348
1360
|
"#A76DBC", // Violet #1
|
|
1349
|
-
"#7F4295", // Violet #
|
|
1350
|
-
"#6D2387", // Violet #
|
|
1351
|
-
"#4F1565", // Violet #
|
|
1361
|
+
"#7F4295", // Violet #2
|
|
1362
|
+
"#6D2387", // Violet #3
|
|
1363
|
+
"#4F1565", // Violet #4
|
|
1352
1364
|
"#EA6175", // Red #1
|
|
1353
1365
|
"#CE4257", // Red #2
|
|
1354
1366
|
"#982738", // Red #3
|
|
@@ -1374,6 +1386,81 @@ const COLORS_XL = [
|
|
|
1374
1386
|
"#C08A16", // Yellow #3
|
|
1375
1387
|
"#936A12", // Yellow #4
|
|
1376
1388
|
];
|
|
1389
|
+
// Same as above but with alternating colors
|
|
1390
|
+
const ALTERNATING_COLORS_MD = [
|
|
1391
|
+
"#4EA7F2", // Blue #1
|
|
1392
|
+
"#43C5B1", // Teal #1
|
|
1393
|
+
"#EA6175", // Red #1
|
|
1394
|
+
"#F4A261", // Orange #1
|
|
1395
|
+
"#8481DD", // Purple #1
|
|
1396
|
+
"#FFD86D", // Yellow #1
|
|
1397
|
+
"#3188E6", // Blue #2
|
|
1398
|
+
"#00A78D", // Teal #2
|
|
1399
|
+
"#CE4257", // Red #2
|
|
1400
|
+
"#F48935", // Orange #2
|
|
1401
|
+
"#5752D1", // Purple #2
|
|
1402
|
+
"#FFBC2C", // Yellow #2
|
|
1403
|
+
];
|
|
1404
|
+
const ALTERNATING_COLORS_LG = [
|
|
1405
|
+
"#4EA7F2", // Blue #1
|
|
1406
|
+
"#A76DBC", // Violet #1
|
|
1407
|
+
"#EA6175", // Red #1
|
|
1408
|
+
"#43C5B1", // Teal #1
|
|
1409
|
+
"#F4A261", // Orange #1
|
|
1410
|
+
"#8481DD", // Purple #1
|
|
1411
|
+
"#A4A8B6", // Gray #1
|
|
1412
|
+
"#FFD86D", // Yellow #1
|
|
1413
|
+
"#3188E6", // Blue #2
|
|
1414
|
+
"#7F4295", // Violet #2
|
|
1415
|
+
"#CE4257", // Red #2
|
|
1416
|
+
"#00A78D", // Teal #2
|
|
1417
|
+
"#F48935", // Orange #2
|
|
1418
|
+
"#5752D1", // Purple #2
|
|
1419
|
+
"#7E8290", // Gray #2
|
|
1420
|
+
"#FFBC2C", // Yellow #2
|
|
1421
|
+
"#056BD9", // Blue #3
|
|
1422
|
+
"#6D2387", // Violet #3
|
|
1423
|
+
"#982738", // Red #3
|
|
1424
|
+
"#0E8270", // Teal #3
|
|
1425
|
+
"#BE5D10", // Orange #3
|
|
1426
|
+
"#3A3580", // Purple #3
|
|
1427
|
+
"#545B70", // Gray #3
|
|
1428
|
+
"#C08A16", // Yellow #3
|
|
1429
|
+
];
|
|
1430
|
+
const ALTERNATING_COLORS_XL = [
|
|
1431
|
+
"#4EA7F2", // Blue #1
|
|
1432
|
+
"#A76DBC", // Violet #1
|
|
1433
|
+
"#EA6175", // Red #1
|
|
1434
|
+
"#43C5B1", // Teal #1
|
|
1435
|
+
"#F4A261", // Orange #1
|
|
1436
|
+
"#8481DD", // Purple #1
|
|
1437
|
+
"#A4A8B6", // Grey #1
|
|
1438
|
+
"#FFD86D", // Yellow #1
|
|
1439
|
+
"#3188E6", // Blue #2
|
|
1440
|
+
"#7F4295", // Violet #2
|
|
1441
|
+
"#CE4257", // Red #2
|
|
1442
|
+
"#00A78D", // Teal #2
|
|
1443
|
+
"#F48935", // Orange #2
|
|
1444
|
+
"#5752D1", // Purple #2
|
|
1445
|
+
"#7E8290", // Grey #2
|
|
1446
|
+
"#FFBC2C", // Yellow #2
|
|
1447
|
+
"#056BD9", // Blue #3
|
|
1448
|
+
"#6D2387", // Violet #3
|
|
1449
|
+
"#982738", // Red #3
|
|
1450
|
+
"#0E8270", // Teal #3
|
|
1451
|
+
"#BE5D10", // Orange #3
|
|
1452
|
+
"#3A3580", // Purple #3
|
|
1453
|
+
"#545B70", // Grey #3
|
|
1454
|
+
"#C08A16", // Yellow #3
|
|
1455
|
+
"#155193", // Blue #4
|
|
1456
|
+
"#4F1565", // Violet #4
|
|
1457
|
+
"#791B29", // Red #4
|
|
1458
|
+
"#105F53", // Teal #4
|
|
1459
|
+
"#7D380D", // Orange #4
|
|
1460
|
+
"#26235F", // Purple #4
|
|
1461
|
+
"#3F4250", // Grey #4
|
|
1462
|
+
"#936A12", // Yellow #4
|
|
1463
|
+
];
|
|
1377
1464
|
function getNthColor(index, palette) {
|
|
1378
1465
|
return palette[index % palette.length];
|
|
1379
1466
|
}
|
|
@@ -1391,6 +1478,20 @@ function getColorsPalette(quantity) {
|
|
|
1391
1478
|
return COLORS_XL;
|
|
1392
1479
|
}
|
|
1393
1480
|
}
|
|
1481
|
+
function getAlternatingColorsPalette(quantity) {
|
|
1482
|
+
if (quantity <= 6) {
|
|
1483
|
+
return COLORS_SM;
|
|
1484
|
+
}
|
|
1485
|
+
else if (quantity <= 12) {
|
|
1486
|
+
return ALTERNATING_COLORS_MD;
|
|
1487
|
+
}
|
|
1488
|
+
else if (quantity <= 24) {
|
|
1489
|
+
return ALTERNATING_COLORS_LG;
|
|
1490
|
+
}
|
|
1491
|
+
else {
|
|
1492
|
+
return ALTERNATING_COLORS_XL;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1394
1495
|
class ColorGenerator {
|
|
1395
1496
|
preferredColors;
|
|
1396
1497
|
currentColorIndex = 0;
|
|
@@ -1405,6 +1506,62 @@ class ColorGenerator {
|
|
|
1405
1506
|
: getNthColor(this.currentColorIndex++, this.palette);
|
|
1406
1507
|
}
|
|
1407
1508
|
}
|
|
1509
|
+
class AlternatingColorGenerator extends ColorGenerator {
|
|
1510
|
+
constructor(paletteSize, preferredColors = []) {
|
|
1511
|
+
super(paletteSize, preferredColors);
|
|
1512
|
+
this.palette = getAlternatingColorsPalette(paletteSize).filter((c) => !preferredColors.includes(c));
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
/**
|
|
1516
|
+
* Returns a function that maps a value to a color using a color scale defined by the given
|
|
1517
|
+
* color/threshold values pairs.
|
|
1518
|
+
*/
|
|
1519
|
+
function getColorScale(colorScalePoints) {
|
|
1520
|
+
if (colorScalePoints.length < 2) {
|
|
1521
|
+
throw new Error("Color scale must have at least 2 points");
|
|
1522
|
+
}
|
|
1523
|
+
const sortedColorScalePoints = [...colorScalePoints.sort((a, b) => a.value - b.value)];
|
|
1524
|
+
const thresholds = [];
|
|
1525
|
+
for (let i = 1; i < sortedColorScalePoints.length; i++) {
|
|
1526
|
+
const minColor = colorToNumber(sortedColorScalePoints[i - 1].color);
|
|
1527
|
+
const maxColor = colorToNumber(sortedColorScalePoints[i].color);
|
|
1528
|
+
thresholds.push({
|
|
1529
|
+
min: sortedColorScalePoints[i - 1].value,
|
|
1530
|
+
max: sortedColorScalePoints[i].value,
|
|
1531
|
+
minColor,
|
|
1532
|
+
maxColor,
|
|
1533
|
+
colorDiff: computeColorDiffUnits(sortedColorScalePoints[i - 1].value, sortedColorScalePoints[i].value, minColor, maxColor),
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
return (value) => {
|
|
1537
|
+
if (value < thresholds[0].min) {
|
|
1538
|
+
return colorNumberString(thresholds[0].minColor);
|
|
1539
|
+
}
|
|
1540
|
+
for (const threshold of thresholds) {
|
|
1541
|
+
if (value >= threshold.min && value <= threshold.max) {
|
|
1542
|
+
return colorNumberString(colorCell(value, threshold.min, threshold.minColor, threshold.colorDiff));
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
return colorNumberString(thresholds[thresholds.length - 1].maxColor);
|
|
1546
|
+
};
|
|
1547
|
+
}
|
|
1548
|
+
function computeColorDiffUnits(minValue, maxValue, minColor, maxColor) {
|
|
1549
|
+
const deltaValue = maxValue - minValue;
|
|
1550
|
+
const deltaColorR = ((minColor >> 16) % 256) - ((maxColor >> 16) % 256);
|
|
1551
|
+
const deltaColorG = ((minColor >> 8) % 256) - ((maxColor >> 8) % 256);
|
|
1552
|
+
const deltaColorB = (minColor % 256) - (maxColor % 256);
|
|
1553
|
+
const colorDiffUnitR = deltaColorR / deltaValue;
|
|
1554
|
+
const colorDiffUnitG = deltaColorG / deltaValue;
|
|
1555
|
+
const colorDiffUnitB = deltaColorB / deltaValue;
|
|
1556
|
+
return [colorDiffUnitR, colorDiffUnitG, colorDiffUnitB];
|
|
1557
|
+
}
|
|
1558
|
+
function colorCell(value, minValue, minColor, colorDiffUnit) {
|
|
1559
|
+
const [colorDiffUnitR, colorDiffUnitG, colorDiffUnitB] = colorDiffUnit;
|
|
1560
|
+
const r = Math.round(((minColor >> 16) % 256) - colorDiffUnitR * (value - minValue));
|
|
1561
|
+
const g = Math.round(((minColor >> 8) % 256) - colorDiffUnitG * (value - minValue));
|
|
1562
|
+
const b = Math.round((minColor % 256) - colorDiffUnitB * (value - minValue));
|
|
1563
|
+
return (r << 16) | (g << 8) | b;
|
|
1564
|
+
}
|
|
1408
1565
|
|
|
1409
1566
|
//------------------------------------------------------------------------------
|
|
1410
1567
|
// Coordinate
|
|
@@ -3276,6 +3433,7 @@ const invalidateEvaluationCommands = new Set([
|
|
|
3276
3433
|
]);
|
|
3277
3434
|
const invalidateChartEvaluationCommands = new Set([
|
|
3278
3435
|
"EVALUATE_CELLS",
|
|
3436
|
+
"EVALUATE_CHARTS",
|
|
3279
3437
|
"UPDATE_CELL",
|
|
3280
3438
|
"UNHIDE_COLUMNS_ROWS",
|
|
3281
3439
|
"HIDE_COLUMNS_ROWS",
|
|
@@ -3312,6 +3470,7 @@ const readonlyAllowedCommands = new Set([
|
|
|
3312
3470
|
"RESIZE_SHEETVIEW",
|
|
3313
3471
|
"SET_VIEWPORT_OFFSET",
|
|
3314
3472
|
"EVALUATE_CELLS",
|
|
3473
|
+
"EVALUATE_CHARTS",
|
|
3315
3474
|
"SET_FORMULA_VISIBILITY",
|
|
3316
3475
|
"UPDATE_FILTER",
|
|
3317
3476
|
]);
|
|
@@ -6516,7 +6675,7 @@ class BorderClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
6516
6675
|
const POSTFIX_UNARY_OPERATORS = ["%"];
|
|
6517
6676
|
const OPERATORS = "+,-,*,/,:,=,<>,>=,>,<=,<,^,&".split(",").concat(POSTFIX_UNARY_OPERATORS);
|
|
6518
6677
|
function tokenize(str, locale = DEFAULT_LOCALE) {
|
|
6519
|
-
str =
|
|
6678
|
+
str = replaceNewLines(str);
|
|
6520
6679
|
const chars = new TokenizingChars(str);
|
|
6521
6680
|
const result = [];
|
|
6522
6681
|
while (!chars.isOver()) {
|
|
@@ -6663,12 +6822,12 @@ function tokenizeSpace(chars) {
|
|
|
6663
6822
|
if (length) {
|
|
6664
6823
|
return { type: "SPACE", value: NEWLINE.repeat(length) };
|
|
6665
6824
|
}
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
chars.shift();
|
|
6825
|
+
let spaces = "";
|
|
6826
|
+
while (chars.current && chars.current.match(whiteSpaceRegexp)) {
|
|
6827
|
+
spaces += chars.shift();
|
|
6669
6828
|
}
|
|
6670
|
-
if (
|
|
6671
|
-
return { type: "SPACE", value:
|
|
6829
|
+
if (spaces) {
|
|
6830
|
+
return { type: "SPACE", value: spaces };
|
|
6672
6831
|
}
|
|
6673
6832
|
return null;
|
|
6674
6833
|
}
|
|
@@ -7527,6 +7686,16 @@ function getRunningTotalDomainKey(domain, fieldNameWithGranularity) {
|
|
|
7527
7686
|
}
|
|
7528
7687
|
return domainToString([...domain.slice(0, index), ...domain.slice(index + 1)]);
|
|
7529
7688
|
}
|
|
7689
|
+
function sortPivotTree(tree, baseDomain, sortFn) {
|
|
7690
|
+
const sortedTree = [...tree];
|
|
7691
|
+
const domain = [...baseDomain];
|
|
7692
|
+
sortedTree.sort((node1, node2) => sortFn([...domain, node1], [...domain, node2]));
|
|
7693
|
+
for (const node of tree) {
|
|
7694
|
+
const children = sortPivotTree(node.children, [...domain, node], sortFn);
|
|
7695
|
+
node.children = children;
|
|
7696
|
+
}
|
|
7697
|
+
return sortedTree;
|
|
7698
|
+
}
|
|
7530
7699
|
|
|
7531
7700
|
const pivotTimeAdapterRegistry = new Registry();
|
|
7532
7701
|
function pivotTimeAdapter(granularity) {
|
|
@@ -8037,6 +8206,29 @@ function addIndentAndAlignToPivotHeader(pivot, domain, functionResult) {
|
|
|
8037
8206
|
format: `${" ".repeat(indent)}${format}* `,
|
|
8038
8207
|
};
|
|
8039
8208
|
}
|
|
8209
|
+
function isSortedColumnValid(sortedColumn, pivot) {
|
|
8210
|
+
try {
|
|
8211
|
+
if (!pivot.getMeasure(sortedColumn.measure)) {
|
|
8212
|
+
return false;
|
|
8213
|
+
}
|
|
8214
|
+
const columns = pivot.definition.columns;
|
|
8215
|
+
for (let i = 0; i < sortedColumn.domain.length; i++) {
|
|
8216
|
+
if (columns[i].nameWithGranularity !== sortedColumn.domain[i].field) {
|
|
8217
|
+
return false;
|
|
8218
|
+
}
|
|
8219
|
+
const possibleValues = pivot
|
|
8220
|
+
.getPossibleFieldValues(columns[i])
|
|
8221
|
+
.map((v) => v.value);
|
|
8222
|
+
if (!possibleValues.includes(sortedColumn.domain[i].value)) {
|
|
8223
|
+
return false;
|
|
8224
|
+
}
|
|
8225
|
+
}
|
|
8226
|
+
return true;
|
|
8227
|
+
}
|
|
8228
|
+
catch (e) {
|
|
8229
|
+
return false;
|
|
8230
|
+
}
|
|
8231
|
+
}
|
|
8040
8232
|
|
|
8041
8233
|
class CellClipboardHandler extends AbstractCellClipboardHandler {
|
|
8042
8234
|
isCutAllowed(data) {
|
|
@@ -9516,6 +9708,12 @@ function chartFontColor(backgroundColor) {
|
|
|
9516
9708
|
}
|
|
9517
9709
|
return relativeLuminance(backgroundColor) < 0.3 ? "#FFFFFF" : "#000000";
|
|
9518
9710
|
}
|
|
9711
|
+
function chartMutedFontColor(backgroundColor) {
|
|
9712
|
+
if (!backgroundColor) {
|
|
9713
|
+
return "#666666";
|
|
9714
|
+
}
|
|
9715
|
+
return relativeLuminance(backgroundColor) < 0.3 ? "#C8C8C8" : "#666666";
|
|
9716
|
+
}
|
|
9519
9717
|
function checkDataset(definition) {
|
|
9520
9718
|
if (definition.dataSets) {
|
|
9521
9719
|
const invalidRanges = definition.dataSets.find((range) => !rangeReference.test(range.dataRange)) !== undefined;
|
|
@@ -9651,8 +9849,8 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
9651
9849
|
const yMin = chart.chartArea.top;
|
|
9652
9850
|
const textsPositions = {};
|
|
9653
9851
|
for (const dataset of chart._metasets) {
|
|
9654
|
-
if (dataset.xAxisID === TREND_LINE_XAXIS_ID) {
|
|
9655
|
-
|
|
9852
|
+
if (dataset.xAxisID === TREND_LINE_XAXIS_ID || dataset.hidden) {
|
|
9853
|
+
continue;
|
|
9656
9854
|
}
|
|
9657
9855
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
9658
9856
|
const parsedValue = dataset._parsed[i];
|
|
@@ -10099,7 +10297,7 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
|
|
|
10099
10297
|
function drawScoreChart(structure, canvas) {
|
|
10100
10298
|
const ctx = canvas.getContext("2d");
|
|
10101
10299
|
canvas.width = structure.canvas.width;
|
|
10102
|
-
const availableWidth = canvas.width -
|
|
10300
|
+
const availableWidth = canvas.width - CHART_PADDING$1 * 2;
|
|
10103
10301
|
canvas.height = structure.canvas.height;
|
|
10104
10302
|
ctx.fillStyle = structure.canvas.backgroundColor;
|
|
10105
10303
|
ctx.fillRect(0, 0, structure.canvas.width, structure.canvas.height);
|
|
@@ -10234,10 +10432,9 @@ function createScorecardChartRuntime(chart, getters) {
|
|
|
10234
10432
|
}
|
|
10235
10433
|
|
|
10236
10434
|
/* Padding at the border of the chart */
|
|
10237
|
-
const CHART_PADDING =
|
|
10435
|
+
const CHART_PADDING = 10;
|
|
10238
10436
|
const BOTTOM_PADDING_RATIO = 0.05;
|
|
10239
10437
|
/* Maximum font sizes of each element */
|
|
10240
|
-
const CHART_TITLE_FONT_SIZE = SCORECARD_GAUGE_CHART_FONT_SIZE;
|
|
10241
10438
|
const KEY_VALUE_FONT_SIZE = 32;
|
|
10242
10439
|
const BASELINE_MAX_FONT_SIZE = 16;
|
|
10243
10440
|
function formatBaselineDescr(baselineDescr, baseline) {
|
|
@@ -10309,7 +10506,7 @@ class ScorecardChartConfigBuilder {
|
|
|
10309
10506
|
: this.height - (this.height - titleHeight - baselineHeight) / 2 - CHART_PADDING,
|
|
10310
10507
|
},
|
|
10311
10508
|
};
|
|
10312
|
-
const minimalBaselinePosition = baselineArrowSize +
|
|
10509
|
+
const minimalBaselinePosition = baselineArrowSize + CHART_PADDING * 2;
|
|
10313
10510
|
if (structure.baseline.position.x < minimalBaselinePosition) {
|
|
10314
10511
|
structure.baseline.position.x = minimalBaselinePosition;
|
|
10315
10512
|
}
|
|
@@ -10389,7 +10586,7 @@ class ScorecardChartConfigBuilder {
|
|
|
10389
10586
|
return this.runtime.background;
|
|
10390
10587
|
}
|
|
10391
10588
|
get secondaryFontColor() {
|
|
10392
|
-
return
|
|
10589
|
+
return chartMutedFontColor(this.backgroundColor);
|
|
10393
10590
|
}
|
|
10394
10591
|
getTextDimensions(text, font) {
|
|
10395
10592
|
this.context.font = font;
|
|
@@ -10415,7 +10612,7 @@ class ScorecardChartConfigBuilder {
|
|
|
10415
10612
|
}
|
|
10416
10613
|
return {
|
|
10417
10614
|
title: {
|
|
10418
|
-
font: getDefaultContextFont(
|
|
10615
|
+
font: getDefaultContextFont(this.runtime.title.fontSize ?? SCORECARD_CHART_TITLE_FONT_SIZE, this.runtime.title.bold, this.runtime.title.italic),
|
|
10419
10616
|
color: this.runtime.title.color ?? this.secondaryFontColor,
|
|
10420
10617
|
},
|
|
10421
10618
|
keyValue: {
|
|
@@ -14640,7 +14837,7 @@ const SORT_TYPES = [
|
|
|
14640
14837
|
CellValueType.boolean,
|
|
14641
14838
|
];
|
|
14642
14839
|
function cellsSortingCriterion(sortingOrder) {
|
|
14643
|
-
const inverse = sortingOrder === "
|
|
14840
|
+
const inverse = sortingOrder === "asc" ? 1 : -1;
|
|
14644
14841
|
return (left, right) => {
|
|
14645
14842
|
if (left.type === CellValueType.empty) {
|
|
14646
14843
|
return right.type === CellValueType.empty ? 0 : 1;
|
|
@@ -14732,7 +14929,7 @@ function sortMatrix(matrix, locale, ...criteria) {
|
|
|
14732
14929
|
const sortColumns = [];
|
|
14733
14930
|
const nRows = matrix.length;
|
|
14734
14931
|
for (let i = 0; i < criteria.length; i += 2) {
|
|
14735
|
-
sortingOrders.push(toBoolean(toScalar(criteria[i + 1])?.value) ? "
|
|
14932
|
+
sortingOrders.push(toBoolean(toScalar(criteria[i + 1])?.value) ? "asc" : "desc");
|
|
14736
14933
|
const sortColumn = criteria[i];
|
|
14737
14934
|
if (isMatrix(sortColumn) && (sortColumn.length > 1 || sortColumn[0].length > 1)) {
|
|
14738
14935
|
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));
|
|
@@ -14749,12 +14946,12 @@ function sortMatrix(matrix, locale, ...criteria) {
|
|
|
14749
14946
|
if (sortColumns.length === 0) {
|
|
14750
14947
|
for (let i = 0; i < matrix[0].length; i++) {
|
|
14751
14948
|
sortColumns.push(matrix.map((row) => row[i].value));
|
|
14752
|
-
sortingOrders.push("
|
|
14949
|
+
sortingOrders.push("asc");
|
|
14753
14950
|
}
|
|
14754
14951
|
}
|
|
14755
14952
|
const sortingCriteria = {
|
|
14756
|
-
|
|
14757
|
-
|
|
14953
|
+
desc: cellsSortingCriterion("desc"),
|
|
14954
|
+
asc: cellsSortingCriterion("asc"),
|
|
14758
14955
|
};
|
|
14759
14956
|
const indexes = range(0, matrix.length);
|
|
14760
14957
|
indexes.sort((a, b) => {
|
|
@@ -20478,20 +20675,8 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
20478
20675
|
replaceSelectedRange(zone) {
|
|
20479
20676
|
const ref = this.getZoneReference(zone);
|
|
20480
20677
|
const currentToken = this.tokenAtCursor;
|
|
20481
|
-
|
|
20482
|
-
|
|
20483
|
-
replaceStart = currentToken.start;
|
|
20484
|
-
}
|
|
20485
|
-
else if (currentToken?.type === "RIGHT_PAREN") {
|
|
20486
|
-
// match left parenthesis
|
|
20487
|
-
const leftParenthesisIndex = this.currentTokens.findIndex((token) => token.type === "LEFT_PAREN" && token.parenthesesCode === currentToken.parenthesesCode);
|
|
20488
|
-
const functionToken = this.currentTokens[leftParenthesisIndex - 1];
|
|
20489
|
-
if (functionToken === undefined) {
|
|
20490
|
-
return;
|
|
20491
|
-
}
|
|
20492
|
-
replaceStart = functionToken.start;
|
|
20493
|
-
}
|
|
20494
|
-
this.replaceText(ref, replaceStart, this.selectionEnd);
|
|
20678
|
+
const start = currentToken?.type === "REFERENCE" ? currentToken.start : this.selectionStart;
|
|
20679
|
+
this.replaceText(ref, start, this.selectionEnd);
|
|
20495
20680
|
}
|
|
20496
20681
|
/**
|
|
20497
20682
|
* Replace the reference of the old zone by the new one.
|
|
@@ -20524,17 +20709,6 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
20524
20709
|
getZoneReference(zone) {
|
|
20525
20710
|
const inputSheetId = this.sheetId;
|
|
20526
20711
|
const sheetId = this.getters.getActiveSheetId();
|
|
20527
|
-
if (zone.top === zone.bottom && zone.left === zone.right) {
|
|
20528
|
-
const position = { sheetId, col: zone.left, row: zone.top };
|
|
20529
|
-
const pivotId = this.getters.getPivotIdFromPosition(position);
|
|
20530
|
-
const pivotCell = this.getters.getPivotCellFromPosition(position);
|
|
20531
|
-
const cell = this.getters.getCell(position);
|
|
20532
|
-
if (pivotId && pivotCell.type !== "EMPTY" && !cell?.isFormula) {
|
|
20533
|
-
const formulaPivotId = this.getters.getPivotFormulaId(pivotId);
|
|
20534
|
-
const formula = createPivotFormula(formulaPivotId, pivotCell);
|
|
20535
|
-
return localizeFormula(formula, this.getters.getLocale()).slice(1); // strip leading =
|
|
20536
|
-
}
|
|
20537
|
-
}
|
|
20538
20712
|
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
20539
20713
|
return this.getters.getSelectionRangeString(range, inputSheetId);
|
|
20540
20714
|
}
|
|
@@ -20705,37 +20879,21 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
20705
20879
|
const editionSheetId = this.sheetId;
|
|
20706
20880
|
const rangeColor = (rangeString) => {
|
|
20707
20881
|
const colorIndex = this.colorIndexByRange[rangeString];
|
|
20708
|
-
return colors
|
|
20882
|
+
return colors[colorIndex % colors.length];
|
|
20709
20883
|
};
|
|
20710
|
-
|
|
20711
|
-
for (const range of this.getReferencedRanges()) {
|
|
20884
|
+
return this.getReferencedRanges().map((range) => {
|
|
20712
20885
|
const rangeString = this.getters.getRangeString(range, editionSheetId);
|
|
20713
20886
|
const { numberOfRows, numberOfCols } = zoneToDimension(range.zone);
|
|
20714
20887
|
const zone = numberOfRows * numberOfCols === 1
|
|
20715
20888
|
? this.getters.expandZone(range.sheetId, range.zone)
|
|
20716
20889
|
: range.zone;
|
|
20717
|
-
|
|
20890
|
+
return {
|
|
20718
20891
|
zone,
|
|
20719
20892
|
color: rangeColor(rangeString),
|
|
20720
20893
|
sheetId: range.sheetId,
|
|
20721
20894
|
interactive: true,
|
|
20722
|
-
}
|
|
20723
|
-
}
|
|
20724
|
-
const activeSheetId = this.getters.getActiveSheetId();
|
|
20725
|
-
const selectionZone = this.model.selection.getAnchor().zone;
|
|
20726
|
-
const isSelectionHightlighted = highlights.find((highlight) => highlight.sheetId === activeSheetId && isEqual(highlight.zone, selectionZone));
|
|
20727
|
-
if (this.editionMode === "selecting" && !isSelectionHightlighted) {
|
|
20728
|
-
highlights.push({
|
|
20729
|
-
zone: selectionZone,
|
|
20730
|
-
color: "#445566",
|
|
20731
|
-
sheetId: activeSheetId,
|
|
20732
|
-
dashed: true,
|
|
20733
|
-
interactive: false,
|
|
20734
|
-
noFill: true,
|
|
20735
|
-
thinLine: true,
|
|
20736
|
-
});
|
|
20737
|
-
}
|
|
20738
|
-
return highlights;
|
|
20895
|
+
};
|
|
20896
|
+
});
|
|
20739
20897
|
}
|
|
20740
20898
|
/**
|
|
20741
20899
|
* Return ranges currently referenced in the composer
|
|
@@ -20963,6 +21121,7 @@ function compileTokens(tokens) {
|
|
|
20963
21121
|
return error;
|
|
20964
21122
|
},
|
|
20965
21123
|
isBadExpression: true,
|
|
21124
|
+
normalizedFormula: tokens.map((t) => t.value).join(""),
|
|
20966
21125
|
};
|
|
20967
21126
|
}
|
|
20968
21127
|
}
|
|
@@ -21090,6 +21249,7 @@ function compileTokensOrThrow(tokens) {
|
|
|
21090
21249
|
symbols,
|
|
21091
21250
|
tokens,
|
|
21092
21251
|
isBadExpression: false,
|
|
21252
|
+
normalizedFormula: cacheKey,
|
|
21093
21253
|
};
|
|
21094
21254
|
return compiledFormula;
|
|
21095
21255
|
}
|
|
@@ -21236,7 +21396,7 @@ function getFunctionsFromAST(ast, functionNames) {
|
|
|
21236
21396
|
|
|
21237
21397
|
const PIVOT_FUNCTIONS = ["PIVOT.VALUE", "PIVOT.HEADER", "PIVOT"];
|
|
21238
21398
|
/**
|
|
21239
|
-
* Create a proposal entry for the
|
|
21399
|
+
* Create a proposal entry for the composer autocomplete
|
|
21240
21400
|
* to insert a field name string in a formula.
|
|
21241
21401
|
*/
|
|
21242
21402
|
function makeFieldProposal(field, granularity) {
|
|
@@ -21354,6 +21514,7 @@ autoCompleteProviders.add("pivot_ids", {
|
|
|
21354
21514
|
description: definition.name,
|
|
21355
21515
|
htmlContent: [{ value: str, color: tokenColors.NUMBER }],
|
|
21356
21516
|
fuzzySearchKey: str + definition.name,
|
|
21517
|
+
alwaysExpanded: true,
|
|
21357
21518
|
};
|
|
21358
21519
|
})
|
|
21359
21520
|
.filter(isDefined);
|
|
@@ -22019,14 +22180,8 @@ const GAUGE_PADDING_BOTTOM = 20;
|
|
|
22019
22180
|
const GAUGE_LABELS_FONT_SIZE = 12;
|
|
22020
22181
|
const GAUGE_DEFAULT_VALUE_FONT_SIZE = 80;
|
|
22021
22182
|
const GAUGE_BACKGROUND_COLOR = "#F3F2F1";
|
|
22022
|
-
const GAUGE_TEXT_COLOR = "#666666";
|
|
22023
|
-
const GAUGE_TEXT_COLOR_HIGH_CONTRAST = "#C8C8C8";
|
|
22024
|
-
const GAUGE_INFLECTION_MARKER_COLOR = "#666666aa";
|
|
22025
22183
|
const GAUGE_INFLECTION_LABEL_BOTTOM_MARGIN = 6;
|
|
22026
22184
|
const GAUGE_TITLE_SECTION_HEIGHT = 25;
|
|
22027
|
-
const GAUGE_TITLE_FONT_SIZE = SCORECARD_GAUGE_CHART_FONT_SIZE;
|
|
22028
|
-
const GAUGE_TITLE_PADDING_LEFT = SCORECARD_GAUGE_CHART_PADDING;
|
|
22029
|
-
const GAUGE_TITLE_PADDING_TOP = SCORECARD_GAUGE_CHART_PADDING;
|
|
22030
22185
|
function drawGaugeChart(canvas, runtime) {
|
|
22031
22186
|
const canvasBoundingRect = canvas.getBoundingClientRect();
|
|
22032
22187
|
canvas.width = canvasBoundingRect.width;
|
|
@@ -22085,7 +22240,7 @@ function drawInflectionValues(ctx, config) {
|
|
|
22085
22240
|
ctx.translate(rectX + width / 2 - 0.5, rectY + height - 0.5); // -0.5 for sharper lines. see RendererPlugin.drawBorders comment
|
|
22086
22241
|
ctx.rotate(Math.PI / 2 - inflectionValue.rotation);
|
|
22087
22242
|
ctx.lineWidth = 2;
|
|
22088
|
-
ctx.strokeStyle =
|
|
22243
|
+
ctx.strokeStyle = chartMutedFontColor(config.backgroundColor) + "aa";
|
|
22089
22244
|
ctx.beginPath();
|
|
22090
22245
|
ctx.moveTo(0, -(height - config.gauge.arcWidth));
|
|
22091
22246
|
ctx.lineTo(0, -height - 3);
|
|
@@ -22139,22 +22294,22 @@ function getGaugeRenderingConfig(boundingRect, runtime, ctx) {
|
|
|
22139
22294
|
x: gaugeRect.x + gaugeRect.width - gaugeArcWidth / 2,
|
|
22140
22295
|
y: gaugeRect.y + gaugeRect.height + GAUGE_LABELS_FONT_SIZE,
|
|
22141
22296
|
};
|
|
22142
|
-
const textColor =
|
|
22297
|
+
const textColor = chartMutedFontColor(runtime.background);
|
|
22143
22298
|
const inflectionValues = getInflectionValues(runtime, gaugeRect, textColor, ctx);
|
|
22144
22299
|
let x = 0, titleWidth = 0, titleHeight = 0;
|
|
22145
22300
|
if (runtime.title.text) {
|
|
22146
|
-
({ width: titleWidth, height: titleHeight } = computeTextDimension(ctx, runtime.title.text, { ...runtime.title
|
|
22301
|
+
({ width: titleWidth, height: titleHeight } = computeTextDimension(ctx, runtime.title.text, { fontSize: CHART_TITLE_FONT_SIZE, ...runtime.title }, "px"));
|
|
22147
22302
|
}
|
|
22148
22303
|
switch (runtime.title.align) {
|
|
22149
22304
|
case "right":
|
|
22150
|
-
x = boundingRect.width - titleWidth -
|
|
22305
|
+
x = boundingRect.width - titleWidth - CHART_PADDING$1;
|
|
22151
22306
|
break;
|
|
22152
22307
|
case "center":
|
|
22153
22308
|
x = (boundingRect.width - titleWidth) / 2;
|
|
22154
22309
|
break;
|
|
22155
22310
|
case "left":
|
|
22156
22311
|
default:
|
|
22157
|
-
x =
|
|
22312
|
+
x = CHART_PADDING$1;
|
|
22158
22313
|
break;
|
|
22159
22314
|
}
|
|
22160
22315
|
return {
|
|
@@ -22162,10 +22317,10 @@ function getGaugeRenderingConfig(boundingRect, runtime, ctx) {
|
|
|
22162
22317
|
height: boundingRect.height,
|
|
22163
22318
|
title: {
|
|
22164
22319
|
label: runtime.title.text ?? "",
|
|
22165
|
-
fontSize:
|
|
22320
|
+
fontSize: runtime.title.fontSize ?? CHART_TITLE_FONT_SIZE,
|
|
22166
22321
|
textPosition: {
|
|
22167
22322
|
x,
|
|
22168
|
-
y:
|
|
22323
|
+
y: CHART_PADDING_TOP + titleHeight / 2,
|
|
22169
22324
|
},
|
|
22170
22325
|
color: runtime.title.color ?? textColor,
|
|
22171
22326
|
bold: runtime.title.bold,
|
|
@@ -22282,11 +22437,6 @@ function getGaugeColor(runtime) {
|
|
|
22282
22437
|
}
|
|
22283
22438
|
return runtime.colors.at(-1);
|
|
22284
22439
|
}
|
|
22285
|
-
function getContrastedTextColor(backgroundColor) {
|
|
22286
|
-
return relativeLuminance(backgroundColor) > 0.3
|
|
22287
|
-
? GAUGE_TEXT_COLOR
|
|
22288
|
-
: GAUGE_TEXT_COLOR_HIGH_CONTRAST;
|
|
22289
|
-
}
|
|
22290
22440
|
function getSegmentsOfRectangle(rectangle) {
|
|
22291
22441
|
return [
|
|
22292
22442
|
{ start: rectangle.topLeft, end: rectangle.topRight },
|
|
@@ -27000,13 +27150,12 @@ migrationStepRegistry
|
|
|
27000
27150
|
versionFrom: "7",
|
|
27001
27151
|
migrate(data) {
|
|
27002
27152
|
const namesTaken = [];
|
|
27003
|
-
const globalForbiddenInExcel = new RegExp(FORBIDDEN_IN_EXCEL_REGEX, "g");
|
|
27004
27153
|
for (let sheet of data.sheets || []) {
|
|
27005
27154
|
if (!sheet.name) {
|
|
27006
27155
|
continue;
|
|
27007
27156
|
}
|
|
27008
27157
|
const oldName = sheet.name;
|
|
27009
|
-
const escapedName = oldName
|
|
27158
|
+
const escapedName = sanitizeSheetName(oldName, "_");
|
|
27010
27159
|
let i = 1;
|
|
27011
27160
|
let newName = escapedName;
|
|
27012
27161
|
while (namesTaken.includes(newName)) {
|
|
@@ -27759,6 +27908,19 @@ const ChartTerms = {
|
|
|
27759
27908
|
["GaugeLowerInflectionPointNaN" /* CommandResult.GaugeLowerInflectionPointNaN */]: _t("The lower inflection point value must be a number"),
|
|
27760
27909
|
["GaugeUpperInflectionPointNaN" /* CommandResult.GaugeUpperInflectionPointNaN */]: _t("The upper inflection point value must be a number"),
|
|
27761
27910
|
},
|
|
27911
|
+
GeoChart: {
|
|
27912
|
+
ColorScales: {
|
|
27913
|
+
blues: _t("Blues"),
|
|
27914
|
+
cividis: _t("Cividis"),
|
|
27915
|
+
greens: _t("Greens"),
|
|
27916
|
+
greys: _t("Greys"),
|
|
27917
|
+
oranges: _t("Oranges"),
|
|
27918
|
+
purples: _t("Purples"),
|
|
27919
|
+
rainbow: _t("Rainbow"),
|
|
27920
|
+
reds: _t("Reds"),
|
|
27921
|
+
viridis: _t("Viridis"),
|
|
27922
|
+
},
|
|
27923
|
+
},
|
|
27762
27924
|
};
|
|
27763
27925
|
const CustomCurrencyTerms = {
|
|
27764
27926
|
Custom: _t("Custom"),
|
|
@@ -28162,6 +28324,26 @@ function getRadarChartData(definition, dataSets, labelRange, getters) {
|
|
|
28162
28324
|
locale: getters.getLocale(),
|
|
28163
28325
|
};
|
|
28164
28326
|
}
|
|
28327
|
+
function getGeoChartData(definition, dataSets, labelRange, getters) {
|
|
28328
|
+
const labelValues = getChartLabelValues(getters, dataSets, labelRange);
|
|
28329
|
+
let labels = labelValues.formattedValues;
|
|
28330
|
+
if (definition.dataSetsHaveTitle) {
|
|
28331
|
+
labels.shift();
|
|
28332
|
+
}
|
|
28333
|
+
let dataSetsValues = getChartDatasetValues(getters, dataSets);
|
|
28334
|
+
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
28335
|
+
const format = getChartDatasetFormat(getters, dataSets, "left") ||
|
|
28336
|
+
getChartDatasetFormat(getters, dataSets, "right");
|
|
28337
|
+
return {
|
|
28338
|
+
dataSetsValues,
|
|
28339
|
+
axisFormats: { y: format },
|
|
28340
|
+
labels,
|
|
28341
|
+
locale: getters.getLocale(),
|
|
28342
|
+
availableRegions: getters.getGeoChartAvailableRegions(),
|
|
28343
|
+
geoFeatureNameToId: getters.geoFeatureNameToId,
|
|
28344
|
+
getGeoJsonFeatures: getters.getGeoJsonFeatures,
|
|
28345
|
+
};
|
|
28346
|
+
}
|
|
28165
28347
|
function getTrendDatasetForBarChart(config, data) {
|
|
28166
28348
|
const filteredValues = [];
|
|
28167
28349
|
const filteredLabels = [];
|
|
@@ -28242,37 +28424,45 @@ function interpolateData(config, values, labels, newLabels) {
|
|
|
28242
28424
|
const labelRange = labelMax - labelMin;
|
|
28243
28425
|
const normalizedLabels = labels.map((v) => (v - labelMin) / labelRange);
|
|
28244
28426
|
const normalizedNewLabels = newLabels.map((v) => (v - labelMin) / labelRange);
|
|
28245
|
-
|
|
28246
|
-
|
|
28247
|
-
|
|
28248
|
-
|
|
28249
|
-
|
|
28250
|
-
|
|
28251
|
-
|
|
28252
|
-
|
|
28253
|
-
|
|
28254
|
-
|
|
28255
|
-
|
|
28256
|
-
|
|
28257
|
-
|
|
28258
|
-
|
|
28259
|
-
|
|
28260
|
-
|
|
28427
|
+
try {
|
|
28428
|
+
switch (config.type) {
|
|
28429
|
+
case "polynomial": {
|
|
28430
|
+
const order = config.order;
|
|
28431
|
+
if (!order) {
|
|
28432
|
+
return Array.from({ length: newLabels.length }, () => NaN);
|
|
28433
|
+
}
|
|
28434
|
+
if (order === 1) {
|
|
28435
|
+
return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0];
|
|
28436
|
+
}
|
|
28437
|
+
const coeffs = polynomialRegression(values, normalizedLabels, order, true).flat();
|
|
28438
|
+
return normalizedNewLabels.map((v) => evaluatePolynomial(coeffs, v, order));
|
|
28439
|
+
}
|
|
28440
|
+
case "exponential": {
|
|
28441
|
+
const positiveLogValues = [];
|
|
28442
|
+
const filteredLabels = [];
|
|
28443
|
+
for (let i = 0; i < values.length; i++) {
|
|
28444
|
+
if (values[i] > 0) {
|
|
28445
|
+
positiveLogValues.push(Math.log(values[i]));
|
|
28446
|
+
filteredLabels.push(normalizedLabels[i]);
|
|
28447
|
+
}
|
|
28448
|
+
}
|
|
28449
|
+
if (!filteredLabels.length) {
|
|
28450
|
+
return Array.from({ length: newLabels.length }, () => NaN);
|
|
28261
28451
|
}
|
|
28452
|
+
return expM(predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true))[0];
|
|
28262
28453
|
}
|
|
28263
|
-
|
|
28264
|
-
return [];
|
|
28454
|
+
case "logarithmic": {
|
|
28455
|
+
return predictLinearValues([values], logM([normalizedLabels]), logM([normalizedNewLabels]), true)[0];
|
|
28265
28456
|
}
|
|
28266
|
-
|
|
28267
|
-
|
|
28268
|
-
|
|
28269
|
-
|
|
28270
|
-
|
|
28271
|
-
case "trailingMovingAverage": {
|
|
28272
|
-
return getMovingAverageValues(values, config.window);
|
|
28457
|
+
case "trailingMovingAverage": {
|
|
28458
|
+
return getMovingAverageValues(values, config.window);
|
|
28459
|
+
}
|
|
28460
|
+
default:
|
|
28461
|
+
return Array.from({ length: newLabels.length }, () => NaN);
|
|
28273
28462
|
}
|
|
28274
|
-
|
|
28275
|
-
|
|
28463
|
+
}
|
|
28464
|
+
catch (e) {
|
|
28465
|
+
return Array.from({ length: newLabels.length }, () => NaN);
|
|
28276
28466
|
}
|
|
28277
28467
|
}
|
|
28278
28468
|
function getChartAxisType(chart, labelRange, getters) {
|
|
@@ -28706,6 +28896,43 @@ function getRadarChartDatasets(definition, args) {
|
|
|
28706
28896
|
}
|
|
28707
28897
|
return datasets;
|
|
28708
28898
|
}
|
|
28899
|
+
function getGeoChartDatasets(definition, args) {
|
|
28900
|
+
const { availableRegions, dataSetsValues, labels } = args;
|
|
28901
|
+
const regionName = definition.region || availableRegions[0]?.id;
|
|
28902
|
+
const features = regionName ? args.getGeoJsonFeatures(regionName) : undefined;
|
|
28903
|
+
const dataset = {
|
|
28904
|
+
outline: features,
|
|
28905
|
+
showOutline: !!features,
|
|
28906
|
+
data: [],
|
|
28907
|
+
};
|
|
28908
|
+
if (features && regionName) {
|
|
28909
|
+
const labelsAndValues = {};
|
|
28910
|
+
if (dataSetsValues[0]) {
|
|
28911
|
+
for (let i = 0; i < dataSetsValues[0].data.length; i++) {
|
|
28912
|
+
if (!labels[i] || dataSetsValues[0].data[i] === undefined) {
|
|
28913
|
+
continue;
|
|
28914
|
+
}
|
|
28915
|
+
const featureId = args.geoFeatureNameToId(regionName, labels[i]);
|
|
28916
|
+
if (featureId) {
|
|
28917
|
+
labelsAndValues[featureId] = { value: dataSetsValues[0].data[i], label: labels[i] };
|
|
28918
|
+
}
|
|
28919
|
+
}
|
|
28920
|
+
}
|
|
28921
|
+
for (const feature of features) {
|
|
28922
|
+
if (!feature.id) {
|
|
28923
|
+
continue;
|
|
28924
|
+
}
|
|
28925
|
+
dataset.data.push({
|
|
28926
|
+
feature: {
|
|
28927
|
+
...feature,
|
|
28928
|
+
properties: { name: labelsAndValues[feature.id]?.label },
|
|
28929
|
+
},
|
|
28930
|
+
value: labelsAndValues[feature.id]?.value,
|
|
28931
|
+
});
|
|
28932
|
+
}
|
|
28933
|
+
}
|
|
28934
|
+
return [dataset];
|
|
28935
|
+
}
|
|
28709
28936
|
function getTrendingLineDataSet(dataset, config, data) {
|
|
28710
28937
|
const defaultBorderColor = colorToRGBA(dataset.backgroundColor);
|
|
28711
28938
|
defaultBorderColor.a = 1;
|
|
@@ -28743,54 +28970,16 @@ function getChartColorsGenerator(definition, dataSetsSize) {
|
|
|
28743
28970
|
return new ColorGenerator(dataSetsSize, definition.dataSets?.map((ds) => ds.backgroundColor) || []);
|
|
28744
28971
|
}
|
|
28745
28972
|
|
|
28746
|
-
function
|
|
28747
|
-
// TODO FIXME: this is unused ATM. All the charts should probably use this instead oh whatever padding they are using now
|
|
28748
|
-
// also look into how DEFAULT_CHART_PADDING is used in scorecards, it look strange
|
|
28973
|
+
function getChartLayout(definition) {
|
|
28749
28974
|
return {
|
|
28750
28975
|
padding: {
|
|
28751
|
-
left:
|
|
28752
|
-
right:
|
|
28753
|
-
top:
|
|
28754
|
-
bottom:
|
|
28976
|
+
left: CHART_PADDING$1,
|
|
28977
|
+
right: CHART_PADDING$1,
|
|
28978
|
+
top: CHART_PADDING_TOP,
|
|
28979
|
+
bottom: CHART_PADDING_BOTTOM,
|
|
28755
28980
|
},
|
|
28756
28981
|
};
|
|
28757
28982
|
}
|
|
28758
|
-
function getBarChartLayout(definition) {
|
|
28759
|
-
return {
|
|
28760
|
-
padding: computeChartPadding({
|
|
28761
|
-
displayTitle: !!definition.title?.text,
|
|
28762
|
-
displayLegend: definition.legendPosition === "top",
|
|
28763
|
-
}),
|
|
28764
|
-
};
|
|
28765
|
-
}
|
|
28766
|
-
function getLineChartLayout(definition) {
|
|
28767
|
-
return {
|
|
28768
|
-
padding: computeChartPadding({
|
|
28769
|
-
displayTitle: !!definition.title?.text,
|
|
28770
|
-
displayLegend: definition.legendPosition === "top",
|
|
28771
|
-
}),
|
|
28772
|
-
};
|
|
28773
|
-
}
|
|
28774
|
-
function getPieChartLayout(definition) {
|
|
28775
|
-
return {
|
|
28776
|
-
padding: { left: 20, right: 20, top: definition.title ? 10 : 25, bottom: 10 },
|
|
28777
|
-
};
|
|
28778
|
-
}
|
|
28779
|
-
function getWaterfallChartLayout(definition) {
|
|
28780
|
-
return {
|
|
28781
|
-
padding: { left: 20, right: 20, top: definition.title ? 10 : 25, bottom: 10 },
|
|
28782
|
-
};
|
|
28783
|
-
}
|
|
28784
|
-
function computeChartPadding({ displayTitle, displayLegend, }) {
|
|
28785
|
-
let top = 25;
|
|
28786
|
-
if (displayTitle) {
|
|
28787
|
-
top = 0;
|
|
28788
|
-
}
|
|
28789
|
-
else if (displayLegend) {
|
|
28790
|
-
top = 10;
|
|
28791
|
-
}
|
|
28792
|
-
return { left: 20, right: 20, top, bottom: 10 };
|
|
28793
|
-
}
|
|
28794
28983
|
|
|
28795
28984
|
function getLegendDisplayOptions(definition, args) {
|
|
28796
28985
|
return {
|
|
@@ -28848,11 +29037,12 @@ function getScatterChartLegend(definition, args) {
|
|
|
28848
29037
|
return {
|
|
28849
29038
|
...INTERACTIVE_LEGEND_CONFIG,
|
|
28850
29039
|
...getLegendDisplayOptions(definition),
|
|
28851
|
-
|
|
28852
|
-
|
|
28853
|
-
|
|
28854
|
-
|
|
28855
|
-
|
|
29040
|
+
...getCustomLegendLabels(chartFontColor(definition.background), {
|
|
29041
|
+
pointStyle: "circle",
|
|
29042
|
+
// the stroke is the border around the circle, so increasing its size with the chart's color reduce the size of the circle
|
|
29043
|
+
strokeStyle: definition.background || "#ffffff",
|
|
29044
|
+
lineWidth: 8,
|
|
29045
|
+
}),
|
|
28856
29046
|
};
|
|
28857
29047
|
}
|
|
28858
29048
|
function getComboChartLegend(definition, args) {
|
|
@@ -28941,10 +29131,10 @@ const INTERACTIVE_LEGEND_CONFIG = {
|
|
|
28941
29131
|
target.style.cursor = "default";
|
|
28942
29132
|
},
|
|
28943
29133
|
onClick: (event, legendItem, legend) => {
|
|
28944
|
-
|
|
29134
|
+
const index = legendItem.datasetIndex;
|
|
29135
|
+
if (!legend.legendItems || index === undefined) {
|
|
28945
29136
|
return;
|
|
28946
29137
|
}
|
|
28947
|
-
const index = legend.legendItems.indexOf(legendItem);
|
|
28948
29138
|
if (legend.chart.isDatasetVisible(index)) {
|
|
28949
29139
|
legend.chart.hide(index);
|
|
28950
29140
|
}
|
|
@@ -28960,15 +29150,29 @@ function getCustomLegendLabels(fontColor, legendLabelConfig) {
|
|
|
28960
29150
|
labels: {
|
|
28961
29151
|
color: fontColor,
|
|
28962
29152
|
usePointStyle: true,
|
|
28963
|
-
generateLabels: (chart) => chart.data.datasets.map((dataset, index) =>
|
|
28964
|
-
|
|
28965
|
-
|
|
28966
|
-
|
|
28967
|
-
|
|
28968
|
-
|
|
28969
|
-
|
|
28970
|
-
|
|
28971
|
-
|
|
29153
|
+
generateLabels: (chart) => chart.data.datasets.map((dataset, index) => {
|
|
29154
|
+
if (dataset["xAxisID"] === TREND_LINE_XAXIS_ID) {
|
|
29155
|
+
return {
|
|
29156
|
+
text: dataset.label ?? "",
|
|
29157
|
+
fontColor,
|
|
29158
|
+
strokeStyle: dataset.borderColor,
|
|
29159
|
+
hidden: !chart.isDatasetVisible(index),
|
|
29160
|
+
pointStyle: "line",
|
|
29161
|
+
datasetIndex: index,
|
|
29162
|
+
lineWidth: 3,
|
|
29163
|
+
};
|
|
29164
|
+
}
|
|
29165
|
+
return {
|
|
29166
|
+
text: dataset.label ?? "",
|
|
29167
|
+
fontColor,
|
|
29168
|
+
strokeStyle: dataset.borderColor,
|
|
29169
|
+
fillStyle: dataset.backgroundColor,
|
|
29170
|
+
hidden: !chart.isDatasetVisible(index),
|
|
29171
|
+
pointStyle: dataset.type === "line" ? "line" : "rect",
|
|
29172
|
+
datasetIndex: index,
|
|
29173
|
+
...legendLabelConfig,
|
|
29174
|
+
};
|
|
29175
|
+
}),
|
|
28972
29176
|
},
|
|
28973
29177
|
};
|
|
28974
29178
|
}
|
|
@@ -29106,6 +29310,44 @@ function getRadarChartScales(definition, args) {
|
|
|
29106
29310
|
},
|
|
29107
29311
|
};
|
|
29108
29312
|
}
|
|
29313
|
+
function getGeoChartScales(definition, args) {
|
|
29314
|
+
const { locale, axisFormats, availableRegions } = args;
|
|
29315
|
+
const geoLegendPosition = legendPositionToGeoLegendPosition(definition.legendPosition);
|
|
29316
|
+
const region = definition.region
|
|
29317
|
+
? availableRegions.find((r) => r.id === definition.region)
|
|
29318
|
+
: availableRegions[0];
|
|
29319
|
+
const format = axisFormats?.y || axisFormats?.y1;
|
|
29320
|
+
return {
|
|
29321
|
+
projection: {
|
|
29322
|
+
// projection: region?.defaultProjection,
|
|
29323
|
+
projection: getGeoChartProjection(region?.defaultProjection || "mercator"),
|
|
29324
|
+
axis: "x",
|
|
29325
|
+
},
|
|
29326
|
+
color: {
|
|
29327
|
+
axis: "x",
|
|
29328
|
+
display: definition.legendPosition !== "none",
|
|
29329
|
+
border: { color: GRAY_300 },
|
|
29330
|
+
grid: { color: GRAY_300 },
|
|
29331
|
+
ticks: {
|
|
29332
|
+
color: chartFontColor(definition.background),
|
|
29333
|
+
callback: formatTickValue({ locale, format }),
|
|
29334
|
+
},
|
|
29335
|
+
legend: {
|
|
29336
|
+
position: geoLegendPosition,
|
|
29337
|
+
align: geoLegendPosition.includes("right") ? "left" : "right",
|
|
29338
|
+
margin: getLegendMargin(definition),
|
|
29339
|
+
},
|
|
29340
|
+
interpolate: getRuntimeColorScale(definition),
|
|
29341
|
+
missing: definition.missingValueColor || "#ffffff",
|
|
29342
|
+
},
|
|
29343
|
+
};
|
|
29344
|
+
}
|
|
29345
|
+
function getGeoChartProjection(projection) {
|
|
29346
|
+
if (projection === "conicConformal") {
|
|
29347
|
+
return window.ChartGeo.geoConicConformal().rotate([100, 0]); // Centered on the US
|
|
29348
|
+
}
|
|
29349
|
+
return projection;
|
|
29350
|
+
}
|
|
29109
29351
|
function getChartAxisTitleRuntime(design) {
|
|
29110
29352
|
if (design?.title?.text) {
|
|
29111
29353
|
const { text, color, align, italic, bold } = design.title;
|
|
@@ -29116,6 +29358,7 @@ function getChartAxisTitleRuntime(design) {
|
|
|
29116
29358
|
font: {
|
|
29117
29359
|
style: italic ? "italic" : "normal",
|
|
29118
29360
|
weight: bold ? "bold" : "normal",
|
|
29361
|
+
size: design.title.fontSize ?? CHART_AXIS_TITLE_FONT_SIZE,
|
|
29119
29362
|
},
|
|
29120
29363
|
align: align === "left" ? "start" : align === "right" ? "end" : "center",
|
|
29121
29364
|
};
|
|
@@ -29168,6 +29411,44 @@ function getChartAxis(definition, position, type, options) {
|
|
|
29168
29411
|
};
|
|
29169
29412
|
}
|
|
29170
29413
|
}
|
|
29414
|
+
function getRuntimeColorScale(definition) {
|
|
29415
|
+
if (!definition.colorScale || typeof definition.colorScale === "string") {
|
|
29416
|
+
return definition.colorScale || "oranges";
|
|
29417
|
+
}
|
|
29418
|
+
const scaleColors = [{ value: 0, color: definition.colorScale.minColor }];
|
|
29419
|
+
if (definition.colorScale.midColor) {
|
|
29420
|
+
scaleColors.push({ value: 0.5, color: definition.colorScale.midColor });
|
|
29421
|
+
}
|
|
29422
|
+
scaleColors.push({ value: 1, color: definition.colorScale.maxColor });
|
|
29423
|
+
return getColorScale(scaleColors);
|
|
29424
|
+
}
|
|
29425
|
+
function getLegendMargin(definition) {
|
|
29426
|
+
switch (definition.legendPosition) {
|
|
29427
|
+
case "top":
|
|
29428
|
+
case "right":
|
|
29429
|
+
const hasTitle = !!definition.title.text;
|
|
29430
|
+
const topMargin = hasTitle ? CHART_PADDING_TOP + 30 : CHART_PADDING_TOP;
|
|
29431
|
+
return { top: topMargin, left: CHART_PADDING$1, right: CHART_PADDING$1 };
|
|
29432
|
+
case "bottom":
|
|
29433
|
+
case "left":
|
|
29434
|
+
case "none":
|
|
29435
|
+
return { left: CHART_PADDING$1, right: CHART_PADDING$1, bottom: CHART_PADDING_BOTTOM };
|
|
29436
|
+
}
|
|
29437
|
+
}
|
|
29438
|
+
function legendPositionToGeoLegendPosition(position) {
|
|
29439
|
+
switch (position) {
|
|
29440
|
+
case "top":
|
|
29441
|
+
return "top-left";
|
|
29442
|
+
case "right":
|
|
29443
|
+
return "top-right";
|
|
29444
|
+
case "bottom":
|
|
29445
|
+
return "bottom-right";
|
|
29446
|
+
case "left":
|
|
29447
|
+
return "bottom-left";
|
|
29448
|
+
case "none":
|
|
29449
|
+
return "bottom-left";
|
|
29450
|
+
}
|
|
29451
|
+
}
|
|
29171
29452
|
|
|
29172
29453
|
function getChartShowValues(definition, args) {
|
|
29173
29454
|
const { axisFormats, locale } = args;
|
|
@@ -29181,17 +29462,22 @@ function getChartShowValues(definition, args) {
|
|
|
29181
29462
|
|
|
29182
29463
|
function getChartTitle(definition) {
|
|
29183
29464
|
const chartTitle = definition.title;
|
|
29184
|
-
const fontColor =
|
|
29465
|
+
const fontColor = chartMutedFontColor(definition.background);
|
|
29185
29466
|
return {
|
|
29186
29467
|
display: !!chartTitle.text,
|
|
29187
29468
|
text: _t(chartTitle.text),
|
|
29188
29469
|
color: chartTitle?.color ?? fontColor,
|
|
29189
29470
|
align: chartTitle.align === "center" ? "center" : chartTitle.align === "right" ? "end" : "start",
|
|
29190
29471
|
font: {
|
|
29191
|
-
size:
|
|
29472
|
+
size: definition.title.fontSize ?? CHART_TITLE_FONT_SIZE,
|
|
29192
29473
|
weight: chartTitle.bold ? "bold" : "normal",
|
|
29193
29474
|
style: chartTitle.italic ? "italic" : "normal",
|
|
29194
29475
|
},
|
|
29476
|
+
padding: {
|
|
29477
|
+
// Disable title top/left/right padding to use the chart padding instead.
|
|
29478
|
+
// The legend already has a top padding, so bottom padding is useless for the title there.
|
|
29479
|
+
bottom: definition.legendPosition === "top" ? 0 : CHART_PADDING$1,
|
|
29480
|
+
},
|
|
29195
29481
|
};
|
|
29196
29482
|
}
|
|
29197
29483
|
|
|
@@ -29322,6 +29608,25 @@ function getRadarChartTooltip(definition, args) {
|
|
|
29322
29608
|
},
|
|
29323
29609
|
};
|
|
29324
29610
|
}
|
|
29611
|
+
function getGeoChartTooltip(definition, args) {
|
|
29612
|
+
const { locale, axisFormats } = args;
|
|
29613
|
+
const format = axisFormats?.y || axisFormats?.y1;
|
|
29614
|
+
return {
|
|
29615
|
+
filter: function (tooltipItem) {
|
|
29616
|
+
return tooltipItem.raw.value !== undefined;
|
|
29617
|
+
},
|
|
29618
|
+
callbacks: {
|
|
29619
|
+
label: function (tooltipItem) {
|
|
29620
|
+
const rawItem = tooltipItem.raw;
|
|
29621
|
+
const xLabel = rawItem.feature.properties.name;
|
|
29622
|
+
const yLabel = rawItem.value;
|
|
29623
|
+
const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
|
|
29624
|
+
const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
|
|
29625
|
+
return xLabel ? `${xLabel}: ${yLabelStr}` : yLabelStr;
|
|
29626
|
+
},
|
|
29627
|
+
},
|
|
29628
|
+
};
|
|
29629
|
+
}
|
|
29325
29630
|
function calculatePercentage(dataset, dataIndex) {
|
|
29326
29631
|
const numericData = dataset.filter((value) => typeof value === "number");
|
|
29327
29632
|
const total = numericData.reduce((sum, value) => sum + value, 0);
|
|
@@ -29338,26 +29643,27 @@ var CHART_RUNTIME_HELPERS = /*#__PURE__*/Object.freeze({
|
|
|
29338
29643
|
canChartParseLabels: canChartParseLabels,
|
|
29339
29644
|
getBarChartData: getBarChartData,
|
|
29340
29645
|
getBarChartDatasets: getBarChartDatasets,
|
|
29341
|
-
getBarChartLayout: getBarChartLayout,
|
|
29342
29646
|
getBarChartLegend: getBarChartLegend,
|
|
29343
29647
|
getBarChartScales: getBarChartScales,
|
|
29344
29648
|
getBarChartTooltip: getBarChartTooltip,
|
|
29345
29649
|
getChartLabelFormat: getChartLabelFormat,
|
|
29650
|
+
getChartLayout: getChartLayout,
|
|
29346
29651
|
getChartShowValues: getChartShowValues,
|
|
29347
29652
|
getChartTitle: getChartTitle,
|
|
29348
29653
|
getComboChartDatasets: getComboChartDatasets,
|
|
29349
29654
|
getComboChartLegend: getComboChartLegend,
|
|
29350
|
-
getCommonChartLayout: getCommonChartLayout,
|
|
29351
29655
|
getData: getData,
|
|
29656
|
+
getGeoChartData: getGeoChartData,
|
|
29657
|
+
getGeoChartDatasets: getGeoChartDatasets,
|
|
29658
|
+
getGeoChartScales: getGeoChartScales,
|
|
29659
|
+
getGeoChartTooltip: getGeoChartTooltip,
|
|
29352
29660
|
getLineChartData: getLineChartData,
|
|
29353
29661
|
getLineChartDatasets: getLineChartDatasets,
|
|
29354
|
-
getLineChartLayout: getLineChartLayout,
|
|
29355
29662
|
getLineChartLegend: getLineChartLegend,
|
|
29356
29663
|
getLineChartScales: getLineChartScales,
|
|
29357
29664
|
getLineChartTooltip: getLineChartTooltip,
|
|
29358
29665
|
getPieChartData: getPieChartData,
|
|
29359
29666
|
getPieChartDatasets: getPieChartDatasets,
|
|
29360
|
-
getPieChartLayout: getPieChartLayout,
|
|
29361
29667
|
getPieChartLegend: getPieChartLegend,
|
|
29362
29668
|
getPieChartTooltip: getPieChartTooltip,
|
|
29363
29669
|
getPyramidChartData: getPyramidChartData,
|
|
@@ -29373,7 +29679,6 @@ var CHART_RUNTIME_HELPERS = /*#__PURE__*/Object.freeze({
|
|
|
29373
29679
|
getScatterChartScales: getScatterChartScales,
|
|
29374
29680
|
getTrendDatasetForBarChart: getTrendDatasetForBarChart,
|
|
29375
29681
|
getTrendDatasetForLineChart: getTrendDatasetForLineChart,
|
|
29376
|
-
getWaterfallChartLayout: getWaterfallChartLayout,
|
|
29377
29682
|
getWaterfallChartLegend: getWaterfallChartLegend,
|
|
29378
29683
|
getWaterfallChartScales: getWaterfallChartScales,
|
|
29379
29684
|
getWaterfallChartTooltip: getWaterfallChartTooltip,
|
|
@@ -29521,7 +29826,7 @@ function createBarChartRuntime(chart, getters) {
|
|
|
29521
29826
|
options: {
|
|
29522
29827
|
...CHART_COMMON_OPTIONS,
|
|
29523
29828
|
indexAxis: chart.horizontal ? "y" : "x",
|
|
29524
|
-
layout:
|
|
29829
|
+
layout: getChartLayout(),
|
|
29525
29830
|
scales: getBarChartScales(definition, chartData),
|
|
29526
29831
|
plugins: {
|
|
29527
29832
|
title: getChartTitle(definition),
|
|
@@ -29673,7 +29978,7 @@ function createComboChartRuntime(chart, getters) {
|
|
|
29673
29978
|
},
|
|
29674
29979
|
options: {
|
|
29675
29980
|
...CHART_COMMON_OPTIONS,
|
|
29676
|
-
layout:
|
|
29981
|
+
layout: getChartLayout(),
|
|
29677
29982
|
scales: getBarChartScales(definition, chartData),
|
|
29678
29983
|
plugins: {
|
|
29679
29984
|
title: getChartTitle(definition),
|
|
@@ -29925,6 +30230,133 @@ function getSectionThresholdValue(threshold, minValue, maxValue) {
|
|
|
29925
30230
|
return clip(value, minValue, maxValue);
|
|
29926
30231
|
}
|
|
29927
30232
|
|
|
30233
|
+
class GeoChart extends AbstractChart {
|
|
30234
|
+
dataSets;
|
|
30235
|
+
labelRange;
|
|
30236
|
+
background;
|
|
30237
|
+
legendPosition;
|
|
30238
|
+
type = "geo";
|
|
30239
|
+
dataSetsHaveTitle;
|
|
30240
|
+
dataSetDesign;
|
|
30241
|
+
colorScale;
|
|
30242
|
+
missingValueColor;
|
|
30243
|
+
region;
|
|
30244
|
+
constructor(definition, sheetId, getters) {
|
|
30245
|
+
super(definition, sheetId, getters);
|
|
30246
|
+
this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
|
|
30247
|
+
this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
|
|
30248
|
+
this.background = definition.background;
|
|
30249
|
+
this.legendPosition = definition.legendPosition;
|
|
30250
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
30251
|
+
this.dataSetDesign = definition.dataSets;
|
|
30252
|
+
this.colorScale = definition.colorScale;
|
|
30253
|
+
this.missingValueColor = definition.missingValueColor;
|
|
30254
|
+
this.region = definition.region;
|
|
30255
|
+
}
|
|
30256
|
+
static transformDefinition(definition, executed) {
|
|
30257
|
+
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
30258
|
+
}
|
|
30259
|
+
static validateChartDefinition(validator, definition) {
|
|
30260
|
+
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
30261
|
+
}
|
|
30262
|
+
static getDefinitionFromContextCreation(context) {
|
|
30263
|
+
return {
|
|
30264
|
+
background: context.background,
|
|
30265
|
+
dataSets: context.range ?? [],
|
|
30266
|
+
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
30267
|
+
legendPosition: context.legendPosition ?? "top",
|
|
30268
|
+
title: context.title || { text: "" },
|
|
30269
|
+
type: "geo",
|
|
30270
|
+
labelRange: context.auxiliaryRange || undefined,
|
|
30271
|
+
aggregated: context.aggregated,
|
|
30272
|
+
};
|
|
30273
|
+
}
|
|
30274
|
+
getContextCreation() {
|
|
30275
|
+
const range = [];
|
|
30276
|
+
for (const [i, dataSet] of this.dataSets.entries()) {
|
|
30277
|
+
range.push({
|
|
30278
|
+
...this.dataSetDesign?.[i],
|
|
30279
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId),
|
|
30280
|
+
});
|
|
30281
|
+
}
|
|
30282
|
+
return {
|
|
30283
|
+
...this,
|
|
30284
|
+
range,
|
|
30285
|
+
auxiliaryRange: this.labelRange
|
|
30286
|
+
? this.getters.getRangeString(this.labelRange, this.sheetId)
|
|
30287
|
+
: undefined,
|
|
30288
|
+
};
|
|
30289
|
+
}
|
|
30290
|
+
copyForSheetId(sheetId) {
|
|
30291
|
+
const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
|
|
30292
|
+
const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
|
|
30293
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
|
|
30294
|
+
return new GeoChart(definition, sheetId, this.getters);
|
|
30295
|
+
}
|
|
30296
|
+
copyInSheetId(sheetId) {
|
|
30297
|
+
const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
|
|
30298
|
+
return new GeoChart(definition, sheetId, this.getters);
|
|
30299
|
+
}
|
|
30300
|
+
getDefinition() {
|
|
30301
|
+
return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
|
|
30302
|
+
}
|
|
30303
|
+
getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
|
|
30304
|
+
const ranges = [];
|
|
30305
|
+
for (const [i, dataSet] of dataSets.entries()) {
|
|
30306
|
+
ranges.push({
|
|
30307
|
+
...this.dataSetDesign?.[i],
|
|
30308
|
+
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
30309
|
+
});
|
|
30310
|
+
}
|
|
30311
|
+
return {
|
|
30312
|
+
type: "geo",
|
|
30313
|
+
dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
|
|
30314
|
+
background: this.background,
|
|
30315
|
+
dataSets: ranges,
|
|
30316
|
+
legendPosition: this.legendPosition,
|
|
30317
|
+
labelRange: labelRange
|
|
30318
|
+
? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
|
|
30319
|
+
: undefined,
|
|
30320
|
+
title: this.title,
|
|
30321
|
+
colorScale: this.colorScale,
|
|
30322
|
+
missingValueColor: this.missingValueColor,
|
|
30323
|
+
region: this.region,
|
|
30324
|
+
};
|
|
30325
|
+
}
|
|
30326
|
+
getDefinitionForExcel() {
|
|
30327
|
+
return undefined;
|
|
30328
|
+
}
|
|
30329
|
+
updateRanges(applyChange) {
|
|
30330
|
+
const { dataSets, labelRange, isStale } = updateChartRangesWithDataSets(this.getters, applyChange, this.dataSets, this.labelRange);
|
|
30331
|
+
if (!isStale) {
|
|
30332
|
+
return this;
|
|
30333
|
+
}
|
|
30334
|
+
const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange);
|
|
30335
|
+
return new GeoChart(definition, this.sheetId, this.getters);
|
|
30336
|
+
}
|
|
30337
|
+
}
|
|
30338
|
+
function createGeoChartRuntime(chart, getters) {
|
|
30339
|
+
const definition = chart.getDefinition();
|
|
30340
|
+
const chartData = getGeoChartData(definition, chart.dataSets, chart.labelRange, getters);
|
|
30341
|
+
const config = {
|
|
30342
|
+
type: "choropleth",
|
|
30343
|
+
data: {
|
|
30344
|
+
datasets: getGeoChartDatasets(definition, chartData),
|
|
30345
|
+
},
|
|
30346
|
+
options: {
|
|
30347
|
+
...CHART_COMMON_OPTIONS,
|
|
30348
|
+
layout: getChartLayout(),
|
|
30349
|
+
scales: getGeoChartScales(definition, chartData),
|
|
30350
|
+
plugins: {
|
|
30351
|
+
title: getChartTitle(definition),
|
|
30352
|
+
tooltip: getGeoChartTooltip(definition, chartData),
|
|
30353
|
+
legend: { display: false },
|
|
30354
|
+
},
|
|
30355
|
+
},
|
|
30356
|
+
};
|
|
30357
|
+
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
30358
|
+
}
|
|
30359
|
+
|
|
29928
30360
|
class LineChart extends AbstractChart {
|
|
29929
30361
|
dataSets;
|
|
29930
30362
|
labelRange;
|
|
@@ -30074,7 +30506,7 @@ function createLineChartRuntime(chart, getters) {
|
|
|
30074
30506
|
},
|
|
30075
30507
|
options: {
|
|
30076
30508
|
...CHART_COMMON_OPTIONS,
|
|
30077
|
-
layout:
|
|
30509
|
+
layout: getChartLayout(),
|
|
30078
30510
|
scales: getLineChartScales(definition, chartData),
|
|
30079
30511
|
plugins: {
|
|
30080
30512
|
title: getChartTitle(definition),
|
|
@@ -30209,7 +30641,7 @@ function createPieChartRuntime(chart, getters) {
|
|
|
30209
30641
|
},
|
|
30210
30642
|
options: {
|
|
30211
30643
|
...CHART_COMMON_OPTIONS,
|
|
30212
|
-
layout:
|
|
30644
|
+
layout: getChartLayout(),
|
|
30213
30645
|
plugins: {
|
|
30214
30646
|
title: getChartTitle(definition),
|
|
30215
30647
|
legend: getPieChartLegend(definition, chartData),
|
|
@@ -30346,7 +30778,7 @@ function createPyramidChartRuntime(chart, getters) {
|
|
|
30346
30778
|
options: {
|
|
30347
30779
|
...CHART_COMMON_OPTIONS,
|
|
30348
30780
|
indexAxis: "y",
|
|
30349
|
-
layout:
|
|
30781
|
+
layout: getChartLayout(),
|
|
30350
30782
|
scales: getPyramidChartScales(definition, chartData),
|
|
30351
30783
|
plugins: {
|
|
30352
30784
|
title: getChartTitle(definition),
|
|
@@ -30495,7 +30927,7 @@ function createRadarChartRuntime(chart, getters) {
|
|
|
30495
30927
|
},
|
|
30496
30928
|
options: {
|
|
30497
30929
|
...CHART_COMMON_OPTIONS,
|
|
30498
|
-
layout:
|
|
30930
|
+
layout: getChartLayout(),
|
|
30499
30931
|
scales: getRadarChartScales(definition, chartData),
|
|
30500
30932
|
plugins: {
|
|
30501
30933
|
title: getChartTitle(definition),
|
|
@@ -30648,7 +31080,7 @@ function createScatterChartRuntime(chart, getters) {
|
|
|
30648
31080
|
},
|
|
30649
31081
|
options: {
|
|
30650
31082
|
...CHART_COMMON_OPTIONS,
|
|
30651
|
-
layout:
|
|
31083
|
+
layout: getChartLayout(),
|
|
30652
31084
|
scales: getScatterChartScales(definition, chartData),
|
|
30653
31085
|
plugins: {
|
|
30654
31086
|
title: getChartTitle(definition),
|
|
@@ -30809,7 +31241,7 @@ function createWaterfallChartRuntime(chart, getters) {
|
|
|
30809
31241
|
},
|
|
30810
31242
|
options: {
|
|
30811
31243
|
...CHART_COMMON_OPTIONS,
|
|
30812
|
-
layout:
|
|
31244
|
+
layout: getChartLayout(),
|
|
30813
31245
|
scales: getWaterfallChartScales(definition, chartData),
|
|
30814
31246
|
plugins: {
|
|
30815
31247
|
title: getChartTitle(definition),
|
|
@@ -30918,6 +31350,15 @@ chartRegistry.add("radar", {
|
|
|
30918
31350
|
getChartDefinitionFromContextCreation: RadarChart.getDefinitionFromContextCreation,
|
|
30919
31351
|
sequence: 80,
|
|
30920
31352
|
});
|
|
31353
|
+
chartRegistry.add("geo", {
|
|
31354
|
+
match: (type) => type === "geo",
|
|
31355
|
+
createChart: (definition, sheetId, getters) => new GeoChart(definition, sheetId, getters),
|
|
31356
|
+
getChartRuntime: createGeoChartRuntime,
|
|
31357
|
+
validateChartDefinition: GeoChart.validateChartDefinition,
|
|
31358
|
+
transformDefinition: GeoChart.transformDefinition,
|
|
31359
|
+
getChartDefinitionFromContextCreation: GeoChart.getDefinitionFromContextCreation,
|
|
31360
|
+
sequence: 90,
|
|
31361
|
+
});
|
|
30921
31362
|
const chartComponentRegistry = new Registry();
|
|
30922
31363
|
chartComponentRegistry.add("line", ChartJsComponent);
|
|
30923
31364
|
chartComponentRegistry.add("bar", ChartJsComponent);
|
|
@@ -30929,6 +31370,7 @@ chartComponentRegistry.add("scorecard", ScorecardChart);
|
|
|
30929
31370
|
chartComponentRegistry.add("waterfall", ChartJsComponent);
|
|
30930
31371
|
chartComponentRegistry.add("pyramid", ChartJsComponent);
|
|
30931
31372
|
chartComponentRegistry.add("radar", ChartJsComponent);
|
|
31373
|
+
chartComponentRegistry.add("geo", ChartJsComponent);
|
|
30932
31374
|
const chartCategories = {
|
|
30933
31375
|
line: _t("Line"),
|
|
30934
31376
|
column: _t("Column"),
|
|
@@ -31088,6 +31530,13 @@ chartSubtypeRegistry
|
|
|
31088
31530
|
subtypeDefinition: { fillArea: true },
|
|
31089
31531
|
category: "misc",
|
|
31090
31532
|
preview: "o-spreadsheet-ChartPreview.FILLED_RADAR_CHART",
|
|
31533
|
+
})
|
|
31534
|
+
.add("geo", {
|
|
31535
|
+
displayName: _t("Geo Chart"),
|
|
31536
|
+
chartSubtype: "geo",
|
|
31537
|
+
chartType: "geo",
|
|
31538
|
+
category: "misc",
|
|
31539
|
+
preview: "o-spreadsheet-ChartPreview.GEO_CHART",
|
|
31091
31540
|
});
|
|
31092
31541
|
|
|
31093
31542
|
/**
|
|
@@ -31938,18 +32387,66 @@ const ErrorToolTipPopoverBuilder = {
|
|
|
31938
32387
|
},
|
|
31939
32388
|
};
|
|
31940
32389
|
|
|
31941
|
-
|
|
31942
|
-
|
|
31943
|
-
|
|
31944
|
-
|
|
31945
|
-
|
|
31946
|
-
|
|
31947
|
-
|
|
32390
|
+
const CHECK_SVG = /*xml*/ `
|
|
32391
|
+
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'>
|
|
32392
|
+
<path fill='none' stroke='#FFF' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/>
|
|
32393
|
+
</svg>
|
|
32394
|
+
`;
|
|
32395
|
+
const CHECKBOX_WIDTH = 14;
|
|
32396
|
+
css /* scss */ `
|
|
32397
|
+
label.o-checkbox {
|
|
32398
|
+
input {
|
|
32399
|
+
appearance: none;
|
|
32400
|
+
-webkit-appearance: none;
|
|
32401
|
+
-moz-appearance: none;
|
|
32402
|
+
border-radius: 0;
|
|
32403
|
+
width: ${CHECKBOX_WIDTH}px;
|
|
32404
|
+
height: ${CHECKBOX_WIDTH}px;
|
|
32405
|
+
vertical-align: top;
|
|
32406
|
+
box-sizing: border-box;
|
|
32407
|
+
outline: none;
|
|
32408
|
+
border: 1px solid ${GRAY_300};
|
|
32409
|
+
cursor: pointer;
|
|
32410
|
+
|
|
32411
|
+
&:hover {
|
|
32412
|
+
border-color: ${ACTION_COLOR};
|
|
32413
|
+
}
|
|
32414
|
+
|
|
32415
|
+
&:checked {
|
|
32416
|
+
background: url("data:image/svg+xml,${encodeURIComponent(CHECK_SVG)}");
|
|
32417
|
+
background-color: ${ACTION_COLOR};
|
|
32418
|
+
border-color: ${ACTION_COLOR};
|
|
32419
|
+
}
|
|
32420
|
+
|
|
32421
|
+
&:focus {
|
|
32422
|
+
outline: none;
|
|
32423
|
+
box-shadow: 0 0 0 0.25rem rgba(113, 75, 103, 0.25);
|
|
32424
|
+
border-color: ${ACTION_COLOR};
|
|
32425
|
+
}
|
|
31948
32426
|
}
|
|
31949
32427
|
}
|
|
31950
32428
|
`;
|
|
32429
|
+
class Checkbox extends owl.Component {
|
|
32430
|
+
static template = "o-spreadsheet.Checkbox";
|
|
32431
|
+
static props = {
|
|
32432
|
+
label: { type: String, optional: true },
|
|
32433
|
+
value: { type: Boolean, optional: true },
|
|
32434
|
+
className: { type: String, optional: true },
|
|
32435
|
+
name: { type: String, optional: true },
|
|
32436
|
+
title: { type: String, optional: true },
|
|
32437
|
+
disabled: { type: Boolean, optional: true },
|
|
32438
|
+
onChange: Function,
|
|
32439
|
+
};
|
|
32440
|
+
static defaultProps = { value: false };
|
|
32441
|
+
onChange(ev) {
|
|
32442
|
+
const value = ev.target.checked;
|
|
32443
|
+
this.props.onChange(value);
|
|
32444
|
+
}
|
|
32445
|
+
}
|
|
32446
|
+
|
|
31951
32447
|
class FilterMenuValueItem extends owl.Component {
|
|
31952
32448
|
static template = "o-spreadsheet-FilterMenuValueItem";
|
|
32449
|
+
static components = { Checkbox };
|
|
31953
32450
|
static props = {
|
|
31954
32451
|
value: String,
|
|
31955
32452
|
isChecked: Boolean,
|
|
@@ -31987,8 +32484,6 @@ const CSS = css /* scss */ `
|
|
|
31987
32484
|
.o-filter-menu-item {
|
|
31988
32485
|
display: flex;
|
|
31989
32486
|
box-sizing: border-box;
|
|
31990
|
-
height: ${MENU_ITEM_HEIGHT}px;
|
|
31991
|
-
padding: 4px 4px 4px 0px;
|
|
31992
32487
|
cursor: pointer;
|
|
31993
32488
|
user-select: none;
|
|
31994
32489
|
|
|
@@ -31997,14 +32492,6 @@ const CSS = css /* scss */ `
|
|
|
31997
32492
|
}
|
|
31998
32493
|
}
|
|
31999
32494
|
|
|
32000
|
-
input {
|
|
32001
|
-
box-sizing: border-box;
|
|
32002
|
-
margin-bottom: 5px;
|
|
32003
|
-
border: 1px solid #949494;
|
|
32004
|
-
height: 24px;
|
|
32005
|
-
padding-right: 28px;
|
|
32006
|
-
}
|
|
32007
|
-
|
|
32008
32495
|
.o-search-icon {
|
|
32009
32496
|
right: 5px;
|
|
32010
32497
|
top: 3px;
|
|
@@ -32021,19 +32508,12 @@ const CSS = css /* scss */ `
|
|
|
32021
32508
|
display: flex;
|
|
32022
32509
|
flex-direction: row;
|
|
32023
32510
|
margin-bottom: 4px;
|
|
32024
|
-
|
|
32025
|
-
.o-filter-menu-action-text {
|
|
32026
|
-
cursor: pointer;
|
|
32027
|
-
margin-right: 10px;
|
|
32028
|
-
color: blue;
|
|
32029
|
-
text-decoration: underline;
|
|
32030
|
-
}
|
|
32031
32511
|
}
|
|
32032
32512
|
|
|
32033
32513
|
.o-filter-menu-list {
|
|
32034
32514
|
flex: auto;
|
|
32035
32515
|
overflow-y: auto;
|
|
32036
|
-
border: 1px solid
|
|
32516
|
+
border: 1px solid ${GRAY_300};
|
|
32037
32517
|
|
|
32038
32518
|
.o-filter-menu-no-values {
|
|
32039
32519
|
color: #949494;
|
|
@@ -33119,6 +33599,7 @@ var CHART_HELPERS = /*#__PURE__*/Object.freeze({
|
|
|
33119
33599
|
adaptChartRange: adaptChartRange,
|
|
33120
33600
|
chartFactory: chartFactory,
|
|
33121
33601
|
chartFontColor: chartFontColor,
|
|
33602
|
+
chartMutedFontColor: chartMutedFontColor,
|
|
33122
33603
|
chartRuntimeFactory: chartRuntimeFactory,
|
|
33123
33604
|
chartToImage: chartToImage,
|
|
33124
33605
|
checkDataset: checkDataset,
|
|
@@ -34224,6 +34705,21 @@ const pivotProperties = {
|
|
|
34224
34705
|
isReadonlyAllowed: true,
|
|
34225
34706
|
icon: "o-spreadsheet-Icon.PIVOT",
|
|
34226
34707
|
};
|
|
34708
|
+
const pivotSortingAsc = {
|
|
34709
|
+
name: _t("Ascending"),
|
|
34710
|
+
execute: (env) => sortPivot(env, "asc"),
|
|
34711
|
+
isActive: (env) => isPivotSortMenuItemActive(env, "asc"),
|
|
34712
|
+
};
|
|
34713
|
+
const pivotSortingDesc = {
|
|
34714
|
+
name: _t("Descending"),
|
|
34715
|
+
execute: (env) => sortPivot(env, "desc"),
|
|
34716
|
+
isActive: (env) => isPivotSortMenuItemActive(env, "desc"),
|
|
34717
|
+
};
|
|
34718
|
+
const noPivotSorting = {
|
|
34719
|
+
name: _t("No sorting"),
|
|
34720
|
+
execute: (env) => sortPivot(env, "none"),
|
|
34721
|
+
isActive: (env) => isPivotSortMenuItemActive(env, "none"),
|
|
34722
|
+
};
|
|
34227
34723
|
const FIX_FORMULAS = {
|
|
34228
34724
|
name: _t("Convert to individual formulas"),
|
|
34229
34725
|
execute(env) {
|
|
@@ -34260,6 +34756,66 @@ const FIX_FORMULAS = {
|
|
|
34260
34756
|
},
|
|
34261
34757
|
icon: "o-spreadsheet-Icon.PIVOT",
|
|
34262
34758
|
};
|
|
34759
|
+
function canSortPivot(env) {
|
|
34760
|
+
const position = env.model.getters.getActivePosition();
|
|
34761
|
+
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
34762
|
+
if (!pivotId ||
|
|
34763
|
+
!env.model.getters.isExistingPivot(pivotId) ||
|
|
34764
|
+
!env.model.getters.isSpillPivotFormula(position)) {
|
|
34765
|
+
return false;
|
|
34766
|
+
}
|
|
34767
|
+
const pivot = env.model.getters.getPivot(pivotId);
|
|
34768
|
+
if (!pivot.isValid()) {
|
|
34769
|
+
return false;
|
|
34770
|
+
}
|
|
34771
|
+
const pivotCell = env.model.getters.getPivotCellFromPosition(position);
|
|
34772
|
+
return pivotCell.type === "VALUE" || pivotCell.type === "MEASURE_HEADER";
|
|
34773
|
+
}
|
|
34774
|
+
function sortPivot(env, order) {
|
|
34775
|
+
const position = env.model.getters.getActivePosition();
|
|
34776
|
+
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
34777
|
+
const pivotCell = env.model.getters.getPivotCellFromPosition(position);
|
|
34778
|
+
if (pivotCell.type === "EMPTY" || pivotCell.type === "HEADER" || !pivotId) {
|
|
34779
|
+
return;
|
|
34780
|
+
}
|
|
34781
|
+
if (order === "none") {
|
|
34782
|
+
env.model.dispatch("UPDATE_PIVOT", {
|
|
34783
|
+
pivotId: pivotId,
|
|
34784
|
+
pivot: {
|
|
34785
|
+
...env.model.getters.getPivotCoreDefinition(pivotId),
|
|
34786
|
+
sortedColumn: undefined,
|
|
34787
|
+
},
|
|
34788
|
+
});
|
|
34789
|
+
return;
|
|
34790
|
+
}
|
|
34791
|
+
const pivot = env.model.getters.getPivot(pivotId);
|
|
34792
|
+
const colDomain = domainToColRowDomain(pivot, pivotCell.domain).colDomain;
|
|
34793
|
+
env.model.dispatch("UPDATE_PIVOT", {
|
|
34794
|
+
pivotId: pivotId,
|
|
34795
|
+
pivot: {
|
|
34796
|
+
...env.model.getters.getPivotCoreDefinition(pivotId),
|
|
34797
|
+
sortedColumn: { domain: colDomain, order, measure: pivotCell.measure },
|
|
34798
|
+
},
|
|
34799
|
+
});
|
|
34800
|
+
}
|
|
34801
|
+
function isPivotSortMenuItemActive(env, order) {
|
|
34802
|
+
const position = env.model.getters.getActivePosition();
|
|
34803
|
+
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
34804
|
+
const pivotCell = env.model.getters.getPivotCellFromPosition(position);
|
|
34805
|
+
if (pivotCell.type === "EMPTY" || pivotCell.type === "HEADER" || !pivotId) {
|
|
34806
|
+
return false;
|
|
34807
|
+
}
|
|
34808
|
+
const pivot = env.model.getters.getPivot(pivotId);
|
|
34809
|
+
const colDomain = domainToColRowDomain(pivot, pivotCell.domain).colDomain;
|
|
34810
|
+
const sortedColumn = pivot.definition.sortedColumn;
|
|
34811
|
+
if (order === "none") {
|
|
34812
|
+
return !sortedColumn;
|
|
34813
|
+
}
|
|
34814
|
+
if (!sortedColumn || sortedColumn.order !== order) {
|
|
34815
|
+
return false;
|
|
34816
|
+
}
|
|
34817
|
+
return sortedColumn.measure === pivotCell.measure && deepEquals(sortedColumn.domain, colDomain);
|
|
34818
|
+
}
|
|
34263
34819
|
|
|
34264
34820
|
//------------------------------------------------------------------------------
|
|
34265
34821
|
// Context Menu Registry
|
|
@@ -34358,14 +34914,33 @@ cellMenuRegistry
|
|
|
34358
34914
|
name: INSERT_LINK_NAME,
|
|
34359
34915
|
sequence: 150,
|
|
34360
34916
|
separator: true,
|
|
34917
|
+
})
|
|
34918
|
+
.add("pivot_sorting", {
|
|
34919
|
+
name: _t("Sort pivot"),
|
|
34920
|
+
sequence: 155,
|
|
34921
|
+
icon: "o-spreadsheet-Icon.SORT_RANGE",
|
|
34922
|
+
isVisible: canSortPivot,
|
|
34361
34923
|
})
|
|
34362
34924
|
.add("pivot_fix_formulas", {
|
|
34363
34925
|
...FIX_FORMULAS,
|
|
34364
|
-
sequence:
|
|
34926
|
+
sequence: 160,
|
|
34365
34927
|
})
|
|
34366
34928
|
.add("pivot_properties", {
|
|
34367
34929
|
...pivotProperties,
|
|
34368
34930
|
sequence: 170,
|
|
34931
|
+
separator: true,
|
|
34932
|
+
})
|
|
34933
|
+
.addChild("pivot_sorting_asc", ["pivot_sorting"], {
|
|
34934
|
+
...pivotSortingAsc,
|
|
34935
|
+
sequence: 10,
|
|
34936
|
+
})
|
|
34937
|
+
.addChild("pivot_sorting_desc", ["pivot_sorting"], {
|
|
34938
|
+
...pivotSortingDesc,
|
|
34939
|
+
sequence: 20,
|
|
34940
|
+
})
|
|
34941
|
+
.addChild("pivot_sorting_none", ["pivot_sorting"], {
|
|
34942
|
+
...noPivotSorting,
|
|
34943
|
+
sequence: 30,
|
|
34369
34944
|
});
|
|
34370
34945
|
|
|
34371
34946
|
const sortRange = {
|
|
@@ -34378,7 +34953,7 @@ const sortAscending = {
|
|
|
34378
34953
|
execute: (env) => {
|
|
34379
34954
|
const { anchor, zones } = env.model.getters.getSelection();
|
|
34380
34955
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
34381
|
-
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "
|
|
34956
|
+
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "asc");
|
|
34382
34957
|
},
|
|
34383
34958
|
icon: "o-spreadsheet-Icon.SORT_ASCENDING",
|
|
34384
34959
|
};
|
|
@@ -34406,7 +34981,7 @@ const sortDescending = {
|
|
|
34406
34981
|
execute: (env) => {
|
|
34407
34982
|
const { anchor, zones } = env.model.getters.getSelection();
|
|
34408
34983
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
34409
|
-
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "
|
|
34984
|
+
interactiveSortSelection(env, sheetId, anchor.cell, zones[0], "desc");
|
|
34410
34985
|
},
|
|
34411
34986
|
icon: "o-spreadsheet-Icon.SORT_DESCENDING",
|
|
34412
34987
|
};
|
|
@@ -34889,6 +35464,227 @@ function interactiveFreezeColumnsRows(env, dimension, base) {
|
|
|
34889
35464
|
}
|
|
34890
35465
|
}
|
|
34891
35466
|
|
|
35467
|
+
class PositionMap {
|
|
35468
|
+
map = {};
|
|
35469
|
+
constructor(entries = []) {
|
|
35470
|
+
for (const [position, value] of entries) {
|
|
35471
|
+
this.set(position, value);
|
|
35472
|
+
}
|
|
35473
|
+
}
|
|
35474
|
+
set({ sheetId, col, row }, value) {
|
|
35475
|
+
const map = this.map;
|
|
35476
|
+
if (!map[sheetId]) {
|
|
35477
|
+
map[sheetId] = {};
|
|
35478
|
+
}
|
|
35479
|
+
if (!map[sheetId][col]) {
|
|
35480
|
+
map[sheetId][col] = {};
|
|
35481
|
+
}
|
|
35482
|
+
map[sheetId][col][row] = value;
|
|
35483
|
+
}
|
|
35484
|
+
get({ sheetId, col, row }) {
|
|
35485
|
+
return this.map[sheetId]?.[col]?.[row];
|
|
35486
|
+
}
|
|
35487
|
+
getSheet(sheetId) {
|
|
35488
|
+
return this.map[sheetId];
|
|
35489
|
+
}
|
|
35490
|
+
has({ sheetId, col, row }) {
|
|
35491
|
+
return this.map[sheetId]?.[col]?.[row] !== undefined;
|
|
35492
|
+
}
|
|
35493
|
+
delete({ sheetId, col, row }) {
|
|
35494
|
+
delete this.map[sheetId]?.[col]?.[row];
|
|
35495
|
+
}
|
|
35496
|
+
keys() {
|
|
35497
|
+
const map = this.map;
|
|
35498
|
+
const keys = [];
|
|
35499
|
+
for (const sheetId in map) {
|
|
35500
|
+
for (const col in map[sheetId]) {
|
|
35501
|
+
for (const row in map[sheetId][col]) {
|
|
35502
|
+
keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
|
|
35503
|
+
}
|
|
35504
|
+
}
|
|
35505
|
+
}
|
|
35506
|
+
return keys;
|
|
35507
|
+
}
|
|
35508
|
+
keysForSheet(sheetId) {
|
|
35509
|
+
const map = this.map[sheetId];
|
|
35510
|
+
if (!map) {
|
|
35511
|
+
return [];
|
|
35512
|
+
}
|
|
35513
|
+
const keys = [];
|
|
35514
|
+
for (const col in map) {
|
|
35515
|
+
for (const row in map[col]) {
|
|
35516
|
+
keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
|
|
35517
|
+
}
|
|
35518
|
+
}
|
|
35519
|
+
return keys;
|
|
35520
|
+
}
|
|
35521
|
+
*entries() {
|
|
35522
|
+
const map = this.map;
|
|
35523
|
+
for (const position of this.keys()) {
|
|
35524
|
+
const { sheetId, col, row } = position;
|
|
35525
|
+
yield [position, map[sheetId][col][row]];
|
|
35526
|
+
}
|
|
35527
|
+
}
|
|
35528
|
+
}
|
|
35529
|
+
|
|
35530
|
+
class FormulaFingerprintStore extends SpreadsheetStore {
|
|
35531
|
+
mutators = ["enable", "disable"];
|
|
35532
|
+
isInvalidated = false;
|
|
35533
|
+
fingerprintColors = {
|
|
35534
|
+
[DATA_FINGERPRINT]: "#D9D9D9",
|
|
35535
|
+
};
|
|
35536
|
+
isEnabled = false;
|
|
35537
|
+
colors = new PositionMap();
|
|
35538
|
+
handle(cmd) {
|
|
35539
|
+
if (isCoreCommand(cmd) && this.isEnabled) {
|
|
35540
|
+
this.isInvalidated = true;
|
|
35541
|
+
}
|
|
35542
|
+
switch (cmd.type) {
|
|
35543
|
+
case "UNDO":
|
|
35544
|
+
case "REDO":
|
|
35545
|
+
case "ACTIVATE_SHEET":
|
|
35546
|
+
if (this.isEnabled) {
|
|
35547
|
+
this.isInvalidated = true;
|
|
35548
|
+
}
|
|
35549
|
+
break;
|
|
35550
|
+
}
|
|
35551
|
+
}
|
|
35552
|
+
finalize() {
|
|
35553
|
+
if (this.isInvalidated) {
|
|
35554
|
+
this.isInvalidated = false;
|
|
35555
|
+
this.computeFingerprints();
|
|
35556
|
+
}
|
|
35557
|
+
}
|
|
35558
|
+
enable() {
|
|
35559
|
+
this.isEnabled = true;
|
|
35560
|
+
this.computeFingerprints();
|
|
35561
|
+
}
|
|
35562
|
+
disable() {
|
|
35563
|
+
this.isEnabled = false;
|
|
35564
|
+
this.colors = new PositionMap();
|
|
35565
|
+
}
|
|
35566
|
+
computeFingerprints() {
|
|
35567
|
+
this.colors = new PositionMap();
|
|
35568
|
+
const fingerprints = new PositionMap();
|
|
35569
|
+
const allFingerprints = new Set();
|
|
35570
|
+
const activeSheetId = this.getters.getActiveSheetId();
|
|
35571
|
+
const cells = this.getters.getCells(activeSheetId);
|
|
35572
|
+
for (const cellId in cells) {
|
|
35573
|
+
const fingerprint = this.computeFingerprint(cells[cellId]);
|
|
35574
|
+
if (!fingerprint) {
|
|
35575
|
+
continue;
|
|
35576
|
+
}
|
|
35577
|
+
allFingerprints.add(fingerprint);
|
|
35578
|
+
const position = this.getters.getCellPosition(cellId);
|
|
35579
|
+
fingerprints.set(position, fingerprint);
|
|
35580
|
+
}
|
|
35581
|
+
this.assignColors(allFingerprints);
|
|
35582
|
+
for (const [position, fingerprint] of fingerprints.entries()) {
|
|
35583
|
+
const color = this.fingerprintColors[fingerprint];
|
|
35584
|
+
this.colors.set(position, color);
|
|
35585
|
+
this.colorSpreadZone(position, color);
|
|
35586
|
+
}
|
|
35587
|
+
}
|
|
35588
|
+
colorSpreadZone(position, fingerprintColor) {
|
|
35589
|
+
const spreadZone = this.getters.getSpreadZone(position);
|
|
35590
|
+
if (!spreadZone) {
|
|
35591
|
+
return;
|
|
35592
|
+
}
|
|
35593
|
+
const sheetId = position.sheetId;
|
|
35594
|
+
for (let row = spreadZone.top; row <= spreadZone.bottom; row++) {
|
|
35595
|
+
for (let col = spreadZone.left; col <= spreadZone.right; col++) {
|
|
35596
|
+
const spreadPosition = { sheetId, col, row };
|
|
35597
|
+
this.colors.set(spreadPosition, fingerprintColor);
|
|
35598
|
+
}
|
|
35599
|
+
}
|
|
35600
|
+
}
|
|
35601
|
+
assignColors(fingerprints) {
|
|
35602
|
+
const colors = new AlternatingColorGenerator(fingerprints.size);
|
|
35603
|
+
Object.keys(this.fingerprintColors).forEach(() => colors.next());
|
|
35604
|
+
for (const fingerprint of fingerprints) {
|
|
35605
|
+
if (!this.fingerprintColors[fingerprint]) {
|
|
35606
|
+
this.fingerprintColors[fingerprint] = setColorAlpha(colors.next(), 0.8);
|
|
35607
|
+
}
|
|
35608
|
+
}
|
|
35609
|
+
}
|
|
35610
|
+
computeFingerprint(cell) {
|
|
35611
|
+
const position = this.getters.getCellPosition(cell.id);
|
|
35612
|
+
if (cell.isFormula) {
|
|
35613
|
+
return this.computeFormulaFingerprint(position, cell);
|
|
35614
|
+
}
|
|
35615
|
+
else {
|
|
35616
|
+
return this.getLiteralFingerprint(position);
|
|
35617
|
+
}
|
|
35618
|
+
}
|
|
35619
|
+
computeFormulaFingerprint(position, cell) {
|
|
35620
|
+
const dependencies = cell.compiledFormula.dependencies;
|
|
35621
|
+
const colCellOffset = position.col;
|
|
35622
|
+
const rowCellOffset = position.row;
|
|
35623
|
+
const positionSheetIndex = this.getters.getSheetIds().indexOf(position.sheetId);
|
|
35624
|
+
// As an optimization, we do not build each reference vector individually
|
|
35625
|
+
// to sum them up, but instead we directly add each component to the resulting
|
|
35626
|
+
// vector. This is equivalent to summing up all reference vectors.
|
|
35627
|
+
const fingerprintVector = {
|
|
35628
|
+
dx: 0,
|
|
35629
|
+
dy: 0,
|
|
35630
|
+
dSheet: 0,
|
|
35631
|
+
};
|
|
35632
|
+
for (const range of dependencies) {
|
|
35633
|
+
const zone = range.zone;
|
|
35634
|
+
const [left, right] = range.parts;
|
|
35635
|
+
const rangeSheetIndex = this.getters.getSheetIds().indexOf(range.sheetId);
|
|
35636
|
+
fingerprintVector.dSheet = rangeSheetIndex - positionSheetIndex;
|
|
35637
|
+
// in relative mode, we offset the col and row by the cell's position
|
|
35638
|
+
// in absolute mode, we offset the col and row relative to the sheet
|
|
35639
|
+
const isLeftUnbounded = range.isFullRow && !range.unboundedZone.hasHeader;
|
|
35640
|
+
const isTopUnbounded = range.isFullCol && !range.unboundedZone.hasHeader;
|
|
35641
|
+
const leftOffset = isLeftUnbounded || left?.colFixed ? 0 : colCellOffset;
|
|
35642
|
+
const topOffset = isTopUnbounded || left?.rowFixed ? 0 : rowCellOffset;
|
|
35643
|
+
const isRightFixed = (!right && left?.colFixed) || right?.colFixed;
|
|
35644
|
+
const isBottomFixed = (!right && left.rowFixed) || right?.rowFixed;
|
|
35645
|
+
const isRightUnbounded = range.unboundedZone.right === undefined;
|
|
35646
|
+
const isBottomUnbounded = range.unboundedZone.bottom === undefined;
|
|
35647
|
+
const rightOffset = isRightUnbounded || isRightFixed ? 0 : colCellOffset;
|
|
35648
|
+
const bottomOffset = isBottomUnbounded || isBottomFixed ? 0 : rowCellOffset;
|
|
35649
|
+
const referenceZone = reorderZone({
|
|
35650
|
+
top: zone.top - topOffset,
|
|
35651
|
+
left: zone.left - leftOffset,
|
|
35652
|
+
right: zone.right - rightOffset,
|
|
35653
|
+
bottom: zone.bottom - bottomOffset,
|
|
35654
|
+
});
|
|
35655
|
+
for (let dy = referenceZone.top; dy <= referenceZone.bottom; dy++) {
|
|
35656
|
+
for (let dx = referenceZone.left; dx <= referenceZone.right; dx++) {
|
|
35657
|
+
fingerprintVector.dx += dx;
|
|
35658
|
+
fingerprintVector.dy += dy;
|
|
35659
|
+
}
|
|
35660
|
+
}
|
|
35661
|
+
}
|
|
35662
|
+
// removes the index placeholders from the normalized formula
|
|
35663
|
+
// =|N0|+|N1|+|N0| -> =|N|+|N|+|N|
|
|
35664
|
+
const normalizedFormula = cell.compiledFormula.normalizedFormula.replace(/(|\w)(\d)(|)/g, "$1$3");
|
|
35665
|
+
return hash(fingerprintVector) + normalizedFormula;
|
|
35666
|
+
}
|
|
35667
|
+
getLiteralFingerprint(position) {
|
|
35668
|
+
const evaluatedCell = this.getters.getEvaluatedCell(position);
|
|
35669
|
+
switch (evaluatedCell.type) {
|
|
35670
|
+
case CellValueType.number:
|
|
35671
|
+
case CellValueType.boolean:
|
|
35672
|
+
return DATA_FINGERPRINT;
|
|
35673
|
+
case CellValueType.text:
|
|
35674
|
+
case CellValueType.empty:
|
|
35675
|
+
case CellValueType.error:
|
|
35676
|
+
return undefined;
|
|
35677
|
+
}
|
|
35678
|
+
}
|
|
35679
|
+
}
|
|
35680
|
+
function hash(vector) {
|
|
35681
|
+
return Object.entries(vector)
|
|
35682
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
35683
|
+
.map(([_, value]) => value)
|
|
35684
|
+
.join(",");
|
|
35685
|
+
}
|
|
35686
|
+
const DATA_FINGERPRINT = "DATA_FINGERPRINT";
|
|
35687
|
+
|
|
34892
35688
|
const hideCols = {
|
|
34893
35689
|
name: HIDE_COLUMNS_NAME,
|
|
34894
35690
|
execute: (env) => {
|
|
@@ -35060,6 +35856,19 @@ const viewGridlines = {
|
|
|
35060
35856
|
return env.model.getters.getGridLinesVisibility(sheetId);
|
|
35061
35857
|
},
|
|
35062
35858
|
};
|
|
35859
|
+
const irregularityMap = {
|
|
35860
|
+
name: _t("Irregularity map"),
|
|
35861
|
+
execute: (env) => {
|
|
35862
|
+
const fingerprintStore = env.getStore(FormulaFingerprintStore);
|
|
35863
|
+
if (fingerprintStore.isEnabled) {
|
|
35864
|
+
fingerprintStore.disable();
|
|
35865
|
+
}
|
|
35866
|
+
else {
|
|
35867
|
+
fingerprintStore.enable();
|
|
35868
|
+
}
|
|
35869
|
+
},
|
|
35870
|
+
icon: "o-spreadsheet-Icon.IRREGULARITY_MAP",
|
|
35871
|
+
};
|
|
35063
35872
|
const viewFormulas = {
|
|
35064
35873
|
name: _t("Formulas"),
|
|
35065
35874
|
isActive: (env) => env.model.getters.shouldShowFormulas(),
|
|
@@ -35677,6 +36486,11 @@ topbarMenuRegistry
|
|
|
35677
36486
|
.addChild("view_formulas", ["view", "show"], {
|
|
35678
36487
|
...viewFormulas,
|
|
35679
36488
|
sequence: 10,
|
|
36489
|
+
})
|
|
36490
|
+
.addChild("view_irregularity_map", ["view"], {
|
|
36491
|
+
...irregularityMap,
|
|
36492
|
+
sequence: 40,
|
|
36493
|
+
separator: true,
|
|
35680
36494
|
})
|
|
35681
36495
|
// ---------------------------------------------------------------------
|
|
35682
36496
|
// INSERT MENU ITEMS
|
|
@@ -35979,62 +36793,6 @@ class OTRegistry extends Registry {
|
|
|
35979
36793
|
}
|
|
35980
36794
|
const otRegistry = new OTRegistry();
|
|
35981
36795
|
|
|
35982
|
-
const CHECK_SVG = /*xml*/ `
|
|
35983
|
-
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'>
|
|
35984
|
-
<path fill='none' stroke='#FFF' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/>
|
|
35985
|
-
</svg>
|
|
35986
|
-
`;
|
|
35987
|
-
const CHECKBOX_WIDTH = 14;
|
|
35988
|
-
css /* scss */ `
|
|
35989
|
-
label.o-checkbox {
|
|
35990
|
-
input {
|
|
35991
|
-
appearance: none;
|
|
35992
|
-
-webkit-appearance: none;
|
|
35993
|
-
-moz-appearance: none;
|
|
35994
|
-
border-radius: 0;
|
|
35995
|
-
width: ${CHECKBOX_WIDTH}px;
|
|
35996
|
-
height: ${CHECKBOX_WIDTH}px;
|
|
35997
|
-
vertical-align: top;
|
|
35998
|
-
box-sizing: border-box;
|
|
35999
|
-
outline: none;
|
|
36000
|
-
border: 1px solid ${GRAY_300};
|
|
36001
|
-
|
|
36002
|
-
&:hover {
|
|
36003
|
-
border-color: ${ACTION_COLOR};
|
|
36004
|
-
}
|
|
36005
|
-
|
|
36006
|
-
&:checked {
|
|
36007
|
-
background: url("data:image/svg+xml,${encodeURIComponent(CHECK_SVG)}");
|
|
36008
|
-
background-color: ${ACTION_COLOR};
|
|
36009
|
-
border-color: ${ACTION_COLOR};
|
|
36010
|
-
}
|
|
36011
|
-
|
|
36012
|
-
&:focus {
|
|
36013
|
-
outline: none;
|
|
36014
|
-
box-shadow: 0 0 0 0.25rem rgba(113, 75, 103, 0.25);
|
|
36015
|
-
border-color: ${ACTION_COLOR};
|
|
36016
|
-
}
|
|
36017
|
-
}
|
|
36018
|
-
}
|
|
36019
|
-
`;
|
|
36020
|
-
class Checkbox extends owl.Component {
|
|
36021
|
-
static template = "o-spreadsheet.Checkbox";
|
|
36022
|
-
static props = {
|
|
36023
|
-
label: { type: String, optional: true },
|
|
36024
|
-
value: { type: Boolean, optional: true },
|
|
36025
|
-
className: { type: String, optional: true },
|
|
36026
|
-
name: { type: String, optional: true },
|
|
36027
|
-
title: { type: String, optional: true },
|
|
36028
|
-
disabled: { type: Boolean, optional: true },
|
|
36029
|
-
onChange: Function,
|
|
36030
|
-
};
|
|
36031
|
-
static defaultProps = { value: false };
|
|
36032
|
-
onChange(ev) {
|
|
36033
|
-
const value = ev.target.checked;
|
|
36034
|
-
this.props.onChange(value);
|
|
36035
|
-
}
|
|
36036
|
-
}
|
|
36037
|
-
|
|
36038
36796
|
class Section extends owl.Component {
|
|
36039
36797
|
static template = "o_spreadsheet.Section";
|
|
36040
36798
|
static props = {
|
|
@@ -37411,6 +38169,95 @@ class ColorPickerWidget extends owl.Component {
|
|
|
37411
38169
|
}
|
|
37412
38170
|
}
|
|
37413
38171
|
|
|
38172
|
+
css /* scss */ `
|
|
38173
|
+
.o-font-size-editor {
|
|
38174
|
+
height: calc(100% - 4px);
|
|
38175
|
+
input.o-font-size {
|
|
38176
|
+
outline-color: ${SELECTION_BORDER_COLOR};
|
|
38177
|
+
height: 20px;
|
|
38178
|
+
width: 23px;
|
|
38179
|
+
}
|
|
38180
|
+
}
|
|
38181
|
+
.o-text-options > div {
|
|
38182
|
+
cursor: pointer;
|
|
38183
|
+
line-height: 26px;
|
|
38184
|
+
padding: 3px 12px;
|
|
38185
|
+
&:hover {
|
|
38186
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
38187
|
+
}
|
|
38188
|
+
}
|
|
38189
|
+
`;
|
|
38190
|
+
class FontSizeEditor extends owl.Component {
|
|
38191
|
+
static template = "o-spreadsheet-FontSizeEditor";
|
|
38192
|
+
static props = {
|
|
38193
|
+
currentFontSize: Number,
|
|
38194
|
+
onFontSizeChanged: Function,
|
|
38195
|
+
onToggle: { type: Function, optional: true },
|
|
38196
|
+
class: String,
|
|
38197
|
+
};
|
|
38198
|
+
static components = { Popover };
|
|
38199
|
+
fontSizes = FONT_SIZES;
|
|
38200
|
+
dropdown = owl.useState({ isOpen: false });
|
|
38201
|
+
inputRef = owl.useRef("inputFontSize");
|
|
38202
|
+
rootEditorRef = owl.useRef("FontSizeEditor");
|
|
38203
|
+
fontSizeListRef = owl.useRef("fontSizeList");
|
|
38204
|
+
setup() {
|
|
38205
|
+
owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
|
|
38206
|
+
}
|
|
38207
|
+
get popoverProps() {
|
|
38208
|
+
const { x, y, width, height } = this.rootEditorRef.el.getBoundingClientRect();
|
|
38209
|
+
return {
|
|
38210
|
+
anchorRect: { x, y, width, height },
|
|
38211
|
+
positioning: "BottomLeft",
|
|
38212
|
+
verticalOffset: 0,
|
|
38213
|
+
};
|
|
38214
|
+
}
|
|
38215
|
+
onExternalClick(ev) {
|
|
38216
|
+
if (!isChildEvent(this.fontSizeListRef.el, ev) && !isChildEvent(this.rootEditorRef.el, ev)) {
|
|
38217
|
+
this.closeFontList();
|
|
38218
|
+
}
|
|
38219
|
+
}
|
|
38220
|
+
toggleFontList() {
|
|
38221
|
+
const isOpen = this.dropdown.isOpen;
|
|
38222
|
+
if (!isOpen) {
|
|
38223
|
+
this.props.onToggle?.();
|
|
38224
|
+
this.inputRef.el.focus();
|
|
38225
|
+
}
|
|
38226
|
+
else {
|
|
38227
|
+
this.closeFontList();
|
|
38228
|
+
}
|
|
38229
|
+
}
|
|
38230
|
+
closeFontList() {
|
|
38231
|
+
this.dropdown.isOpen = false;
|
|
38232
|
+
}
|
|
38233
|
+
setSize(fontSizeStr) {
|
|
38234
|
+
const fontSize = clip(Math.floor(parseFloat(fontSizeStr)), 1, 400);
|
|
38235
|
+
this.props.onFontSizeChanged(fontSize);
|
|
38236
|
+
this.closeFontList();
|
|
38237
|
+
}
|
|
38238
|
+
setSizeFromInput(ev) {
|
|
38239
|
+
this.setSize(ev.target.value);
|
|
38240
|
+
}
|
|
38241
|
+
setSizeFromList(fontSizeStr) {
|
|
38242
|
+
this.setSize(fontSizeStr);
|
|
38243
|
+
}
|
|
38244
|
+
onInputFocused(ev) {
|
|
38245
|
+
this.dropdown.isOpen = true;
|
|
38246
|
+
ev.target.select();
|
|
38247
|
+
}
|
|
38248
|
+
onInputKeydown(ev) {
|
|
38249
|
+
if (ev.key === "Enter" || ev.key === "Escape") {
|
|
38250
|
+
this.closeFontList();
|
|
38251
|
+
const target = ev.target;
|
|
38252
|
+
// In the case of a ESCAPE key, we get the previous font size back
|
|
38253
|
+
if (ev.key === "Escape") {
|
|
38254
|
+
target.value = `${this.props.currentFontSize}`;
|
|
38255
|
+
}
|
|
38256
|
+
this.props.onToggle?.();
|
|
38257
|
+
}
|
|
38258
|
+
}
|
|
38259
|
+
}
|
|
38260
|
+
|
|
37414
38261
|
css /* scss */ `
|
|
37415
38262
|
.o-chart-title-designer {
|
|
37416
38263
|
> span {
|
|
@@ -37445,7 +38292,7 @@ css /* scss */ `
|
|
|
37445
38292
|
`;
|
|
37446
38293
|
class ChartTitle extends owl.Component {
|
|
37447
38294
|
static template = "o-spreadsheet.ChartTitle";
|
|
37448
|
-
static components = { Section, ColorPickerWidget };
|
|
38295
|
+
static components = { Section, ColorPickerWidget, FontSizeEditor };
|
|
37449
38296
|
static props = {
|
|
37450
38297
|
title: { type: String, optional: true },
|
|
37451
38298
|
updateTitle: Function,
|
|
@@ -37454,7 +38301,8 @@ class ChartTitle extends owl.Component {
|
|
|
37454
38301
|
toggleBold: { type: Function, optional: true },
|
|
37455
38302
|
updateAlignment: { type: Function, optional: true },
|
|
37456
38303
|
updateColor: { type: Function, optional: true },
|
|
37457
|
-
style:
|
|
38304
|
+
style: Object,
|
|
38305
|
+
onFontSizeChanged: Function,
|
|
37458
38306
|
};
|
|
37459
38307
|
static defaultProps = {
|
|
37460
38308
|
title: "",
|
|
@@ -37469,6 +38317,9 @@ class ChartTitle extends owl.Component {
|
|
|
37469
38317
|
updateTitle(ev) {
|
|
37470
38318
|
this.props.updateTitle(ev.target.value);
|
|
37471
38319
|
}
|
|
38320
|
+
updateFontSize(fontSize) {
|
|
38321
|
+
this.props.onFontSizeChanged(fontSize);
|
|
38322
|
+
}
|
|
37472
38323
|
toggleDropdownTool(tool, ev) {
|
|
37473
38324
|
const isOpen = this.state.activeTool === tool;
|
|
37474
38325
|
this.closeMenus();
|
|
@@ -37511,6 +38362,7 @@ class AxisDesignEditor extends owl.Component {
|
|
|
37511
38362
|
return {
|
|
37512
38363
|
color: "",
|
|
37513
38364
|
align: "center",
|
|
38365
|
+
fontSize: CHART_AXIS_TITLE_FONT_SIZE,
|
|
37514
38366
|
...axisDesign.title,
|
|
37515
38367
|
};
|
|
37516
38368
|
}
|
|
@@ -37528,6 +38380,17 @@ class AxisDesignEditor extends owl.Component {
|
|
|
37528
38380
|
};
|
|
37529
38381
|
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
37530
38382
|
}
|
|
38383
|
+
updateAxisTitleFontSize(fontSize) {
|
|
38384
|
+
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
38385
|
+
axesDesign[this.state.currentAxis] = {
|
|
38386
|
+
...axesDesign[this.state.currentAxis],
|
|
38387
|
+
title: {
|
|
38388
|
+
...(axesDesign[this.state.currentAxis]?.title ?? {}),
|
|
38389
|
+
fontSize,
|
|
38390
|
+
},
|
|
38391
|
+
};
|
|
38392
|
+
this.props.updateChart(this.props.figureId, { axesDesign });
|
|
38393
|
+
}
|
|
37531
38394
|
toggleBoldAxisTitle() {
|
|
37532
38395
|
const axesDesign = this.props.definition.axesDesign ?? {};
|
|
37533
38396
|
const title = axesDesign[this.state.currentAxis]?.title ?? {};
|
|
@@ -37647,8 +38510,12 @@ class GeneralDesignEditor extends owl.Component {
|
|
|
37647
38510
|
figureId: String,
|
|
37648
38511
|
definition: Object,
|
|
37649
38512
|
updateChart: Function,
|
|
38513
|
+
defaultChartTitleFontSize: { type: Number, optional: true },
|
|
37650
38514
|
slots: { type: Object, optional: true },
|
|
37651
38515
|
};
|
|
38516
|
+
static defaultProps = {
|
|
38517
|
+
defaultChartTitleFontSize: CHART_TITLE_FONT_SIZE,
|
|
38518
|
+
};
|
|
37652
38519
|
state;
|
|
37653
38520
|
setup() {
|
|
37654
38521
|
this.state = owl.useState({
|
|
@@ -37674,6 +38541,7 @@ class GeneralDesignEditor extends owl.Component {
|
|
|
37674
38541
|
get titleStyle() {
|
|
37675
38542
|
return {
|
|
37676
38543
|
align: "left",
|
|
38544
|
+
fontSize: this.props.defaultChartTitleFontSize,
|
|
37677
38545
|
...this.title,
|
|
37678
38546
|
};
|
|
37679
38547
|
}
|
|
@@ -37682,6 +38550,10 @@ class GeneralDesignEditor extends owl.Component {
|
|
|
37682
38550
|
this.props.updateChart(this.props.figureId, { title });
|
|
37683
38551
|
this.state.activeTool = "";
|
|
37684
38552
|
}
|
|
38553
|
+
updateChartTitleFontSize(fontSize) {
|
|
38554
|
+
const title = { ...this.title, fontSize };
|
|
38555
|
+
this.props.updateChart(this.props.figureId, { title });
|
|
38556
|
+
}
|
|
37685
38557
|
toggleBoldChartTitle() {
|
|
37686
38558
|
let title = this.title;
|
|
37687
38559
|
title = { ...title, bold: !title.bold };
|
|
@@ -37889,7 +38761,7 @@ class SeriesWithAxisDesignEditor extends owl.Component {
|
|
|
37889
38761
|
case "polynomial":
|
|
37890
38762
|
config = {
|
|
37891
38763
|
type: "polynomial",
|
|
37892
|
-
order: type === "linear" ? 1 :
|
|
38764
|
+
order: type === "linear" ? 1 : this.getMaxPolynomialDegree(index),
|
|
37893
38765
|
};
|
|
37894
38766
|
break;
|
|
37895
38767
|
case "exponential":
|
|
@@ -38160,6 +39032,104 @@ class GaugeChartDesignPanel extends owl.Component {
|
|
|
38160
39032
|
}
|
|
38161
39033
|
}
|
|
38162
39034
|
|
|
39035
|
+
class GeoChartRegionSelectSection extends owl.Component {
|
|
39036
|
+
static template = "o-spreadsheet-GeoChartRegionSelectSection";
|
|
39037
|
+
static components = { Section };
|
|
39038
|
+
static props = {
|
|
39039
|
+
figureId: String,
|
|
39040
|
+
definition: Object,
|
|
39041
|
+
updateChart: Function,
|
|
39042
|
+
};
|
|
39043
|
+
updateSelectedRegion(ev) {
|
|
39044
|
+
const value = ev.target.value;
|
|
39045
|
+
this.props.updateChart(this.props.figureId, { region: value });
|
|
39046
|
+
}
|
|
39047
|
+
get availableRegions() {
|
|
39048
|
+
return this.env.model.getters.getGeoChartAvailableRegions();
|
|
39049
|
+
}
|
|
39050
|
+
get selectedRegion() {
|
|
39051
|
+
return this.props.definition.region || this.availableRegions[0]?.id;
|
|
39052
|
+
}
|
|
39053
|
+
}
|
|
39054
|
+
|
|
39055
|
+
class GeoChartConfigPanel extends GenericChartConfigPanel {
|
|
39056
|
+
static template = "o-spreadsheet-GeoChartConfigPanel";
|
|
39057
|
+
static components = { ...GenericChartConfigPanel.components, GeoChartRegionSelectSection };
|
|
39058
|
+
get dataRanges() {
|
|
39059
|
+
return this.getDataSeriesRanges().slice(0, 1);
|
|
39060
|
+
}
|
|
39061
|
+
onDataSeriesConfirmed() {
|
|
39062
|
+
this.dataSeriesRanges = spreadRange(this.env.model.getters, this.dataSeriesRanges).slice(0, 1);
|
|
39063
|
+
this.state.datasetDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
39064
|
+
dataSets: this.dataSeriesRanges,
|
|
39065
|
+
});
|
|
39066
|
+
}
|
|
39067
|
+
getLabelRangeOptions() {
|
|
39068
|
+
return [
|
|
39069
|
+
{
|
|
39070
|
+
name: "dataSetsHaveTitle",
|
|
39071
|
+
label: this.dataSetsHaveTitleLabel,
|
|
39072
|
+
value: this.props.definition.dataSetsHaveTitle,
|
|
39073
|
+
onChange: this.onUpdateDataSetsHaveTitle.bind(this),
|
|
39074
|
+
},
|
|
39075
|
+
];
|
|
39076
|
+
}
|
|
39077
|
+
}
|
|
39078
|
+
|
|
39079
|
+
const DEFAULT_CUSTOM_COLOR_SCALE = {
|
|
39080
|
+
minColor: "#FFF5EB",
|
|
39081
|
+
midColor: "#FD8D3C",
|
|
39082
|
+
maxColor: "#7F2704",
|
|
39083
|
+
};
|
|
39084
|
+
class GeoChartDesignPanel extends ChartWithAxisDesignPanel {
|
|
39085
|
+
static template = "o-spreadsheet-GeoChartDesignPanel";
|
|
39086
|
+
static components = { ...ChartWithAxisDesignPanel.components, RoundColorPicker };
|
|
39087
|
+
colorScalesChoices = ChartTerms.GeoChart.ColorScales;
|
|
39088
|
+
updateColorScaleType(ev) {
|
|
39089
|
+
const value = ev.target.value;
|
|
39090
|
+
value === "custom"
|
|
39091
|
+
? this.updateColorScale(DEFAULT_CUSTOM_COLOR_SCALE)
|
|
39092
|
+
: this.updateColorScale(value);
|
|
39093
|
+
}
|
|
39094
|
+
updateColorScale(colorScale) {
|
|
39095
|
+
this.props.updateChart(this.props.figureId, { colorScale });
|
|
39096
|
+
}
|
|
39097
|
+
updateMissingValueColor(color) {
|
|
39098
|
+
this.props.updateChart(this.props.figureId, { missingValueColor: color });
|
|
39099
|
+
}
|
|
39100
|
+
updateLegendPosition(ev) {
|
|
39101
|
+
const value = ev.target.value;
|
|
39102
|
+
this.props.updateChart(this.props.figureId, { legendPosition: value });
|
|
39103
|
+
}
|
|
39104
|
+
get selectedColorScale() {
|
|
39105
|
+
return typeof this.props.definition.colorScale === "object"
|
|
39106
|
+
? "custom"
|
|
39107
|
+
: this.props.definition.colorScale || "oranges";
|
|
39108
|
+
}
|
|
39109
|
+
get selectedMissingValueColor() {
|
|
39110
|
+
return this.props.definition.missingValueColor || "#ffffff";
|
|
39111
|
+
}
|
|
39112
|
+
get customColorScale() {
|
|
39113
|
+
if (typeof this.props.definition.colorScale === "object") {
|
|
39114
|
+
return this.props.definition.colorScale;
|
|
39115
|
+
}
|
|
39116
|
+
return undefined;
|
|
39117
|
+
}
|
|
39118
|
+
getCustomColorScaleColor(color) {
|
|
39119
|
+
return this.customColorScale?.[color] ?? "";
|
|
39120
|
+
}
|
|
39121
|
+
setCustomColorScaleColor(colorType, color) {
|
|
39122
|
+
if (!color && colorType !== "midColor") {
|
|
39123
|
+
color = "#fff";
|
|
39124
|
+
}
|
|
39125
|
+
const customColorScale = this.customColorScale;
|
|
39126
|
+
if (!customColorScale) {
|
|
39127
|
+
return;
|
|
39128
|
+
}
|
|
39129
|
+
this.updateColorScale({ ...customColorScale, [colorType]: color });
|
|
39130
|
+
}
|
|
39131
|
+
}
|
|
39132
|
+
|
|
38163
39133
|
class LineConfigPanel extends GenericChartConfigPanel {
|
|
38164
39134
|
static template = "o-spreadsheet-LineConfigPanel";
|
|
38165
39135
|
get canTreatLabelsAsText() {
|
|
@@ -38349,6 +39319,9 @@ class ScorecardChartDesignPanel extends owl.Component {
|
|
|
38349
39319
|
get humanizeNumbersLabel() {
|
|
38350
39320
|
return _t("Humanize numbers");
|
|
38351
39321
|
}
|
|
39322
|
+
get defaultScorecardTitleFontSize() {
|
|
39323
|
+
return SCORECARD_CHART_TITLE_FONT_SIZE;
|
|
39324
|
+
}
|
|
38352
39325
|
updateHumanizeNumbers(humanize) {
|
|
38353
39326
|
this.props.updateChart(this.props.figureId, { humanize });
|
|
38354
39327
|
}
|
|
@@ -38470,6 +39443,10 @@ chartSidePanelComponentRegistry
|
|
|
38470
39443
|
.add("radar", {
|
|
38471
39444
|
configuration: GenericChartConfigPanel,
|
|
38472
39445
|
design: RadarChartDesignPanel,
|
|
39446
|
+
})
|
|
39447
|
+
.add("geo", {
|
|
39448
|
+
configuration: GeoChartConfigPanel,
|
|
39449
|
+
design: GeoChartDesignPanel,
|
|
38473
39450
|
});
|
|
38474
39451
|
|
|
38475
39452
|
css /* scss */ `
|
|
@@ -39812,6 +40789,15 @@ class StandaloneComposerStore extends AbstractComposerStore {
|
|
|
39812
40789
|
confirmEdition(content) {
|
|
39813
40790
|
this.args().onConfirm(content);
|
|
39814
40791
|
}
|
|
40792
|
+
getTokenColor(token) {
|
|
40793
|
+
if (token.type === "SYMBOL") {
|
|
40794
|
+
const matchedColor = this.args().getContextualColoredSymbolToken?.(token);
|
|
40795
|
+
if (matchedColor) {
|
|
40796
|
+
return matchedColor;
|
|
40797
|
+
}
|
|
40798
|
+
}
|
|
40799
|
+
return super.getTokenColor(token);
|
|
40800
|
+
}
|
|
39815
40801
|
}
|
|
39816
40802
|
|
|
39817
40803
|
css /* scss */ `
|
|
@@ -39824,7 +40810,7 @@ css /* scss */ `
|
|
|
39824
40810
|
border-color: ${GRAY_300};
|
|
39825
40811
|
|
|
39826
40812
|
&.active {
|
|
39827
|
-
border-color: ${
|
|
40813
|
+
border-color: ${ACTION_COLOR};
|
|
39828
40814
|
}
|
|
39829
40815
|
|
|
39830
40816
|
&.o-invalid {
|
|
@@ -39849,6 +40835,7 @@ class StandaloneComposer extends owl.Component {
|
|
|
39849
40835
|
placeholder: { type: String, optional: true },
|
|
39850
40836
|
class: { type: String, optional: true },
|
|
39851
40837
|
invalid: { type: Boolean, optional: true },
|
|
40838
|
+
getContextualColoredSymbolToken: { type: Function, optional: true },
|
|
39852
40839
|
};
|
|
39853
40840
|
static components = { Composer };
|
|
39854
40841
|
static defaultProps = {
|
|
@@ -39865,6 +40852,7 @@ class StandaloneComposer extends owl.Component {
|
|
|
39865
40852
|
content: this.props.composerContent,
|
|
39866
40853
|
contextualAutocomplete: this.props.contextualAutocomplete,
|
|
39867
40854
|
defaultRangeSheetId: this.props.defaultRangeSheetId,
|
|
40855
|
+
getContextualColoredSymbolToken: this.props.getContextualColoredSymbolToken,
|
|
39868
40856
|
}));
|
|
39869
40857
|
this.standaloneComposerStore = standaloneComposerStore;
|
|
39870
40858
|
this.composerInterface = {
|
|
@@ -40780,7 +41768,7 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
40780
41768
|
}
|
|
40781
41769
|
const point = this.state.rules.colorScale[target];
|
|
40782
41770
|
if (point) {
|
|
40783
|
-
point.color =
|
|
41771
|
+
point.color = colorToNumber(color);
|
|
40784
41772
|
}
|
|
40785
41773
|
this.updateConditionalFormat({ rule: this.state.rules.colorScale });
|
|
40786
41774
|
this.closeMenus();
|
|
@@ -40925,6 +41913,9 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
40925
41913
|
return [this.state.rules.dataBar.rangeValues || ""];
|
|
40926
41914
|
}
|
|
40927
41915
|
updateDataBarColor(color) {
|
|
41916
|
+
if (!isColorValid(color)) {
|
|
41917
|
+
return;
|
|
41918
|
+
}
|
|
40928
41919
|
this.state.rules.dataBar.color = Number.parseInt(color.slice(1), 16);
|
|
40929
41920
|
this.updateConditionalFormat({ rule: this.state.rules.dataBar });
|
|
40930
41921
|
}
|
|
@@ -43425,7 +44416,7 @@ function createMeasureAutoComplete(pivot, forComputedMeasure) {
|
|
|
43425
44416
|
return {
|
|
43426
44417
|
text: text,
|
|
43427
44418
|
description: measure.displayName,
|
|
43428
|
-
htmlContent: [{ value: text, color:
|
|
44419
|
+
htmlContent: [{ value: text, color: PIVOT_TOKEN_COLOR }],
|
|
43429
44420
|
fuzzySearchKey: measure.displayName + text + measure.fieldName,
|
|
43430
44421
|
};
|
|
43431
44422
|
});
|
|
@@ -43434,7 +44425,7 @@ function createMeasureAutoComplete(pivot, forComputedMeasure) {
|
|
|
43434
44425
|
return {
|
|
43435
44426
|
text: text,
|
|
43436
44427
|
description: dimension.displayName,
|
|
43437
|
-
htmlContent: [{ value: text, color:
|
|
44428
|
+
htmlContent: [{ value: text, color: PIVOT_TOKEN_COLOR }],
|
|
43438
44429
|
fuzzySearchKey: dimension.displayName + text + dimension.fieldName,
|
|
43439
44430
|
};
|
|
43440
44431
|
});
|
|
@@ -43514,6 +44505,76 @@ class PivotMeasureEditor extends owl.Component {
|
|
|
43514
44505
|
measure: this.props.measure,
|
|
43515
44506
|
});
|
|
43516
44507
|
}
|
|
44508
|
+
getColoredSymbolToken(token) {
|
|
44509
|
+
if (token.type !== "SYMBOL") {
|
|
44510
|
+
return undefined;
|
|
44511
|
+
}
|
|
44512
|
+
const tokenValue = unquote(token.value, "'");
|
|
44513
|
+
if (this.props.definition.columns.some((col) => col.nameWithGranularity === tokenValue) ||
|
|
44514
|
+
this.props.definition.rows.some((row) => row.nameWithGranularity === tokenValue) ||
|
|
44515
|
+
this.props.definition.measures.some((measure) => measure.id === tokenValue && measure.id !== this.props.measure.id)) {
|
|
44516
|
+
return PIVOT_TOKEN_COLOR;
|
|
44517
|
+
}
|
|
44518
|
+
return undefined;
|
|
44519
|
+
}
|
|
44520
|
+
}
|
|
44521
|
+
|
|
44522
|
+
css /* scss */ `
|
|
44523
|
+
.o-pivot-sort {
|
|
44524
|
+
.o-sort-card {
|
|
44525
|
+
width: fit-content;
|
|
44526
|
+
background-color: ${GRAY_100};
|
|
44527
|
+
border: 1px solid ${GRAY_300};
|
|
44528
|
+
|
|
44529
|
+
.o-sort-value {
|
|
44530
|
+
color: ${PRIMARY_BUTTON_BG};
|
|
44531
|
+
}
|
|
44532
|
+
}
|
|
44533
|
+
}
|
|
44534
|
+
`;
|
|
44535
|
+
class PivotSortSection extends owl.Component {
|
|
44536
|
+
static template = "o-spreadsheet-PivotSortSection";
|
|
44537
|
+
static components = {
|
|
44538
|
+
Section,
|
|
44539
|
+
};
|
|
44540
|
+
static props = {
|
|
44541
|
+
definition: Object,
|
|
44542
|
+
pivotId: String,
|
|
44543
|
+
};
|
|
44544
|
+
get hasValidSort() {
|
|
44545
|
+
const pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
44546
|
+
return (!!this.props.definition.sortedColumn &&
|
|
44547
|
+
isSortedColumnValid(this.props.definition.sortedColumn, pivot));
|
|
44548
|
+
}
|
|
44549
|
+
get sortDescription() {
|
|
44550
|
+
const sortOrder = this.props.definition.sortedColumn?.order === "asc" ? _t("ascending") : _t("descending");
|
|
44551
|
+
return _t("Sorted on column (%(ascOrDesc)s):", {
|
|
44552
|
+
ascOrDesc: sortOrder,
|
|
44553
|
+
});
|
|
44554
|
+
}
|
|
44555
|
+
get sortValuesAndFields() {
|
|
44556
|
+
const sortedColumn = this.props.definition.sortedColumn;
|
|
44557
|
+
if (!sortedColumn) {
|
|
44558
|
+
return [];
|
|
44559
|
+
}
|
|
44560
|
+
const pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
44561
|
+
const locale = this.env.model.getters.getLocale();
|
|
44562
|
+
const currentDomain = [];
|
|
44563
|
+
const sortValues = [];
|
|
44564
|
+
for (const domainItem of sortedColumn.domain) {
|
|
44565
|
+
currentDomain.push(domainItem);
|
|
44566
|
+
const { value, format } = pivot.getPivotHeaderValueAndFormat(currentDomain);
|
|
44567
|
+
const label = formatValue(value, { format, locale });
|
|
44568
|
+
const field = pivot.definition.getDimension(domainItem.field);
|
|
44569
|
+
sortValues.push({ field: getFieldDisplayName(field), value: label });
|
|
44570
|
+
}
|
|
44571
|
+
if (sortedColumn.domain.length === 0) {
|
|
44572
|
+
sortValues.push({ value: _t("Total") });
|
|
44573
|
+
}
|
|
44574
|
+
const measureLabel = pivot.getMeasure(sortedColumn.measure).displayName;
|
|
44575
|
+
sortValues.push({ value: measureLabel, field: _t("Measure") });
|
|
44576
|
+
return sortValues;
|
|
44577
|
+
}
|
|
43517
44578
|
}
|
|
43518
44579
|
|
|
43519
44580
|
css /* scss */ `
|
|
@@ -43529,6 +44590,7 @@ class PivotLayoutConfigurator extends owl.Component {
|
|
|
43529
44590
|
PivotDimensionOrder,
|
|
43530
44591
|
PivotDimensionGranularity,
|
|
43531
44592
|
PivotMeasureEditor,
|
|
44593
|
+
PivotSortSection,
|
|
43532
44594
|
};
|
|
43533
44595
|
static props = {
|
|
43534
44596
|
definition: Object,
|
|
@@ -43685,9 +44747,13 @@ class PivotLayoutConfigurator extends owl.Component {
|
|
|
43685
44747
|
}
|
|
43686
44748
|
updateMeasure(measure, newMeasure) {
|
|
43687
44749
|
const { measures } = this.props.definition;
|
|
43688
|
-
|
|
44750
|
+
const update = {
|
|
43689
44751
|
measures: measures.map((m) => (m.id === measure.id ? newMeasure : m)),
|
|
43690
|
-
}
|
|
44752
|
+
};
|
|
44753
|
+
if (this.props.definition.sortedColumn?.measure === measure.id) {
|
|
44754
|
+
update.sortedColumn = { ...this.props.definition.sortedColumn, measure: newMeasure.id };
|
|
44755
|
+
}
|
|
44756
|
+
this.props.onDimensionsUpdated(update);
|
|
43691
44757
|
}
|
|
43692
44758
|
getMeasureId(fieldName, aggregator) {
|
|
43693
44759
|
const baseId = fieldName + (aggregator ? `:${aggregator}` : "");
|
|
@@ -43843,10 +44909,12 @@ class PivotRuntimeDefinition {
|
|
|
43843
44909
|
measures;
|
|
43844
44910
|
columns;
|
|
43845
44911
|
rows;
|
|
44912
|
+
sortedColumn;
|
|
43846
44913
|
constructor(definition, fields) {
|
|
43847
44914
|
this.measures = definition.measures.map((measure) => createMeasure(fields, measure));
|
|
43848
44915
|
this.columns = definition.columns.map((dimension) => createPivotDimension(fields, dimension));
|
|
43849
44916
|
this.rows = definition.rows.map((dimension) => createPivotDimension(fields, dimension));
|
|
44917
|
+
this.sortedColumn = definition.sortedColumn;
|
|
43850
44918
|
}
|
|
43851
44919
|
getDimension(nameWithGranularity) {
|
|
43852
44920
|
const dimension = this.columns.find((d) => d.nameWithGranularity === nameWithGranularity) ||
|
|
@@ -44000,6 +45068,7 @@ class SpreadsheetPivotTable {
|
|
|
44000
45068
|
pivotCells = {};
|
|
44001
45069
|
rowTree;
|
|
44002
45070
|
colTree;
|
|
45071
|
+
isSorted = false;
|
|
44003
45072
|
constructor(columns, rows, measures, fieldsType) {
|
|
44004
45073
|
this.columns = columns.map((row) => {
|
|
44005
45074
|
// offset in the pivot table
|
|
@@ -44173,6 +45242,7 @@ class SpreadsheetPivotTable {
|
|
|
44173
45242
|
value,
|
|
44174
45243
|
field: row.fields[rowDepth],
|
|
44175
45244
|
children: [],
|
|
45245
|
+
type: this.fieldsType[fieldName] || "char",
|
|
44176
45246
|
width: 0, // not used
|
|
44177
45247
|
};
|
|
44178
45248
|
treesAtDepth[depth].push(node);
|
|
@@ -44195,6 +45265,7 @@ class SpreadsheetPivotTable {
|
|
|
44195
45265
|
field: leaf.fields[depth],
|
|
44196
45266
|
children: [],
|
|
44197
45267
|
width: leaf.width,
|
|
45268
|
+
type: this.fieldsType[fieldName] || "char",
|
|
44198
45269
|
};
|
|
44199
45270
|
if (treesAtDepth[depth]?.at(-1)?.value !== value) {
|
|
44200
45271
|
treesAtDepth[depth + 1] = [];
|
|
@@ -44213,6 +45284,35 @@ class SpreadsheetPivotTable {
|
|
|
44213
45284
|
fieldsType: this.fieldsType,
|
|
44214
45285
|
};
|
|
44215
45286
|
}
|
|
45287
|
+
sort(measure, sortedColumn, getValue) {
|
|
45288
|
+
if (this.isSorted) {
|
|
45289
|
+
return;
|
|
45290
|
+
}
|
|
45291
|
+
const getSortValue = (measure, domain) => {
|
|
45292
|
+
const rawValue = getValue(measure, domain).value;
|
|
45293
|
+
return typeof rawValue === "number" ? rawValue : -Infinity;
|
|
45294
|
+
};
|
|
45295
|
+
const sortColDomain = sortedColumn.domain;
|
|
45296
|
+
const sortFn = (rowDomain1, rowDomain2) => {
|
|
45297
|
+
const value1 = getSortValue(measure, [...rowDomain1, ...sortColDomain]);
|
|
45298
|
+
const value2 = getSortValue(measure, [...rowDomain2, ...sortColDomain]);
|
|
45299
|
+
return sortedColumn.order === "asc" ? value1 - value2 : value2 - value1;
|
|
45300
|
+
};
|
|
45301
|
+
const sortedRowTree = sortPivotTree(this.rowTree(), [], sortFn);
|
|
45302
|
+
this.rowTree = lazy(sortedRowTree);
|
|
45303
|
+
this.rows = [...this.rowTreeToRows(sortedRowTree), this.rows[this.rows.length - 1]];
|
|
45304
|
+
this.isSorted = true;
|
|
45305
|
+
}
|
|
45306
|
+
rowTreeToRows(tree, parentRow) {
|
|
45307
|
+
return tree.flatMap((node) => {
|
|
45308
|
+
const row = {
|
|
45309
|
+
indent: parentRow ? parentRow.indent + 1 : 0,
|
|
45310
|
+
fields: [...(parentRow?.fields || []), node.field],
|
|
45311
|
+
values: [...(parentRow?.values || []), node.value],
|
|
45312
|
+
};
|
|
45313
|
+
return [row, ...this.rowTreeToRows(node.children, row)];
|
|
45314
|
+
});
|
|
45315
|
+
}
|
|
44216
45316
|
}
|
|
44217
45317
|
const EMPTY_PIVOT_CELL = { type: "EMPTY" };
|
|
44218
45318
|
|
|
@@ -44290,6 +45390,7 @@ function dataEntriesToColumnsTree(dataEntries, columns, index) {
|
|
|
44290
45390
|
value: groups[key]?.[0]?.[column.nameWithGranularity]?.value ?? null,
|
|
44291
45391
|
field: colName,
|
|
44292
45392
|
children: dataEntriesToColumnsTree(groups[key] || [], columns, index + 1),
|
|
45393
|
+
type: column.type,
|
|
44293
45394
|
width: 0,
|
|
44294
45395
|
};
|
|
44295
45396
|
});
|
|
@@ -45155,6 +46256,7 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
45155
46256
|
format: measure.format,
|
|
45156
46257
|
display: measure.display,
|
|
45157
46258
|
})),
|
|
46259
|
+
sortedColumn: this.shouldKeepSortedColumn(definition) ? definition.sortedColumn : undefined,
|
|
45158
46260
|
};
|
|
45159
46261
|
if (!this.draft && deepEquals(coreDefinition, cleanedDefinition)) {
|
|
45160
46262
|
return;
|
|
@@ -45213,6 +46315,19 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
45213
46315
|
}
|
|
45214
46316
|
return granularitiesPerFields;
|
|
45215
46317
|
}
|
|
46318
|
+
/**
|
|
46319
|
+
* Check if we want to keep the sorted column when updating the pivot definition. We should remove it if either
|
|
46320
|
+
* the measure is not in the new definition or the columns have changed.
|
|
46321
|
+
*/
|
|
46322
|
+
shouldKeepSortedColumn(newDefinition) {
|
|
46323
|
+
const { sortedColumn } = newDefinition;
|
|
46324
|
+
if (!sortedColumn) {
|
|
46325
|
+
return true;
|
|
46326
|
+
}
|
|
46327
|
+
const oldDefinition = this.getters.getPivotCoreDefinition(this.pivotId);
|
|
46328
|
+
return (newDefinition.measures.find((measure) => measure.id === sortedColumn.measure) &&
|
|
46329
|
+
deepEquals(oldDefinition.columns, newDefinition.columns));
|
|
46330
|
+
}
|
|
45216
46331
|
}
|
|
45217
46332
|
|
|
45218
46333
|
class PivotSpreadsheetSidePanel extends owl.Component {
|
|
@@ -46314,6 +47429,7 @@ css /* scss */ `
|
|
|
46314
47429
|
}
|
|
46315
47430
|
}
|
|
46316
47431
|
`;
|
|
47432
|
+
const DEFAULT_TABLE_STYLE_COLOR = "#3C78D8";
|
|
46317
47433
|
class TableStyleEditorPanel extends owl.Component {
|
|
46318
47434
|
static template = "o-spreadsheet-TableStyleEditorPanel";
|
|
46319
47435
|
static components = { Section, RoundColorPicker, TableStylePreview };
|
|
@@ -46332,7 +47448,7 @@ class TableStyleEditorPanel extends owl.Component {
|
|
|
46332
47448
|
: null;
|
|
46333
47449
|
return {
|
|
46334
47450
|
pickerOpened: false,
|
|
46335
|
-
primaryColor: editedStyle?.primaryColor ||
|
|
47451
|
+
primaryColor: editedStyle?.primaryColor || DEFAULT_TABLE_STYLE_COLOR,
|
|
46336
47452
|
selectedTemplateName: editedStyle?.templateName || "lightColoredText",
|
|
46337
47453
|
styleName: editedStyle?.displayName || this.env.model.getters.getNewCustomTableStyleName(),
|
|
46338
47454
|
};
|
|
@@ -46341,7 +47457,7 @@ class TableStyleEditorPanel extends owl.Component {
|
|
|
46341
47457
|
this.state.pickerOpened = !this.state.pickerOpened;
|
|
46342
47458
|
}
|
|
46343
47459
|
onColorPicked(color) {
|
|
46344
|
-
this.state.primaryColor = color;
|
|
47460
|
+
this.state.primaryColor = isColorValid(color) ? color : DEFAULT_TABLE_STYLE_COLOR;
|
|
46345
47461
|
this.state.pickerOpened = false;
|
|
46346
47462
|
}
|
|
46347
47463
|
onTemplatePicked(templateName) {
|
|
@@ -47957,6 +49073,7 @@ class FiguresContainer extends owl.Component {
|
|
|
47957
49073
|
draggedFigure: undefined,
|
|
47958
49074
|
horizontalSnap: undefined,
|
|
47959
49075
|
verticalSnap: undefined,
|
|
49076
|
+
cancelDnd: undefined,
|
|
47960
49077
|
});
|
|
47961
49078
|
setup() {
|
|
47962
49079
|
owl.onMounted(() => {
|
|
@@ -47969,12 +49086,28 @@ class FiguresContainer extends owl.Component {
|
|
|
47969
49086
|
// new rendering
|
|
47970
49087
|
this.render();
|
|
47971
49088
|
});
|
|
49089
|
+
owl.onWillUpdateProps(() => {
|
|
49090
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
49091
|
+
const draggedFigureId = this.dnd.draggedFigure?.id;
|
|
49092
|
+
if (draggedFigureId && !this.env.model.getters.getFigure(sheetId, draggedFigureId)) {
|
|
49093
|
+
if (this.dnd.cancelDnd) {
|
|
49094
|
+
this.dnd.cancelDnd();
|
|
49095
|
+
}
|
|
49096
|
+
this.dnd.draggedFigure = undefined;
|
|
49097
|
+
this.dnd.horizontalSnap = undefined;
|
|
49098
|
+
this.dnd.verticalSnap = undefined;
|
|
49099
|
+
this.dnd.cancelDnd = undefined;
|
|
49100
|
+
}
|
|
49101
|
+
});
|
|
47972
49102
|
}
|
|
47973
49103
|
getVisibleFigures() {
|
|
47974
49104
|
const visibleFigures = this.env.model.getters.getVisibleFigures();
|
|
47975
49105
|
if (this.dnd.draggedFigure &&
|
|
47976
49106
|
!visibleFigures.some((figure) => figure.id === this.dnd.draggedFigure?.id)) {
|
|
47977
|
-
|
|
49107
|
+
const draggedFigure = this.env.model.getters.getFigure(this.env.model.getters.getActiveSheetId(), this.dnd.draggedFigure?.id);
|
|
49108
|
+
if (draggedFigure) {
|
|
49109
|
+
visibleFigures.push(draggedFigure);
|
|
49110
|
+
}
|
|
47978
49111
|
}
|
|
47979
49112
|
return visibleFigures;
|
|
47980
49113
|
}
|
|
@@ -48093,7 +49226,7 @@ class FiguresContainer extends owl.Component {
|
|
|
48093
49226
|
this.dnd.verticalSnap = undefined;
|
|
48094
49227
|
this.env.model.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x, y });
|
|
48095
49228
|
};
|
|
48096
|
-
startDnd(onMouseMove, onMouseUp);
|
|
49229
|
+
this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
|
|
48097
49230
|
}
|
|
48098
49231
|
/**
|
|
48099
49232
|
* Initialize the resize of a figure with mouse movements
|
|
@@ -48141,7 +49274,7 @@ class FiguresContainer extends owl.Component {
|
|
|
48141
49274
|
this.dnd.horizontalSnap = undefined;
|
|
48142
49275
|
this.dnd.verticalSnap = undefined;
|
|
48143
49276
|
};
|
|
48144
|
-
startDnd(onMouseMove, onMouseUp);
|
|
49277
|
+
this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
|
|
48145
49278
|
}
|
|
48146
49279
|
getOtherFigures(figId) {
|
|
48147
49280
|
return this.getVisibleFigures().filter((f) => f.id !== figId);
|
|
@@ -49248,9 +50381,11 @@ class HeadersOverlay extends owl.Component {
|
|
|
49248
50381
|
class GridRenderer {
|
|
49249
50382
|
getters;
|
|
49250
50383
|
renderer;
|
|
50384
|
+
fingerprints;
|
|
49251
50385
|
constructor(get) {
|
|
49252
50386
|
this.getters = get(ModelStore).getters;
|
|
49253
50387
|
this.renderer = get(RendererStore);
|
|
50388
|
+
this.fingerprints = get(FormulaFingerprintStore);
|
|
49254
50389
|
this.renderer.register(this);
|
|
49255
50390
|
}
|
|
49256
50391
|
get renderingLayers() {
|
|
@@ -49728,14 +50863,22 @@ class GridRenderer {
|
|
|
49728
50863
|
const showFormula = this.getters.shouldShowFormulas();
|
|
49729
50864
|
const { x, y, width, height } = this.getters.getVisibleRect(zone);
|
|
49730
50865
|
const { verticalAlign } = this.getters.getCellStyle(position);
|
|
50866
|
+
let style = this.getters.getCellComputedStyle(position);
|
|
50867
|
+
if (this.fingerprints.isEnabled) {
|
|
50868
|
+
const fingerprintColor = this.fingerprints.colors.get(position);
|
|
50869
|
+
style = { ...style, fillColor: fingerprintColor };
|
|
50870
|
+
}
|
|
50871
|
+
const dataBarFill = this.fingerprints.isEnabled
|
|
50872
|
+
? undefined
|
|
50873
|
+
: this.getters.getConditionalDataBar(position);
|
|
49731
50874
|
const box = {
|
|
49732
50875
|
x,
|
|
49733
50876
|
y,
|
|
49734
50877
|
width,
|
|
49735
50878
|
height,
|
|
49736
50879
|
border: this.getters.getCellComputedBorder(position) || undefined,
|
|
49737
|
-
style
|
|
49738
|
-
dataBarFill
|
|
50880
|
+
style,
|
|
50881
|
+
dataBarFill,
|
|
49739
50882
|
verticalAlign,
|
|
49740
50883
|
isError: (cell.type === CellValueType.error && !!cell.message) ||
|
|
49741
50884
|
this.getters.isDataValidationInvalid(position),
|
|
@@ -49760,7 +50903,6 @@ class GridRenderer {
|
|
|
49760
50903
|
box.hasIcon = this.getters.doesCellHaveGridIcon(position);
|
|
49761
50904
|
const headerIconWidth = box.hasIcon ? GRID_ICON_EDGE_LENGTH + GRID_ICON_MARGIN : 0;
|
|
49762
50905
|
/** Content */
|
|
49763
|
-
const style = this.getters.getCellComputedStyle(position);
|
|
49764
50906
|
const wrapping = style.wrapping || "overflow";
|
|
49765
50907
|
const wrapText = wrapping === "wrap" && !showFormula;
|
|
49766
50908
|
const maxWidth = width - 2 * MIN_CELL_TEXT_MARGIN;
|
|
@@ -51738,62 +52880,6 @@ class BordersPlugin extends CorePlugin {
|
|
|
51738
52880
|
}
|
|
51739
52881
|
}
|
|
51740
52882
|
|
|
51741
|
-
class PositionMap {
|
|
51742
|
-
map = {};
|
|
51743
|
-
constructor(entries = []) {
|
|
51744
|
-
for (const [position, value] of entries) {
|
|
51745
|
-
this.set(position, value);
|
|
51746
|
-
}
|
|
51747
|
-
}
|
|
51748
|
-
set({ sheetId, col, row }, value) {
|
|
51749
|
-
const map = this.map;
|
|
51750
|
-
if (!map[sheetId]) {
|
|
51751
|
-
map[sheetId] = {};
|
|
51752
|
-
}
|
|
51753
|
-
if (!map[sheetId][col]) {
|
|
51754
|
-
map[sheetId][col] = {};
|
|
51755
|
-
}
|
|
51756
|
-
map[sheetId][col][row] = value;
|
|
51757
|
-
}
|
|
51758
|
-
get({ sheetId, col, row }) {
|
|
51759
|
-
return this.map[sheetId]?.[col]?.[row];
|
|
51760
|
-
}
|
|
51761
|
-
getSheet(sheetId) {
|
|
51762
|
-
return this.map[sheetId];
|
|
51763
|
-
}
|
|
51764
|
-
has({ sheetId, col, row }) {
|
|
51765
|
-
return this.map[sheetId]?.[col]?.[row] !== undefined;
|
|
51766
|
-
}
|
|
51767
|
-
delete({ sheetId, col, row }) {
|
|
51768
|
-
delete this.map[sheetId]?.[col]?.[row];
|
|
51769
|
-
}
|
|
51770
|
-
keys() {
|
|
51771
|
-
const map = this.map;
|
|
51772
|
-
const keys = [];
|
|
51773
|
-
for (const sheetId in map) {
|
|
51774
|
-
for (const col in map[sheetId]) {
|
|
51775
|
-
for (const row in map[sheetId][col]) {
|
|
51776
|
-
keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
|
|
51777
|
-
}
|
|
51778
|
-
}
|
|
51779
|
-
}
|
|
51780
|
-
return keys;
|
|
51781
|
-
}
|
|
51782
|
-
keysForSheet(sheetId) {
|
|
51783
|
-
const map = this.map[sheetId];
|
|
51784
|
-
if (!map) {
|
|
51785
|
-
return [];
|
|
51786
|
-
}
|
|
51787
|
-
const keys = [];
|
|
51788
|
-
for (const col in map) {
|
|
51789
|
-
for (const row in map[col]) {
|
|
51790
|
-
keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
|
|
51791
|
-
}
|
|
51792
|
-
}
|
|
51793
|
-
return keys;
|
|
51794
|
-
}
|
|
51795
|
-
}
|
|
51796
|
-
|
|
51797
52883
|
/**
|
|
51798
52884
|
* Core Plugin
|
|
51799
52885
|
*
|
|
@@ -51888,7 +52974,7 @@ class CellPlugin extends CorePlugin {
|
|
|
51888
52974
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
51889
52975
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
51890
52976
|
const cell = this.getters.getCell({ sheetId, col, row });
|
|
51891
|
-
if (cell) {
|
|
52977
|
+
if (cell?.isFormula || cell?.content) {
|
|
51892
52978
|
this.dispatch("UPDATE_CELL", {
|
|
51893
52979
|
sheetId: sheetId,
|
|
51894
52980
|
content: "",
|
|
@@ -51924,7 +53010,6 @@ class CellPlugin extends CorePlugin {
|
|
|
51924
53010
|
for (let zone of recomputeZones(zones)) {
|
|
51925
53011
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
51926
53012
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
51927
|
-
// commandHelpers.updateCell(sheetId, col, row, { style: undefined});
|
|
51928
53013
|
this.dispatch("UPDATE_CELL", {
|
|
51929
53014
|
sheetId,
|
|
51930
53015
|
col,
|
|
@@ -52233,7 +53318,7 @@ class CellPlugin extends CorePlugin {
|
|
|
52233
53318
|
const before = this.getters.getCell({ sheetId, col, row });
|
|
52234
53319
|
const hasContent = "content" in after || "formula" in after;
|
|
52235
53320
|
// Compute the new cell properties
|
|
52236
|
-
const afterContent = hasContent ?
|
|
53321
|
+
const afterContent = hasContent ? replaceNewLines(after?.content) : before?.content || "";
|
|
52237
53322
|
let style;
|
|
52238
53323
|
if (after.style !== undefined) {
|
|
52239
53324
|
style = after.style || undefined;
|
|
@@ -55178,6 +56263,9 @@ class SheetPlugin extends CorePlugin {
|
|
|
55178
56263
|
};
|
|
55179
56264
|
}
|
|
55180
56265
|
getUnboundedZone(sheetId, zone) {
|
|
56266
|
+
if (zone.bottom === undefined || zone.right === undefined) {
|
|
56267
|
+
return zone;
|
|
56268
|
+
}
|
|
55181
56269
|
const isFullRow = zone.left === 0 && zone.right === this.getNumberCols(sheetId) - 1;
|
|
55182
56270
|
const isFullCol = zone.top === 0 && zone.bottom === this.getNumberRows(sheetId) - 1;
|
|
55183
56271
|
return {
|
|
@@ -55343,7 +56431,7 @@ class SheetPlugin extends CorePlugin {
|
|
|
55343
56431
|
if (orderedSheetIds.find((id) => sheets[id]?.name.toLowerCase() === name && id !== cmd.sheetId)) {
|
|
55344
56432
|
return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
|
|
55345
56433
|
}
|
|
55346
|
-
if (
|
|
56434
|
+
if (FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX.test(name)) {
|
|
55347
56435
|
return "ForbiddenCharactersInSheetName" /* CommandResult.ForbiddenCharactersInSheetName */;
|
|
55348
56436
|
}
|
|
55349
56437
|
return "Success" /* CommandResult.Success */;
|
|
@@ -59461,66 +60549,25 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
59461
60549
|
return;
|
|
59462
60550
|
}
|
|
59463
60551
|
const zone = this.getters.getRangeFromSheetXC(sheetId, range).zone;
|
|
59464
|
-
const
|
|
60552
|
+
const colorThresholds = [{ value: minValue, color: rule.minimum.color }];
|
|
59465
60553
|
if (rule.midpoint && midValue) {
|
|
59466
|
-
|
|
59467
|
-
minValue,
|
|
59468
|
-
minColor: rule.minimum.color,
|
|
59469
|
-
colorDiffUnit: this.computeColorDiffUnits(minValue, midValue, rule.minimum.color, rule.midpoint.color),
|
|
59470
|
-
});
|
|
59471
|
-
colorCellArgs.push({
|
|
59472
|
-
minValue: midValue,
|
|
59473
|
-
minColor: rule.midpoint.color,
|
|
59474
|
-
colorDiffUnit: this.computeColorDiffUnits(midValue, maxValue, rule.midpoint.color, rule.maximum.color),
|
|
59475
|
-
});
|
|
59476
|
-
}
|
|
59477
|
-
else {
|
|
59478
|
-
colorCellArgs.push({
|
|
59479
|
-
minValue,
|
|
59480
|
-
minColor: rule.minimum.color,
|
|
59481
|
-
colorDiffUnit: this.computeColorDiffUnits(minValue, maxValue, rule.minimum.color, rule.maximum.color),
|
|
59482
|
-
});
|
|
60554
|
+
colorThresholds.push({ value: midValue, color: rule.midpoint.color });
|
|
59483
60555
|
}
|
|
60556
|
+
colorThresholds.push({ value: maxValue, color: rule.maximum.color });
|
|
60557
|
+
const colorScale = getColorScale(colorThresholds);
|
|
59484
60558
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
59485
60559
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
59486
60560
|
const cell = this.getters.getEvaluatedCell({ sheetId, col, row });
|
|
59487
60561
|
if (cell.type === CellValueType.number) {
|
|
59488
60562
|
const value = clip(cell.value, minValue, maxValue);
|
|
59489
|
-
let color;
|
|
59490
|
-
if (colorCellArgs.length === 2 && midValue) {
|
|
59491
|
-
color =
|
|
59492
|
-
value <= midValue
|
|
59493
|
-
? this.colorCell(value, colorCellArgs[0].minValue, colorCellArgs[0].minColor, colorCellArgs[0].colorDiffUnit)
|
|
59494
|
-
: this.colorCell(value, colorCellArgs[1].minValue, colorCellArgs[1].minColor, colorCellArgs[1].colorDiffUnit);
|
|
59495
|
-
}
|
|
59496
|
-
else {
|
|
59497
|
-
color = this.colorCell(value, colorCellArgs[0].minValue, colorCellArgs[0].minColor, colorCellArgs[0].colorDiffUnit);
|
|
59498
|
-
}
|
|
59499
60563
|
if (!computedStyle[col])
|
|
59500
60564
|
computedStyle[col] = [];
|
|
59501
60565
|
computedStyle[col][row] = computedStyle[col]?.[row] || {};
|
|
59502
|
-
computedStyle[col][row].fillColor =
|
|
60566
|
+
computedStyle[col][row].fillColor = colorScale(value);
|
|
59503
60567
|
}
|
|
59504
60568
|
}
|
|
59505
60569
|
}
|
|
59506
60570
|
}
|
|
59507
|
-
computeColorDiffUnits(minValue, maxValue, minColor, maxColor) {
|
|
59508
|
-
const deltaValue = maxValue - minValue;
|
|
59509
|
-
const deltaColorR = ((minColor >> 16) % 256) - ((maxColor >> 16) % 256);
|
|
59510
|
-
const deltaColorG = ((minColor >> 8) % 256) - ((maxColor >> 8) % 256);
|
|
59511
|
-
const deltaColorB = (minColor % 256) - (maxColor % 256);
|
|
59512
|
-
const colorDiffUnitR = deltaColorR / deltaValue;
|
|
59513
|
-
const colorDiffUnitG = deltaColorG / deltaValue;
|
|
59514
|
-
const colorDiffUnitB = deltaColorB / deltaValue;
|
|
59515
|
-
return [colorDiffUnitR, colorDiffUnitG, colorDiffUnitB];
|
|
59516
|
-
}
|
|
59517
|
-
colorCell(value, minValue, minColor, colorDiffUnit) {
|
|
59518
|
-
const [colorDiffUnitR, colorDiffUnitG, colorDiffUnitB] = colorDiffUnit;
|
|
59519
|
-
const r = Math.round(((minColor >> 16) % 256) - colorDiffUnitR * (value - minValue));
|
|
59520
|
-
const g = Math.round(((minColor >> 8) % 256) - colorDiffUnitG * (value - minValue));
|
|
59521
|
-
const b = Math.round((minColor % 256) - colorDiffUnitB * (value - minValue));
|
|
59522
|
-
return (r << 16) | (g << 8) | b;
|
|
59523
|
-
}
|
|
59524
60571
|
/**
|
|
59525
60572
|
* Execute the predicate to know if a conditional formatting rule should be applied to a cell
|
|
59526
60573
|
*/
|
|
@@ -60146,7 +61193,7 @@ function withPivotPresentationLayer (PivotClass) {
|
|
|
60146
61193
|
}
|
|
60147
61194
|
getValuesToAggregate(measure, domain) {
|
|
60148
61195
|
const { rowDomain, colDomain } = domainToColRowDomain(this, domain);
|
|
60149
|
-
const table =
|
|
61196
|
+
const table = super.getTableStructure();
|
|
60150
61197
|
const values = [];
|
|
60151
61198
|
if (colDomain.length === 0 &&
|
|
60152
61199
|
rowDomain.length < this.definition.rows.length &&
|
|
@@ -60580,6 +61627,21 @@ function withPivotPresentationLayer (PivotClass) {
|
|
|
60580
61627
|
}
|
|
60581
61628
|
throw new Error(`Value ${result.value} is not a number`);
|
|
60582
61629
|
}
|
|
61630
|
+
getTableStructure() {
|
|
61631
|
+
const table = super.getTableStructure();
|
|
61632
|
+
this.sortTableStructure(table);
|
|
61633
|
+
return table;
|
|
61634
|
+
}
|
|
61635
|
+
sortTableStructure(table) {
|
|
61636
|
+
if (!this.definition.sortedColumn || table.isSorted) {
|
|
61637
|
+
return;
|
|
61638
|
+
}
|
|
61639
|
+
const measure = this.definition.sortedColumn.measure;
|
|
61640
|
+
const isSortValid = isSortedColumnValid(this.definition.sortedColumn, this);
|
|
61641
|
+
if (isSortValid) {
|
|
61642
|
+
table.sort(measure, this.definition.sortedColumn, (measure, domain) => this._getPivotCellValueAndFormat(measure, domain));
|
|
61643
|
+
}
|
|
61644
|
+
}
|
|
60583
61645
|
}
|
|
60584
61646
|
return PivotPresentationLayer;
|
|
60585
61647
|
}
|
|
@@ -60751,11 +61813,13 @@ class PivotUIPlugin extends UIPlugin {
|
|
|
60751
61813
|
return EMPTY_PIVOT_CELL;
|
|
60752
61814
|
}
|
|
60753
61815
|
if (functionName === "PIVOT") {
|
|
60754
|
-
const includeTotal = args[2]
|
|
60755
|
-
const
|
|
61816
|
+
const includeTotal = toScalar(args[2]);
|
|
61817
|
+
const shouldIncludeTotal = includeTotal === undefined ? true : toBoolean(includeTotal);
|
|
61818
|
+
const includeColumnHeaders = toScalar(args[3]);
|
|
61819
|
+
const shouldIncludeColumnHeaders = includeColumnHeaders === undefined ? true : toBoolean(includeColumnHeaders);
|
|
60756
61820
|
const pivotCells = pivot
|
|
60757
61821
|
.getTableStructure()
|
|
60758
|
-
.getPivotCells(
|
|
61822
|
+
.getPivotCells(shouldIncludeTotal, shouldIncludeColumnHeaders);
|
|
60759
61823
|
const pivotCol = position.col - mainPosition.col;
|
|
60760
61824
|
const pivotRow = position.row - mainPosition.row;
|
|
60761
61825
|
return pivotCells[pivotCol][pivotRow];
|
|
@@ -62353,23 +63417,6 @@ class Session extends EventBus {
|
|
|
62353
63417
|
}
|
|
62354
63418
|
}
|
|
62355
63419
|
|
|
62356
|
-
function randomChoice(arr) {
|
|
62357
|
-
return arr[Math.floor(Math.random() * arr.length)];
|
|
62358
|
-
}
|
|
62359
|
-
const colors = [
|
|
62360
|
-
"#ff851b",
|
|
62361
|
-
"#0074d9",
|
|
62362
|
-
"#7fdbff",
|
|
62363
|
-
"#b10dc9",
|
|
62364
|
-
"#39cccc",
|
|
62365
|
-
"#f012be",
|
|
62366
|
-
"#3d9970",
|
|
62367
|
-
"#111111",
|
|
62368
|
-
"#ff4136",
|
|
62369
|
-
"#aaaaaa",
|
|
62370
|
-
"#85144b",
|
|
62371
|
-
"#001f3f",
|
|
62372
|
-
];
|
|
62373
63420
|
class CollaborativePlugin extends UIPlugin {
|
|
62374
63421
|
static getters = [
|
|
62375
63422
|
"getClientsToDisplay",
|
|
@@ -62378,7 +63425,7 @@ class CollaborativePlugin extends UIPlugin {
|
|
|
62378
63425
|
"isFullySynchronized",
|
|
62379
63426
|
];
|
|
62380
63427
|
static layers = ["Selection"];
|
|
62381
|
-
availableColors = new
|
|
63428
|
+
availableColors = new AlternatingColorGenerator(12);
|
|
62382
63429
|
colors = {};
|
|
62383
63430
|
session;
|
|
62384
63431
|
constructor(config) {
|
|
@@ -62389,14 +63436,6 @@ class CollaborativePlugin extends UIPlugin {
|
|
|
62389
63436
|
return (position.row < this.getters.getNumberRows(position.sheetId) &&
|
|
62390
63437
|
position.col < this.getters.getNumberCols(position.sheetId));
|
|
62391
63438
|
}
|
|
62392
|
-
chooseNewColor() {
|
|
62393
|
-
if (this.availableColors.size === 0) {
|
|
62394
|
-
this.availableColors = new Set(colors);
|
|
62395
|
-
}
|
|
62396
|
-
const color = randomChoice([...this.availableColors.values()]);
|
|
62397
|
-
this.availableColors.delete(color);
|
|
62398
|
-
return color;
|
|
62399
|
-
}
|
|
62400
63439
|
getClient() {
|
|
62401
63440
|
return this.session.getClient();
|
|
62402
63441
|
}
|
|
@@ -62431,7 +63470,7 @@ class CollaborativePlugin extends UIPlugin {
|
|
|
62431
63470
|
this.isPositionValid(client.position)) {
|
|
62432
63471
|
const position = client.position;
|
|
62433
63472
|
if (!this.colors[client.id]) {
|
|
62434
|
-
this.colors[client.id] = this.
|
|
63473
|
+
this.colors[client.id] = this.availableColors.next();
|
|
62435
63474
|
}
|
|
62436
63475
|
const color = this.colors[client.id];
|
|
62437
63476
|
clients.push({ ...client, position, color });
|
|
@@ -62668,7 +63707,7 @@ class FormatPlugin extends UIPlugin {
|
|
|
62668
63707
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
62669
63708
|
const position = { sheetId, col, row };
|
|
62670
63709
|
const pivotCell = this.getters.getPivotCellFromPosition(position);
|
|
62671
|
-
if (
|
|
63710
|
+
if (this.isSpilledPivotValueFormula(position, pivotCell)) {
|
|
62672
63711
|
measurePositions.push(position);
|
|
62673
63712
|
const pivotId = this.getters.getPivotIdFromPosition(position) || "";
|
|
62674
63713
|
measuresByPivotId[pivotId] ??= new Set();
|
|
@@ -62705,6 +63744,10 @@ class FormatPlugin extends UIPlugin {
|
|
|
62705
63744
|
format,
|
|
62706
63745
|
});
|
|
62707
63746
|
}
|
|
63747
|
+
isSpilledPivotValueFormula(position, pivotCell) {
|
|
63748
|
+
const cell = this.getters.getCell(position);
|
|
63749
|
+
return pivotCell.type === "VALUE" && !cell?.isFormula;
|
|
63750
|
+
}
|
|
62708
63751
|
/**
|
|
62709
63752
|
* This function allows to adjust the quantity of decimal places after a decimal
|
|
62710
63753
|
* point on cells containing number value. It does this by changing the cells
|
|
@@ -62755,6 +63798,69 @@ class FormatPlugin extends UIPlugin {
|
|
|
62755
63798
|
}
|
|
62756
63799
|
}
|
|
62757
63800
|
|
|
63801
|
+
class GeoFeaturePlugin extends UIPlugin {
|
|
63802
|
+
static getters = [
|
|
63803
|
+
"getGeoJsonFeatures",
|
|
63804
|
+
"geoFeatureNameToId",
|
|
63805
|
+
"getGeoChartAvailableRegions",
|
|
63806
|
+
];
|
|
63807
|
+
geoJsonService;
|
|
63808
|
+
geoJsonCache = {};
|
|
63809
|
+
constructor(config) {
|
|
63810
|
+
super(config);
|
|
63811
|
+
this.geoJsonService = config.external.geoJsonService;
|
|
63812
|
+
}
|
|
63813
|
+
getGeoChartAvailableRegions() {
|
|
63814
|
+
if (!this.geoJsonService) {
|
|
63815
|
+
console.error("No geoJsonService provided to the model");
|
|
63816
|
+
return [];
|
|
63817
|
+
}
|
|
63818
|
+
return this.geoJsonService.getAvailableRegions() || [];
|
|
63819
|
+
}
|
|
63820
|
+
getGeoJsonFeatures(region) {
|
|
63821
|
+
if (!this.geoJsonService) {
|
|
63822
|
+
console.error("No geoJsonService provided to the model");
|
|
63823
|
+
return;
|
|
63824
|
+
}
|
|
63825
|
+
const cachedGeoJson = this.geoJsonCache[region];
|
|
63826
|
+
if (cachedGeoJson instanceof Promise) {
|
|
63827
|
+
return undefined;
|
|
63828
|
+
}
|
|
63829
|
+
if (cachedGeoJson !== undefined) {
|
|
63830
|
+
return cachedGeoJson ?? undefined;
|
|
63831
|
+
}
|
|
63832
|
+
this.geoJsonCache[region] = new Promise(async (resolve) => {
|
|
63833
|
+
const json = await this.geoJsonService?.getTopoJson(region);
|
|
63834
|
+
this.geoJsonCache[region] = this.convertToGeoJson(json);
|
|
63835
|
+
this.dispatch("EVALUATE_CHARTS");
|
|
63836
|
+
resolve();
|
|
63837
|
+
});
|
|
63838
|
+
return undefined;
|
|
63839
|
+
}
|
|
63840
|
+
geoFeatureNameToId(region, featureName) {
|
|
63841
|
+
if (!this.geoJsonService) {
|
|
63842
|
+
console.error("No geoJsonService provided to the model");
|
|
63843
|
+
return;
|
|
63844
|
+
}
|
|
63845
|
+
return this.geoJsonService.geoFeatureNameToId(region, featureName);
|
|
63846
|
+
}
|
|
63847
|
+
convertToGeoJson(json) {
|
|
63848
|
+
if (!json) {
|
|
63849
|
+
return null;
|
|
63850
|
+
}
|
|
63851
|
+
// TopoJSON
|
|
63852
|
+
if (json.type === "Topology") {
|
|
63853
|
+
const features = window.ChartGeo.topojson.feature(json, Object.values(json.objects)[0]);
|
|
63854
|
+
return features.type === "FeatureCollection" ? features.features : [features];
|
|
63855
|
+
}
|
|
63856
|
+
// GeoJSON
|
|
63857
|
+
else if (json.type === "FeatureCollection") {
|
|
63858
|
+
return json.features;
|
|
63859
|
+
}
|
|
63860
|
+
throw new Error("Invalid TopoJSON");
|
|
63861
|
+
}
|
|
63862
|
+
}
|
|
63863
|
+
|
|
62758
63864
|
class HeaderVisibilityUIPlugin extends UIPlugin {
|
|
62759
63865
|
static getters = [
|
|
62760
63866
|
"getNextVisibleCellPosition",
|
|
@@ -62909,7 +64015,7 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
62909
64015
|
getPivotDuplicateSheetName(pivotName) {
|
|
62910
64016
|
let i = 1;
|
|
62911
64017
|
const names = this.getters.getSheetIds().map((id) => this.getters.getSheetName(id));
|
|
62912
|
-
const sanitizedName = pivotName
|
|
64018
|
+
const sanitizedName = sanitizeSheetName(pivotName);
|
|
62913
64019
|
let name = sanitizedName;
|
|
62914
64020
|
while (names.includes(name)) {
|
|
62915
64021
|
name = `${sanitizedName} (${i})`;
|
|
@@ -64292,10 +65398,13 @@ class TableResizeUI extends UIPlugin {
|
|
|
64292
65398
|
case "RESIZE_TABLE": {
|
|
64293
65399
|
const table = this.getters.getCoreTableMatchingTopLeft(cmd.sheetId, cmd.zone);
|
|
64294
65400
|
this.dispatch("UPDATE_TABLE", { ...cmd });
|
|
64295
|
-
if (!table
|
|
65401
|
+
if (!table)
|
|
64296
65402
|
return;
|
|
64297
|
-
const oldTableZone = table.range.zone;
|
|
64298
65403
|
const newTableZone = this.getters.getRangeFromRangeData(cmd.newTableRange).zone;
|
|
65404
|
+
this.selection.selectCell(newTableZone.right, newTableZone.bottom);
|
|
65405
|
+
if (!table.config.automaticAutofill)
|
|
65406
|
+
return;
|
|
65407
|
+
const oldTableZone = table.range.zone;
|
|
64299
65408
|
if (newTableZone.bottom >= oldTableZone.bottom) {
|
|
64300
65409
|
for (let col = newTableZone.left; col <= newTableZone.right; col++) {
|
|
64301
65410
|
const autofillSource = { col, row: oldTableZone.bottom, sheetId: cmd.sheetId };
|
|
@@ -65501,15 +66610,23 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
65501
66610
|
handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
|
|
65502
66611
|
const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
|
|
65503
66612
|
let currentIndex = cmd.base;
|
|
66613
|
+
const resizingGroups = {};
|
|
65504
66614
|
for (const element of toRemove) {
|
|
65505
66615
|
const size = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, element);
|
|
66616
|
+
const currentSize = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, currentIndex);
|
|
66617
|
+
if (size != currentSize) {
|
|
66618
|
+
resizingGroups[size] ??= [];
|
|
66619
|
+
resizingGroups[size].push(currentIndex);
|
|
66620
|
+
currentIndex += 1;
|
|
66621
|
+
}
|
|
66622
|
+
}
|
|
66623
|
+
for (const size in resizingGroups) {
|
|
65506
66624
|
this.dispatch("RESIZE_COLUMNS_ROWS", {
|
|
65507
66625
|
dimension: cmd.dimension,
|
|
65508
66626
|
sheetId: cmd.sheetId,
|
|
65509
|
-
size,
|
|
65510
|
-
elements: [
|
|
66627
|
+
size: parseInt(size, 10),
|
|
66628
|
+
elements: resizingGroups[size],
|
|
65511
66629
|
});
|
|
65512
|
-
currentIndex += 1;
|
|
65513
66630
|
}
|
|
65514
66631
|
this.dispatch("REMOVE_COLUMNS_ROWS", {
|
|
65515
66632
|
dimension: cmd.dimension,
|
|
@@ -66091,6 +67208,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
66091
67208
|
break;
|
|
66092
67209
|
case "DELETE_SHEET":
|
|
66093
67210
|
this.cleanViewports();
|
|
67211
|
+
this.sheetsWithDirtyViewports.delete(cmd.sheetId);
|
|
66094
67212
|
break;
|
|
66095
67213
|
case "ACTIVATE_SHEET":
|
|
66096
67214
|
this.sheetsWithDirtyViewports.add(cmd.sheetIdTo);
|
|
@@ -66741,7 +67859,8 @@ const featurePluginRegistry = new Registry()
|
|
|
66741
67859
|
.add("data_cleanup", DataCleanupPlugin)
|
|
66742
67860
|
.add("table_autofill", TableAutofillPlugin)
|
|
66743
67861
|
.add("table_ui_resize", TableResizeUI)
|
|
66744
|
-
.add("datavalidation_insert", DataValidationInsertionPlugin)
|
|
67862
|
+
.add("datavalidation_insert", DataValidationInsertionPlugin)
|
|
67863
|
+
.add("geo_features", GeoFeaturePlugin);
|
|
66745
67864
|
// Plugins which have a state, but which should not be shared in collaborative
|
|
66746
67865
|
const statefulUIPluginRegistry = new Registry()
|
|
66747
67866
|
.add("selection", GridSelectionPlugin)
|
|
@@ -66985,7 +68104,7 @@ function interactiveRenameSheet(env, sheetId, name, errorCallback) {
|
|
|
66985
68104
|
env.raiseError(_t("A sheet with the name %s already exists. Please select another name.", name), errorCallback);
|
|
66986
68105
|
}
|
|
66987
68106
|
else if (result.reasons.includes("ForbiddenCharactersInSheetName" /* CommandResult.ForbiddenCharactersInSheetName */)) {
|
|
66988
|
-
env.raiseError(_t("Some used characters are not allowed in a sheet name (Forbidden characters are %s).",
|
|
68107
|
+
env.raiseError(_t("Some used characters are not allowed in a sheet name (Forbidden characters are %s).", FORBIDDEN_SHEETNAME_CHARS.join(" ")), errorCallback);
|
|
66989
68108
|
}
|
|
66990
68109
|
}
|
|
66991
68110
|
|
|
@@ -68215,7 +69334,7 @@ class ActionButton extends owl.Component {
|
|
|
68215
69334
|
setup() {
|
|
68216
69335
|
owl.onWillUpdateProps((nextProps) => {
|
|
68217
69336
|
if (nextProps.action !== this.props.action) {
|
|
68218
|
-
this.actionButton = createAction(
|
|
69337
|
+
this.actionButton = createAction(nextProps.action);
|
|
68219
69338
|
}
|
|
68220
69339
|
});
|
|
68221
69340
|
}
|
|
@@ -68485,8 +69604,8 @@ css /* scss */ `
|
|
|
68485
69604
|
.o-topbar-composer {
|
|
68486
69605
|
height: fit-content;
|
|
68487
69606
|
margin-top: -1px;
|
|
69607
|
+
margin-bottom: -1px;
|
|
68488
69608
|
border: 1px solid;
|
|
68489
|
-
z-index: ${ComponentsImportance.TopBarComposer};
|
|
68490
69609
|
font-family: ${DEFAULT_FONT};
|
|
68491
69610
|
|
|
68492
69611
|
.o-composer:empty:not(:focus):not(.active)::before {
|
|
@@ -68544,6 +69663,7 @@ class TopBarComposer extends owl.Component {
|
|
|
68544
69663
|
}
|
|
68545
69664
|
return cssPropertiesToCss({
|
|
68546
69665
|
"border-color": SELECTION_BORDER_COLOR,
|
|
69666
|
+
"z-index": String(ComponentsImportance.TopBarComposer),
|
|
68547
69667
|
});
|
|
68548
69668
|
}
|
|
68549
69669
|
onFocus(selection) {
|
|
@@ -68551,88 +69671,6 @@ class TopBarComposer extends owl.Component {
|
|
|
68551
69671
|
}
|
|
68552
69672
|
}
|
|
68553
69673
|
|
|
68554
|
-
css /* scss */ `
|
|
68555
|
-
.o-font-size-editor {
|
|
68556
|
-
height: calc(100% - 4px);
|
|
68557
|
-
input.o-font-size {
|
|
68558
|
-
outline-color: ${SELECTION_BORDER_COLOR};
|
|
68559
|
-
height: 20px;
|
|
68560
|
-
width: 23px;
|
|
68561
|
-
}
|
|
68562
|
-
}
|
|
68563
|
-
.o-text-options > div {
|
|
68564
|
-
cursor: pointer;
|
|
68565
|
-
line-height: 26px;
|
|
68566
|
-
padding: 3px 12px;
|
|
68567
|
-
&:hover {
|
|
68568
|
-
background-color: rgba(0, 0, 0, 0.08);
|
|
68569
|
-
}
|
|
68570
|
-
}
|
|
68571
|
-
`;
|
|
68572
|
-
class FontSizeEditor extends owl.Component {
|
|
68573
|
-
static template = "o-spreadsheet-FontSizeEditor";
|
|
68574
|
-
static props = {
|
|
68575
|
-
onToggle: Function,
|
|
68576
|
-
dropdownStyle: String,
|
|
68577
|
-
class: String,
|
|
68578
|
-
};
|
|
68579
|
-
static components = {};
|
|
68580
|
-
fontSizes = FONT_SIZES;
|
|
68581
|
-
dropdown = owl.useState({ isOpen: false });
|
|
68582
|
-
inputRef = owl.useRef("inputFontSize");
|
|
68583
|
-
rootEditorRef = owl.useRef("FontSizeEditor");
|
|
68584
|
-
setup() {
|
|
68585
|
-
owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
|
|
68586
|
-
}
|
|
68587
|
-
onExternalClick(ev) {
|
|
68588
|
-
if (!isChildEvent(this.rootEditorRef.el, ev)) {
|
|
68589
|
-
this.closeFontList();
|
|
68590
|
-
}
|
|
68591
|
-
}
|
|
68592
|
-
get currentFontSize() {
|
|
68593
|
-
return this.env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
|
|
68594
|
-
}
|
|
68595
|
-
toggleFontList() {
|
|
68596
|
-
const isOpen = this.dropdown.isOpen;
|
|
68597
|
-
if (!isOpen) {
|
|
68598
|
-
this.props.onToggle();
|
|
68599
|
-
this.inputRef.el.focus();
|
|
68600
|
-
}
|
|
68601
|
-
else {
|
|
68602
|
-
this.closeFontList();
|
|
68603
|
-
}
|
|
68604
|
-
}
|
|
68605
|
-
closeFontList() {
|
|
68606
|
-
this.dropdown.isOpen = false;
|
|
68607
|
-
}
|
|
68608
|
-
setSize(fontSizeStr) {
|
|
68609
|
-
const fontSize = clip(Math.floor(parseFloat(fontSizeStr)), 1, 400);
|
|
68610
|
-
setStyle(this.env, { fontSize });
|
|
68611
|
-
this.closeFontList();
|
|
68612
|
-
}
|
|
68613
|
-
setSizeFromInput(ev) {
|
|
68614
|
-
this.setSize(ev.target.value);
|
|
68615
|
-
}
|
|
68616
|
-
setSizeFromList(fontSizeStr) {
|
|
68617
|
-
this.setSize(fontSizeStr);
|
|
68618
|
-
}
|
|
68619
|
-
onInputFocused(ev) {
|
|
68620
|
-
this.dropdown.isOpen = true;
|
|
68621
|
-
ev.target.select();
|
|
68622
|
-
}
|
|
68623
|
-
onInputKeydown(ev) {
|
|
68624
|
-
if (ev.key === "Enter" || ev.key === "Escape") {
|
|
68625
|
-
this.closeFontList();
|
|
68626
|
-
const target = ev.target;
|
|
68627
|
-
// In the case of a ESCAPE key, we get the previous font size back
|
|
68628
|
-
if (ev.key === "Escape") {
|
|
68629
|
-
target.value = `${this.currentFontSize}`;
|
|
68630
|
-
}
|
|
68631
|
-
this.props.onToggle();
|
|
68632
|
-
}
|
|
68633
|
-
}
|
|
68634
|
-
}
|
|
68635
|
-
|
|
68636
69674
|
class TableDropdownButton extends owl.Component {
|
|
68637
69675
|
static template = "o-spreadsheet-TableDropdownButton";
|
|
68638
69676
|
static components = { TableStylesPopover, ActionButton };
|
|
@@ -68734,6 +69772,15 @@ css /* scss */ `
|
|
|
68734
69772
|
}
|
|
68735
69773
|
}
|
|
68736
69774
|
|
|
69775
|
+
.irregularity-map {
|
|
69776
|
+
border-top: 1px solid ${SEPARATOR_COLOR};
|
|
69777
|
+
height: ${TOPBAR_TOOLBAR_HEIGHT}px;
|
|
69778
|
+
|
|
69779
|
+
.alert-info {
|
|
69780
|
+
border-left: 3px solid ${ALERT_INFO_BORDER};
|
|
69781
|
+
}
|
|
69782
|
+
}
|
|
69783
|
+
|
|
68737
69784
|
.o-topbar-composer {
|
|
68738
69785
|
flex-grow: 1;
|
|
68739
69786
|
}
|
|
@@ -68801,9 +69848,6 @@ class TopBar extends owl.Component {
|
|
|
68801
69848
|
onClick: Function,
|
|
68802
69849
|
dropdownMaxHeight: Number,
|
|
68803
69850
|
};
|
|
68804
|
-
get dropdownStyle() {
|
|
68805
|
-
return `max-height:${this.props.dropdownMaxHeight}px`;
|
|
68806
|
-
}
|
|
68807
69851
|
static components = {
|
|
68808
69852
|
ColorPickerWidget,
|
|
68809
69853
|
ColorPicker,
|
|
@@ -68830,8 +69874,10 @@ class TopBar extends owl.Component {
|
|
|
68830
69874
|
formatNumberMenuItemSpec = formatNumberMenuItemSpec;
|
|
68831
69875
|
isntToolbarMenu = false;
|
|
68832
69876
|
composerFocusStore;
|
|
69877
|
+
fingerprints;
|
|
68833
69878
|
setup() {
|
|
68834
69879
|
this.composerFocusStore = useStore(ComposerFocusStore);
|
|
69880
|
+
this.fingerprints = useStore(FormulaFingerprintStore);
|
|
68835
69881
|
owl.useExternalListener(window, "click", this.onExternalClick);
|
|
68836
69882
|
owl.onWillStart(() => this.updateCellState());
|
|
68837
69883
|
owl.onWillUpdateProps(() => this.updateCellState());
|
|
@@ -68841,6 +69887,9 @@ class TopBar extends owl.Component {
|
|
|
68841
69887
|
.getAllOrdered()
|
|
68842
69888
|
.filter((item) => !item.isVisible || item.isVisible(this.env));
|
|
68843
69889
|
}
|
|
69890
|
+
get currentFontSize() {
|
|
69891
|
+
return this.env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
|
|
69892
|
+
}
|
|
68844
69893
|
onExternalClick(ev) {
|
|
68845
69894
|
// TODO : manage click events better. We need this piece of code
|
|
68846
69895
|
// otherwise the event opening the menu would close it on the same frame.
|
|
@@ -68919,6 +69968,9 @@ class TopBar extends owl.Component {
|
|
|
68919
69968
|
setStyle(this.env, { [target]: color });
|
|
68920
69969
|
this.onClick();
|
|
68921
69970
|
}
|
|
69971
|
+
setFontSize(fontSize) {
|
|
69972
|
+
setStyle(this.env, { fontSize });
|
|
69973
|
+
}
|
|
68922
69974
|
}
|
|
68923
69975
|
|
|
68924
69976
|
function instantiateClipboard() {
|
|
@@ -69296,7 +70348,7 @@ class Spreadsheet extends owl.Component {
|
|
|
69296
70348
|
properties["grid-template-rows"] = `auto`;
|
|
69297
70349
|
}
|
|
69298
70350
|
else {
|
|
69299
|
-
properties["grid-template-rows"] =
|
|
70351
|
+
properties["grid-template-rows"] = `max-content auto ${BOTTOMBAR_HEIGHT + 1}px`;
|
|
69300
70352
|
}
|
|
69301
70353
|
properties["grid-template-columns"] = `auto ${this.sidePanel.panelSize}px`;
|
|
69302
70354
|
return cssPropertiesToCss(properties);
|
|
@@ -70374,9 +71426,6 @@ class SelectionStreamProcessorImpl {
|
|
|
70374
71426
|
getBackToDefault() {
|
|
70375
71427
|
this.stream.getBackToDefault();
|
|
70376
71428
|
}
|
|
70377
|
-
getAnchor() {
|
|
70378
|
-
return this.anchor;
|
|
70379
|
-
}
|
|
70380
71429
|
modifyAnchor(anchor, mode, options) {
|
|
70381
71430
|
const sheetId = this.getters.getActiveSheetId();
|
|
70382
71431
|
anchor = {
|
|
@@ -70919,12 +71968,11 @@ function createChart(chart, chartSheetIndex, data) {
|
|
|
70919
71968
|
// <manualLayout/> to manually position the chart in the figure container
|
|
70920
71969
|
let title = escapeXml ``;
|
|
70921
71970
|
if (chart.data.title?.text) {
|
|
70922
|
-
const
|
|
70923
|
-
|
|
70924
|
-
: chart.data.fontColor;
|
|
71971
|
+
const titleColor = toXlsxHexColor(chartMutedFontColor(chart.data.backgroundColor));
|
|
71972
|
+
const fontSize = chart.data.title.fontSize ?? CHART_TITLE_FONT_SIZE;
|
|
70925
71973
|
title = escapeXml /*xml*/ `
|
|
70926
71974
|
<c:title>
|
|
70927
|
-
${insertText(chart.data.title.text,
|
|
71975
|
+
${insertText(chart.data.title.text, titleColor, fontSize, chart.data.title)}
|
|
70928
71976
|
<c:overlay val="0" />
|
|
70929
71977
|
</c:title>
|
|
70930
71978
|
`;
|
|
@@ -71014,7 +72062,7 @@ function lineAttributes(params) {
|
|
|
71014
72062
|
</a:ln>
|
|
71015
72063
|
`;
|
|
71016
72064
|
}
|
|
71017
|
-
function insertText(text, fontColor = "000000", fontsize =
|
|
72065
|
+
function insertText(text, fontColor = "000000", fontsize = CHART_TITLE_FONT_SIZE, style = {}) {
|
|
71018
72066
|
return escapeXml /*xml*/ `
|
|
71019
72067
|
<c:tx>
|
|
71020
72068
|
<c:rich>
|
|
@@ -71515,6 +72563,7 @@ function addAx(position, axisName, axId, crossAxId, title, defaultFontColor, del
|
|
|
71515
72563
|
// Each Axis present inside a graph needs to be identified by an unsigned integer in order to be referenced by its crossAxis.
|
|
71516
72564
|
// I.e. x-axis, will reference y-axis and vice-versa.
|
|
71517
72565
|
const color = title?.color ? toXlsxHexColor(title.color) : defaultFontColor;
|
|
72566
|
+
const fontSize = title?.fontSize ?? CHART_AXIS_TITLE_FONT_SIZE;
|
|
71518
72567
|
return escapeXml /*xml*/ `
|
|
71519
72568
|
<${axisName}>
|
|
71520
72569
|
<c:axId val="${axId}"/>
|
|
@@ -71530,7 +72579,7 @@ function addAx(position, axisName, axId, crossAxId, title, defaultFontColor, del
|
|
|
71530
72579
|
<c:minorTickMark val="none" />
|
|
71531
72580
|
<c:numFmt formatCode="General" sourceLinked="1" />
|
|
71532
72581
|
<c:title>
|
|
71533
|
-
${insertText(title?.text ?? "", color,
|
|
72582
|
+
${insertText(title?.text ?? "", color, fontSize, title)}
|
|
71534
72583
|
</c:title>
|
|
71535
72584
|
${insertTextProperties(10, defaultFontColor)}
|
|
71536
72585
|
</${axisName}>
|
|
@@ -73308,6 +74357,7 @@ class Model extends EventBus {
|
|
|
73308
74357
|
session: this.session,
|
|
73309
74358
|
defaultCurrency: this.config.defaultCurrency,
|
|
73310
74359
|
customColors: this.config.customColors || [],
|
|
74360
|
+
external: this.config.external,
|
|
73311
74361
|
};
|
|
73312
74362
|
}
|
|
73313
74363
|
// ---------------------------------------------------------------------------
|
|
@@ -73539,7 +74589,6 @@ const SPREADSHEET_DIMENSIONS = {
|
|
|
73539
74589
|
MIN_COL_WIDTH,
|
|
73540
74590
|
HEADER_HEIGHT,
|
|
73541
74591
|
HEADER_WIDTH,
|
|
73542
|
-
TOPBAR_HEIGHT,
|
|
73543
74592
|
BOTTOMBAR_HEIGHT,
|
|
73544
74593
|
DEFAULT_CELL_WIDTH,
|
|
73545
74594
|
DEFAULT_CELL_HEIGHT,
|
|
@@ -73641,6 +74690,7 @@ const helpers = {
|
|
|
73641
74690
|
createPivotFormula,
|
|
73642
74691
|
areDomainArgsFieldsValid,
|
|
73643
74692
|
splitReference,
|
|
74693
|
+
sanitizeSheetName,
|
|
73644
74694
|
};
|
|
73645
74695
|
const links = {
|
|
73646
74696
|
isMarkdownLink,
|
|
@@ -73779,6 +74829,6 @@ exports.tokenColors = tokenColors;
|
|
|
73779
74829
|
exports.tokenize = tokenize;
|
|
73780
74830
|
|
|
73781
74831
|
|
|
73782
|
-
__info__.version = "18.1.0-alpha.
|
|
73783
|
-
__info__.date = "2024-
|
|
73784
|
-
__info__.hash = "
|
|
74832
|
+
__info__.version = "18.1.0-alpha.8";
|
|
74833
|
+
__info__.date = "2024-12-19T07:49:54.421Z";
|
|
74834
|
+
__info__.hash = "87a1567";
|