@odoo/o-spreadsheet 17.4.7 → 17.4.9
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 +225 -160
- package/dist/o-spreadsheet.d.ts +6 -0
- package/dist/o-spreadsheet.esm.js +225 -160
- package/dist/o-spreadsheet.iife.js +225 -160
- package/dist/o-spreadsheet.iife.min.js +265 -265
- 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.9
|
|
6
|
+
* @date 2024-10-14T07:53:51.633Z
|
|
7
|
+
* @hash b7015b7
|
|
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) {
|
|
@@ -19156,9 +19163,10 @@ const PIVOT_VALUE = {
|
|
|
19156
19163
|
return error;
|
|
19157
19164
|
}
|
|
19158
19165
|
if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
|
|
19166
|
+
const suggestion = _t("Consider using a dynamic pivot formula: %s. Or re-insert the static pivot from the Data menu.", `=PIVOT(${_pivotFormulaId})`);
|
|
19159
19167
|
return {
|
|
19160
19168
|
value: CellErrorType.GenericError,
|
|
19161
|
-
message: _t("Dimensions don't match the pivot definition"),
|
|
19169
|
+
message: _t("Dimensions don't match the pivot definition") + ". " + suggestion,
|
|
19162
19170
|
};
|
|
19163
19171
|
}
|
|
19164
19172
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
@@ -19185,9 +19193,10 @@ const PIVOT_HEADER = {
|
|
|
19185
19193
|
return error;
|
|
19186
19194
|
}
|
|
19187
19195
|
if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
|
|
19196
|
+
const suggestion = _t("Consider using a dynamic pivot formula: %s. Or re-insert the static pivot from the Data menu.", `=PIVOT(${_pivotFormulaId})`);
|
|
19188
19197
|
return {
|
|
19189
19198
|
value: CellErrorType.GenericError,
|
|
19190
|
-
message: _t("Dimensions don't match the pivot definition"),
|
|
19199
|
+
message: _t("Dimensions don't match the pivot definition") + ". " + suggestion,
|
|
19191
19200
|
};
|
|
19192
19201
|
}
|
|
19193
19202
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
@@ -22363,6 +22372,7 @@ function insertTokenAfterArgSeparator(tokenAtCursor, value) {
|
|
|
22363
22372
|
// replace the whole token
|
|
22364
22373
|
start = tokenAtCursor.start;
|
|
22365
22374
|
}
|
|
22375
|
+
this.composer.stopComposerRangeSelection();
|
|
22366
22376
|
this.composer.changeComposerCursorSelection(start, end);
|
|
22367
22377
|
this.composer.replaceComposerCursorSelection(value);
|
|
22368
22378
|
}
|
|
@@ -22380,6 +22390,7 @@ function insertTokenAfterLeftParenthesis(tokenAtCursor, value) {
|
|
|
22380
22390
|
// replace the whole token
|
|
22381
22391
|
start = tokenAtCursor.start;
|
|
22382
22392
|
}
|
|
22393
|
+
this.composer.stopComposerRangeSelection();
|
|
22383
22394
|
this.composer.changeComposerCursorSelection(start, end);
|
|
22384
22395
|
this.composer.replaceComposerCursorSelection(value);
|
|
22385
22396
|
}
|
|
@@ -28410,6 +28421,7 @@ const REINSERT_DYNAMIC_PIVOT_CHILDREN = (env) => env.model.getters.getPivotIds()
|
|
|
28410
28421
|
});
|
|
28411
28422
|
env.model.dispatch("REFRESH_PIVOT", { id: pivotId });
|
|
28412
28423
|
},
|
|
28424
|
+
isVisible: (env) => env.model.getters.getPivot(pivotId).isValid(),
|
|
28413
28425
|
}));
|
|
28414
28426
|
const REINSERT_STATIC_PIVOT_CHILDREN = (env) => env.model.getters.getPivotIds().map((pivotId, index) => ({
|
|
28415
28427
|
id: `reinsert_static_pivot_${env.model.getters.getPivotFormulaId(pivotId)}`,
|
|
@@ -28428,6 +28440,7 @@ const REINSERT_STATIC_PIVOT_CHILDREN = (env) => env.model.getters.getPivotIds().
|
|
|
28428
28440
|
});
|
|
28429
28441
|
env.model.dispatch("REFRESH_PIVOT", { id: pivotId });
|
|
28430
28442
|
},
|
|
28443
|
+
isVisible: (env) => env.model.getters.getPivot(pivotId).isValid(),
|
|
28431
28444
|
}));
|
|
28432
28445
|
//------------------------------------------------------------------------------
|
|
28433
28446
|
// Image
|
|
@@ -29299,7 +29312,7 @@ const reinsertDynamicPivotMenu = {
|
|
|
29299
29312
|
sequence: 1020,
|
|
29300
29313
|
icon: "o-spreadsheet-Icon.INSERT_PIVOT",
|
|
29301
29314
|
children: [REINSERT_DYNAMIC_PIVOT_CHILDREN],
|
|
29302
|
-
isVisible: (env) => env.model.getters.getPivotIds().
|
|
29315
|
+
isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
|
|
29303
29316
|
};
|
|
29304
29317
|
const reinsertStaticPivotMenu = {
|
|
29305
29318
|
id: "reinsert_static_pivot",
|
|
@@ -29307,7 +29320,7 @@ const reinsertStaticPivotMenu = {
|
|
|
29307
29320
|
sequence: 1020,
|
|
29308
29321
|
icon: "o-spreadsheet-Icon.INSERT_PIVOT",
|
|
29309
29322
|
children: [REINSERT_STATIC_PIVOT_CHILDREN],
|
|
29310
|
-
isVisible: (env) => env.model.getters.getPivotIds().
|
|
29323
|
+
isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
|
|
29311
29324
|
};
|
|
29312
29325
|
|
|
29313
29326
|
var ACTION_DATA = /*#__PURE__*/Object.freeze({
|
|
@@ -37193,6 +37206,8 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
37193
37206
|
mutators = ["reset", "deferUpdates", "applyUpdate", "discardPendingUpdate", "update"];
|
|
37194
37207
|
updatesAreDeferred = false;
|
|
37195
37208
|
draft = null;
|
|
37209
|
+
notification = this.get(NotificationStore);
|
|
37210
|
+
alreadyNotified = false;
|
|
37196
37211
|
constructor(get, pivotId) {
|
|
37197
37212
|
super(get);
|
|
37198
37213
|
this.pivotId = pivotId;
|
|
@@ -37299,6 +37314,16 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
37299
37314
|
pivot: this.draft,
|
|
37300
37315
|
});
|
|
37301
37316
|
this.draft = null;
|
|
37317
|
+
if (!this.alreadyNotified && !this.isDynamicPivotInViewport()) {
|
|
37318
|
+
const formulaId = this.getters.getPivotFormulaId(this.pivotId);
|
|
37319
|
+
const pivotExample = `=PIVOT(${formulaId})`;
|
|
37320
|
+
this.alreadyNotified = true;
|
|
37321
|
+
this.notification.notifyUser({
|
|
37322
|
+
type: "info",
|
|
37323
|
+
text: _t("Pivot updates only work with dynamic pivot tables. Use %s or re-insert the static pivot from the Data menu.", pivotExample),
|
|
37324
|
+
sticky: false,
|
|
37325
|
+
});
|
|
37326
|
+
}
|
|
37302
37327
|
}
|
|
37303
37328
|
}
|
|
37304
37329
|
discardPendingUpdate() {
|
|
@@ -37329,15 +37354,22 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
37329
37354
|
return;
|
|
37330
37355
|
}
|
|
37331
37356
|
const cleanedWithGranularity = this.addDefaultDateTimeGranularity(this.fields, cleanedDefinition);
|
|
37332
|
-
|
|
37333
|
-
|
|
37357
|
+
this.draft = cleanedWithGranularity;
|
|
37358
|
+
if (!this.updatesAreDeferred) {
|
|
37359
|
+
this.applyUpdate();
|
|
37334
37360
|
}
|
|
37335
|
-
|
|
37336
|
-
|
|
37337
|
-
|
|
37338
|
-
|
|
37339
|
-
|
|
37361
|
+
}
|
|
37362
|
+
isDynamicPivotInViewport() {
|
|
37363
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
37364
|
+
for (const col of this.getters.getSheetViewVisibleCols()) {
|
|
37365
|
+
for (const row of this.getters.getSheetViewVisibleRows()) {
|
|
37366
|
+
const isDynamicPivot = this.getters.isSpillPivotFormula({ sheetId, col, row });
|
|
37367
|
+
if (isDynamicPivot) {
|
|
37368
|
+
return true;
|
|
37369
|
+
}
|
|
37370
|
+
}
|
|
37340
37371
|
}
|
|
37372
|
+
return false;
|
|
37341
37373
|
}
|
|
37342
37374
|
addDefaultDateTimeGranularity(fields, definition) {
|
|
37343
37375
|
const { columns, rows } = definition;
|
|
@@ -52428,7 +52460,7 @@ class PivotCorePlugin extends CorePlugin {
|
|
|
52428
52460
|
case "DUPLICATE_PIVOT": {
|
|
52429
52461
|
const { pivotId, newPivotId } = cmd;
|
|
52430
52462
|
const pivot = deepCopy(this.getPivotCore(pivotId).definition);
|
|
52431
|
-
pivot.name =
|
|
52463
|
+
pivot.name = cmd.duplicatedPivotName ?? pivot.name + " (copy)";
|
|
52432
52464
|
this.addPivot(newPivotId, pivot);
|
|
52433
52465
|
break;
|
|
52434
52466
|
}
|
|
@@ -57517,6 +57549,7 @@ class Session extends EventBus {
|
|
|
57517
57549
|
case "REMOTE_REVISION":
|
|
57518
57550
|
case "REVISION_REDONE":
|
|
57519
57551
|
case "REVISION_UNDONE":
|
|
57552
|
+
case "SNAPSHOT_CREATED":
|
|
57520
57553
|
return this.processedRevisions.has(message.nextRevisionId);
|
|
57521
57554
|
default:
|
|
57522
57555
|
return false;
|
|
@@ -58032,12 +58065,13 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
58032
58065
|
this.dispatch("DUPLICATE_PIVOT", {
|
|
58033
58066
|
pivotId,
|
|
58034
58067
|
newPivotId,
|
|
58068
|
+
duplicatedPivotName: _t("%s (copy)", this.getters.getPivotCoreDefinition(pivotId).name),
|
|
58035
58069
|
});
|
|
58036
58070
|
const activeSheetId = this.getters.getActiveSheetId();
|
|
58037
58071
|
const position = this.getters.getSheetIds().indexOf(activeSheetId) + 1;
|
|
58038
58072
|
const formulaId = this.getters.getPivotFormulaId(newPivotId);
|
|
58039
58073
|
const newPivotName = this.getters.getPivotName(newPivotId);
|
|
58040
|
-
this.dispatch("CREATE_SHEET", {
|
|
58074
|
+
const result = this.dispatch("CREATE_SHEET", {
|
|
58041
58075
|
sheetId: newSheetId,
|
|
58042
58076
|
name: this.getPivotDuplicateSheetName(_t("%(newPivotName)s (Pivot #%(formulaId)s)", {
|
|
58043
58077
|
newPivotName,
|
|
@@ -58045,20 +58079,23 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
58045
58079
|
})),
|
|
58046
58080
|
position,
|
|
58047
58081
|
});
|
|
58048
|
-
|
|
58049
|
-
|
|
58050
|
-
|
|
58051
|
-
|
|
58052
|
-
|
|
58053
|
-
|
|
58054
|
-
|
|
58082
|
+
if (result.isSuccessful) {
|
|
58083
|
+
this.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: newSheetId });
|
|
58084
|
+
this.dispatch("UPDATE_CELL", {
|
|
58085
|
+
sheetId: newSheetId,
|
|
58086
|
+
col: 0,
|
|
58087
|
+
row: 0,
|
|
58088
|
+
content: `=PIVOT(${formulaId})`,
|
|
58089
|
+
});
|
|
58090
|
+
}
|
|
58055
58091
|
}
|
|
58056
58092
|
getPivotDuplicateSheetName(pivotName) {
|
|
58057
58093
|
let i = 1;
|
|
58058
58094
|
const names = this.getters.getSheetIds().map((id) => this.getters.getSheetName(id));
|
|
58059
|
-
|
|
58095
|
+
const sanitizedName = pivotName.replace(new RegExp(FORBIDDEN_IN_EXCEL_REGEX, "g"), " ");
|
|
58096
|
+
let name = sanitizedName;
|
|
58060
58097
|
while (names.includes(name)) {
|
|
58061
|
-
name = `${
|
|
58098
|
+
name = `${sanitizedName} (${i})`;
|
|
58062
58099
|
i++;
|
|
58063
58100
|
}
|
|
58064
58101
|
return name;
|
|
@@ -58639,9 +58676,12 @@ const invalidateTableStyleCommands = [
|
|
|
58639
58676
|
"HIDE_COLUMNS_ROWS",
|
|
58640
58677
|
"UNHIDE_COLUMNS_ROWS",
|
|
58641
58678
|
"UNFOLD_HEADER_GROUP",
|
|
58679
|
+
"UNGROUP_HEADERS",
|
|
58642
58680
|
"FOLD_HEADER_GROUP",
|
|
58643
58681
|
"FOLD_ALL_HEADER_GROUPS",
|
|
58644
58682
|
"UNFOLD_ALL_HEADER_GROUPS",
|
|
58683
|
+
"FOLD_HEADER_GROUPS_IN_ZONE",
|
|
58684
|
+
"UNFOLD_HEADER_GROUPS_IN_ZONE",
|
|
58645
58685
|
"CREATE_TABLE",
|
|
58646
58686
|
"UPDATE_TABLE",
|
|
58647
58687
|
"UPDATE_FILTER",
|
|
@@ -58662,6 +58702,7 @@ class CellComputedStylePlugin extends UIPlugin {
|
|
|
58662
58702
|
handle(cmd) {
|
|
58663
58703
|
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
58664
58704
|
cmd.type === "UPDATE_CELL" ||
|
|
58705
|
+
cmd.type === "SET_FORMATTING" ||
|
|
58665
58706
|
cmd.type === "EVALUATE_CELLS") {
|
|
58666
58707
|
this.styles = {};
|
|
58667
58708
|
this.borders = {};
|
|
@@ -59956,6 +59997,8 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
59956
59997
|
case "UNFOLD_HEADER_GROUP":
|
|
59957
59998
|
case "FOLD_ALL_HEADER_GROUPS":
|
|
59958
59999
|
case "UNFOLD_ALL_HEADER_GROUPS":
|
|
60000
|
+
case "FOLD_HEADER_GROUPS_IN_ZONE":
|
|
60001
|
+
case "UNFOLD_HEADER_GROUPS_IN_ZONE":
|
|
59959
60002
|
this.updateHiddenRows(cmd.sheetId);
|
|
59960
60003
|
break;
|
|
59961
60004
|
case "UPDATE_FILTER":
|
|
@@ -65902,7 +65945,9 @@ class StateObserver {
|
|
|
65902
65945
|
* The value does not matter, it can be hardcoded.
|
|
65903
65946
|
*/
|
|
65904
65947
|
const catAxId = 17781237;
|
|
65948
|
+
const secondaryCatAxId = 17781238;
|
|
65905
65949
|
const valAxId = 88853993;
|
|
65950
|
+
const secondaryValAxId = 88853994;
|
|
65906
65951
|
function createChart(chart, chartSheetIndex, data) {
|
|
65907
65952
|
const namespaces = [
|
|
65908
65953
|
["xmlns:r", RELATIONSHIP_NSR],
|
|
@@ -66218,8 +66263,8 @@ function addComboChart(chart) {
|
|
|
66218
66263
|
<!-- each data marker in the series does not have a different color -->
|
|
66219
66264
|
<c:varyColors val="0"/>
|
|
66220
66265
|
${barDataSetNode}
|
|
66221
|
-
<c:axId val="${
|
|
66222
|
-
<c:axId val="${
|
|
66266
|
+
<c:axId val="${useRightAxisForBarSerie ? secondaryCatAxId : catAxId}" />
|
|
66267
|
+
<c:axId val="${useRightAxisForBarSerie ? secondaryValAxId : valAxId}" />
|
|
66223
66268
|
</c:barChart>
|
|
66224
66269
|
${leftDataSetsNodes.length
|
|
66225
66270
|
? escapeXml /*xml*/ `
|
|
@@ -66240,21 +66285,21 @@ function addComboChart(chart) {
|
|
|
66240
66285
|
<!-- each data marker in the series does not have a different color -->
|
|
66241
66286
|
<c:varyColors val="0"/>
|
|
66242
66287
|
${joinXmlNodes(rightDataSetsNodes)}
|
|
66243
|
-
<c:axId val="${
|
|
66244
|
-
<c:axId val="${
|
|
66288
|
+
<c:axId val="${secondaryCatAxId}" />
|
|
66289
|
+
<c:axId val="${secondaryValAxId}" />
|
|
66245
66290
|
</c:lineChart>
|
|
66246
66291
|
`
|
|
66247
66292
|
: ""}
|
|
66248
66293
|
${!useRightAxisForBarSerie || leftDataSetsNodes.length
|
|
66249
66294
|
? escapeXml /*xml*/ `
|
|
66250
|
-
${addAx("b", "c:catAx", catAxId
|
|
66251
|
-
${addAx("
|
|
66295
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
66296
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
66252
66297
|
`
|
|
66253
66298
|
: ""}
|
|
66254
66299
|
${useRightAxisForBarSerie || rightDataSetsNodes.length
|
|
66255
66300
|
? escapeXml /*xml*/ `
|
|
66256
|
-
${addAx("b", "c:catAx",
|
|
66257
|
-
${addAx("
|
|
66301
|
+
${addAx("b", "c:catAx", secondaryCatAxId, secondaryValAxId, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length || !useRightAxisForBarSerie ? 1 : 0)}
|
|
66302
|
+
${addAx("r", "c:valAx", secondaryValAxId, secondaryCatAxId, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
66258
66303
|
`
|
|
66259
66304
|
: ""}
|
|
66260
66305
|
`;
|
|
@@ -67275,6 +67320,15 @@ function addTableColumns(table, sheetData) {
|
|
|
67275
67320
|
["id", i + 1], // id cannot be 0
|
|
67276
67321
|
["name", colName],
|
|
67277
67322
|
];
|
|
67323
|
+
if (table.config.totalRow) {
|
|
67324
|
+
// Note: To be 100% complete, we could also add a `totalsRowLabel` attribute for total strings, and a tag
|
|
67325
|
+
// `<totalsRowFormula>` for the formula of the total. But those doesn't seem to be mandatory for Excel.
|
|
67326
|
+
const colTotalXc = toXC(tableZone.left + i, tableZone.bottom);
|
|
67327
|
+
const colTotalContent = sheetData.cells[colTotalXc]?.content;
|
|
67328
|
+
if (colTotalContent?.startsWith("=")) {
|
|
67329
|
+
colAttributes.push(["totalsRowFunction", "custom"]);
|
|
67330
|
+
}
|
|
67331
|
+
}
|
|
67278
67332
|
columns.push(escapeXml /*xml*/ `<tableColumn ${formatAttributes(colAttributes)}/>`);
|
|
67279
67333
|
}
|
|
67280
67334
|
return escapeXml /*xml*/ `
|
|
@@ -67369,8 +67423,9 @@ function addRows(construct, data, sheet) {
|
|
|
67369
67423
|
}
|
|
67370
67424
|
else if (cell.content && cell.content !== "") {
|
|
67371
67425
|
const isTableHeader = isCellTableHeader(c, r, sheet);
|
|
67426
|
+
const isTableTotal = isCellTableTotal(c, r, sheet);
|
|
67372
67427
|
const isPlainText = !!(cell.format && data.formats[cell.format] === PLAIN_TEXT_FORMAT);
|
|
67373
|
-
({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader || isPlainText));
|
|
67428
|
+
({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader || isTableTotal || isPlainText));
|
|
67374
67429
|
}
|
|
67375
67430
|
attributes.push(...additionalAttrs);
|
|
67376
67431
|
// prettier-ignore
|
|
@@ -67404,6 +67459,16 @@ function isCellTableHeader(col, row, sheet) {
|
|
|
67404
67459
|
return isInside(col, row, headerZone);
|
|
67405
67460
|
});
|
|
67406
67461
|
}
|
|
67462
|
+
function isCellTableTotal(col, row, sheet) {
|
|
67463
|
+
return sheet.tables.some((table) => {
|
|
67464
|
+
if (!table.config.totalRow) {
|
|
67465
|
+
return false;
|
|
67466
|
+
}
|
|
67467
|
+
const zone = toZone(table.range);
|
|
67468
|
+
const totalZone = { ...zone, top: zone.bottom };
|
|
67469
|
+
return isInside(col, row, totalZone);
|
|
67470
|
+
});
|
|
67471
|
+
}
|
|
67407
67472
|
function addHyperlinks(construct, data, sheetIndex) {
|
|
67408
67473
|
const sheet = data.sheets[sheetIndex];
|
|
67409
67474
|
const cells = sheet.cells;
|
|
@@ -67882,7 +67947,6 @@ class Model extends EventBus {
|
|
|
67882
67947
|
isReadonly: () => this.config.mode === "readonly" || this.config.mode === "dashboard",
|
|
67883
67948
|
isDashboard: () => this.config.mode === "dashboard",
|
|
67884
67949
|
};
|
|
67885
|
-
this.uuidGenerator.setIsFastStrategy(true);
|
|
67886
67950
|
// Initiate stream processor
|
|
67887
67951
|
this.selection = new SelectionStreamProcessorImpl(this.getters);
|
|
67888
67952
|
this.coreHandlers.push(this.range);
|
|
@@ -68415,6 +68479,7 @@ const helpers = {
|
|
|
68415
68479
|
UNDO_REDO_PIVOT_COMMANDS,
|
|
68416
68480
|
createPivotFormula,
|
|
68417
68481
|
areDomainArgsFieldsValid,
|
|
68482
|
+
formatTickValue,
|
|
68418
68483
|
};
|
|
68419
68484
|
const links = {
|
|
68420
68485
|
isMarkdownLink,
|
|
@@ -68545,6 +68610,6 @@ exports.tokenColors = tokenColors;
|
|
|
68545
68610
|
exports.tokenize = tokenize;
|
|
68546
68611
|
|
|
68547
68612
|
|
|
68548
|
-
__info__.version = "17.4.
|
|
68549
|
-
__info__.date = "2024-
|
|
68550
|
-
__info__.hash = "
|
|
68613
|
+
__info__.version = "17.4.9";
|
|
68614
|
+
__info__.date = "2024-10-14T07:53:51.633Z";
|
|
68615
|
+
__info__.hash = "b7015b7";
|
package/dist/o-spreadsheet.d.ts
CHANGED
|
@@ -1011,6 +1011,7 @@ interface DuplicatePivotCommand {
|
|
|
1011
1011
|
type: "DUPLICATE_PIVOT";
|
|
1012
1012
|
pivotId: UID;
|
|
1013
1013
|
newPivotId: string;
|
|
1014
|
+
duplicatedPivotName?: string;
|
|
1014
1015
|
}
|
|
1015
1016
|
interface RemoveDuplicatesCommand {
|
|
1016
1017
|
type: "REMOVE_DUPLICATES";
|
|
@@ -9374,6 +9375,8 @@ declare class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
9374
9375
|
mutators: readonly ["reset", "deferUpdates", "applyUpdate", "discardPendingUpdate", "update"];
|
|
9375
9376
|
private updatesAreDeferred;
|
|
9376
9377
|
private draft;
|
|
9378
|
+
private notification;
|
|
9379
|
+
private alreadyNotified;
|
|
9377
9380
|
constructor(get: Get, pivotId: UID);
|
|
9378
9381
|
handle(cmd: Command): void;
|
|
9379
9382
|
get fields(): PivotFields;
|
|
@@ -9389,6 +9392,7 @@ declare class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
9389
9392
|
applyUpdate(): void;
|
|
9390
9393
|
discardPendingUpdate(): void;
|
|
9391
9394
|
update(definitionUpdate: Partial<PivotCoreDefinition>): void;
|
|
9395
|
+
private isDynamicPivotInViewport;
|
|
9392
9396
|
private addDefaultDateTimeGranularity;
|
|
9393
9397
|
private getUnusedDateTimeGranularities;
|
|
9394
9398
|
}
|
|
@@ -9456,6 +9460,7 @@ declare function getChartAxisTitleRuntime(design?: AxisDesign): {
|
|
|
9456
9460
|
};
|
|
9457
9461
|
align: "start" | "center" | "end";
|
|
9458
9462
|
} | undefined;
|
|
9463
|
+
declare function formatTickValue(localeFormat: LocaleFormat): (value: any) => any;
|
|
9459
9464
|
|
|
9460
9465
|
/**
|
|
9461
9466
|
* Get a default chart js configuration
|
|
@@ -11514,6 +11519,7 @@ declare const helpers: {
|
|
|
11514
11519
|
UNDO_REDO_PIVOT_COMMANDS: string[];
|
|
11515
11520
|
createPivotFormula: typeof createPivotFormula;
|
|
11516
11521
|
areDomainArgsFieldsValid: typeof areDomainArgsFieldsValid;
|
|
11522
|
+
formatTickValue: typeof formatTickValue;
|
|
11517
11523
|
};
|
|
11518
11524
|
declare const links: {
|
|
11519
11525
|
isMarkdownLink: typeof isMarkdownLink;
|