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