@odoo/o-spreadsheet 18.1.0-alpha.0 → 18.1.0-alpha.1
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 +571 -358
- package/dist/o-spreadsheet.d.ts +40 -18
- package/dist/o-spreadsheet.esm.js +571 -358
- package/dist/o-spreadsheet.iife.js +571 -358
- package/dist/o-spreadsheet.iife.min.js +517 -519
- package/dist/o_spreadsheet.xml +154 -9
- package/package.json +12 -12
|
@@ -2,15 +2,121 @@
|
|
|
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.1
|
|
6
|
+
* @date 2024-10-14T07:53:17.717Z
|
|
7
|
+
* @hash e9ce3aa
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
11
11
|
|
|
12
12
|
var owl = require('@odoo/owl');
|
|
13
13
|
|
|
14
|
+
function createActions(menuItems) {
|
|
15
|
+
return menuItems.map(createAction).sort((a, b) => a.sequence - b.sequence);
|
|
16
|
+
}
|
|
17
|
+
let nextItemId = 1;
|
|
18
|
+
function createAction(item) {
|
|
19
|
+
const name = item.name;
|
|
20
|
+
const children = item.children;
|
|
21
|
+
const description = item.description;
|
|
22
|
+
const icon = item.icon;
|
|
23
|
+
const secondaryIcon = item.secondaryIcon;
|
|
24
|
+
const itemId = item.id || nextItemId++;
|
|
25
|
+
return {
|
|
26
|
+
id: itemId.toString(),
|
|
27
|
+
name: typeof name === "function" ? name : () => name,
|
|
28
|
+
isVisible: item.isVisible ? item.isVisible : () => true,
|
|
29
|
+
isEnabled: item.isEnabled ? item.isEnabled : () => true,
|
|
30
|
+
isActive: item.isActive,
|
|
31
|
+
execute: item.execute,
|
|
32
|
+
children: children
|
|
33
|
+
? (env) => {
|
|
34
|
+
return children
|
|
35
|
+
.map((child) => (typeof child === "function" ? child(env) : child))
|
|
36
|
+
.flat()
|
|
37
|
+
.map(createAction);
|
|
38
|
+
}
|
|
39
|
+
: () => [],
|
|
40
|
+
isReadonlyAllowed: item.isReadonlyAllowed || false,
|
|
41
|
+
separator: item.separator || false,
|
|
42
|
+
icon: typeof icon === "function" ? icon : () => icon || "",
|
|
43
|
+
iconColor: item.iconColor,
|
|
44
|
+
secondaryIcon: typeof secondaryIcon === "function" ? secondaryIcon : () => secondaryIcon || "",
|
|
45
|
+
description: typeof description === "function" ? description : () => description || "",
|
|
46
|
+
textColor: item.textColor,
|
|
47
|
+
sequence: item.sequence || 0,
|
|
48
|
+
onStartHover: item.onStartHover,
|
|
49
|
+
onStopHover: item.onStopHover,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Registry
|
|
55
|
+
*
|
|
56
|
+
* The Registry class is basically just a mapping from a string key to an object.
|
|
57
|
+
* It is really not much more than an object. It is however useful for the
|
|
58
|
+
* following reasons:
|
|
59
|
+
*
|
|
60
|
+
* 1. it let us react and execute code when someone add something to the registry
|
|
61
|
+
* (for example, the FunctionRegistry subclass this for this purpose)
|
|
62
|
+
* 2. it throws an error when the get operation fails
|
|
63
|
+
* 3. it provides a chained API to add items to the registry.
|
|
64
|
+
*/
|
|
65
|
+
class Registry {
|
|
66
|
+
content = {};
|
|
67
|
+
/**
|
|
68
|
+
* Add an item to the registry
|
|
69
|
+
*
|
|
70
|
+
* Note that this also returns the registry, so another add method call can
|
|
71
|
+
* be chained
|
|
72
|
+
*/
|
|
73
|
+
add(key, value) {
|
|
74
|
+
this.content[key] = value;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get an item from the registry
|
|
79
|
+
*/
|
|
80
|
+
get(key) {
|
|
81
|
+
/**
|
|
82
|
+
* Note: key in {} is ~12 times slower than {}[key].
|
|
83
|
+
* So, we check the absence of key only when the direct access returns
|
|
84
|
+
* a falsy value. It's done to ensure that the registry can contains falsy values
|
|
85
|
+
*/
|
|
86
|
+
const content = this.content[key];
|
|
87
|
+
if (!content) {
|
|
88
|
+
if (!(key in this.content)) {
|
|
89
|
+
throw new Error(`Cannot find ${key} in this registry!`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return content;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Check if the key is already in the registry
|
|
96
|
+
*/
|
|
97
|
+
contains(key) {
|
|
98
|
+
return key in this.content;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get a list of all elements in the registry
|
|
102
|
+
*/
|
|
103
|
+
getAll() {
|
|
104
|
+
return Object.values(this.content);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get a list of all keys in the registry
|
|
108
|
+
*/
|
|
109
|
+
getKeys() {
|
|
110
|
+
return Object.keys(this.content);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Remove an item from the registry
|
|
114
|
+
*/
|
|
115
|
+
remove(key) {
|
|
116
|
+
delete this.content[key];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
14
120
|
const CANVAS_SHIFT = 0.5;
|
|
15
121
|
// Colors
|
|
16
122
|
const HIGHLIGHT_COLOR = "#37A850";
|
|
@@ -5970,18 +6076,9 @@ function drawDecoratedText(context, text, position, underline = false, strikethr
|
|
|
5970
6076
|
* https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
|
|
5971
6077
|
* */
|
|
5972
6078
|
class UuidGenerator {
|
|
5973
|
-
isFastIdStrategy = false;
|
|
5974
|
-
fastIdStart = 0;
|
|
5975
|
-
setIsFastStrategy(isFast) {
|
|
5976
|
-
this.isFastIdStrategy = isFast;
|
|
5977
|
-
}
|
|
5978
6079
|
uuidv4() {
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
return String(this.fastIdStart);
|
|
5982
|
-
//@ts-ignore
|
|
5983
|
-
}
|
|
5984
|
-
else if (window.crypto && window.crypto.getRandomValues) {
|
|
6080
|
+
//@ts-ignore
|
|
6081
|
+
if (window.crypto && window.crypto.getRandomValues) {
|
|
5985
6082
|
//@ts-ignore
|
|
5986
6083
|
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
|
|
5987
6084
|
}
|
|
@@ -5995,111 +6092,6 @@ class UuidGenerator {
|
|
|
5995
6092
|
}
|
|
5996
6093
|
}
|
|
5997
6094
|
|
|
5998
|
-
function createActions(menuItems) {
|
|
5999
|
-
return menuItems.map(createAction).sort((a, b) => a.sequence - b.sequence);
|
|
6000
|
-
}
|
|
6001
|
-
const uuidGenerator$1 = new UuidGenerator();
|
|
6002
|
-
function createAction(item) {
|
|
6003
|
-
const name = item.name;
|
|
6004
|
-
const children = item.children;
|
|
6005
|
-
const description = item.description;
|
|
6006
|
-
const icon = item.icon;
|
|
6007
|
-
const secondaryIcon = item.secondaryIcon;
|
|
6008
|
-
return {
|
|
6009
|
-
id: item.id || uuidGenerator$1.uuidv4(),
|
|
6010
|
-
name: typeof name === "function" ? name : () => name,
|
|
6011
|
-
isVisible: item.isVisible ? item.isVisible : () => true,
|
|
6012
|
-
isEnabled: item.isEnabled ? item.isEnabled : () => true,
|
|
6013
|
-
isActive: item.isActive,
|
|
6014
|
-
execute: item.execute,
|
|
6015
|
-
children: children
|
|
6016
|
-
? (env) => {
|
|
6017
|
-
return children
|
|
6018
|
-
.map((child) => (typeof child === "function" ? child(env) : child))
|
|
6019
|
-
.flat()
|
|
6020
|
-
.map(createAction);
|
|
6021
|
-
}
|
|
6022
|
-
: () => [],
|
|
6023
|
-
isReadonlyAllowed: item.isReadonlyAllowed || false,
|
|
6024
|
-
separator: item.separator || false,
|
|
6025
|
-
icon: typeof icon === "function" ? icon : () => icon || "",
|
|
6026
|
-
iconColor: item.iconColor,
|
|
6027
|
-
secondaryIcon: typeof secondaryIcon === "function" ? secondaryIcon : () => secondaryIcon || "",
|
|
6028
|
-
description: typeof description === "function" ? description : () => description || "",
|
|
6029
|
-
textColor: item.textColor,
|
|
6030
|
-
sequence: item.sequence || 0,
|
|
6031
|
-
onStartHover: item.onStartHover,
|
|
6032
|
-
onStopHover: item.onStopHover,
|
|
6033
|
-
};
|
|
6034
|
-
}
|
|
6035
|
-
|
|
6036
|
-
/**
|
|
6037
|
-
* Registry
|
|
6038
|
-
*
|
|
6039
|
-
* The Registry class is basically just a mapping from a string key to an object.
|
|
6040
|
-
* It is really not much more than an object. It is however useful for the
|
|
6041
|
-
* following reasons:
|
|
6042
|
-
*
|
|
6043
|
-
* 1. it let us react and execute code when someone add something to the registry
|
|
6044
|
-
* (for example, the FunctionRegistry subclass this for this purpose)
|
|
6045
|
-
* 2. it throws an error when the get operation fails
|
|
6046
|
-
* 3. it provides a chained API to add items to the registry.
|
|
6047
|
-
*/
|
|
6048
|
-
class Registry {
|
|
6049
|
-
content = {};
|
|
6050
|
-
/**
|
|
6051
|
-
* Add an item to the registry
|
|
6052
|
-
*
|
|
6053
|
-
* Note that this also returns the registry, so another add method call can
|
|
6054
|
-
* be chained
|
|
6055
|
-
*/
|
|
6056
|
-
add(key, value) {
|
|
6057
|
-
this.content[key] = value;
|
|
6058
|
-
return this;
|
|
6059
|
-
}
|
|
6060
|
-
/**
|
|
6061
|
-
* Get an item from the registry
|
|
6062
|
-
*/
|
|
6063
|
-
get(key) {
|
|
6064
|
-
/**
|
|
6065
|
-
* Note: key in {} is ~12 times slower than {}[key].
|
|
6066
|
-
* So, we check the absence of key only when the direct access returns
|
|
6067
|
-
* a falsy value. It's done to ensure that the registry can contains falsy values
|
|
6068
|
-
*/
|
|
6069
|
-
const content = this.content[key];
|
|
6070
|
-
if (!content) {
|
|
6071
|
-
if (!(key in this.content)) {
|
|
6072
|
-
throw new Error(`Cannot find ${key} in this registry!`);
|
|
6073
|
-
}
|
|
6074
|
-
}
|
|
6075
|
-
return content;
|
|
6076
|
-
}
|
|
6077
|
-
/**
|
|
6078
|
-
* Check if the key is already in the registry
|
|
6079
|
-
*/
|
|
6080
|
-
contains(key) {
|
|
6081
|
-
return key in this.content;
|
|
6082
|
-
}
|
|
6083
|
-
/**
|
|
6084
|
-
* Get a list of all elements in the registry
|
|
6085
|
-
*/
|
|
6086
|
-
getAll() {
|
|
6087
|
-
return Object.values(this.content);
|
|
6088
|
-
}
|
|
6089
|
-
/**
|
|
6090
|
-
* Get a list of all keys in the registry
|
|
6091
|
-
*/
|
|
6092
|
-
getKeys() {
|
|
6093
|
-
return Object.keys(this.content);
|
|
6094
|
-
}
|
|
6095
|
-
/**
|
|
6096
|
-
* Remove an item from the registry
|
|
6097
|
-
*/
|
|
6098
|
-
remove(key) {
|
|
6099
|
-
delete this.content[key];
|
|
6100
|
-
}
|
|
6101
|
-
}
|
|
6102
|
-
|
|
6103
6095
|
function getClipboardDataPositions(sheetId, zones) {
|
|
6104
6096
|
const lefts = new Set(zones.map((z) => z.left));
|
|
6105
6097
|
const rights = new Set(zones.map((z) => z.right));
|
|
@@ -8454,31 +8446,34 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
8454
8446
|
for (let col of columnsIndexes) {
|
|
8455
8447
|
const position = { col, row, sheetId };
|
|
8456
8448
|
const table = this.getters.getTable(position);
|
|
8457
|
-
if (!table
|
|
8449
|
+
if (!table) {
|
|
8458
8450
|
tableCellsInRow.push({});
|
|
8459
8451
|
continue;
|
|
8460
8452
|
}
|
|
8461
8453
|
const coreTable = this.getters.getCoreTable(position);
|
|
8462
8454
|
const tableZone = coreTable?.range.zone;
|
|
8455
|
+
let copiedTable = undefined;
|
|
8463
8456
|
// Copy whole table
|
|
8464
|
-
if (
|
|
8465
|
-
|
|
8457
|
+
if (!copiedTablesIds.has(table.id) &&
|
|
8458
|
+
coreTable &&
|
|
8459
|
+
tableZone &&
|
|
8460
|
+
zones.some((z) => isZoneInside(tableZone, z))) {
|
|
8461
|
+
copiedTablesIds.add(table.id);
|
|
8466
8462
|
const values = [];
|
|
8467
8463
|
for (const col of range(tableZone.left, tableZone.right + 1)) {
|
|
8468
8464
|
values.push(this.getters.getFilterHiddenValues({ sheetId, col, row: tableZone.top }));
|
|
8469
8465
|
}
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
},
|
|
8476
|
-
});
|
|
8477
|
-
}
|
|
8478
|
-
// Copy only style of cell
|
|
8479
|
-
else if (table) {
|
|
8480
|
-
tableCellsInRow.push({ style: this.getTableStyleToCopy(position) });
|
|
8466
|
+
copiedTable = {
|
|
8467
|
+
range: coreTable.range.rangeData,
|
|
8468
|
+
config: coreTable.config,
|
|
8469
|
+
type: coreTable.type,
|
|
8470
|
+
};
|
|
8481
8471
|
}
|
|
8472
|
+
tableCellsInRow.push({
|
|
8473
|
+
table: copiedTable,
|
|
8474
|
+
style: this.getTableStyleToCopy(position),
|
|
8475
|
+
isWholeTableCopied: copiedTablesIds.has(table.id),
|
|
8476
|
+
});
|
|
8482
8477
|
}
|
|
8483
8478
|
}
|
|
8484
8479
|
return {
|
|
@@ -8559,11 +8554,14 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
8559
8554
|
tableType: tableCell.table.type,
|
|
8560
8555
|
});
|
|
8561
8556
|
}
|
|
8562
|
-
// Do not paste table style if we're inside another table
|
|
8563
8557
|
// We cannot check for dynamic tables, because at this point the paste can have changed the evaluation, and the
|
|
8564
8558
|
// dynamic tables are not yet computed
|
|
8565
|
-
if (
|
|
8566
|
-
|
|
8559
|
+
if (this.getters.getCoreTable(position) || options?.pasteOption === "asValue") {
|
|
8560
|
+
return;
|
|
8561
|
+
}
|
|
8562
|
+
if ((!options?.pasteOption && !tableCell.isWholeTableCopied) ||
|
|
8563
|
+
options?.pasteOption === "onlyFormat") {
|
|
8564
|
+
if (tableCell.style?.style) {
|
|
8567
8565
|
this.dispatch("UPDATE_CELL", { ...position, style: tableCell.style.style });
|
|
8568
8566
|
}
|
|
8569
8567
|
if (tableCell.style?.border) {
|
|
@@ -9283,6 +9281,49 @@ function getDefinedAxis(definition) {
|
|
|
9283
9281
|
useLeftAxis ||= !useRightAxis;
|
|
9284
9282
|
return { useLeftAxis, useRightAxis };
|
|
9285
9283
|
}
|
|
9284
|
+
function getChartAxis(definition, position, type, options) {
|
|
9285
|
+
const { useLeftAxis, useRightAxis } = getDefinedAxis(definition);
|
|
9286
|
+
if ((position === "left" && !useLeftAxis) || (position === "right" && !useRightAxis)) {
|
|
9287
|
+
return undefined;
|
|
9288
|
+
}
|
|
9289
|
+
const fontColor = chartFontColor(definition.background);
|
|
9290
|
+
let design;
|
|
9291
|
+
if (position === "bottom") {
|
|
9292
|
+
design = definition.axesDesign?.x;
|
|
9293
|
+
}
|
|
9294
|
+
else if (position === "left") {
|
|
9295
|
+
design = definition.axesDesign?.y;
|
|
9296
|
+
}
|
|
9297
|
+
else {
|
|
9298
|
+
design = definition.axesDesign?.y1;
|
|
9299
|
+
}
|
|
9300
|
+
if (type === "values") {
|
|
9301
|
+
const displayGridLines = position === "left" || (position === "right" && !useLeftAxis);
|
|
9302
|
+
return {
|
|
9303
|
+
position: position,
|
|
9304
|
+
title: getChartAxisTitleRuntime(design),
|
|
9305
|
+
grid: {
|
|
9306
|
+
display: displayGridLines,
|
|
9307
|
+
},
|
|
9308
|
+
beginAtZero: true,
|
|
9309
|
+
stacked: options?.stacked,
|
|
9310
|
+
ticks: {
|
|
9311
|
+
color: fontColor,
|
|
9312
|
+
callback: formatTickValue(options),
|
|
9313
|
+
},
|
|
9314
|
+
};
|
|
9315
|
+
}
|
|
9316
|
+
else {
|
|
9317
|
+
return {
|
|
9318
|
+
ticks: {
|
|
9319
|
+
padding: 5,
|
|
9320
|
+
color: fontColor,
|
|
9321
|
+
},
|
|
9322
|
+
stacked: options?.stacked,
|
|
9323
|
+
title: getChartAxisTitleRuntime(design),
|
|
9324
|
+
};
|
|
9325
|
+
}
|
|
9326
|
+
}
|
|
9286
9327
|
function computeChartPadding({ displayTitle, displayLegend, }) {
|
|
9287
9328
|
let top = 25;
|
|
9288
9329
|
if (displayTitle) {
|
|
@@ -9369,6 +9410,12 @@ function interpolateData(config, values, labels, newLabels) {
|
|
|
9369
9410
|
return [];
|
|
9370
9411
|
}
|
|
9371
9412
|
}
|
|
9413
|
+
function formatChartDatasetValue(axisFormats, locale) {
|
|
9414
|
+
return (value, axisId) => {
|
|
9415
|
+
const format = axisId ? axisFormats?.[axisId] : undefined;
|
|
9416
|
+
return formatTickValue({ format, locale })(value);
|
|
9417
|
+
};
|
|
9418
|
+
}
|
|
9372
9419
|
function formatTickValue(localeFormat) {
|
|
9373
9420
|
return (value) => {
|
|
9374
9421
|
value = Number(value);
|
|
@@ -9431,10 +9478,12 @@ const chartShowValuesPlugin = {
|
|
|
9431
9478
|
case "bar":
|
|
9432
9479
|
case "line": {
|
|
9433
9480
|
const yOffset = dataset.type === "bar" && !options.horizontal ? 0 : 3;
|
|
9481
|
+
const horizontalChart = dataset.type === "bar" && options.horizontal;
|
|
9482
|
+
const axisId = horizontalChart ? dataset.xAxisID : dataset.yAxisID;
|
|
9434
9483
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
9435
9484
|
const point = dataset.data[i];
|
|
9436
9485
|
const value = options.horizontal ? dataset._parsed[i].x : dataset._parsed[i].y;
|
|
9437
|
-
const displayedValue = options.callback(value - 0);
|
|
9486
|
+
const displayedValue = options.callback(value - 0, axisId);
|
|
9438
9487
|
let xPosition = 0, yPosition = 0;
|
|
9439
9488
|
if (options.horizontal) {
|
|
9440
9489
|
yPosition = point.y;
|
|
@@ -17843,7 +17892,7 @@ function assertDomainLength(domain) {
|
|
|
17843
17892
|
throw new EvaluationError(_t("Function PIVOT takes an even number of arguments."));
|
|
17844
17893
|
}
|
|
17845
17894
|
}
|
|
17846
|
-
function addPivotDependencies(evalContext, coreDefinition) {
|
|
17895
|
+
function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
|
|
17847
17896
|
//TODO This function can be very costly when used with PIVOT.VALUE and PIVOT.HEADER
|
|
17848
17897
|
const dependencies = [];
|
|
17849
17898
|
if (coreDefinition.type === "SPREADSHEET" && coreDefinition.dataSet) {
|
|
@@ -17855,7 +17904,7 @@ function addPivotDependencies(evalContext, coreDefinition) {
|
|
|
17855
17904
|
}
|
|
17856
17905
|
dependencies.push(range);
|
|
17857
17906
|
}
|
|
17858
|
-
for (const measure of
|
|
17907
|
+
for (const measure of forMeasures) {
|
|
17859
17908
|
if (measure.computedBy) {
|
|
17860
17909
|
const formula = evalContext.getters.getMeasureCompiledFormula(measure);
|
|
17861
17910
|
dependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
|
|
@@ -18288,7 +18337,7 @@ const PIVOT_VALUE = {
|
|
|
18288
18337
|
assertDomainLength(domainArgs);
|
|
18289
18338
|
const pivot = this.getters.getPivot(pivotId);
|
|
18290
18339
|
const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
|
|
18291
|
-
addPivotDependencies(this, coreDefinition);
|
|
18340
|
+
addPivotDependencies(this, coreDefinition, coreDefinition.measures.filter((m) => m.id === _measure));
|
|
18292
18341
|
pivot.init({ reload: pivot.needsReevaluation });
|
|
18293
18342
|
const error = pivot.assertIsValid({ throwOnError: false });
|
|
18294
18343
|
if (error) {
|
|
@@ -18318,7 +18367,7 @@ const PIVOT_HEADER = {
|
|
|
18318
18367
|
assertDomainLength(domainArgs);
|
|
18319
18368
|
const pivot = this.getters.getPivot(_pivotId);
|
|
18320
18369
|
const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
|
|
18321
|
-
addPivotDependencies(this, coreDefinition);
|
|
18370
|
+
addPivotDependencies(this, coreDefinition, []);
|
|
18322
18371
|
pivot.init({ reload: pivot.needsReevaluation });
|
|
18323
18372
|
const error = pivot.assertIsValid({ throwOnError: false });
|
|
18324
18373
|
if (error) {
|
|
@@ -18369,7 +18418,7 @@ const PIVOT = {
|
|
|
18369
18418
|
const pivotId = getPivotId(_pivotFormulaId, this.getters);
|
|
18370
18419
|
const pivot = this.getters.getPivot(pivotId);
|
|
18371
18420
|
const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
|
|
18372
|
-
addPivotDependencies(this, coreDefinition);
|
|
18421
|
+
addPivotDependencies(this, coreDefinition, coreDefinition.measures);
|
|
18373
18422
|
pivot.init({ reload: pivot.needsReevaluation });
|
|
18374
18423
|
const error = pivot.assertIsValid({ throwOnError: false });
|
|
18375
18424
|
if (error) {
|
|
@@ -20165,7 +20214,7 @@ class ContentEditableHelper {
|
|
|
20165
20214
|
let startNode = this.findChildAtCharacterIndex(start);
|
|
20166
20215
|
let endNode = this.findChildAtCharacterIndex(end);
|
|
20167
20216
|
range.setStart(startNode.node, startNode.offset);
|
|
20168
|
-
|
|
20217
|
+
range.setEnd(endNode.node, endNode.offset);
|
|
20169
20218
|
}
|
|
20170
20219
|
}
|
|
20171
20220
|
/**
|
|
@@ -20663,7 +20712,7 @@ class Composer extends owl.Component {
|
|
|
20663
20712
|
"Alt+Enter": this.processNewLineEvent,
|
|
20664
20713
|
"Ctrl+Enter": this.processNewLineEvent,
|
|
20665
20714
|
Escape: this.processEscapeKey,
|
|
20666
|
-
F2: () =>
|
|
20715
|
+
F2: (ev) => this.toggleEditionMode(ev),
|
|
20667
20716
|
F4: (ev) => this.processF4Key(ev),
|
|
20668
20717
|
Tab: (ev) => this.processTabKey(ev, "right"),
|
|
20669
20718
|
"Shift+Tab": (ev) => this.processTabKey(ev, "left"),
|
|
@@ -20782,6 +20831,11 @@ class Composer extends owl.Component {
|
|
|
20782
20831
|
this.props.composerStore.cycleReferences();
|
|
20783
20832
|
this.processContent();
|
|
20784
20833
|
}
|
|
20834
|
+
toggleEditionMode(ev) {
|
|
20835
|
+
ev.stopPropagation();
|
|
20836
|
+
this.props.composerStore.toggleEditionMode();
|
|
20837
|
+
this.processContent();
|
|
20838
|
+
}
|
|
20785
20839
|
processNumpadDecimal(ev) {
|
|
20786
20840
|
ev.stopPropagation();
|
|
20787
20841
|
ev.preventDefault();
|
|
@@ -21007,7 +21061,13 @@ class Composer extends owl.Component {
|
|
|
21007
21061
|
break;
|
|
21008
21062
|
case "REFERENCE":
|
|
21009
21063
|
const { xc, sheetName } = splitReference(token.value);
|
|
21010
|
-
result.push({
|
|
21064
|
+
result.push({
|
|
21065
|
+
value: token.value,
|
|
21066
|
+
color: this.rangeColor(xc, sheetName) || "#000",
|
|
21067
|
+
class: tokenAtCursor === token && this.props.composerStore.editionMode === "selecting"
|
|
21068
|
+
? "text-decoration-underline"
|
|
21069
|
+
: undefined,
|
|
21070
|
+
});
|
|
21011
21071
|
break;
|
|
21012
21072
|
case "SYMBOL":
|
|
21013
21073
|
const value = token.value;
|
|
@@ -21578,6 +21638,7 @@ function insertTokenAfterArgSeparator(tokenAtCursor, value) {
|
|
|
21578
21638
|
// replace the whole token
|
|
21579
21639
|
start = tokenAtCursor.start;
|
|
21580
21640
|
}
|
|
21641
|
+
this.composer.stopComposerRangeSelection();
|
|
21581
21642
|
this.composer.changeComposerCursorSelection(start, end);
|
|
21582
21643
|
this.composer.replaceComposerCursorSelection(value);
|
|
21583
21644
|
}
|
|
@@ -21595,6 +21656,7 @@ function insertTokenAfterLeftParenthesis(tokenAtCursor, value) {
|
|
|
21595
21656
|
// replace the whole token
|
|
21596
21657
|
start = tokenAtCursor.start;
|
|
21597
21658
|
}
|
|
21659
|
+
this.composer.stopComposerRangeSelection();
|
|
21598
21660
|
this.composer.changeComposerCursorSelection(start, end);
|
|
21599
21661
|
this.composer.replaceComposerCursorSelection(value);
|
|
21600
21662
|
}
|
|
@@ -22187,6 +22249,27 @@ autofillModifiersRegistry
|
|
|
22187
22249
|
tooltip: content ? { props: { content: tooltipValue } } : undefined,
|
|
22188
22250
|
};
|
|
22189
22251
|
},
|
|
22252
|
+
})
|
|
22253
|
+
.add("DATE_INCREMENT_MODIFIER", {
|
|
22254
|
+
apply: (rule, data, getters) => {
|
|
22255
|
+
const date = toJsDate(rule.current, getters.getLocale());
|
|
22256
|
+
date.setFullYear(date.getFullYear() + rule.increment.years || 0);
|
|
22257
|
+
date.setMonth(date.getMonth() + rule.increment.months || 0);
|
|
22258
|
+
date.setDate(date.getDate() + rule.increment.days || 0);
|
|
22259
|
+
const value = jsDateToNumber(date);
|
|
22260
|
+
rule.current = value;
|
|
22261
|
+
const locale = getters.getLocale();
|
|
22262
|
+
const tooltipValue = formatValue(value, { format: data.cell?.format, locale });
|
|
22263
|
+
return {
|
|
22264
|
+
cellData: {
|
|
22265
|
+
border: data.border,
|
|
22266
|
+
style: data.cell && data.cell.style,
|
|
22267
|
+
format: data.cell && data.cell.format,
|
|
22268
|
+
content: value.toString(),
|
|
22269
|
+
},
|
|
22270
|
+
tooltip: value ? { props: { content: tooltipValue } } : undefined,
|
|
22271
|
+
};
|
|
22272
|
+
},
|
|
22190
22273
|
})
|
|
22191
22274
|
.add("COPY_MODIFIER", {
|
|
22192
22275
|
apply: (rule, data, getters) => {
|
|
@@ -22267,7 +22350,9 @@ function getGroup(cell, cells, filter) {
|
|
|
22267
22350
|
if (x === cell) {
|
|
22268
22351
|
found = true;
|
|
22269
22352
|
}
|
|
22270
|
-
const cellValue = x === undefined || x.isFormula
|
|
22353
|
+
const cellValue = x === undefined || x.isFormula
|
|
22354
|
+
? undefined
|
|
22355
|
+
: evaluateLiteral(x, { locale: DEFAULT_LOCALE, format: x.format });
|
|
22271
22356
|
if (cellValue && filter(cellValue)) {
|
|
22272
22357
|
group.push(cellValue);
|
|
22273
22358
|
}
|
|
@@ -22303,6 +22388,72 @@ function calculateIncrementBasedOnGroup(group) {
|
|
|
22303
22388
|
}
|
|
22304
22389
|
return increment;
|
|
22305
22390
|
}
|
|
22391
|
+
/**
|
|
22392
|
+
* Iterates on a list of date intervals.
|
|
22393
|
+
* if every interval is the same, return the interval
|
|
22394
|
+
* Otherwise return undefined
|
|
22395
|
+
*
|
|
22396
|
+
*/
|
|
22397
|
+
function getEqualInterval(intervals) {
|
|
22398
|
+
if (intervals.length < 2) {
|
|
22399
|
+
return intervals[0] || { years: 0, months: 0, days: 0 };
|
|
22400
|
+
}
|
|
22401
|
+
const equal = intervals.every((interval) => interval.years === intervals[0].years &&
|
|
22402
|
+
interval.months === intervals[0].months &&
|
|
22403
|
+
interval.days === intervals[0].days);
|
|
22404
|
+
return equal ? intervals[0] : undefined;
|
|
22405
|
+
}
|
|
22406
|
+
/**
|
|
22407
|
+
* Based on a group of dates, calculate the increment that should be applied
|
|
22408
|
+
* to the next date.
|
|
22409
|
+
*
|
|
22410
|
+
* This will compute the date difference in calendar terms (years, months, days)
|
|
22411
|
+
* In order to make abstraction of leap years and months with different number of days.
|
|
22412
|
+
*
|
|
22413
|
+
* In case the dates are not equidistant in calendar terms, no rule can be extrapolated
|
|
22414
|
+
* In case of equidistant dates, we either have in that order:
|
|
22415
|
+
* - exact date interval (e.g. +n year OR +n month OR +n day) in which case we increment by the same interval
|
|
22416
|
+
* - exact day interval (e.g. +n days) in which case we increment by the same day interval
|
|
22417
|
+
* - equidistant dates but not the same interval, in which case we return increment of the same interval
|
|
22418
|
+
*
|
|
22419
|
+
* */
|
|
22420
|
+
function calculateDateIncrementBasedOnGroup(group) {
|
|
22421
|
+
if (group.length < 2) {
|
|
22422
|
+
return 1;
|
|
22423
|
+
}
|
|
22424
|
+
const jsDates = group.map((date) => toJsDate(date, DEFAULT_LOCALE));
|
|
22425
|
+
const datesIntervals = getDateIntervals(jsDates);
|
|
22426
|
+
const datesEquidistantInterval = getEqualInterval(datesIntervals);
|
|
22427
|
+
if (datesEquidistantInterval === undefined) {
|
|
22428
|
+
// dates are not equidistant in terms of years, months or days, thus no rule can be extrapolated
|
|
22429
|
+
return undefined;
|
|
22430
|
+
}
|
|
22431
|
+
// The dates are apart by an exact interval of years, months or days
|
|
22432
|
+
// but not a combination of them
|
|
22433
|
+
const exactDateInterval = Object.values(datesEquidistantInterval).filter((value) => value !== 0).length === 1;
|
|
22434
|
+
const isSameDay = Object.values(datesEquidistantInterval).every((el) => el === 0); // handles time values (strict decimals)
|
|
22435
|
+
if (!exactDateInterval || isSameDay) {
|
|
22436
|
+
const timeIntervals = jsDates
|
|
22437
|
+
.map((date, index) => {
|
|
22438
|
+
if (index === 0) {
|
|
22439
|
+
return 0;
|
|
22440
|
+
}
|
|
22441
|
+
const previous = jsDates[index - 1];
|
|
22442
|
+
const days = Math.floor(date.getTime()) - Math.floor(previous.getTime());
|
|
22443
|
+
return days;
|
|
22444
|
+
})
|
|
22445
|
+
.slice(1);
|
|
22446
|
+
const equidistantDates = timeIntervals.every((interval) => interval === timeIntervals[0]);
|
|
22447
|
+
if (equidistantDates) {
|
|
22448
|
+
return group.length * (group[1] - group[0]);
|
|
22449
|
+
}
|
|
22450
|
+
}
|
|
22451
|
+
return {
|
|
22452
|
+
years: datesEquidistantInterval.years * group.length,
|
|
22453
|
+
months: datesEquidistantInterval.months * group.length,
|
|
22454
|
+
days: datesEquidistantInterval.days * group.length,
|
|
22455
|
+
};
|
|
22456
|
+
}
|
|
22306
22457
|
autofillRulesRegistry
|
|
22307
22458
|
.add("simple_value_copy", {
|
|
22308
22459
|
condition: (cell, cells) => {
|
|
@@ -22350,12 +22501,47 @@ autofillRulesRegistry
|
|
|
22350
22501
|
return { type: "FORMULA_MODIFIER", increment: cells.length, current: 0 };
|
|
22351
22502
|
},
|
|
22352
22503
|
sequence: 30,
|
|
22504
|
+
})
|
|
22505
|
+
.add("increment_dates", {
|
|
22506
|
+
condition: (cell, cells) => {
|
|
22507
|
+
return (!cell.isFormula &&
|
|
22508
|
+
evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.number &&
|
|
22509
|
+
!!cell.format &&
|
|
22510
|
+
isDateTimeFormat(cell.format));
|
|
22511
|
+
},
|
|
22512
|
+
generateRule: (cell, cells) => {
|
|
22513
|
+
const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.number &&
|
|
22514
|
+
!!evaluatedCell.format &&
|
|
22515
|
+
isDateTimeFormat(evaluatedCell.format)).map((cell) => Number(cell.value));
|
|
22516
|
+
const increment = calculateDateIncrementBasedOnGroup(group);
|
|
22517
|
+
if (increment === undefined) {
|
|
22518
|
+
return { type: "COPY_MODIFIER" };
|
|
22519
|
+
}
|
|
22520
|
+
/** requires to detect the current date (requires to be an integer value with the right format)
|
|
22521
|
+
* detect if year or if month or if day then extrapolate increment required (+1 month, +1 year + 1 day)
|
|
22522
|
+
*/
|
|
22523
|
+
const evaluation = evaluateLiteral(cell, { locale: DEFAULT_LOCALE });
|
|
22524
|
+
if (typeof increment === "object") {
|
|
22525
|
+
return {
|
|
22526
|
+
type: "DATE_INCREMENT_MODIFIER",
|
|
22527
|
+
increment,
|
|
22528
|
+
current: evaluation.type === CellValueType.number ? evaluation.value : 0,
|
|
22529
|
+
};
|
|
22530
|
+
}
|
|
22531
|
+
return {
|
|
22532
|
+
type: "INCREMENT_MODIFIER",
|
|
22533
|
+
increment,
|
|
22534
|
+
current: evaluation.type === CellValueType.number ? evaluation.value : 0,
|
|
22535
|
+
};
|
|
22536
|
+
},
|
|
22537
|
+
sequence: 25,
|
|
22353
22538
|
})
|
|
22354
22539
|
.add("increment_number", {
|
|
22355
22540
|
condition: (cell) => !cell.isFormula &&
|
|
22356
22541
|
evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.number,
|
|
22357
22542
|
generateRule: (cell, cells) => {
|
|
22358
|
-
const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.number
|
|
22543
|
+
const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.number &&
|
|
22544
|
+
!isDateTimeFormat(evaluatedCell.format || "")).map((cell) => Number(cell.value));
|
|
22359
22545
|
const increment = calculateIncrementBasedOnGroup(group);
|
|
22360
22546
|
const evaluation = evaluateLiteral(cell, { locale: DEFAULT_LOCALE });
|
|
22361
22547
|
return {
|
|
@@ -22366,6 +22552,37 @@ autofillRulesRegistry
|
|
|
22366
22552
|
},
|
|
22367
22553
|
sequence: 40,
|
|
22368
22554
|
});
|
|
22555
|
+
/**
|
|
22556
|
+
* Returns the date intervals between consecutive dates of an array
|
|
22557
|
+
* in the format of { years: number, months: number, days: number }
|
|
22558
|
+
*
|
|
22559
|
+
* The split is necessary to make abstraction of leap years and
|
|
22560
|
+
* months with different number of days.
|
|
22561
|
+
*
|
|
22562
|
+
* @param dates
|
|
22563
|
+
*/
|
|
22564
|
+
function getDateIntervals(dates) {
|
|
22565
|
+
if (dates.length < 2) {
|
|
22566
|
+
return [{ years: 0, months: 0, days: 0 }];
|
|
22567
|
+
}
|
|
22568
|
+
const res = dates.map((date, index) => {
|
|
22569
|
+
if (index === 0) {
|
|
22570
|
+
return { years: 0, months: 0, days: 0 };
|
|
22571
|
+
}
|
|
22572
|
+
const previous = DateTime.fromTimestamp(dates[index - 1].getTime());
|
|
22573
|
+
const years = getTimeDifferenceInWholeYears(previous, date);
|
|
22574
|
+
const months = getTimeDifferenceInWholeMonths(previous, date) % 12;
|
|
22575
|
+
previous.setFullYear(previous.getFullYear() + years);
|
|
22576
|
+
previous.setMonth(previous.getMonth() + months);
|
|
22577
|
+
const days = getTimeDifferenceInWholeDays(previous, date);
|
|
22578
|
+
return {
|
|
22579
|
+
years,
|
|
22580
|
+
months,
|
|
22581
|
+
days,
|
|
22582
|
+
};
|
|
22583
|
+
});
|
|
22584
|
+
return res.slice(1);
|
|
22585
|
+
}
|
|
22369
22586
|
|
|
22370
22587
|
const cellPopoverRegistry = new Registry();
|
|
22371
22588
|
|
|
@@ -27876,9 +28093,9 @@ function truncateLabel(label) {
|
|
|
27876
28093
|
/**
|
|
27877
28094
|
* Get a default chart js configuration
|
|
27878
28095
|
*/
|
|
27879
|
-
function getDefaultChartJsRuntime(chart, labels, fontColor, {
|
|
28096
|
+
function getDefaultChartJsRuntime(chart, labels, fontColor, { axisFormats, locale, truncateLabels = true, horizontalChart }) {
|
|
27880
28097
|
const chartTitle = chart.title.text ? chart.title : { ...chart.title, content: "" };
|
|
27881
|
-
const
|
|
28098
|
+
const chartOptions = {
|
|
27882
28099
|
// https://www.chartjs.org/docs/latest/general/responsive.html
|
|
27883
28100
|
responsive: true, // will resize when its container is resized
|
|
27884
28101
|
maintainAspectRatio: false, // doesn't maintain the aspect ration (width/height =2 by default) so the user has the choice of the exact layout
|
|
@@ -27925,8 +28142,10 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, tr
|
|
|
27925
28142
|
if (!yLabel) {
|
|
27926
28143
|
yLabel = tooltipItem.parsed;
|
|
27927
28144
|
}
|
|
27928
|
-
const
|
|
27929
|
-
|
|
28145
|
+
const axisId = horizontalChart
|
|
28146
|
+
? tooltipItem.dataset.xAxisID
|
|
28147
|
+
: tooltipItem.dataset.yAxisID;
|
|
28148
|
+
const yLabelStr = formatChartDatasetValue(axisFormats, locale)(yLabel, axisId);
|
|
27930
28149
|
return xLabel ? `${xLabel}: ${yLabelStr}` : yLabelStr;
|
|
27931
28150
|
},
|
|
27932
28151
|
},
|
|
@@ -27935,7 +28154,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, tr
|
|
|
27935
28154
|
};
|
|
27936
28155
|
return {
|
|
27937
28156
|
type: chart.type,
|
|
27938
|
-
options,
|
|
28157
|
+
options: chartOptions,
|
|
27939
28158
|
data: {
|
|
27940
28159
|
labels: truncateLabels ? labels.map(truncateLabel) : labels,
|
|
27941
28160
|
datasets: [],
|
|
@@ -27994,7 +28213,8 @@ function getChartLabelValues(getters, dataSets, labelRange) {
|
|
|
27994
28213
|
* Get the format to apply to the the dataset values. This format is defined as the first format
|
|
27995
28214
|
* found in the dataset ranges that isn't a date format.
|
|
27996
28215
|
*/
|
|
27997
|
-
function getChartDatasetFormat(getters,
|
|
28216
|
+
function getChartDatasetFormat(getters, allDataSets, axis) {
|
|
28217
|
+
const dataSets = allDataSets.filter((ds) => (axis === "right") === !!ds.rightYAxis);
|
|
27998
28218
|
for (const ds of dataSets) {
|
|
27999
28219
|
const formatsInDataset = getters.getRangeFormats(ds.dataRange);
|
|
28000
28220
|
const format = formatsInDataset.find((f) => f !== undefined && !isDateTimeFormat(f));
|
|
@@ -28248,12 +28468,16 @@ function createBarChartRuntime(chart, getters) {
|
|
|
28248
28468
|
if (chart.aggregated) {
|
|
28249
28469
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
28250
28470
|
}
|
|
28251
|
-
const
|
|
28471
|
+
const leftAxisFormat = getChartDatasetFormat(getters, chart.dataSets, "left");
|
|
28472
|
+
const rightAxisFormat = getChartDatasetFormat(getters, chart.dataSets, "right");
|
|
28252
28473
|
const locale = getters.getLocale();
|
|
28253
|
-
const localeFormat = { format: dataSetFormat, locale };
|
|
28254
28474
|
const fontColor = chartFontColor(chart.background);
|
|
28475
|
+
const axisFormats = chart.horizontal
|
|
28476
|
+
? { x: leftAxisFormat || rightAxisFormat }
|
|
28477
|
+
: { y: leftAxisFormat, y1: rightAxisFormat };
|
|
28255
28478
|
const config = getDefaultChartJsRuntime(chart, labels, fontColor, {
|
|
28256
|
-
|
|
28479
|
+
locale,
|
|
28480
|
+
axisFormats,
|
|
28257
28481
|
horizontalChart: chart.horizontal,
|
|
28258
28482
|
});
|
|
28259
28483
|
const legend = {
|
|
@@ -28274,51 +28498,27 @@ function createBarChartRuntime(chart, getters) {
|
|
|
28274
28498
|
};
|
|
28275
28499
|
config.options.indexAxis = chart.horizontal ? "y" : "x";
|
|
28276
28500
|
config.options.scales = {};
|
|
28277
|
-
const
|
|
28278
|
-
const
|
|
28279
|
-
|
|
28280
|
-
|
|
28281
|
-
|
|
28282
|
-
|
|
28283
|
-
},
|
|
28284
|
-
};
|
|
28285
|
-
const xAxis = chart.horizontal ? valuesAxis : labelsAxis;
|
|
28286
|
-
const yAxis = chart.horizontal ? labelsAxis : valuesAxis;
|
|
28287
|
-
const { useLeftAxis, useRightAxis } = getDefinedAxis(chart.getDefinition());
|
|
28288
|
-
config.options.scales.x = { ...xAxis, title: getChartAxisTitleRuntime(chart.axesDesign?.x) };
|
|
28289
|
-
if (useLeftAxis) {
|
|
28290
|
-
config.options.scales.y = {
|
|
28291
|
-
...yAxis,
|
|
28292
|
-
position: "left",
|
|
28293
|
-
title: getChartAxisTitleRuntime(chart.axesDesign?.y),
|
|
28294
|
-
};
|
|
28295
|
-
}
|
|
28296
|
-
if (useRightAxis) {
|
|
28297
|
-
config.options.scales.y1 = {
|
|
28298
|
-
...yAxis,
|
|
28299
|
-
position: "right",
|
|
28300
|
-
title: getChartAxisTitleRuntime(chart.axesDesign?.y1),
|
|
28301
|
-
};
|
|
28501
|
+
const definition = chart.getDefinition();
|
|
28502
|
+
const options = { stacked: chart.stacked, locale };
|
|
28503
|
+
if (chart.horizontal) {
|
|
28504
|
+
const format = leftAxisFormat || rightAxisFormat;
|
|
28505
|
+
config.options.scales.x = getChartAxis(definition, "bottom", "values", { ...options, format });
|
|
28506
|
+
config.options.scales.y = getChartAxis(definition, "left", "labels", options);
|
|
28302
28507
|
}
|
|
28303
|
-
|
|
28304
|
-
|
|
28305
|
-
|
|
28306
|
-
|
|
28307
|
-
|
|
28308
|
-
|
|
28309
|
-
}
|
|
28310
|
-
if (useRightAxis) {
|
|
28311
|
-
// @ts-ignore chart.js type is broken
|
|
28312
|
-
config.options.scales.y1.stacked = true;
|
|
28313
|
-
}
|
|
28508
|
+
else {
|
|
28509
|
+
config.options.scales.x = getChartAxis(definition, "bottom", "labels", options);
|
|
28510
|
+
const leftAxisOptions = { ...options, format: leftAxisFormat };
|
|
28511
|
+
config.options.scales.y = getChartAxis(definition, "left", "values", leftAxisOptions);
|
|
28512
|
+
const rightAxisOptions = { ...options, format: rightAxisFormat };
|
|
28513
|
+
config.options.scales.y1 = getChartAxis(definition, "right", "values", rightAxisOptions);
|
|
28314
28514
|
}
|
|
28515
|
+
config.options.scales = removeFalsyAttributes(config.options.scales);
|
|
28315
28516
|
config.options.plugins.chartShowValuesPlugin = {
|
|
28316
28517
|
showValues: chart.showValues,
|
|
28317
28518
|
background: chart.background,
|
|
28318
28519
|
horizontal: chart.horizontal,
|
|
28319
|
-
callback:
|
|
28520
|
+
callback: formatChartDatasetValue(axisFormats, locale),
|
|
28320
28521
|
};
|
|
28321
|
-
const definition = chart.getDefinition();
|
|
28322
28522
|
const colors = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
28323
28523
|
const trendDatasets = [];
|
|
28324
28524
|
for (const index in dataSetsValues) {
|
|
@@ -28336,9 +28536,8 @@ function createBarChartRuntime(chart, getters) {
|
|
|
28336
28536
|
const label = definition.dataSets[index].label;
|
|
28337
28537
|
dataset.label = label;
|
|
28338
28538
|
}
|
|
28339
|
-
|
|
28340
|
-
|
|
28341
|
-
}
|
|
28539
|
+
dataset.yAxisID = chart.horizontal ? "y" : definition.dataSets[index].yAxisId || "y";
|
|
28540
|
+
dataset.xAxisID = "x";
|
|
28342
28541
|
const trend = definition.dataSets?.[index].trend;
|
|
28343
28542
|
if (!trend?.display || chart.horizontal) {
|
|
28344
28543
|
continue;
|
|
@@ -28354,7 +28553,7 @@ function createBarChartRuntime(chart, getters) {
|
|
|
28354
28553
|
*/
|
|
28355
28554
|
const maxLength = Math.max(...trendDatasets.map((trendDataset) => trendDataset.data.length));
|
|
28356
28555
|
config.options.scales[TREND_LINE_XAXIS_ID] = {
|
|
28357
|
-
...
|
|
28556
|
+
...config.options.scales.x,
|
|
28358
28557
|
labels: Array(maxLength).fill(""),
|
|
28359
28558
|
offset: false,
|
|
28360
28559
|
display: false,
|
|
@@ -28644,8 +28843,10 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28644
28843
|
}
|
|
28645
28844
|
const locale = getters.getLocale();
|
|
28646
28845
|
const truncateLabels = axisType === "category";
|
|
28647
|
-
const
|
|
28648
|
-
const
|
|
28846
|
+
const leftAxisFormat = getChartDatasetFormat(getters, chart.dataSets, "left");
|
|
28847
|
+
const rightAxisFormat = getChartDatasetFormat(getters, chart.dataSets, "right");
|
|
28848
|
+
const axisFormats = { y: leftAxisFormat, y1: rightAxisFormat };
|
|
28849
|
+
const options = { locale, truncateLabels, axisFormats };
|
|
28649
28850
|
const fontColor = chartFontColor(chart.background);
|
|
28650
28851
|
const config = getDefaultChartJsRuntime(chart, labels, fontColor, options);
|
|
28651
28852
|
const legend = {
|
|
@@ -28675,52 +28876,18 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28675
28876
|
displayLegend: chart.legendPosition === "top",
|
|
28676
28877
|
}),
|
|
28677
28878
|
};
|
|
28678
|
-
const
|
|
28679
|
-
|
|
28680
|
-
padding: 5,
|
|
28681
|
-
color: fontColor,
|
|
28682
|
-
},
|
|
28683
|
-
title: getChartAxisTitleRuntime(chart.axesDesign?.x),
|
|
28684
|
-
};
|
|
28879
|
+
const definition = chart.getDefinition();
|
|
28880
|
+
const stacked = "stacked" in chart && chart.stacked;
|
|
28685
28881
|
config.options.scales = {
|
|
28686
|
-
x:
|
|
28687
|
-
|
|
28688
|
-
|
|
28689
|
-
beginAtZero: true, // the origin of the y axis is always zero
|
|
28690
|
-
ticks: {
|
|
28691
|
-
color: fontColor,
|
|
28692
|
-
callback: formatTickValue(options),
|
|
28693
|
-
},
|
|
28882
|
+
x: getChartAxis(definition, "bottom", "labels", { locale }),
|
|
28883
|
+
y: getChartAxis(definition, "left", "values", { locale, stacked, format: leftAxisFormat }),
|
|
28884
|
+
y1: getChartAxis(definition, "right", "values", { locale, stacked, format: rightAxisFormat }),
|
|
28694
28885
|
};
|
|
28695
|
-
|
|
28696
|
-
if (useLeftAxis) {
|
|
28697
|
-
config.options.scales.y = {
|
|
28698
|
-
...yAxis,
|
|
28699
|
-
position: "left",
|
|
28700
|
-
title: getChartAxisTitleRuntime(chart.axesDesign?.y),
|
|
28701
|
-
};
|
|
28702
|
-
}
|
|
28703
|
-
if (useRightAxis) {
|
|
28704
|
-
config.options.scales.y1 = {
|
|
28705
|
-
...yAxis,
|
|
28706
|
-
position: "right",
|
|
28707
|
-
title: getChartAxisTitleRuntime(chart.axesDesign?.y1),
|
|
28708
|
-
};
|
|
28709
|
-
}
|
|
28710
|
-
if ("stacked" in chart && chart.stacked) {
|
|
28711
|
-
if (useLeftAxis) {
|
|
28712
|
-
// @ts-ignore chart.js type is broken
|
|
28713
|
-
config.options.scales.y.stacked = true;
|
|
28714
|
-
}
|
|
28715
|
-
if (useRightAxis) {
|
|
28716
|
-
// @ts-ignore chart.js type is broken
|
|
28717
|
-
config.options.scales.y1.stacked = true;
|
|
28718
|
-
}
|
|
28719
|
-
}
|
|
28886
|
+
config.options.scales = removeFalsyAttributes(config.options.scales);
|
|
28720
28887
|
config.options.plugins.chartShowValuesPlugin = {
|
|
28721
28888
|
showValues: chart.showValues,
|
|
28722
28889
|
background: chart.background,
|
|
28723
|
-
callback:
|
|
28890
|
+
callback: formatChartDatasetValue(axisFormats, locale),
|
|
28724
28891
|
};
|
|
28725
28892
|
if (chart.dataSetsHaveTitle &&
|
|
28726
28893
|
dataSetsValues[0] &&
|
|
@@ -28747,7 +28914,7 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28747
28914
|
label = toNumber(label, locale);
|
|
28748
28915
|
}
|
|
28749
28916
|
const formattedX = formatValue(label, { locale, format: labelFormat });
|
|
28750
|
-
const formattedY = formatValue(dataSetPoint, { locale, format:
|
|
28917
|
+
const formattedY = formatValue(dataSetPoint, { locale, format: leftAxisFormat });
|
|
28751
28918
|
const dataSetTitle = tooltipItem.dataset.label;
|
|
28752
28919
|
return formattedX
|
|
28753
28920
|
? `${dataSetTitle}: (${formattedX}, ${formattedY})`
|
|
@@ -28757,7 +28924,6 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28757
28924
|
const areaChart = "fillArea" in chart ? chart.fillArea : false;
|
|
28758
28925
|
const stackedChart = "stacked" in chart ? chart.stacked : false;
|
|
28759
28926
|
const cumulative = "cumulative" in chart ? chart.cumulative : false;
|
|
28760
|
-
const definition = chart.getDefinition();
|
|
28761
28927
|
const colors = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
28762
28928
|
for (let [index, { label, data }] of dataSetsValues.entries()) {
|
|
28763
28929
|
const color = colors.next();
|
|
@@ -28798,9 +28964,7 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28798
28964
|
const label = definition.dataSets[index].label;
|
|
28799
28965
|
dataset.label = label;
|
|
28800
28966
|
}
|
|
28801
|
-
|
|
28802
|
-
dataset["yAxisID"] = definition.dataSets[index].yAxisId;
|
|
28803
|
-
}
|
|
28967
|
+
dataset["yAxisID"] = definition.dataSets[index].yAxisId || "y";
|
|
28804
28968
|
const trend = definition.dataSets?.[index].trend;
|
|
28805
28969
|
if (!trend?.display) {
|
|
28806
28970
|
continue;
|
|
@@ -28817,7 +28981,7 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28817
28981
|
* set so that the second axis points match the classical x axis
|
|
28818
28982
|
*/
|
|
28819
28983
|
config.options.scales[TREND_LINE_XAXIS_ID] = {
|
|
28820
|
-
...
|
|
28984
|
+
...config.options.scales.x,
|
|
28821
28985
|
type: "category",
|
|
28822
28986
|
labels: range(0, maxLength).map((x) => x.toString()),
|
|
28823
28987
|
offset: false,
|
|
@@ -28839,10 +29003,6 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
28839
29003
|
return {
|
|
28840
29004
|
chartJsConfig: config,
|
|
28841
29005
|
background: chart.background || BACKGROUND_CHART_COLOR,
|
|
28842
|
-
dataSetsValues,
|
|
28843
|
-
labelValues,
|
|
28844
|
-
dataSetFormat,
|
|
28845
|
-
labelFormat,
|
|
28846
29006
|
};
|
|
28847
29007
|
}
|
|
28848
29008
|
|
|
@@ -28900,6 +29060,7 @@ class ComboChart extends AbstractChart {
|
|
|
28900
29060
|
ranges.push({
|
|
28901
29061
|
...this.dataSetDesign?.[i],
|
|
28902
29062
|
dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId),
|
|
29063
|
+
type: this.dataSetDesign?.[i]?.type ?? (i ? "line" : "bar"),
|
|
28903
29064
|
});
|
|
28904
29065
|
}
|
|
28905
29066
|
return {
|
|
@@ -28945,9 +29106,13 @@ class ComboChart extends AbstractChart {
|
|
|
28945
29106
|
return new ComboChart(definition, this.sheetId, this.getters);
|
|
28946
29107
|
}
|
|
28947
29108
|
static getDefinitionFromContextCreation(context) {
|
|
29109
|
+
const dataSets = (context.range ?? []).map((ds, index) => ({
|
|
29110
|
+
...ds,
|
|
29111
|
+
type: index ? "line" : "bar",
|
|
29112
|
+
}));
|
|
28948
29113
|
return {
|
|
28949
29114
|
background: context.background,
|
|
28950
|
-
dataSets
|
|
29115
|
+
dataSets,
|
|
28951
29116
|
dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
|
|
28952
29117
|
aggregated: context.aggregated,
|
|
28953
29118
|
legendPosition: context.legendPosition ?? "top",
|
|
@@ -28970,10 +29135,8 @@ class ComboChart extends AbstractChart {
|
|
|
28970
29135
|
}
|
|
28971
29136
|
}
|
|
28972
29137
|
function createComboChartRuntime(chart, getters) {
|
|
28973
|
-
const mainDataSetFormat = chart.dataSets
|
|
28974
|
-
|
|
28975
|
-
: undefined;
|
|
28976
|
-
const lineDataSetsFormat = getChartDatasetFormat(getters, chart.dataSets.slice(1));
|
|
29138
|
+
const mainDataSetFormat = getChartDatasetFormat(getters, chart.dataSets, "left");
|
|
29139
|
+
const lineDataSetsFormat = getChartDatasetFormat(getters, chart.dataSets, "right");
|
|
28977
29140
|
const locale = getters.getLocale();
|
|
28978
29141
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
28979
29142
|
let labels = labelValues.formattedValues;
|
|
@@ -28987,12 +29150,11 @@ function createComboChartRuntime(chart, getters) {
|
|
|
28987
29150
|
if (chart.aggregated) {
|
|
28988
29151
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
28989
29152
|
}
|
|
28990
|
-
const localeFormat = { format: mainDataSetFormat, locale };
|
|
28991
29153
|
const fontColor = chartFontColor(chart.background);
|
|
28992
|
-
const
|
|
29154
|
+
const axisFormats = { y: mainDataSetFormat, y1: lineDataSetsFormat };
|
|
29155
|
+
const config = getDefaultChartJsRuntime(chart, labels, fontColor, { locale, axisFormats });
|
|
28993
29156
|
const legend = {
|
|
28994
29157
|
labels: { color: fontColor },
|
|
28995
|
-
reverse: true,
|
|
28996
29158
|
};
|
|
28997
29159
|
if (chart.legendPosition === "none") {
|
|
28998
29160
|
legend.display = false;
|
|
@@ -29007,52 +29169,17 @@ function createComboChartRuntime(chart, getters) {
|
|
|
29007
29169
|
displayLegend: chart.legendPosition === "top",
|
|
29008
29170
|
}),
|
|
29009
29171
|
};
|
|
29172
|
+
const definition = chart.getDefinition();
|
|
29010
29173
|
config.options.scales = {
|
|
29011
|
-
x: {
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
color: fontColor,
|
|
29015
|
-
},
|
|
29016
|
-
title: getChartAxisTitleRuntime(chart.axesDesign?.x),
|
|
29017
|
-
},
|
|
29174
|
+
x: getChartAxis(definition, "bottom", "labels", { locale }),
|
|
29175
|
+
y: getChartAxis(definition, "left", "values", { locale, format: mainDataSetFormat }),
|
|
29176
|
+
y1: getChartAxis(definition, "right", "values", { locale, format: lineDataSetsFormat }),
|
|
29018
29177
|
};
|
|
29019
|
-
|
|
29020
|
-
beginAtZero: true, // the origin of the y axis is always zero
|
|
29021
|
-
ticks: {
|
|
29022
|
-
color: fontColor,
|
|
29023
|
-
callback: formatTickValue({ format: mainDataSetFormat, locale }),
|
|
29024
|
-
},
|
|
29025
|
-
};
|
|
29026
|
-
const rightVerticalAxis = {
|
|
29027
|
-
beginAtZero: true, // the origin of the y axis is always zero
|
|
29028
|
-
ticks: {
|
|
29029
|
-
color: fontColor,
|
|
29030
|
-
callback: formatTickValue({ format: lineDataSetsFormat, locale }),
|
|
29031
|
-
},
|
|
29032
|
-
};
|
|
29033
|
-
const definition = chart.getDefinition();
|
|
29034
|
-
const { useLeftAxis, useRightAxis } = getDefinedAxis(definition);
|
|
29035
|
-
if (useLeftAxis) {
|
|
29036
|
-
config.options.scales.y = {
|
|
29037
|
-
...leftVerticalAxis,
|
|
29038
|
-
position: "left",
|
|
29039
|
-
title: getChartAxisTitleRuntime(chart.axesDesign?.y),
|
|
29040
|
-
};
|
|
29041
|
-
}
|
|
29042
|
-
if (useRightAxis) {
|
|
29043
|
-
config.options.scales.y1 = {
|
|
29044
|
-
...rightVerticalAxis,
|
|
29045
|
-
position: "right",
|
|
29046
|
-
grid: {
|
|
29047
|
-
display: false,
|
|
29048
|
-
},
|
|
29049
|
-
title: getChartAxisTitleRuntime(chart.axesDesign?.y1),
|
|
29050
|
-
};
|
|
29051
|
-
}
|
|
29178
|
+
config.options.scales = removeFalsyAttributes(config.options.scales);
|
|
29052
29179
|
config.options.plugins.chartShowValuesPlugin = {
|
|
29053
29180
|
showValues: chart.showValues,
|
|
29054
29181
|
background: chart.background,
|
|
29055
|
-
callback:
|
|
29182
|
+
callback: formatChartDatasetValue(axisFormats, locale),
|
|
29056
29183
|
};
|
|
29057
29184
|
const colors = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
29058
29185
|
let maxLength = 0;
|
|
@@ -29060,14 +29187,15 @@ function createComboChartRuntime(chart, getters) {
|
|
|
29060
29187
|
for (let [index, { label, data }] of dataSetsValues.entries()) {
|
|
29061
29188
|
const design = definition.dataSets[index];
|
|
29062
29189
|
const color = colors.next();
|
|
29190
|
+
const type = design?.type ?? "line";
|
|
29063
29191
|
const dataset = {
|
|
29064
29192
|
label: design?.label ?? label,
|
|
29065
29193
|
data,
|
|
29066
29194
|
borderColor: color,
|
|
29067
29195
|
backgroundColor: color,
|
|
29068
29196
|
yAxisID: design?.yAxisId ?? "y",
|
|
29069
|
-
type
|
|
29070
|
-
order:
|
|
29197
|
+
type,
|
|
29198
|
+
order: type === "bar" ? dataSetsValues.length + index : index,
|
|
29071
29199
|
};
|
|
29072
29200
|
config.data.datasets.push(dataset);
|
|
29073
29201
|
const trend = definition.dataSets?.[index].trend;
|
|
@@ -29680,7 +29808,7 @@ function createPieChartRuntime(chart, getters) {
|
|
|
29680
29808
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
29681
29809
|
}
|
|
29682
29810
|
({ dataSetsValues, labels } = filterNegativeValues(labels, dataSetsValues));
|
|
29683
|
-
const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
|
|
29811
|
+
const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets, "left");
|
|
29684
29812
|
const locale = getters.getLocale();
|
|
29685
29813
|
const config = getPieConfiguration(chart, labels, { format: dataSetFormat, locale });
|
|
29686
29814
|
const dataSetsLength = Math.max(0, ...dataSetsValues.map((ds) => ds?.data?.length ?? 0));
|
|
@@ -29835,7 +29963,7 @@ function createPyramidChartRuntime(chart, getters) {
|
|
|
29835
29963
|
return tooltipLabelCallback(tooltipItem);
|
|
29836
29964
|
};
|
|
29837
29965
|
const callback = config.options.plugins.chartShowValuesPlugin.callback;
|
|
29838
|
-
config.options.plugins.chartShowValuesPlugin.callback = (x) => callback(Math.abs(x));
|
|
29966
|
+
config.options.plugins.chartShowValuesPlugin.callback = (x, axisId) => callback(Math.abs(x), axisId);
|
|
29839
29967
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
29840
29968
|
}
|
|
29841
29969
|
|
|
@@ -30226,7 +30354,8 @@ function createWaterfallChartRuntime(chart, getters) {
|
|
|
30226
30354
|
if (chart.showSubTotals) {
|
|
30227
30355
|
labels.push(_t("Subtotal"));
|
|
30228
30356
|
}
|
|
30229
|
-
const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets)
|
|
30357
|
+
const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets, "left") ||
|
|
30358
|
+
getChartDatasetFormat(getters, chart.dataSets, "right");
|
|
30230
30359
|
const locale = getters.getLocale();
|
|
30231
30360
|
const dataSeriesLabels = dataSetsValues.map((dataSet) => dataSet.label);
|
|
30232
30361
|
const config = getWaterfallConfiguration(chart, labels, dataSeriesLabels, {
|
|
@@ -35296,6 +35425,7 @@ const CHECK_SVG = /*xml*/ `
|
|
|
35296
35425
|
<path fill='none' stroke='#FFF' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/>
|
|
35297
35426
|
</svg>
|
|
35298
35427
|
`;
|
|
35428
|
+
const CHECKBOX_WIDTH = 14;
|
|
35299
35429
|
css /* scss */ `
|
|
35300
35430
|
label.o-checkbox {
|
|
35301
35431
|
input {
|
|
@@ -35303,8 +35433,8 @@ css /* scss */ `
|
|
|
35303
35433
|
-webkit-appearance: none;
|
|
35304
35434
|
-moz-appearance: none;
|
|
35305
35435
|
border-radius: 0;
|
|
35306
|
-
width:
|
|
35307
|
-
height:
|
|
35436
|
+
width: ${CHECKBOX_WIDTH}px;
|
|
35437
|
+
height: ${CHECKBOX_WIDTH}px;
|
|
35308
35438
|
vertical-align: top;
|
|
35309
35439
|
box-sizing: border-box;
|
|
35310
35440
|
outline: none;
|
|
@@ -37214,6 +37344,32 @@ class ChartWithAxisDesignPanel extends owl.Component {
|
|
|
37214
37344
|
}
|
|
37215
37345
|
}
|
|
37216
37346
|
|
|
37347
|
+
class ComboChartDesignPanel extends ChartWithAxisDesignPanel {
|
|
37348
|
+
static template = "o-spreadsheet-ComboChartDesignPanel";
|
|
37349
|
+
seriesTypeChoices = [
|
|
37350
|
+
{ value: "bar", label: _t("Bar") },
|
|
37351
|
+
{ value: "line", label: _t("Line") },
|
|
37352
|
+
];
|
|
37353
|
+
updateDataSeriesType(type) {
|
|
37354
|
+
const dataSets = [...this.props.definition.dataSets];
|
|
37355
|
+
if (!dataSets?.[this.state.index]) {
|
|
37356
|
+
return;
|
|
37357
|
+
}
|
|
37358
|
+
dataSets[this.state.index] = {
|
|
37359
|
+
...dataSets[this.state.index],
|
|
37360
|
+
type,
|
|
37361
|
+
};
|
|
37362
|
+
this.props.updateChart(this.props.figureId, { dataSets });
|
|
37363
|
+
}
|
|
37364
|
+
getDataSeriesType() {
|
|
37365
|
+
const dataSets = this.props.definition.dataSets;
|
|
37366
|
+
if (!dataSets?.[this.state.index]) {
|
|
37367
|
+
return "bar";
|
|
37368
|
+
}
|
|
37369
|
+
return dataSets[this.state.index].type ?? "line";
|
|
37370
|
+
}
|
|
37371
|
+
}
|
|
37372
|
+
|
|
37217
37373
|
class GaugeChartConfigPanel extends owl.Component {
|
|
37218
37374
|
static template = "o-spreadsheet-GaugeChartConfigPanel";
|
|
37219
37375
|
static components = { ChartErrorSection, ChartDataSeries };
|
|
@@ -37640,7 +37796,7 @@ chartSidePanelComponentRegistry
|
|
|
37640
37796
|
})
|
|
37641
37797
|
.add("combo", {
|
|
37642
37798
|
configuration: GenericChartConfigPanel,
|
|
37643
|
-
design:
|
|
37799
|
+
design: ComboChartDesignPanel,
|
|
37644
37800
|
})
|
|
37645
37801
|
.add("pie", {
|
|
37646
37802
|
configuration: GenericChartConfigPanel,
|
|
@@ -37926,6 +38082,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
37926
38082
|
"stopComposerRangeSelection",
|
|
37927
38083
|
"cancelEdition",
|
|
37928
38084
|
"cycleReferences",
|
|
38085
|
+
"toggleEditionMode",
|
|
37929
38086
|
"changeComposerCursorSelection",
|
|
37930
38087
|
"replaceComposerCursorSelection",
|
|
37931
38088
|
];
|
|
@@ -38081,6 +38238,42 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
38081
38238
|
}
|
|
38082
38239
|
this.setCurrentContent(updated.content, updated.selection);
|
|
38083
38240
|
}
|
|
38241
|
+
toggleEditionMode() {
|
|
38242
|
+
if (this.editionMode === "inactive")
|
|
38243
|
+
return;
|
|
38244
|
+
const start = Math.min(this.selectionStart, this.selectionEnd);
|
|
38245
|
+
const end = Math.max(this.selectionStart, this.selectionEnd);
|
|
38246
|
+
const refToken = [...this.currentTokens]
|
|
38247
|
+
.reverse()
|
|
38248
|
+
.find((tk) => tk.end >= start && end >= tk.start && tk.type === "REFERENCE");
|
|
38249
|
+
if (this.editionMode === "editing" && refToken) {
|
|
38250
|
+
const currentSheetId = this.getters.getActiveSheetId();
|
|
38251
|
+
const { sheetName, xc } = splitReference(refToken.value);
|
|
38252
|
+
const sheetId = this.getters.getSheetIdByName(sheetName);
|
|
38253
|
+
if (sheetId && sheetId !== currentSheetId) {
|
|
38254
|
+
this.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: currentSheetId, sheetIdTo: sheetId });
|
|
38255
|
+
}
|
|
38256
|
+
// move cursor to the right part of the token
|
|
38257
|
+
this.selectionStart = this.selectionEnd = refToken.end;
|
|
38258
|
+
const zone = this.getters.getRangeFromSheetXC(this.sheetId, xc).zone;
|
|
38259
|
+
this.captureSelection(zone);
|
|
38260
|
+
this.editionMode = "selecting";
|
|
38261
|
+
}
|
|
38262
|
+
else {
|
|
38263
|
+
this.editionMode = "editing";
|
|
38264
|
+
}
|
|
38265
|
+
}
|
|
38266
|
+
captureSelection(zone, col, row) {
|
|
38267
|
+
this.model.selection.capture(this, {
|
|
38268
|
+
cell: { col: col || zone.left, row: row || zone.right },
|
|
38269
|
+
zone,
|
|
38270
|
+
}, {
|
|
38271
|
+
handleEvent: this.handleEvent.bind(this),
|
|
38272
|
+
release: () => {
|
|
38273
|
+
this._stopEdition();
|
|
38274
|
+
},
|
|
38275
|
+
});
|
|
38276
|
+
}
|
|
38084
38277
|
isSelectionValid(length, start, end) {
|
|
38085
38278
|
return start >= 0 && start <= length && end >= 0 && end <= length;
|
|
38086
38279
|
}
|
|
@@ -38119,12 +38312,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
38119
38312
|
this.setContent(str || this.initialContent, selection);
|
|
38120
38313
|
this.colorIndexByRange = {};
|
|
38121
38314
|
const zone = positionToZone({ col: this.col, row: this.row });
|
|
38122
|
-
this.
|
|
38123
|
-
handleEvent: this.handleEvent.bind(this),
|
|
38124
|
-
release: () => {
|
|
38125
|
-
this._stopEdition();
|
|
38126
|
-
},
|
|
38127
|
-
});
|
|
38315
|
+
this.captureSelection(zone, col, row);
|
|
38128
38316
|
}
|
|
38129
38317
|
_stopEdition() {
|
|
38130
38318
|
if (this.editionMode !== "inactive") {
|
|
@@ -42819,8 +43007,9 @@ const EMPTY_PIVOT_CELL = { type: "EMPTY" };
|
|
|
42819
43007
|
* This function converts a list of data entry into a spreadsheet pivot table.
|
|
42820
43008
|
*/
|
|
42821
43009
|
function dataEntriesToSpreadsheetPivotTable(dataEntries, definition) {
|
|
43010
|
+
const measureIds = definition.measures.filter((measure) => !measure.isHidden).map((m) => m.id);
|
|
42822
43011
|
const columnsTree = dataEntriesToColumnsTree(dataEntries, definition.columns, 0);
|
|
42823
|
-
computeWidthOfColumnsNodes(columnsTree,
|
|
43012
|
+
computeWidthOfColumnsNodes(columnsTree, measureIds.length);
|
|
42824
43013
|
const cols = columnsTreeToColumns(columnsTree, definition);
|
|
42825
43014
|
const rows = dataEntriesToRows(dataEntries, 0, definition.rows, [], []);
|
|
42826
43015
|
// Add the total row
|
|
@@ -42829,7 +43018,6 @@ function dataEntriesToSpreadsheetPivotTable(dataEntries, definition) {
|
|
|
42829
43018
|
values: [],
|
|
42830
43019
|
indent: 0,
|
|
42831
43020
|
});
|
|
42832
|
-
const measureIds = definition.measures.filter((measure) => !measure.isHidden).map((m) => m.id);
|
|
42833
43021
|
const fieldsType = {};
|
|
42834
43022
|
for (const columns of definition.columns) {
|
|
42835
43023
|
fieldsType[columns.fieldName] = columns.type;
|
|
@@ -43590,7 +43778,7 @@ pivotRegistry.add("SPREADSHEET", {
|
|
|
43590
43778
|
onIterationEndEvaluation: (pivot) => pivot.markAsDirtyForEvaluation(),
|
|
43591
43779
|
dateGranularities: [...dateGranularities],
|
|
43592
43780
|
datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
|
|
43593
|
-
isMeasureCandidate: (field) => !["
|
|
43781
|
+
isMeasureCandidate: (field) => !["datetime", "boolean"].includes(field.type),
|
|
43594
43782
|
isGroupable: () => true,
|
|
43595
43783
|
});
|
|
43596
43784
|
|
|
@@ -46119,13 +46307,10 @@ class GridCellIcon extends owl.Component {
|
|
|
46119
46307
|
}
|
|
46120
46308
|
}
|
|
46121
46309
|
|
|
46122
|
-
const CHECKBOX_WIDTH = 15;
|
|
46123
46310
|
const MARGIN = (GRID_ICON_EDGE_LENGTH - CHECKBOX_WIDTH) / 2;
|
|
46124
46311
|
css /* scss */ `
|
|
46125
46312
|
.o-dv-checkbox {
|
|
46126
46313
|
box-sizing: border-box !important;
|
|
46127
|
-
width: ${CHECKBOX_WIDTH}px;
|
|
46128
|
-
height: ${CHECKBOX_WIDTH}px;
|
|
46129
46314
|
accent-color: #808080;
|
|
46130
46315
|
margin: ${MARGIN}px;
|
|
46131
46316
|
/** required to prevent the checkbox position to be sensible to the font-size (affects Firefox) */
|
|
@@ -46134,13 +46319,15 @@ css /* scss */ `
|
|
|
46134
46319
|
`;
|
|
46135
46320
|
class DataValidationCheckbox extends owl.Component {
|
|
46136
46321
|
static template = "o-spreadsheet-DataValidationCheckbox";
|
|
46322
|
+
static components = {
|
|
46323
|
+
Checkbox,
|
|
46324
|
+
};
|
|
46137
46325
|
static props = {
|
|
46138
46326
|
cellPosition: Object,
|
|
46139
46327
|
};
|
|
46140
|
-
onCheckboxChange(
|
|
46141
|
-
const newValue = ev.target.checked;
|
|
46328
|
+
onCheckboxChange(value) {
|
|
46142
46329
|
const { sheetId, col, row } = this.props.cellPosition;
|
|
46143
|
-
const cellContent =
|
|
46330
|
+
const cellContent = value ? "TRUE" : "FALSE";
|
|
46144
46331
|
this.env.model.dispatch("UPDATE_CELL", { sheetId, col, row, content: cellContent });
|
|
46145
46332
|
}
|
|
46146
46333
|
get checkBoxValue() {
|
|
@@ -46954,7 +47141,11 @@ class GridAddRowsFooter extends owl.Component {
|
|
|
46954
47141
|
class PaintFormatStore extends SpreadsheetStore {
|
|
46955
47142
|
mutators = ["activate", "cancel", "pasteFormat"];
|
|
46956
47143
|
highlightStore = this.get(HighlightStore);
|
|
46957
|
-
|
|
47144
|
+
clipboardHandlers = [
|
|
47145
|
+
new CellClipboardHandler(this.getters, this.model.dispatch),
|
|
47146
|
+
new BorderClipboardHandler(this.getters, this.model.dispatch),
|
|
47147
|
+
new TableClipboardHandler(this.getters, this.model.dispatch),
|
|
47148
|
+
];
|
|
46958
47149
|
status = "inactive";
|
|
46959
47150
|
copiedData;
|
|
46960
47151
|
constructor(get) {
|
|
@@ -46975,10 +47166,12 @@ class PaintFormatStore extends SpreadsheetStore {
|
|
|
46975
47166
|
pasteFormat(target) {
|
|
46976
47167
|
if (this.copiedData) {
|
|
46977
47168
|
const sheetId = this.getters.getActiveSheetId();
|
|
46978
|
-
|
|
46979
|
-
|
|
46980
|
-
|
|
46981
|
-
|
|
47169
|
+
for (const handler of this.clipboardHandlers) {
|
|
47170
|
+
handler.paste({ zones: target, sheetId }, this.copiedData, {
|
|
47171
|
+
isCutOperation: false,
|
|
47172
|
+
pasteOption: "onlyFormat",
|
|
47173
|
+
});
|
|
47174
|
+
}
|
|
46982
47175
|
}
|
|
46983
47176
|
if (this.status === "oneOff") {
|
|
46984
47177
|
this.cancel();
|
|
@@ -46990,7 +47183,11 @@ class PaintFormatStore extends SpreadsheetStore {
|
|
|
46990
47183
|
copyFormats() {
|
|
46991
47184
|
const sheetId = this.getters.getActiveSheetId();
|
|
46992
47185
|
const zones = this.getters.getSelectedZones();
|
|
46993
|
-
|
|
47186
|
+
const copiedData = {};
|
|
47187
|
+
for (const handler of this.clipboardHandlers) {
|
|
47188
|
+
Object.assign(copiedData, handler.copy(getClipboardDataPositions(sheetId, zones)));
|
|
47189
|
+
}
|
|
47190
|
+
return copiedData;
|
|
46994
47191
|
}
|
|
46995
47192
|
get highlights() {
|
|
46996
47193
|
const data = this.copiedData;
|
|
@@ -49798,12 +49995,10 @@ class BasePlugin {
|
|
|
49798
49995
|
*/
|
|
49799
49996
|
class CorePlugin extends BasePlugin {
|
|
49800
49997
|
getters;
|
|
49801
|
-
|
|
49802
|
-
constructor({ getters, stateObserver, range, dispatch, canDispatch, uuidGenerator, }) {
|
|
49998
|
+
constructor({ getters, stateObserver, range, dispatch, canDispatch }) {
|
|
49803
49999
|
super(stateObserver, dispatch, canDispatch);
|
|
49804
50000
|
range.addRangeProvider(this.adaptRanges.bind(this));
|
|
49805
50001
|
this.getters = getters;
|
|
49806
|
-
this.uuidGenerator = uuidGenerator;
|
|
49807
50002
|
}
|
|
49808
50003
|
// ---------------------------------------------------------------------------
|
|
49809
50004
|
// Import/Export
|
|
@@ -54301,6 +54496,7 @@ class SheetPlugin extends CorePlugin {
|
|
|
54301
54496
|
}
|
|
54302
54497
|
}
|
|
54303
54498
|
|
|
54499
|
+
let nextTableId = 1;
|
|
54304
54500
|
class TablePlugin extends CorePlugin {
|
|
54305
54501
|
static getters = ["getCoreTable", "getCoreTables", "getCoreTableMatchingTopLeft"];
|
|
54306
54502
|
tables = {};
|
|
@@ -54368,7 +54564,7 @@ class TablePlugin extends CorePlugin {
|
|
|
54368
54564
|
const union = this.getters.getRangesUnion(ranges);
|
|
54369
54565
|
const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
|
|
54370
54566
|
this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
|
|
54371
|
-
const id =
|
|
54567
|
+
const id = `${nextTableId++}`;
|
|
54372
54568
|
const config = cmd.config || DEFAULT_TABLE_CONFIG;
|
|
54373
54569
|
const newTable = cmd.tableType === "dynamic"
|
|
54374
54570
|
? this.createDynamicTable(id, union, config)
|
|
@@ -54521,7 +54717,7 @@ class TablePlugin extends CorePlugin {
|
|
|
54521
54717
|
filters = [];
|
|
54522
54718
|
for (const i of range(zone.left, zone.right + 1)) {
|
|
54523
54719
|
const filterZone = { ...zone, left: i, right: i };
|
|
54524
|
-
const uid =
|
|
54720
|
+
const uid = `${nextTableId++}`;
|
|
54525
54721
|
filters.push(this.createFilterFromZone(uid, tableRange.sheetId, filterZone, config));
|
|
54526
54722
|
}
|
|
54527
54723
|
}
|
|
@@ -54586,7 +54782,7 @@ class TablePlugin extends CorePlugin {
|
|
|
54586
54782
|
? table.filters.find((f) => f.col === i)
|
|
54587
54783
|
: undefined;
|
|
54588
54784
|
const filterZone = { ...tableZone, left: i, right: i };
|
|
54589
|
-
const filterId = oldFilter?.id ||
|
|
54785
|
+
const filterId = oldFilter?.id || `${nextTableId++}`;
|
|
54590
54786
|
filters.push(this.createFilterFromZone(filterId, tableRange.sheetId, filterZone, config));
|
|
54591
54787
|
}
|
|
54592
54788
|
}
|
|
@@ -54687,7 +54883,7 @@ class TablePlugin extends CorePlugin {
|
|
|
54687
54883
|
if (filters.length < zoneToDimension(tableZone).numberOfCols) {
|
|
54688
54884
|
for (let col = tableZone.left; col <= tableZone.right; col++) {
|
|
54689
54885
|
if (!filters.find((filter) => filter.col === col)) {
|
|
54690
|
-
const uid =
|
|
54886
|
+
const uid = `${nextTableId++}`;
|
|
54691
54887
|
const filterZone = { ...tableZone, left: col, right: col };
|
|
54692
54888
|
filters.push(this.createFilterFromZone(uid, sheetId, filterZone, table.config));
|
|
54693
54889
|
}
|
|
@@ -54703,7 +54899,7 @@ class TablePlugin extends CorePlugin {
|
|
|
54703
54899
|
import(data) {
|
|
54704
54900
|
for (const sheet of data.sheets) {
|
|
54705
54901
|
for (const tableData of sheet.tables || []) {
|
|
54706
|
-
const uuid =
|
|
54902
|
+
const uuid = `${nextTableId++}`;
|
|
54707
54903
|
const tableConfig = tableData.config || DEFAULT_TABLE_CONFIG;
|
|
54708
54904
|
const range = this.getters.getRangeFromSheetXC(sheet.id, tableData.range);
|
|
54709
54905
|
const tableType = tableData.type || "static";
|
|
@@ -59052,7 +59248,7 @@ function withPivotPresentationLayer (PivotClass) {
|
|
|
59052
59248
|
const ranking = {};
|
|
59053
59249
|
const mainDimension = getFieldDimensionType(this, fieldNameWithGranularity);
|
|
59054
59250
|
const secondaryDimension = mainDimension === "row" ? "column" : "row";
|
|
59055
|
-
let pivotCells = this.getPivotValueCells();
|
|
59251
|
+
let pivotCells = this.getPivotValueCells(measure.id);
|
|
59056
59252
|
if (mainDimension === "column") {
|
|
59057
59253
|
// Transpose the pivot cells so we can do the same operations on the columns as on the rows
|
|
59058
59254
|
// This means that we need to transpose back the ranking at the end
|
|
@@ -59096,7 +59292,7 @@ function withPivotPresentationLayer (PivotClass) {
|
|
|
59096
59292
|
const cellsRunningTotals = {};
|
|
59097
59293
|
const mainDimension = getFieldDimensionType(this, fieldNameWithGranularity);
|
|
59098
59294
|
const secondaryDimension = mainDimension === "row" ? "column" : "row";
|
|
59099
|
-
let pivotCells = this.getPivotValueCells();
|
|
59295
|
+
let pivotCells = this.getPivotValueCells(measure.id);
|
|
59100
59296
|
if (mainDimension === "column") {
|
|
59101
59297
|
// Transpose the pivot cells so we can do the same operations on the columns as on the rows
|
|
59102
59298
|
// This means that we need to transpose back the totals at the end
|
|
@@ -59175,10 +59371,10 @@ function withPivotPresentationLayer (PivotClass) {
|
|
|
59175
59371
|
const comparedValueNumber = this.strictMeasureValueToNumber(comparedValue);
|
|
59176
59372
|
return comparedValueNumber;
|
|
59177
59373
|
}
|
|
59178
|
-
getPivotValueCells() {
|
|
59374
|
+
getPivotValueCells(measureId) {
|
|
59179
59375
|
return this.getTableStructure()
|
|
59180
59376
|
.getPivotCells()
|
|
59181
|
-
.map((col) => col.filter((cell) => cell.type === "VALUE"))
|
|
59377
|
+
.map((col) => col.filter((cell) => cell.type === "VALUE" && cell.measure === measureId))
|
|
59182
59378
|
.filter((col) => col.length > 0);
|
|
59183
59379
|
}
|
|
59184
59380
|
measureValueToNumber(result) {
|
|
@@ -60946,6 +61142,7 @@ class Session extends EventBus {
|
|
|
60946
61142
|
case "REMOTE_REVISION":
|
|
60947
61143
|
case "REVISION_REDONE":
|
|
60948
61144
|
case "REVISION_UNDONE":
|
|
61145
|
+
case "SNAPSHOT_CREATED":
|
|
60949
61146
|
return this.processedRevisions.has(message.nextRevisionId);
|
|
60950
61147
|
default:
|
|
60951
61148
|
return false;
|
|
@@ -61508,7 +61705,7 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
61508
61705
|
const position = this.getters.getSheetIds().indexOf(activeSheetId) + 1;
|
|
61509
61706
|
const formulaId = this.getters.getPivotFormulaId(newPivotId);
|
|
61510
61707
|
const newPivotName = this.getters.getPivotName(newPivotId);
|
|
61511
|
-
this.dispatch("CREATE_SHEET", {
|
|
61708
|
+
const result = this.dispatch("CREATE_SHEET", {
|
|
61512
61709
|
sheetId: newSheetId,
|
|
61513
61710
|
name: this.getPivotDuplicateSheetName(_t("%(newPivotName)s (Pivot #%(formulaId)s)", {
|
|
61514
61711
|
newPivotName,
|
|
@@ -61516,20 +61713,19 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
61516
61713
|
})),
|
|
61517
61714
|
position,
|
|
61518
61715
|
});
|
|
61519
|
-
|
|
61520
|
-
|
|
61521
|
-
|
|
61522
|
-
|
|
61523
|
-
|
|
61524
|
-
content: `=PIVOT(${formulaId})`,
|
|
61525
|
-
});
|
|
61716
|
+
if (result.isSuccessful) {
|
|
61717
|
+
this.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: newSheetId });
|
|
61718
|
+
const pivot = this.getters.getPivot(pivotId);
|
|
61719
|
+
this.insertPivotWithTable(newSheetId, 0, 0, newPivotId, pivot.getTableStructure().export(), "dynamic");
|
|
61720
|
+
}
|
|
61526
61721
|
}
|
|
61527
61722
|
getPivotDuplicateSheetName(pivotName) {
|
|
61528
61723
|
let i = 1;
|
|
61529
61724
|
const names = this.getters.getSheetIds().map((id) => this.getters.getSheetName(id));
|
|
61530
|
-
|
|
61725
|
+
const sanitizedName = pivotName.replace(new RegExp(FORBIDDEN_IN_EXCEL_REGEX, "g"), " ");
|
|
61726
|
+
let name = sanitizedName;
|
|
61531
61727
|
while (names.includes(name)) {
|
|
61532
|
-
name = `${
|
|
61728
|
+
name = `${sanitizedName} (${i})`;
|
|
61533
61729
|
i++;
|
|
61534
61730
|
}
|
|
61535
61731
|
return name;
|
|
@@ -70882,6 +71078,15 @@ function addTableColumns(table, sheetData) {
|
|
|
70882
71078
|
["id", i + 1], // id cannot be 0
|
|
70883
71079
|
["name", colName],
|
|
70884
71080
|
];
|
|
71081
|
+
if (table.config.totalRow) {
|
|
71082
|
+
// Note: To be 100% complete, we could also add a `totalsRowLabel` attribute for total strings, and a tag
|
|
71083
|
+
// `<totalsRowFormula>` for the formula of the total. But those doesn't seem to be mandatory for Excel.
|
|
71084
|
+
const colTotalXc = toXC(tableZone.left + i, tableZone.bottom);
|
|
71085
|
+
const colTotalContent = sheetData.cells[colTotalXc]?.content;
|
|
71086
|
+
if (colTotalContent?.startsWith("=")) {
|
|
71087
|
+
colAttributes.push(["totalsRowFunction", "custom"]);
|
|
71088
|
+
}
|
|
71089
|
+
}
|
|
70885
71090
|
columns.push(escapeXml /*xml*/ `<tableColumn ${formatAttributes(colAttributes)}/>`);
|
|
70886
71091
|
}
|
|
70887
71092
|
return escapeXml /*xml*/ `
|
|
@@ -70976,8 +71181,9 @@ function addRows(construct, data, sheet) {
|
|
|
70976
71181
|
}
|
|
70977
71182
|
else if (cell.content && cell.content !== "") {
|
|
70978
71183
|
const isTableHeader = isCellTableHeader(c, r, sheet);
|
|
71184
|
+
const isTableTotal = isCellTableTotal(c, r, sheet);
|
|
70979
71185
|
const isPlainText = !!(cell.format && isTextFormat(data.formats[cell.format]));
|
|
70980
|
-
({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader || isPlainText));
|
|
71186
|
+
({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader || isTableTotal || isPlainText));
|
|
70981
71187
|
}
|
|
70982
71188
|
attributes.push(...additionalAttrs);
|
|
70983
71189
|
// prettier-ignore
|
|
@@ -71011,6 +71217,16 @@ function isCellTableHeader(col, row, sheet) {
|
|
|
71011
71217
|
return isInside(col, row, headerZone);
|
|
71012
71218
|
});
|
|
71013
71219
|
}
|
|
71220
|
+
function isCellTableTotal(col, row, sheet) {
|
|
71221
|
+
return sheet.tables.some((table) => {
|
|
71222
|
+
if (!table.config.totalRow) {
|
|
71223
|
+
return false;
|
|
71224
|
+
}
|
|
71225
|
+
const zone = toZone(table.range);
|
|
71226
|
+
const totalZone = { ...zone, top: zone.bottom };
|
|
71227
|
+
return isInside(col, row, totalZone);
|
|
71228
|
+
});
|
|
71229
|
+
}
|
|
71014
71230
|
function addHyperlinks(construct, data, sheetIndex) {
|
|
71015
71231
|
const sheet = data.sheets[sheetIndex];
|
|
71016
71232
|
const cells = sheet.cells;
|
|
@@ -71501,7 +71717,6 @@ class Model extends EventBus {
|
|
|
71501
71717
|
isReadonly: () => this.config.mode === "readonly" || this.config.mode === "dashboard",
|
|
71502
71718
|
isDashboard: () => this.config.mode === "dashboard",
|
|
71503
71719
|
};
|
|
71504
|
-
this.uuidGenerator.setIsFastStrategy(true);
|
|
71505
71720
|
// Initiate stream processor
|
|
71506
71721
|
this.selection = new SelectionStreamProcessorImpl(this.getters);
|
|
71507
71722
|
this.coreHandlers.push(this.range);
|
|
@@ -71533,7 +71748,6 @@ class Model extends EventBus {
|
|
|
71533
71748
|
this.handlers.push(plugin);
|
|
71534
71749
|
this.uiHandlers.push(plugin);
|
|
71535
71750
|
}
|
|
71536
|
-
this.uuidGenerator.setIsFastStrategy(false);
|
|
71537
71751
|
// starting plugins
|
|
71538
71752
|
this.dispatch("START");
|
|
71539
71753
|
// Model should be the last permanent subscriber in the list since he should render
|
|
@@ -71681,7 +71895,6 @@ class Model extends EventBus {
|
|
|
71681
71895
|
range: this.range,
|
|
71682
71896
|
dispatch: this.dispatchFromCorePlugin,
|
|
71683
71897
|
canDispatch: this.canDispatch,
|
|
71684
|
-
uuidGenerator: this.uuidGenerator,
|
|
71685
71898
|
custom: this.config.custom,
|
|
71686
71899
|
external: this.config.external,
|
|
71687
71900
|
};
|
|
@@ -72175,6 +72388,6 @@ exports.tokenColors = tokenColors;
|
|
|
72175
72388
|
exports.tokenize = tokenize;
|
|
72176
72389
|
|
|
72177
72390
|
|
|
72178
|
-
__info__.version = "18.1.0-alpha.
|
|
72179
|
-
__info__.date = "2024-
|
|
72180
|
-
__info__.hash = "
|
|
72391
|
+
__info__.version = "18.1.0-alpha.1";
|
|
72392
|
+
__info__.date = "2024-10-14T07:53:17.717Z";
|
|
72393
|
+
__info__.hash = "e9ce3aa";
|