@odoo/o-spreadsheet 17.4.8 → 17.4.10
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 +333 -231
- package/dist/o-spreadsheet.d.ts +4 -0
- package/dist/o-spreadsheet.esm.js +333 -231
- package/dist/o-spreadsheet.iife.js +333 -231
- package/dist/o-spreadsheet.iife.min.js +425 -425
- package/dist/o_spreadsheet.xml +3 -3
- package/package.json +2 -2
|
@@ -2,15 +2,120 @@
|
|
|
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 17.4.
|
|
6
|
-
* @date 2024-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.4.10
|
|
6
|
+
* @date 2024-10-24T08:54:56.262Z
|
|
7
|
+
* @hash c82d9c1
|
|
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
|
+
secondaryIcon: typeof secondaryIcon === "function" ? secondaryIcon : () => secondaryIcon || "",
|
|
44
|
+
description: typeof description === "function" ? description : () => description || "",
|
|
45
|
+
textColor: item.textColor,
|
|
46
|
+
sequence: item.sequence || 0,
|
|
47
|
+
onStartHover: item.onStartHover,
|
|
48
|
+
onStopHover: item.onStopHover,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Registry
|
|
54
|
+
*
|
|
55
|
+
* The Registry class is basically just a mapping from a string key to an object.
|
|
56
|
+
* It is really not much more than an object. It is however useful for the
|
|
57
|
+
* following reasons:
|
|
58
|
+
*
|
|
59
|
+
* 1. it let us react and execute code when someone add something to the registry
|
|
60
|
+
* (for example, the FunctionRegistry subclass this for this purpose)
|
|
61
|
+
* 2. it throws an error when the get operation fails
|
|
62
|
+
* 3. it provides a chained API to add items to the registry.
|
|
63
|
+
*/
|
|
64
|
+
class Registry {
|
|
65
|
+
content = {};
|
|
66
|
+
/**
|
|
67
|
+
* Add an item to the registry
|
|
68
|
+
*
|
|
69
|
+
* Note that this also returns the registry, so another add method call can
|
|
70
|
+
* be chained
|
|
71
|
+
*/
|
|
72
|
+
add(key, value) {
|
|
73
|
+
this.content[key] = value;
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get an item from the registry
|
|
78
|
+
*/
|
|
79
|
+
get(key) {
|
|
80
|
+
/**
|
|
81
|
+
* Note: key in {} is ~12 times slower than {}[key].
|
|
82
|
+
* So, we check the absence of key only when the direct access returns
|
|
83
|
+
* a falsy value. It's done to ensure that the registry can contains falsy values
|
|
84
|
+
*/
|
|
85
|
+
const content = this.content[key];
|
|
86
|
+
if (!content) {
|
|
87
|
+
if (!(key in this.content)) {
|
|
88
|
+
throw new Error(`Cannot find ${key} in this registry!`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return content;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if the key is already in the registry
|
|
95
|
+
*/
|
|
96
|
+
contains(key) {
|
|
97
|
+
return key in this.content;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get a list of all elements in the registry
|
|
101
|
+
*/
|
|
102
|
+
getAll() {
|
|
103
|
+
return Object.values(this.content);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get a list of all keys in the registry
|
|
107
|
+
*/
|
|
108
|
+
getKeys() {
|
|
109
|
+
return Object.keys(this.content);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Remove an item from the registry
|
|
113
|
+
*/
|
|
114
|
+
remove(key) {
|
|
115
|
+
delete this.content[key];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
14
119
|
const CANVAS_SHIFT = 0.5;
|
|
15
120
|
// Colors
|
|
16
121
|
const HIGHLIGHT_COLOR = "#37A850";
|
|
@@ -167,7 +272,7 @@ const DEFAULT_STYLE = {
|
|
|
167
272
|
underline: false,
|
|
168
273
|
fontSize: 10,
|
|
169
274
|
fillColor: "",
|
|
170
|
-
textColor: "
|
|
275
|
+
textColor: "",
|
|
171
276
|
};
|
|
172
277
|
const DEFAULT_VERTICAL_ALIGN = DEFAULT_STYLE.verticalAlign;
|
|
173
278
|
const DEFAULT_WRAPPING_MODE = DEFAULT_STYLE.wrapping;
|
|
@@ -5399,110 +5504,6 @@ class UuidGenerator {
|
|
|
5399
5504
|
}
|
|
5400
5505
|
}
|
|
5401
5506
|
|
|
5402
|
-
function createActions(menuItems) {
|
|
5403
|
-
return menuItems.map(createAction).sort((a, b) => a.sequence - b.sequence);
|
|
5404
|
-
}
|
|
5405
|
-
const uuidGenerator$1 = new UuidGenerator();
|
|
5406
|
-
function createAction(item) {
|
|
5407
|
-
const name = item.name;
|
|
5408
|
-
const children = item.children;
|
|
5409
|
-
const description = item.description;
|
|
5410
|
-
const icon = item.icon;
|
|
5411
|
-
const secondaryIcon = item.secondaryIcon;
|
|
5412
|
-
return {
|
|
5413
|
-
id: item.id || uuidGenerator$1.uuidv4(),
|
|
5414
|
-
name: typeof name === "function" ? name : () => name,
|
|
5415
|
-
isVisible: item.isVisible ? item.isVisible : () => true,
|
|
5416
|
-
isEnabled: item.isEnabled ? item.isEnabled : () => true,
|
|
5417
|
-
isActive: item.isActive,
|
|
5418
|
-
execute: item.execute,
|
|
5419
|
-
children: children
|
|
5420
|
-
? (env) => {
|
|
5421
|
-
return children
|
|
5422
|
-
.map((child) => (typeof child === "function" ? child(env) : child))
|
|
5423
|
-
.flat()
|
|
5424
|
-
.map(createAction);
|
|
5425
|
-
}
|
|
5426
|
-
: () => [],
|
|
5427
|
-
isReadonlyAllowed: item.isReadonlyAllowed || false,
|
|
5428
|
-
separator: item.separator || false,
|
|
5429
|
-
icon: typeof icon === "function" ? icon : () => icon || "",
|
|
5430
|
-
secondaryIcon: typeof secondaryIcon === "function" ? secondaryIcon : () => secondaryIcon || "",
|
|
5431
|
-
description: typeof description === "function" ? description : () => description || "",
|
|
5432
|
-
textColor: item.textColor,
|
|
5433
|
-
sequence: item.sequence || 0,
|
|
5434
|
-
onStartHover: item.onStartHover,
|
|
5435
|
-
onStopHover: item.onStopHover,
|
|
5436
|
-
};
|
|
5437
|
-
}
|
|
5438
|
-
|
|
5439
|
-
/**
|
|
5440
|
-
* Registry
|
|
5441
|
-
*
|
|
5442
|
-
* The Registry class is basically just a mapping from a string key to an object.
|
|
5443
|
-
* It is really not much more than an object. It is however useful for the
|
|
5444
|
-
* following reasons:
|
|
5445
|
-
*
|
|
5446
|
-
* 1. it let us react and execute code when someone add something to the registry
|
|
5447
|
-
* (for example, the FunctionRegistry subclass this for this purpose)
|
|
5448
|
-
* 2. it throws an error when the get operation fails
|
|
5449
|
-
* 3. it provides a chained API to add items to the registry.
|
|
5450
|
-
*/
|
|
5451
|
-
class Registry {
|
|
5452
|
-
content = {};
|
|
5453
|
-
/**
|
|
5454
|
-
* Add an item to the registry
|
|
5455
|
-
*
|
|
5456
|
-
* Note that this also returns the registry, so another add method call can
|
|
5457
|
-
* be chained
|
|
5458
|
-
*/
|
|
5459
|
-
add(key, value) {
|
|
5460
|
-
this.content[key] = value;
|
|
5461
|
-
return this;
|
|
5462
|
-
}
|
|
5463
|
-
/**
|
|
5464
|
-
* Get an item from the registry
|
|
5465
|
-
*/
|
|
5466
|
-
get(key) {
|
|
5467
|
-
/**
|
|
5468
|
-
* Note: key in {} is ~12 times slower than {}[key].
|
|
5469
|
-
* So, we check the absence of key only when the direct access returns
|
|
5470
|
-
* a falsy value. It's done to ensure that the registry can contains falsy values
|
|
5471
|
-
*/
|
|
5472
|
-
const content = this.content[key];
|
|
5473
|
-
if (!content) {
|
|
5474
|
-
if (!(key in this.content)) {
|
|
5475
|
-
throw new Error(`Cannot find ${key} in this registry!`);
|
|
5476
|
-
}
|
|
5477
|
-
}
|
|
5478
|
-
return content;
|
|
5479
|
-
}
|
|
5480
|
-
/**
|
|
5481
|
-
* Check if the key is already in the registry
|
|
5482
|
-
*/
|
|
5483
|
-
contains(key) {
|
|
5484
|
-
return key in this.content;
|
|
5485
|
-
}
|
|
5486
|
-
/**
|
|
5487
|
-
* Get a list of all elements in the registry
|
|
5488
|
-
*/
|
|
5489
|
-
getAll() {
|
|
5490
|
-
return Object.values(this.content);
|
|
5491
|
-
}
|
|
5492
|
-
/**
|
|
5493
|
-
* Get a list of all keys in the registry
|
|
5494
|
-
*/
|
|
5495
|
-
getKeys() {
|
|
5496
|
-
return Object.keys(this.content);
|
|
5497
|
-
}
|
|
5498
|
-
/**
|
|
5499
|
-
* Remove an item from the registry
|
|
5500
|
-
*/
|
|
5501
|
-
remove(key) {
|
|
5502
|
-
delete this.content[key];
|
|
5503
|
-
}
|
|
5504
|
-
}
|
|
5505
|
-
|
|
5506
5507
|
function getClipboardDataPositions(sheetId, zones) {
|
|
5507
5508
|
const lefts = new Set(zones.map((z) => z.left));
|
|
5508
5509
|
const rights = new Set(zones.map((z) => z.right));
|
|
@@ -7281,31 +7282,34 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
7281
7282
|
for (let col of columnsIndexes) {
|
|
7282
7283
|
const position = { col, row, sheetId };
|
|
7283
7284
|
const table = this.getters.getTable(position);
|
|
7284
|
-
if (!table
|
|
7285
|
+
if (!table) {
|
|
7285
7286
|
tableCellsInRow.push({});
|
|
7286
7287
|
continue;
|
|
7287
7288
|
}
|
|
7288
7289
|
const coreTable = this.getters.getCoreTable(position);
|
|
7289
7290
|
const tableZone = coreTable?.range.zone;
|
|
7291
|
+
let copiedTable = undefined;
|
|
7290
7292
|
// Copy whole table
|
|
7291
|
-
if (
|
|
7292
|
-
|
|
7293
|
+
if (!copiedTablesIds.has(table.id) &&
|
|
7294
|
+
coreTable &&
|
|
7295
|
+
tableZone &&
|
|
7296
|
+
zones.some((z) => isZoneInside(tableZone, z))) {
|
|
7297
|
+
copiedTablesIds.add(table.id);
|
|
7293
7298
|
const values = [];
|
|
7294
7299
|
for (const col of range(tableZone.left, tableZone.right + 1)) {
|
|
7295
7300
|
values.push(this.getters.getFilterHiddenValues({ sheetId, col, row: tableZone.top }));
|
|
7296
7301
|
}
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7301
|
-
|
|
7302
|
-
},
|
|
7303
|
-
});
|
|
7304
|
-
}
|
|
7305
|
-
// Copy only style of cell
|
|
7306
|
-
else if (table) {
|
|
7307
|
-
tableCellsInRow.push({ style: this.getTableStyleToCopy(position) });
|
|
7302
|
+
copiedTable = {
|
|
7303
|
+
range: coreTable.range,
|
|
7304
|
+
config: coreTable.config,
|
|
7305
|
+
type: coreTable.type,
|
|
7306
|
+
};
|
|
7308
7307
|
}
|
|
7308
|
+
tableCellsInRow.push({
|
|
7309
|
+
table: copiedTable,
|
|
7310
|
+
style: this.getTableStyleToCopy(position),
|
|
7311
|
+
isWholeTableCopied: copiedTablesIds.has(table.id),
|
|
7312
|
+
});
|
|
7309
7313
|
}
|
|
7310
7314
|
}
|
|
7311
7315
|
return {
|
|
@@ -7386,11 +7390,14 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
7386
7390
|
tableType: tableCell.table.type,
|
|
7387
7391
|
});
|
|
7388
7392
|
}
|
|
7389
|
-
// Do not paste table style if we're inside another table
|
|
7390
7393
|
// We cannot check for dynamic tables, because at this point the paste can have changed the evaluation, and the
|
|
7391
7394
|
// dynamic tables are not yet computed
|
|
7392
|
-
if (
|
|
7393
|
-
|
|
7395
|
+
if (this.getters.getCoreTable(position) || options?.pasteOption === "asValue") {
|
|
7396
|
+
return;
|
|
7397
|
+
}
|
|
7398
|
+
if ((!options?.pasteOption && !tableCell.isWholeTableCopied) ||
|
|
7399
|
+
options?.pasteOption === "onlyFormat") {
|
|
7400
|
+
if (tableCell.style?.style) {
|
|
7394
7401
|
this.dispatch("UPDATE_CELL", { ...position, style: tableCell.style.style });
|
|
7395
7402
|
}
|
|
7396
7403
|
if (tableCell.style?.border) {
|
|
@@ -10618,67 +10625,108 @@ const chartShowValuesPlugin = {
|
|
|
10618
10625
|
ctx.save();
|
|
10619
10626
|
ctx.textAlign = "center";
|
|
10620
10627
|
ctx.textBaseline = "middle";
|
|
10621
|
-
ctx.
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
10628
|
-
|
|
10629
|
-
|
|
10630
|
-
|
|
10631
|
-
|
|
10632
|
-
|
|
10633
|
-
|
|
10634
|
-
ctx.fillStyle = chartFontColor(bar.options.backgroundColor);
|
|
10635
|
-
ctx.strokeStyle = chartFontColor(ctx.fillStyle);
|
|
10636
|
-
const value = options.callback(dataset._parsed[i]);
|
|
10637
|
-
ctx.strokeText(value, x, y);
|
|
10638
|
-
ctx.fillText(value, x, y);
|
|
10639
|
-
}
|
|
10640
|
-
break;
|
|
10641
|
-
}
|
|
10642
|
-
case "bar":
|
|
10643
|
-
case "line": {
|
|
10644
|
-
const yOffset = dataset.type === "bar" && !options.horizontal ? 0 : 3;
|
|
10645
|
-
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10646
|
-
const point = dataset.data[i];
|
|
10647
|
-
const value = options.horizontal ? dataset._parsed[i].x : dataset._parsed[i].y;
|
|
10648
|
-
const displayedValue = options.callback(value - 0);
|
|
10649
|
-
let xPosition = 0, yPosition = 0;
|
|
10650
|
-
if (options.horizontal) {
|
|
10651
|
-
yPosition = point.y;
|
|
10652
|
-
if (value < 0) {
|
|
10653
|
-
ctx.textAlign = "right";
|
|
10654
|
-
xPosition = point.x - yOffset;
|
|
10655
|
-
}
|
|
10656
|
-
else {
|
|
10657
|
-
ctx.textAlign = "left";
|
|
10658
|
-
xPosition = point.x + yOffset;
|
|
10659
|
-
}
|
|
10660
|
-
}
|
|
10661
|
-
else {
|
|
10662
|
-
xPosition = point.x;
|
|
10663
|
-
if (value < 0) {
|
|
10664
|
-
ctx.textBaseline = "top";
|
|
10665
|
-
yPosition = point.y + yOffset;
|
|
10666
|
-
}
|
|
10667
|
-
else {
|
|
10668
|
-
ctx.textBaseline = "bottom";
|
|
10669
|
-
yPosition = point.y - yOffset;
|
|
10670
|
-
}
|
|
10671
|
-
}
|
|
10672
|
-
ctx.strokeText(displayedValue, xPosition, yPosition);
|
|
10673
|
-
ctx.fillText(displayedValue, xPosition, yPosition);
|
|
10674
|
-
}
|
|
10675
|
-
break;
|
|
10676
|
-
}
|
|
10677
|
-
}
|
|
10678
|
-
});
|
|
10628
|
+
ctx.miterLimit = 1; // Avoid sharp artifacts on strokeText
|
|
10629
|
+
switch (chart.config.type) {
|
|
10630
|
+
case "pie":
|
|
10631
|
+
case "doughnut":
|
|
10632
|
+
drawPieChartValues(chart, options, ctx);
|
|
10633
|
+
break;
|
|
10634
|
+
case "bar":
|
|
10635
|
+
case "line":
|
|
10636
|
+
options.horizontal
|
|
10637
|
+
? drawHorizontalBarChartValues(chart, options, ctx)
|
|
10638
|
+
: drawLineOrBarChartValues(chart, options, ctx);
|
|
10639
|
+
break;
|
|
10640
|
+
}
|
|
10679
10641
|
ctx.restore();
|
|
10680
10642
|
},
|
|
10681
10643
|
};
|
|
10644
|
+
function drawTextWithBackground(text, x, y, ctx) {
|
|
10645
|
+
ctx.lineWidth = 3; // Stroke the text with a big lineWidth width to have some kind of background
|
|
10646
|
+
ctx.strokeText(text, x, y);
|
|
10647
|
+
ctx.lineWidth = 1;
|
|
10648
|
+
ctx.fillText(text, x, y);
|
|
10649
|
+
}
|
|
10650
|
+
function drawLineOrBarChartValues(chart, options, ctx) {
|
|
10651
|
+
const yMax = chart.chartArea.bottom;
|
|
10652
|
+
const yMin = chart.chartArea.top;
|
|
10653
|
+
const textsPositions = {};
|
|
10654
|
+
for (const dataset of chart._metasets) {
|
|
10655
|
+
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10656
|
+
const value = dataset._parsed[i].y;
|
|
10657
|
+
const point = dataset.data[i];
|
|
10658
|
+
const xPosition = point.x;
|
|
10659
|
+
let yPosition = 0;
|
|
10660
|
+
if (chart.config.type === "line") {
|
|
10661
|
+
yPosition = point.y - 10;
|
|
10662
|
+
}
|
|
10663
|
+
else {
|
|
10664
|
+
yPosition = value < 0 ? point.y - point.height / 2 : point.y + point.height / 2;
|
|
10665
|
+
}
|
|
10666
|
+
yPosition = Math.min(yPosition, yMax);
|
|
10667
|
+
yPosition = Math.max(yPosition, yMin);
|
|
10668
|
+
// Avoid overlapping texts with same X
|
|
10669
|
+
if (!textsPositions[xPosition]) {
|
|
10670
|
+
textsPositions[xPosition] = [];
|
|
10671
|
+
}
|
|
10672
|
+
for (const otherPosition of textsPositions[xPosition] || []) {
|
|
10673
|
+
if (Math.abs(otherPosition - yPosition) < 13) {
|
|
10674
|
+
yPosition = otherPosition - 13;
|
|
10675
|
+
}
|
|
10676
|
+
}
|
|
10677
|
+
textsPositions[xPosition].push(yPosition);
|
|
10678
|
+
ctx.fillStyle = point.options.backgroundColor;
|
|
10679
|
+
ctx.strokeStyle = options.background || "#ffffff";
|
|
10680
|
+
drawTextWithBackground(options.callback(value - 0), xPosition, yPosition, ctx);
|
|
10681
|
+
}
|
|
10682
|
+
}
|
|
10683
|
+
}
|
|
10684
|
+
function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
10685
|
+
const xMax = chart.chartArea.right;
|
|
10686
|
+
const xMin = chart.chartArea.left;
|
|
10687
|
+
const textsPositions = {};
|
|
10688
|
+
for (const dataset of chart._metasets) {
|
|
10689
|
+
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10690
|
+
const value = dataset._parsed[i].x;
|
|
10691
|
+
const displayValue = options.callback(value - 0);
|
|
10692
|
+
const point = dataset.data[i];
|
|
10693
|
+
const yPosition = point.y;
|
|
10694
|
+
let xPosition = value < 0 ? point.x + point.width / 2 : point.x - point.width / 2;
|
|
10695
|
+
xPosition = Math.min(xPosition, xMax);
|
|
10696
|
+
xPosition = Math.max(xPosition, xMin);
|
|
10697
|
+
// Avoid overlapping texts with same Y
|
|
10698
|
+
if (!textsPositions[yPosition]) {
|
|
10699
|
+
textsPositions[yPosition] = [];
|
|
10700
|
+
}
|
|
10701
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
10702
|
+
for (const otherPosition of textsPositions[yPosition]) {
|
|
10703
|
+
if (Math.abs(otherPosition - xPosition) < textWidth) {
|
|
10704
|
+
xPosition = otherPosition + textWidth + 3;
|
|
10705
|
+
}
|
|
10706
|
+
}
|
|
10707
|
+
textsPositions[yPosition].push(xPosition);
|
|
10708
|
+
ctx.fillStyle = point.options.backgroundColor;
|
|
10709
|
+
ctx.strokeStyle = options.background || "#ffffff";
|
|
10710
|
+
drawTextWithBackground(displayValue, xPosition, yPosition, ctx);
|
|
10711
|
+
}
|
|
10712
|
+
}
|
|
10713
|
+
}
|
|
10714
|
+
function drawPieChartValues(chart, options, ctx) {
|
|
10715
|
+
for (const dataset of chart._metasets) {
|
|
10716
|
+
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10717
|
+
const bar = dataset.data[i];
|
|
10718
|
+
const { startAngle, endAngle, innerRadius, outerRadius } = bar;
|
|
10719
|
+
const midAngle = (startAngle + endAngle) / 2;
|
|
10720
|
+
const midRadius = (innerRadius + outerRadius) / 2;
|
|
10721
|
+
const x = bar.x + midRadius * Math.cos(midAngle);
|
|
10722
|
+
const y = bar.y + midRadius * Math.sin(midAngle) + 7;
|
|
10723
|
+
ctx.fillStyle = chartFontColor(options.background);
|
|
10724
|
+
ctx.strokeStyle = options.background || "#ffffff";
|
|
10725
|
+
const value = options.callback(dataset._parsed[i]);
|
|
10726
|
+
drawTextWithBackground(value, x, y, ctx);
|
|
10727
|
+
}
|
|
10728
|
+
}
|
|
10729
|
+
}
|
|
10682
10730
|
|
|
10683
10731
|
/** This is a chartJS plugin that will draw connector lines between the bars of a Waterfall chart */
|
|
10684
10732
|
const waterfallLinesPlugin = {
|
|
@@ -19156,9 +19204,10 @@ const PIVOT_VALUE = {
|
|
|
19156
19204
|
return error;
|
|
19157
19205
|
}
|
|
19158
19206
|
if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
|
|
19207
|
+
const suggestion = _t("Consider using a dynamic pivot formula: %s. Or re-insert the static pivot from the Data menu.", `=PIVOT(${_pivotFormulaId})`);
|
|
19159
19208
|
return {
|
|
19160
19209
|
value: CellErrorType.GenericError,
|
|
19161
|
-
message: _t("Dimensions don't match the pivot definition"),
|
|
19210
|
+
message: _t("Dimensions don't match the pivot definition") + ". " + suggestion,
|
|
19162
19211
|
};
|
|
19163
19212
|
}
|
|
19164
19213
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
@@ -19185,9 +19234,10 @@ const PIVOT_HEADER = {
|
|
|
19185
19234
|
return error;
|
|
19186
19235
|
}
|
|
19187
19236
|
if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
|
|
19237
|
+
const suggestion = _t("Consider using a dynamic pivot formula: %s. Or re-insert the static pivot from the Data menu.", `=PIVOT(${_pivotFormulaId})`);
|
|
19188
19238
|
return {
|
|
19189
19239
|
value: CellErrorType.GenericError,
|
|
19190
|
-
message: _t("Dimensions don't match the pivot definition"),
|
|
19240
|
+
message: _t("Dimensions don't match the pivot definition") + ". " + suggestion,
|
|
19191
19241
|
};
|
|
19192
19242
|
}
|
|
19193
19243
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
@@ -22363,6 +22413,7 @@ function insertTokenAfterArgSeparator(tokenAtCursor, value) {
|
|
|
22363
22413
|
// replace the whole token
|
|
22364
22414
|
start = tokenAtCursor.start;
|
|
22365
22415
|
}
|
|
22416
|
+
this.composer.stopComposerRangeSelection();
|
|
22366
22417
|
this.composer.changeComposerCursorSelection(start, end);
|
|
22367
22418
|
this.composer.replaceComposerCursorSelection(value);
|
|
22368
22419
|
}
|
|
@@ -22380,6 +22431,7 @@ function insertTokenAfterLeftParenthesis(tokenAtCursor, value) {
|
|
|
22380
22431
|
// replace the whole token
|
|
22381
22432
|
start = tokenAtCursor.start;
|
|
22382
22433
|
}
|
|
22434
|
+
this.composer.stopComposerRangeSelection();
|
|
22383
22435
|
this.composer.changeComposerCursorSelection(start, end);
|
|
22384
22436
|
this.composer.replaceComposerCursorSelection(value);
|
|
22385
22437
|
}
|
|
@@ -23404,7 +23456,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, tr
|
|
|
23404
23456
|
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
23405
23457
|
// tooltipItem.parsed can be an object or a number for pie charts
|
|
23406
23458
|
let yLabel = horizontalChart ? tooltipItem.parsed.x : tooltipItem.parsed.y;
|
|
23407
|
-
if (
|
|
23459
|
+
if (yLabel === undefined || yLabel === null) {
|
|
23408
23460
|
yLabel = tooltipItem.parsed;
|
|
23409
23461
|
}
|
|
23410
23462
|
const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
|
|
@@ -37195,6 +37247,8 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
37195
37247
|
mutators = ["reset", "deferUpdates", "applyUpdate", "discardPendingUpdate", "update"];
|
|
37196
37248
|
updatesAreDeferred = false;
|
|
37197
37249
|
draft = null;
|
|
37250
|
+
notification = this.get(NotificationStore);
|
|
37251
|
+
alreadyNotified = false;
|
|
37198
37252
|
constructor(get, pivotId) {
|
|
37199
37253
|
super(get);
|
|
37200
37254
|
this.pivotId = pivotId;
|
|
@@ -37301,6 +37355,16 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
37301
37355
|
pivot: this.draft,
|
|
37302
37356
|
});
|
|
37303
37357
|
this.draft = null;
|
|
37358
|
+
if (!this.alreadyNotified && !this.isDynamicPivotInViewport()) {
|
|
37359
|
+
const formulaId = this.getters.getPivotFormulaId(this.pivotId);
|
|
37360
|
+
const pivotExample = `=PIVOT(${formulaId})`;
|
|
37361
|
+
this.alreadyNotified = true;
|
|
37362
|
+
this.notification.notifyUser({
|
|
37363
|
+
type: "info",
|
|
37364
|
+
text: _t("Pivot updates only work with dynamic pivot tables. Use %s or re-insert the static pivot from the Data menu.", pivotExample),
|
|
37365
|
+
sticky: false,
|
|
37366
|
+
});
|
|
37367
|
+
}
|
|
37304
37368
|
}
|
|
37305
37369
|
}
|
|
37306
37370
|
discardPendingUpdate() {
|
|
@@ -37331,15 +37395,22 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
37331
37395
|
return;
|
|
37332
37396
|
}
|
|
37333
37397
|
const cleanedWithGranularity = this.addDefaultDateTimeGranularity(this.fields, cleanedDefinition);
|
|
37334
|
-
|
|
37335
|
-
|
|
37398
|
+
this.draft = cleanedWithGranularity;
|
|
37399
|
+
if (!this.updatesAreDeferred) {
|
|
37400
|
+
this.applyUpdate();
|
|
37336
37401
|
}
|
|
37337
|
-
|
|
37338
|
-
|
|
37339
|
-
|
|
37340
|
-
|
|
37341
|
-
|
|
37402
|
+
}
|
|
37403
|
+
isDynamicPivotInViewport() {
|
|
37404
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
37405
|
+
for (const col of this.getters.getSheetViewVisibleCols()) {
|
|
37406
|
+
for (const row of this.getters.getSheetViewVisibleRows()) {
|
|
37407
|
+
const isDynamicPivot = this.getters.isSpillPivotFormula({ sheetId, col, row });
|
|
37408
|
+
if (isDynamicPivot) {
|
|
37409
|
+
return true;
|
|
37410
|
+
}
|
|
37411
|
+
}
|
|
37342
37412
|
}
|
|
37413
|
+
return false;
|
|
37343
37414
|
}
|
|
37344
37415
|
addDefaultDateTimeGranularity(fields, definition) {
|
|
37345
37416
|
const { columns, rows } = definition;
|
|
@@ -46502,7 +46573,7 @@ function load(data, verboseImport) {
|
|
|
46502
46573
|
if (!data) {
|
|
46503
46574
|
return createEmptyWorkbookData();
|
|
46504
46575
|
}
|
|
46505
|
-
console.
|
|
46576
|
+
console.debug("### Loading data ###");
|
|
46506
46577
|
const start = performance.now();
|
|
46507
46578
|
if (data["[Content_Types].xml"]) {
|
|
46508
46579
|
const reader = new XlsxReader(data);
|
|
@@ -46516,13 +46587,13 @@ function load(data, verboseImport) {
|
|
|
46516
46587
|
// apply migrations, if needed
|
|
46517
46588
|
if ("version" in data) {
|
|
46518
46589
|
if (data.version < CURRENT_VERSION) {
|
|
46519
|
-
console.
|
|
46590
|
+
console.debug("Migrating data from version", data.version);
|
|
46520
46591
|
data = migrate(data);
|
|
46521
46592
|
}
|
|
46522
46593
|
}
|
|
46523
46594
|
data = repairData(data);
|
|
46524
|
-
console.
|
|
46525
|
-
console.
|
|
46595
|
+
console.debug("Data loaded in", performance.now() - start, "ms");
|
|
46596
|
+
console.debug("###");
|
|
46526
46597
|
return data;
|
|
46527
46598
|
}
|
|
46528
46599
|
function migrate(data) {
|
|
@@ -46531,7 +46602,7 @@ function migrate(data) {
|
|
|
46531
46602
|
for (let i = index; i < MIGRATIONS.length; i++) {
|
|
46532
46603
|
data = MIGRATIONS[i].applyMigration(data);
|
|
46533
46604
|
}
|
|
46534
|
-
console.
|
|
46605
|
+
console.debug("Data migrated in", performance.now() - start, "ms");
|
|
46535
46606
|
return data;
|
|
46536
46607
|
}
|
|
46537
46608
|
const MIGRATIONS = [
|
|
@@ -52430,7 +52501,7 @@ class PivotCorePlugin extends CorePlugin {
|
|
|
52430
52501
|
case "DUPLICATE_PIVOT": {
|
|
52431
52502
|
const { pivotId, newPivotId } = cmd;
|
|
52432
52503
|
const pivot = deepCopy(this.getPivotCore(pivotId).definition);
|
|
52433
|
-
pivot.name =
|
|
52504
|
+
pivot.name = cmd.duplicatedPivotName ?? pivot.name + " (copy)";
|
|
52434
52505
|
this.addPivot(newPivotId, pivot);
|
|
52435
52506
|
break;
|
|
52436
52507
|
}
|
|
@@ -54091,7 +54162,7 @@ class Evaluator {
|
|
|
54091
54162
|
cellsToCompute.addMany(arrayFormulasPositions);
|
|
54092
54163
|
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositions));
|
|
54093
54164
|
this.evaluate(cellsToCompute);
|
|
54094
|
-
console.
|
|
54165
|
+
console.debug("evaluate Cells", performance.now() - start, "ms");
|
|
54095
54166
|
}
|
|
54096
54167
|
getArrayFormulasImpactedByChangesOf(positions) {
|
|
54097
54168
|
const impactedPositions = this.createEmptyPositionSet();
|
|
@@ -54130,7 +54201,7 @@ class Evaluator {
|
|
|
54130
54201
|
const start = performance.now();
|
|
54131
54202
|
this.evaluatedCells = new PositionMap();
|
|
54132
54203
|
this.evaluate(this.getAllCells());
|
|
54133
|
-
console.
|
|
54204
|
+
console.debug("evaluate all cells", performance.now() - start, "ms");
|
|
54134
54205
|
}
|
|
54135
54206
|
evaluateFormulaResult(sheetId, formulaString) {
|
|
54136
54207
|
try {
|
|
@@ -57280,7 +57351,7 @@ class Session extends EventBus {
|
|
|
57280
57351
|
this.onMessageReceived(message);
|
|
57281
57352
|
}
|
|
57282
57353
|
this.isReplayingInitialRevisions = false;
|
|
57283
|
-
console.
|
|
57354
|
+
console.debug("Replayed", numberOfCommands, "commands in", performance.now() - start, "ms");
|
|
57284
57355
|
}
|
|
57285
57356
|
/**
|
|
57286
57357
|
* Notify the server that the user client left the collaborative session
|
|
@@ -57519,6 +57590,7 @@ class Session extends EventBus {
|
|
|
57519
57590
|
case "REMOTE_REVISION":
|
|
57520
57591
|
case "REVISION_REDONE":
|
|
57521
57592
|
case "REVISION_UNDONE":
|
|
57593
|
+
case "SNAPSHOT_CREATED":
|
|
57522
57594
|
return this.processedRevisions.has(message.nextRevisionId);
|
|
57523
57595
|
default:
|
|
57524
57596
|
return false;
|
|
@@ -58034,12 +58106,13 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
58034
58106
|
this.dispatch("DUPLICATE_PIVOT", {
|
|
58035
58107
|
pivotId,
|
|
58036
58108
|
newPivotId,
|
|
58109
|
+
duplicatedPivotName: _t("%s (copy)", this.getters.getPivotCoreDefinition(pivotId).name),
|
|
58037
58110
|
});
|
|
58038
58111
|
const activeSheetId = this.getters.getActiveSheetId();
|
|
58039
58112
|
const position = this.getters.getSheetIds().indexOf(activeSheetId) + 1;
|
|
58040
58113
|
const formulaId = this.getters.getPivotFormulaId(newPivotId);
|
|
58041
58114
|
const newPivotName = this.getters.getPivotName(newPivotId);
|
|
58042
|
-
this.dispatch("CREATE_SHEET", {
|
|
58115
|
+
const result = this.dispatch("CREATE_SHEET", {
|
|
58043
58116
|
sheetId: newSheetId,
|
|
58044
58117
|
name: this.getPivotDuplicateSheetName(_t("%(newPivotName)s (Pivot #%(formulaId)s)", {
|
|
58045
58118
|
newPivotName,
|
|
@@ -58047,20 +58120,23 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
58047
58120
|
})),
|
|
58048
58121
|
position,
|
|
58049
58122
|
});
|
|
58050
|
-
|
|
58051
|
-
|
|
58052
|
-
|
|
58053
|
-
|
|
58054
|
-
|
|
58055
|
-
|
|
58056
|
-
|
|
58123
|
+
if (result.isSuccessful) {
|
|
58124
|
+
this.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: newSheetId });
|
|
58125
|
+
this.dispatch("UPDATE_CELL", {
|
|
58126
|
+
sheetId: newSheetId,
|
|
58127
|
+
col: 0,
|
|
58128
|
+
row: 0,
|
|
58129
|
+
content: `=PIVOT(${formulaId})`,
|
|
58130
|
+
});
|
|
58131
|
+
}
|
|
58057
58132
|
}
|
|
58058
58133
|
getPivotDuplicateSheetName(pivotName) {
|
|
58059
58134
|
let i = 1;
|
|
58060
58135
|
const names = this.getters.getSheetIds().map((id) => this.getters.getSheetName(id));
|
|
58061
|
-
|
|
58136
|
+
const sanitizedName = pivotName.replace(new RegExp(FORBIDDEN_IN_EXCEL_REGEX, "g"), " ");
|
|
58137
|
+
let name = sanitizedName;
|
|
58062
58138
|
while (names.includes(name)) {
|
|
58063
|
-
name = `${
|
|
58139
|
+
name = `${sanitizedName} (${i})`;
|
|
58064
58140
|
i++;
|
|
58065
58141
|
}
|
|
58066
58142
|
return name;
|
|
@@ -58641,9 +58717,12 @@ const invalidateTableStyleCommands = [
|
|
|
58641
58717
|
"HIDE_COLUMNS_ROWS",
|
|
58642
58718
|
"UNHIDE_COLUMNS_ROWS",
|
|
58643
58719
|
"UNFOLD_HEADER_GROUP",
|
|
58720
|
+
"UNGROUP_HEADERS",
|
|
58644
58721
|
"FOLD_HEADER_GROUP",
|
|
58645
58722
|
"FOLD_ALL_HEADER_GROUPS",
|
|
58646
58723
|
"UNFOLD_ALL_HEADER_GROUPS",
|
|
58724
|
+
"FOLD_HEADER_GROUPS_IN_ZONE",
|
|
58725
|
+
"UNFOLD_HEADER_GROUPS_IN_ZONE",
|
|
58647
58726
|
"CREATE_TABLE",
|
|
58648
58727
|
"UPDATE_TABLE",
|
|
58649
58728
|
"UPDATE_FILTER",
|
|
@@ -59959,6 +60038,8 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
59959
60038
|
case "UNFOLD_HEADER_GROUP":
|
|
59960
60039
|
case "FOLD_ALL_HEADER_GROUPS":
|
|
59961
60040
|
case "UNFOLD_ALL_HEADER_GROUPS":
|
|
60041
|
+
case "FOLD_HEADER_GROUPS_IN_ZONE":
|
|
60042
|
+
case "UNFOLD_HEADER_GROUPS_IN_ZONE":
|
|
59962
60043
|
this.updateHiddenRows(cmd.sheetId);
|
|
59963
60044
|
break;
|
|
59964
60045
|
case "UPDATE_FILTER":
|
|
@@ -65905,7 +65986,9 @@ class StateObserver {
|
|
|
65905
65986
|
* The value does not matter, it can be hardcoded.
|
|
65906
65987
|
*/
|
|
65907
65988
|
const catAxId = 17781237;
|
|
65989
|
+
const secondaryCatAxId = 17781238;
|
|
65908
65990
|
const valAxId = 88853993;
|
|
65991
|
+
const secondaryValAxId = 88853994;
|
|
65909
65992
|
function createChart(chart, chartSheetIndex, data) {
|
|
65910
65993
|
const namespaces = [
|
|
65911
65994
|
["xmlns:r", RELATIONSHIP_NSR],
|
|
@@ -66221,8 +66304,8 @@ function addComboChart(chart) {
|
|
|
66221
66304
|
<!-- each data marker in the series does not have a different color -->
|
|
66222
66305
|
<c:varyColors val="0"/>
|
|
66223
66306
|
${barDataSetNode}
|
|
66224
|
-
<c:axId val="${
|
|
66225
|
-
<c:axId val="${
|
|
66307
|
+
<c:axId val="${useRightAxisForBarSerie ? secondaryCatAxId : catAxId}" />
|
|
66308
|
+
<c:axId val="${useRightAxisForBarSerie ? secondaryValAxId : valAxId}" />
|
|
66226
66309
|
</c:barChart>
|
|
66227
66310
|
${leftDataSetsNodes.length
|
|
66228
66311
|
? escapeXml /*xml*/ `
|
|
@@ -66243,21 +66326,21 @@ function addComboChart(chart) {
|
|
|
66243
66326
|
<!-- each data marker in the series does not have a different color -->
|
|
66244
66327
|
<c:varyColors val="0"/>
|
|
66245
66328
|
${joinXmlNodes(rightDataSetsNodes)}
|
|
66246
|
-
<c:axId val="${
|
|
66247
|
-
<c:axId val="${
|
|
66329
|
+
<c:axId val="${secondaryCatAxId}" />
|
|
66330
|
+
<c:axId val="${secondaryValAxId}" />
|
|
66248
66331
|
</c:lineChart>
|
|
66249
66332
|
`
|
|
66250
66333
|
: ""}
|
|
66251
66334
|
${!useRightAxisForBarSerie || leftDataSetsNodes.length
|
|
66252
66335
|
? escapeXml /*xml*/ `
|
|
66253
|
-
${addAx("b", "c:catAx", catAxId
|
|
66254
|
-
${addAx("
|
|
66336
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
66337
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
66255
66338
|
`
|
|
66256
66339
|
: ""}
|
|
66257
66340
|
${useRightAxisForBarSerie || rightDataSetsNodes.length
|
|
66258
66341
|
? escapeXml /*xml*/ `
|
|
66259
|
-
${addAx("b", "c:catAx",
|
|
66260
|
-
${addAx("
|
|
66342
|
+
${addAx("b", "c:catAx", secondaryCatAxId, secondaryValAxId, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length || !useRightAxisForBarSerie ? 1 : 0)}
|
|
66343
|
+
${addAx("r", "c:valAx", secondaryValAxId, secondaryCatAxId, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
66261
66344
|
`
|
|
66262
66345
|
: ""}
|
|
66263
66346
|
`;
|
|
@@ -67278,6 +67361,15 @@ function addTableColumns(table, sheetData) {
|
|
|
67278
67361
|
["id", i + 1], // id cannot be 0
|
|
67279
67362
|
["name", colName],
|
|
67280
67363
|
];
|
|
67364
|
+
if (table.config.totalRow) {
|
|
67365
|
+
// Note: To be 100% complete, we could also add a `totalsRowLabel` attribute for total strings, and a tag
|
|
67366
|
+
// `<totalsRowFormula>` for the formula of the total. But those doesn't seem to be mandatory for Excel.
|
|
67367
|
+
const colTotalXc = toXC(tableZone.left + i, tableZone.bottom);
|
|
67368
|
+
const colTotalContent = sheetData.cells[colTotalXc]?.content;
|
|
67369
|
+
if (colTotalContent?.startsWith("=")) {
|
|
67370
|
+
colAttributes.push(["totalsRowFunction", "custom"]);
|
|
67371
|
+
}
|
|
67372
|
+
}
|
|
67281
67373
|
columns.push(escapeXml /*xml*/ `<tableColumn ${formatAttributes(colAttributes)}/>`);
|
|
67282
67374
|
}
|
|
67283
67375
|
return escapeXml /*xml*/ `
|
|
@@ -67372,8 +67464,9 @@ function addRows(construct, data, sheet) {
|
|
|
67372
67464
|
}
|
|
67373
67465
|
else if (cell.content && cell.content !== "") {
|
|
67374
67466
|
const isTableHeader = isCellTableHeader(c, r, sheet);
|
|
67467
|
+
const isTableTotal = isCellTableTotal(c, r, sheet);
|
|
67375
67468
|
const isPlainText = !!(cell.format && data.formats[cell.format] === PLAIN_TEXT_FORMAT);
|
|
67376
|
-
({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader || isPlainText));
|
|
67469
|
+
({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader || isTableTotal || isPlainText));
|
|
67377
67470
|
}
|
|
67378
67471
|
attributes.push(...additionalAttrs);
|
|
67379
67472
|
// prettier-ignore
|
|
@@ -67407,6 +67500,16 @@ function isCellTableHeader(col, row, sheet) {
|
|
|
67407
67500
|
return isInside(col, row, headerZone);
|
|
67408
67501
|
});
|
|
67409
67502
|
}
|
|
67503
|
+
function isCellTableTotal(col, row, sheet) {
|
|
67504
|
+
return sheet.tables.some((table) => {
|
|
67505
|
+
if (!table.config.totalRow) {
|
|
67506
|
+
return false;
|
|
67507
|
+
}
|
|
67508
|
+
const zone = toZone(table.range);
|
|
67509
|
+
const totalZone = { ...zone, top: zone.bottom };
|
|
67510
|
+
return isInside(col, row, totalZone);
|
|
67511
|
+
});
|
|
67512
|
+
}
|
|
67410
67513
|
function addHyperlinks(construct, data, sheetIndex) {
|
|
67411
67514
|
const sheet = data.sheets[sheetIndex];
|
|
67412
67515
|
const cells = sheet.cells;
|
|
@@ -67858,7 +67961,7 @@ class Model extends EventBus {
|
|
|
67858
67961
|
coreHandlers = [];
|
|
67859
67962
|
constructor(data = {}, config = {}, stateUpdateMessages = [], uuidGenerator = new UuidGenerator(), verboseImport = true) {
|
|
67860
67963
|
const start = performance.now();
|
|
67861
|
-
console.
|
|
67964
|
+
console.debug("##### Model creation #####");
|
|
67862
67965
|
super();
|
|
67863
67966
|
setDefaultTranslationMethod();
|
|
67864
67967
|
stateUpdateMessages = repairInitialMessages(data, stateUpdateMessages);
|
|
@@ -67885,7 +67988,6 @@ class Model extends EventBus {
|
|
|
67885
67988
|
isReadonly: () => this.config.mode === "readonly" || this.config.mode === "dashboard",
|
|
67886
67989
|
isDashboard: () => this.config.mode === "dashboard",
|
|
67887
67990
|
};
|
|
67888
|
-
this.uuidGenerator.setIsFastStrategy(true);
|
|
67889
67991
|
// Initiate stream processor
|
|
67890
67992
|
this.selection = new SelectionStreamProcessorImpl(this.getters);
|
|
67891
67993
|
this.coreHandlers.push(this.range);
|
|
@@ -67931,16 +68033,16 @@ class Model extends EventBus {
|
|
|
67931
68033
|
this.joinSession();
|
|
67932
68034
|
if (config.snapshotRequested) {
|
|
67933
68035
|
const startSnapshot = performance.now();
|
|
67934
|
-
console.
|
|
68036
|
+
console.debug("Snapshot requested");
|
|
67935
68037
|
this.session.snapshot(this.exportData());
|
|
67936
68038
|
this.garbageCollectExternalResources();
|
|
67937
|
-
console.
|
|
68039
|
+
console.debug("Snapshot taken in", performance.now() - startSnapshot, "ms");
|
|
67938
68040
|
}
|
|
67939
68041
|
// mark all models as "raw", so they will not be turned into reactive objects
|
|
67940
68042
|
// by owl, since we do not rely on reactivity
|
|
67941
68043
|
owl.markRaw(this);
|
|
67942
|
-
console.
|
|
67943
|
-
console.
|
|
68044
|
+
console.debug("Model created in", performance.now() - start, "ms");
|
|
68045
|
+
console.debug("######");
|
|
67944
68046
|
}
|
|
67945
68047
|
joinSession() {
|
|
67946
68048
|
this.session.join(this.config.client);
|
|
@@ -68163,7 +68265,7 @@ class Model extends EventBus {
|
|
|
68163
68265
|
this.finalize();
|
|
68164
68266
|
const time = performance.now() - start;
|
|
68165
68267
|
if (time > 5) {
|
|
68166
|
-
console.
|
|
68268
|
+
console.debug(type, time, "ms");
|
|
68167
68269
|
}
|
|
68168
68270
|
});
|
|
68169
68271
|
this.session.save(command, commands, changes);
|
|
@@ -68549,6 +68651,6 @@ exports.tokenColors = tokenColors;
|
|
|
68549
68651
|
exports.tokenize = tokenize;
|
|
68550
68652
|
|
|
68551
68653
|
|
|
68552
|
-
__info__.version = "17.4.
|
|
68553
|
-
__info__.date = "2024-
|
|
68554
|
-
__info__.hash = "
|
|
68654
|
+
__info__.version = "17.4.10";
|
|
68655
|
+
__info__.date = "2024-10-24T08:54:56.262Z";
|
|
68656
|
+
__info__.hash = "c82d9c1";
|