@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,13 +2,118 @@
|
|
|
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
|
import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
|
|
11
11
|
|
|
12
|
+
function createActions(menuItems) {
|
|
13
|
+
return menuItems.map(createAction).sort((a, b) => a.sequence - b.sequence);
|
|
14
|
+
}
|
|
15
|
+
let nextItemId = 1;
|
|
16
|
+
function createAction(item) {
|
|
17
|
+
const name = item.name;
|
|
18
|
+
const children = item.children;
|
|
19
|
+
const description = item.description;
|
|
20
|
+
const icon = item.icon;
|
|
21
|
+
const secondaryIcon = item.secondaryIcon;
|
|
22
|
+
const itemId = item.id || nextItemId++;
|
|
23
|
+
return {
|
|
24
|
+
id: itemId.toString(),
|
|
25
|
+
name: typeof name === "function" ? name : () => name,
|
|
26
|
+
isVisible: item.isVisible ? item.isVisible : () => true,
|
|
27
|
+
isEnabled: item.isEnabled ? item.isEnabled : () => true,
|
|
28
|
+
isActive: item.isActive,
|
|
29
|
+
execute: item.execute,
|
|
30
|
+
children: children
|
|
31
|
+
? (env) => {
|
|
32
|
+
return children
|
|
33
|
+
.map((child) => (typeof child === "function" ? child(env) : child))
|
|
34
|
+
.flat()
|
|
35
|
+
.map(createAction);
|
|
36
|
+
}
|
|
37
|
+
: () => [],
|
|
38
|
+
isReadonlyAllowed: item.isReadonlyAllowed || false,
|
|
39
|
+
separator: item.separator || false,
|
|
40
|
+
icon: typeof icon === "function" ? icon : () => icon || "",
|
|
41
|
+
secondaryIcon: typeof secondaryIcon === "function" ? secondaryIcon : () => secondaryIcon || "",
|
|
42
|
+
description: typeof description === "function" ? description : () => description || "",
|
|
43
|
+
textColor: item.textColor,
|
|
44
|
+
sequence: item.sequence || 0,
|
|
45
|
+
onStartHover: item.onStartHover,
|
|
46
|
+
onStopHover: item.onStopHover,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Registry
|
|
52
|
+
*
|
|
53
|
+
* The Registry class is basically just a mapping from a string key to an object.
|
|
54
|
+
* It is really not much more than an object. It is however useful for the
|
|
55
|
+
* following reasons:
|
|
56
|
+
*
|
|
57
|
+
* 1. it let us react and execute code when someone add something to the registry
|
|
58
|
+
* (for example, the FunctionRegistry subclass this for this purpose)
|
|
59
|
+
* 2. it throws an error when the get operation fails
|
|
60
|
+
* 3. it provides a chained API to add items to the registry.
|
|
61
|
+
*/
|
|
62
|
+
class Registry {
|
|
63
|
+
content = {};
|
|
64
|
+
/**
|
|
65
|
+
* Add an item to the registry
|
|
66
|
+
*
|
|
67
|
+
* Note that this also returns the registry, so another add method call can
|
|
68
|
+
* be chained
|
|
69
|
+
*/
|
|
70
|
+
add(key, value) {
|
|
71
|
+
this.content[key] = value;
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get an item from the registry
|
|
76
|
+
*/
|
|
77
|
+
get(key) {
|
|
78
|
+
/**
|
|
79
|
+
* Note: key in {} is ~12 times slower than {}[key].
|
|
80
|
+
* So, we check the absence of key only when the direct access returns
|
|
81
|
+
* a falsy value. It's done to ensure that the registry can contains falsy values
|
|
82
|
+
*/
|
|
83
|
+
const content = this.content[key];
|
|
84
|
+
if (!content) {
|
|
85
|
+
if (!(key in this.content)) {
|
|
86
|
+
throw new Error(`Cannot find ${key} in this registry!`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return content;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Check if the key is already in the registry
|
|
93
|
+
*/
|
|
94
|
+
contains(key) {
|
|
95
|
+
return key in this.content;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get a list of all elements in the registry
|
|
99
|
+
*/
|
|
100
|
+
getAll() {
|
|
101
|
+
return Object.values(this.content);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get a list of all keys in the registry
|
|
105
|
+
*/
|
|
106
|
+
getKeys() {
|
|
107
|
+
return Object.keys(this.content);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Remove an item from the registry
|
|
111
|
+
*/
|
|
112
|
+
remove(key) {
|
|
113
|
+
delete this.content[key];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
12
117
|
const CANVAS_SHIFT = 0.5;
|
|
13
118
|
// Colors
|
|
14
119
|
const HIGHLIGHT_COLOR = "#37A850";
|
|
@@ -165,7 +270,7 @@ const DEFAULT_STYLE = {
|
|
|
165
270
|
underline: false,
|
|
166
271
|
fontSize: 10,
|
|
167
272
|
fillColor: "",
|
|
168
|
-
textColor: "
|
|
273
|
+
textColor: "",
|
|
169
274
|
};
|
|
170
275
|
const DEFAULT_VERTICAL_ALIGN = DEFAULT_STYLE.verticalAlign;
|
|
171
276
|
const DEFAULT_WRAPPING_MODE = DEFAULT_STYLE.wrapping;
|
|
@@ -5397,110 +5502,6 @@ class UuidGenerator {
|
|
|
5397
5502
|
}
|
|
5398
5503
|
}
|
|
5399
5504
|
|
|
5400
|
-
function createActions(menuItems) {
|
|
5401
|
-
return menuItems.map(createAction).sort((a, b) => a.sequence - b.sequence);
|
|
5402
|
-
}
|
|
5403
|
-
const uuidGenerator$1 = new UuidGenerator();
|
|
5404
|
-
function createAction(item) {
|
|
5405
|
-
const name = item.name;
|
|
5406
|
-
const children = item.children;
|
|
5407
|
-
const description = item.description;
|
|
5408
|
-
const icon = item.icon;
|
|
5409
|
-
const secondaryIcon = item.secondaryIcon;
|
|
5410
|
-
return {
|
|
5411
|
-
id: item.id || uuidGenerator$1.uuidv4(),
|
|
5412
|
-
name: typeof name === "function" ? name : () => name,
|
|
5413
|
-
isVisible: item.isVisible ? item.isVisible : () => true,
|
|
5414
|
-
isEnabled: item.isEnabled ? item.isEnabled : () => true,
|
|
5415
|
-
isActive: item.isActive,
|
|
5416
|
-
execute: item.execute,
|
|
5417
|
-
children: children
|
|
5418
|
-
? (env) => {
|
|
5419
|
-
return children
|
|
5420
|
-
.map((child) => (typeof child === "function" ? child(env) : child))
|
|
5421
|
-
.flat()
|
|
5422
|
-
.map(createAction);
|
|
5423
|
-
}
|
|
5424
|
-
: () => [],
|
|
5425
|
-
isReadonlyAllowed: item.isReadonlyAllowed || false,
|
|
5426
|
-
separator: item.separator || false,
|
|
5427
|
-
icon: typeof icon === "function" ? icon : () => icon || "",
|
|
5428
|
-
secondaryIcon: typeof secondaryIcon === "function" ? secondaryIcon : () => secondaryIcon || "",
|
|
5429
|
-
description: typeof description === "function" ? description : () => description || "",
|
|
5430
|
-
textColor: item.textColor,
|
|
5431
|
-
sequence: item.sequence || 0,
|
|
5432
|
-
onStartHover: item.onStartHover,
|
|
5433
|
-
onStopHover: item.onStopHover,
|
|
5434
|
-
};
|
|
5435
|
-
}
|
|
5436
|
-
|
|
5437
|
-
/**
|
|
5438
|
-
* Registry
|
|
5439
|
-
*
|
|
5440
|
-
* The Registry class is basically just a mapping from a string key to an object.
|
|
5441
|
-
* It is really not much more than an object. It is however useful for the
|
|
5442
|
-
* following reasons:
|
|
5443
|
-
*
|
|
5444
|
-
* 1. it let us react and execute code when someone add something to the registry
|
|
5445
|
-
* (for example, the FunctionRegistry subclass this for this purpose)
|
|
5446
|
-
* 2. it throws an error when the get operation fails
|
|
5447
|
-
* 3. it provides a chained API to add items to the registry.
|
|
5448
|
-
*/
|
|
5449
|
-
class Registry {
|
|
5450
|
-
content = {};
|
|
5451
|
-
/**
|
|
5452
|
-
* Add an item to the registry
|
|
5453
|
-
*
|
|
5454
|
-
* Note that this also returns the registry, so another add method call can
|
|
5455
|
-
* be chained
|
|
5456
|
-
*/
|
|
5457
|
-
add(key, value) {
|
|
5458
|
-
this.content[key] = value;
|
|
5459
|
-
return this;
|
|
5460
|
-
}
|
|
5461
|
-
/**
|
|
5462
|
-
* Get an item from the registry
|
|
5463
|
-
*/
|
|
5464
|
-
get(key) {
|
|
5465
|
-
/**
|
|
5466
|
-
* Note: key in {} is ~12 times slower than {}[key].
|
|
5467
|
-
* So, we check the absence of key only when the direct access returns
|
|
5468
|
-
* a falsy value. It's done to ensure that the registry can contains falsy values
|
|
5469
|
-
*/
|
|
5470
|
-
const content = this.content[key];
|
|
5471
|
-
if (!content) {
|
|
5472
|
-
if (!(key in this.content)) {
|
|
5473
|
-
throw new Error(`Cannot find ${key} in this registry!`);
|
|
5474
|
-
}
|
|
5475
|
-
}
|
|
5476
|
-
return content;
|
|
5477
|
-
}
|
|
5478
|
-
/**
|
|
5479
|
-
* Check if the key is already in the registry
|
|
5480
|
-
*/
|
|
5481
|
-
contains(key) {
|
|
5482
|
-
return key in this.content;
|
|
5483
|
-
}
|
|
5484
|
-
/**
|
|
5485
|
-
* Get a list of all elements in the registry
|
|
5486
|
-
*/
|
|
5487
|
-
getAll() {
|
|
5488
|
-
return Object.values(this.content);
|
|
5489
|
-
}
|
|
5490
|
-
/**
|
|
5491
|
-
* Get a list of all keys in the registry
|
|
5492
|
-
*/
|
|
5493
|
-
getKeys() {
|
|
5494
|
-
return Object.keys(this.content);
|
|
5495
|
-
}
|
|
5496
|
-
/**
|
|
5497
|
-
* Remove an item from the registry
|
|
5498
|
-
*/
|
|
5499
|
-
remove(key) {
|
|
5500
|
-
delete this.content[key];
|
|
5501
|
-
}
|
|
5502
|
-
}
|
|
5503
|
-
|
|
5504
5505
|
function getClipboardDataPositions(sheetId, zones) {
|
|
5505
5506
|
const lefts = new Set(zones.map((z) => z.left));
|
|
5506
5507
|
const rights = new Set(zones.map((z) => z.right));
|
|
@@ -7279,31 +7280,34 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
7279
7280
|
for (let col of columnsIndexes) {
|
|
7280
7281
|
const position = { col, row, sheetId };
|
|
7281
7282
|
const table = this.getters.getTable(position);
|
|
7282
|
-
if (!table
|
|
7283
|
+
if (!table) {
|
|
7283
7284
|
tableCellsInRow.push({});
|
|
7284
7285
|
continue;
|
|
7285
7286
|
}
|
|
7286
7287
|
const coreTable = this.getters.getCoreTable(position);
|
|
7287
7288
|
const tableZone = coreTable?.range.zone;
|
|
7289
|
+
let copiedTable = undefined;
|
|
7288
7290
|
// Copy whole table
|
|
7289
|
-
if (
|
|
7290
|
-
|
|
7291
|
+
if (!copiedTablesIds.has(table.id) &&
|
|
7292
|
+
coreTable &&
|
|
7293
|
+
tableZone &&
|
|
7294
|
+
zones.some((z) => isZoneInside(tableZone, z))) {
|
|
7295
|
+
copiedTablesIds.add(table.id);
|
|
7291
7296
|
const values = [];
|
|
7292
7297
|
for (const col of range(tableZone.left, tableZone.right + 1)) {
|
|
7293
7298
|
values.push(this.getters.getFilterHiddenValues({ sheetId, col, row: tableZone.top }));
|
|
7294
7299
|
}
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
},
|
|
7301
|
-
});
|
|
7302
|
-
}
|
|
7303
|
-
// Copy only style of cell
|
|
7304
|
-
else if (table) {
|
|
7305
|
-
tableCellsInRow.push({ style: this.getTableStyleToCopy(position) });
|
|
7300
|
+
copiedTable = {
|
|
7301
|
+
range: coreTable.range,
|
|
7302
|
+
config: coreTable.config,
|
|
7303
|
+
type: coreTable.type,
|
|
7304
|
+
};
|
|
7306
7305
|
}
|
|
7306
|
+
tableCellsInRow.push({
|
|
7307
|
+
table: copiedTable,
|
|
7308
|
+
style: this.getTableStyleToCopy(position),
|
|
7309
|
+
isWholeTableCopied: copiedTablesIds.has(table.id),
|
|
7310
|
+
});
|
|
7307
7311
|
}
|
|
7308
7312
|
}
|
|
7309
7313
|
return {
|
|
@@ -7384,11 +7388,14 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
7384
7388
|
tableType: tableCell.table.type,
|
|
7385
7389
|
});
|
|
7386
7390
|
}
|
|
7387
|
-
// Do not paste table style if we're inside another table
|
|
7388
7391
|
// We cannot check for dynamic tables, because at this point the paste can have changed the evaluation, and the
|
|
7389
7392
|
// dynamic tables are not yet computed
|
|
7390
|
-
if (
|
|
7391
|
-
|
|
7393
|
+
if (this.getters.getCoreTable(position) || options?.pasteOption === "asValue") {
|
|
7394
|
+
return;
|
|
7395
|
+
}
|
|
7396
|
+
if ((!options?.pasteOption && !tableCell.isWholeTableCopied) ||
|
|
7397
|
+
options?.pasteOption === "onlyFormat") {
|
|
7398
|
+
if (tableCell.style?.style) {
|
|
7392
7399
|
this.dispatch("UPDATE_CELL", { ...position, style: tableCell.style.style });
|
|
7393
7400
|
}
|
|
7394
7401
|
if (tableCell.style?.border) {
|
|
@@ -19154,9 +19161,10 @@ const PIVOT_VALUE = {
|
|
|
19154
19161
|
return error;
|
|
19155
19162
|
}
|
|
19156
19163
|
if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
|
|
19164
|
+
const suggestion = _t("Consider using a dynamic pivot formula: %s. Or re-insert the static pivot from the Data menu.", `=PIVOT(${_pivotFormulaId})`);
|
|
19157
19165
|
return {
|
|
19158
19166
|
value: CellErrorType.GenericError,
|
|
19159
|
-
message: _t("Dimensions don't match the pivot definition"),
|
|
19167
|
+
message: _t("Dimensions don't match the pivot definition") + ". " + suggestion,
|
|
19160
19168
|
};
|
|
19161
19169
|
}
|
|
19162
19170
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
@@ -19183,9 +19191,10 @@ const PIVOT_HEADER = {
|
|
|
19183
19191
|
return error;
|
|
19184
19192
|
}
|
|
19185
19193
|
if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
|
|
19194
|
+
const suggestion = _t("Consider using a dynamic pivot formula: %s. Or re-insert the static pivot from the Data menu.", `=PIVOT(${_pivotFormulaId})`);
|
|
19186
19195
|
return {
|
|
19187
19196
|
value: CellErrorType.GenericError,
|
|
19188
|
-
message: _t("Dimensions don't match the pivot definition"),
|
|
19197
|
+
message: _t("Dimensions don't match the pivot definition") + ". " + suggestion,
|
|
19189
19198
|
};
|
|
19190
19199
|
}
|
|
19191
19200
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
@@ -22361,6 +22370,7 @@ function insertTokenAfterArgSeparator(tokenAtCursor, value) {
|
|
|
22361
22370
|
// replace the whole token
|
|
22362
22371
|
start = tokenAtCursor.start;
|
|
22363
22372
|
}
|
|
22373
|
+
this.composer.stopComposerRangeSelection();
|
|
22364
22374
|
this.composer.changeComposerCursorSelection(start, end);
|
|
22365
22375
|
this.composer.replaceComposerCursorSelection(value);
|
|
22366
22376
|
}
|
|
@@ -22378,6 +22388,7 @@ function insertTokenAfterLeftParenthesis(tokenAtCursor, value) {
|
|
|
22378
22388
|
// replace the whole token
|
|
22379
22389
|
start = tokenAtCursor.start;
|
|
22380
22390
|
}
|
|
22391
|
+
this.composer.stopComposerRangeSelection();
|
|
22381
22392
|
this.composer.changeComposerCursorSelection(start, end);
|
|
22382
22393
|
this.composer.replaceComposerCursorSelection(value);
|
|
22383
22394
|
}
|
|
@@ -28408,6 +28419,7 @@ const REINSERT_DYNAMIC_PIVOT_CHILDREN = (env) => env.model.getters.getPivotIds()
|
|
|
28408
28419
|
});
|
|
28409
28420
|
env.model.dispatch("REFRESH_PIVOT", { id: pivotId });
|
|
28410
28421
|
},
|
|
28422
|
+
isVisible: (env) => env.model.getters.getPivot(pivotId).isValid(),
|
|
28411
28423
|
}));
|
|
28412
28424
|
const REINSERT_STATIC_PIVOT_CHILDREN = (env) => env.model.getters.getPivotIds().map((pivotId, index) => ({
|
|
28413
28425
|
id: `reinsert_static_pivot_${env.model.getters.getPivotFormulaId(pivotId)}`,
|
|
@@ -28426,6 +28438,7 @@ const REINSERT_STATIC_PIVOT_CHILDREN = (env) => env.model.getters.getPivotIds().
|
|
|
28426
28438
|
});
|
|
28427
28439
|
env.model.dispatch("REFRESH_PIVOT", { id: pivotId });
|
|
28428
28440
|
},
|
|
28441
|
+
isVisible: (env) => env.model.getters.getPivot(pivotId).isValid(),
|
|
28429
28442
|
}));
|
|
28430
28443
|
//------------------------------------------------------------------------------
|
|
28431
28444
|
// Image
|
|
@@ -29297,7 +29310,7 @@ const reinsertDynamicPivotMenu = {
|
|
|
29297
29310
|
sequence: 1020,
|
|
29298
29311
|
icon: "o-spreadsheet-Icon.INSERT_PIVOT",
|
|
29299
29312
|
children: [REINSERT_DYNAMIC_PIVOT_CHILDREN],
|
|
29300
|
-
isVisible: (env) => env.model.getters.getPivotIds().
|
|
29313
|
+
isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
|
|
29301
29314
|
};
|
|
29302
29315
|
const reinsertStaticPivotMenu = {
|
|
29303
29316
|
id: "reinsert_static_pivot",
|
|
@@ -29305,7 +29318,7 @@ const reinsertStaticPivotMenu = {
|
|
|
29305
29318
|
sequence: 1020,
|
|
29306
29319
|
icon: "o-spreadsheet-Icon.INSERT_PIVOT",
|
|
29307
29320
|
children: [REINSERT_STATIC_PIVOT_CHILDREN],
|
|
29308
|
-
isVisible: (env) => env.model.getters.getPivotIds().
|
|
29321
|
+
isVisible: (env) => env.model.getters.getPivotIds().some((id) => env.model.getters.getPivot(id).isValid()),
|
|
29309
29322
|
};
|
|
29310
29323
|
|
|
29311
29324
|
var ACTION_DATA = /*#__PURE__*/Object.freeze({
|
|
@@ -37191,6 +37204,8 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
37191
37204
|
mutators = ["reset", "deferUpdates", "applyUpdate", "discardPendingUpdate", "update"];
|
|
37192
37205
|
updatesAreDeferred = false;
|
|
37193
37206
|
draft = null;
|
|
37207
|
+
notification = this.get(NotificationStore);
|
|
37208
|
+
alreadyNotified = false;
|
|
37194
37209
|
constructor(get, pivotId) {
|
|
37195
37210
|
super(get);
|
|
37196
37211
|
this.pivotId = pivotId;
|
|
@@ -37297,6 +37312,16 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
37297
37312
|
pivot: this.draft,
|
|
37298
37313
|
});
|
|
37299
37314
|
this.draft = null;
|
|
37315
|
+
if (!this.alreadyNotified && !this.isDynamicPivotInViewport()) {
|
|
37316
|
+
const formulaId = this.getters.getPivotFormulaId(this.pivotId);
|
|
37317
|
+
const pivotExample = `=PIVOT(${formulaId})`;
|
|
37318
|
+
this.alreadyNotified = true;
|
|
37319
|
+
this.notification.notifyUser({
|
|
37320
|
+
type: "info",
|
|
37321
|
+
text: _t("Pivot updates only work with dynamic pivot tables. Use %s or re-insert the static pivot from the Data menu.", pivotExample),
|
|
37322
|
+
sticky: false,
|
|
37323
|
+
});
|
|
37324
|
+
}
|
|
37300
37325
|
}
|
|
37301
37326
|
}
|
|
37302
37327
|
discardPendingUpdate() {
|
|
@@ -37327,15 +37352,22 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
37327
37352
|
return;
|
|
37328
37353
|
}
|
|
37329
37354
|
const cleanedWithGranularity = this.addDefaultDateTimeGranularity(this.fields, cleanedDefinition);
|
|
37330
|
-
|
|
37331
|
-
|
|
37355
|
+
this.draft = cleanedWithGranularity;
|
|
37356
|
+
if (!this.updatesAreDeferred) {
|
|
37357
|
+
this.applyUpdate();
|
|
37332
37358
|
}
|
|
37333
|
-
|
|
37334
|
-
|
|
37335
|
-
|
|
37336
|
-
|
|
37337
|
-
|
|
37359
|
+
}
|
|
37360
|
+
isDynamicPivotInViewport() {
|
|
37361
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
37362
|
+
for (const col of this.getters.getSheetViewVisibleCols()) {
|
|
37363
|
+
for (const row of this.getters.getSheetViewVisibleRows()) {
|
|
37364
|
+
const isDynamicPivot = this.getters.isSpillPivotFormula({ sheetId, col, row });
|
|
37365
|
+
if (isDynamicPivot) {
|
|
37366
|
+
return true;
|
|
37367
|
+
}
|
|
37368
|
+
}
|
|
37338
37369
|
}
|
|
37370
|
+
return false;
|
|
37339
37371
|
}
|
|
37340
37372
|
addDefaultDateTimeGranularity(fields, definition) {
|
|
37341
37373
|
const { columns, rows } = definition;
|
|
@@ -52426,7 +52458,7 @@ class PivotCorePlugin extends CorePlugin {
|
|
|
52426
52458
|
case "DUPLICATE_PIVOT": {
|
|
52427
52459
|
const { pivotId, newPivotId } = cmd;
|
|
52428
52460
|
const pivot = deepCopy(this.getPivotCore(pivotId).definition);
|
|
52429
|
-
pivot.name =
|
|
52461
|
+
pivot.name = cmd.duplicatedPivotName ?? pivot.name + " (copy)";
|
|
52430
52462
|
this.addPivot(newPivotId, pivot);
|
|
52431
52463
|
break;
|
|
52432
52464
|
}
|
|
@@ -57515,6 +57547,7 @@ class Session extends EventBus {
|
|
|
57515
57547
|
case "REMOTE_REVISION":
|
|
57516
57548
|
case "REVISION_REDONE":
|
|
57517
57549
|
case "REVISION_UNDONE":
|
|
57550
|
+
case "SNAPSHOT_CREATED":
|
|
57518
57551
|
return this.processedRevisions.has(message.nextRevisionId);
|
|
57519
57552
|
default:
|
|
57520
57553
|
return false;
|
|
@@ -58030,12 +58063,13 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
58030
58063
|
this.dispatch("DUPLICATE_PIVOT", {
|
|
58031
58064
|
pivotId,
|
|
58032
58065
|
newPivotId,
|
|
58066
|
+
duplicatedPivotName: _t("%s (copy)", this.getters.getPivotCoreDefinition(pivotId).name),
|
|
58033
58067
|
});
|
|
58034
58068
|
const activeSheetId = this.getters.getActiveSheetId();
|
|
58035
58069
|
const position = this.getters.getSheetIds().indexOf(activeSheetId) + 1;
|
|
58036
58070
|
const formulaId = this.getters.getPivotFormulaId(newPivotId);
|
|
58037
58071
|
const newPivotName = this.getters.getPivotName(newPivotId);
|
|
58038
|
-
this.dispatch("CREATE_SHEET", {
|
|
58072
|
+
const result = this.dispatch("CREATE_SHEET", {
|
|
58039
58073
|
sheetId: newSheetId,
|
|
58040
58074
|
name: this.getPivotDuplicateSheetName(_t("%(newPivotName)s (Pivot #%(formulaId)s)", {
|
|
58041
58075
|
newPivotName,
|
|
@@ -58043,20 +58077,23 @@ class InsertPivotPlugin extends UIPlugin {
|
|
|
58043
58077
|
})),
|
|
58044
58078
|
position,
|
|
58045
58079
|
});
|
|
58046
|
-
|
|
58047
|
-
|
|
58048
|
-
|
|
58049
|
-
|
|
58050
|
-
|
|
58051
|
-
|
|
58052
|
-
|
|
58080
|
+
if (result.isSuccessful) {
|
|
58081
|
+
this.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: newSheetId });
|
|
58082
|
+
this.dispatch("UPDATE_CELL", {
|
|
58083
|
+
sheetId: newSheetId,
|
|
58084
|
+
col: 0,
|
|
58085
|
+
row: 0,
|
|
58086
|
+
content: `=PIVOT(${formulaId})`,
|
|
58087
|
+
});
|
|
58088
|
+
}
|
|
58053
58089
|
}
|
|
58054
58090
|
getPivotDuplicateSheetName(pivotName) {
|
|
58055
58091
|
let i = 1;
|
|
58056
58092
|
const names = this.getters.getSheetIds().map((id) => this.getters.getSheetName(id));
|
|
58057
|
-
|
|
58093
|
+
const sanitizedName = pivotName.replace(new RegExp(FORBIDDEN_IN_EXCEL_REGEX, "g"), " ");
|
|
58094
|
+
let name = sanitizedName;
|
|
58058
58095
|
while (names.includes(name)) {
|
|
58059
|
-
name = `${
|
|
58096
|
+
name = `${sanitizedName} (${i})`;
|
|
58060
58097
|
i++;
|
|
58061
58098
|
}
|
|
58062
58099
|
return name;
|
|
@@ -58637,9 +58674,12 @@ const invalidateTableStyleCommands = [
|
|
|
58637
58674
|
"HIDE_COLUMNS_ROWS",
|
|
58638
58675
|
"UNHIDE_COLUMNS_ROWS",
|
|
58639
58676
|
"UNFOLD_HEADER_GROUP",
|
|
58677
|
+
"UNGROUP_HEADERS",
|
|
58640
58678
|
"FOLD_HEADER_GROUP",
|
|
58641
58679
|
"FOLD_ALL_HEADER_GROUPS",
|
|
58642
58680
|
"UNFOLD_ALL_HEADER_GROUPS",
|
|
58681
|
+
"FOLD_HEADER_GROUPS_IN_ZONE",
|
|
58682
|
+
"UNFOLD_HEADER_GROUPS_IN_ZONE",
|
|
58643
58683
|
"CREATE_TABLE",
|
|
58644
58684
|
"UPDATE_TABLE",
|
|
58645
58685
|
"UPDATE_FILTER",
|
|
@@ -58660,6 +58700,7 @@ class CellComputedStylePlugin extends UIPlugin {
|
|
|
58660
58700
|
handle(cmd) {
|
|
58661
58701
|
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
58662
58702
|
cmd.type === "UPDATE_CELL" ||
|
|
58703
|
+
cmd.type === "SET_FORMATTING" ||
|
|
58663
58704
|
cmd.type === "EVALUATE_CELLS") {
|
|
58664
58705
|
this.styles = {};
|
|
58665
58706
|
this.borders = {};
|
|
@@ -59954,6 +59995,8 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
59954
59995
|
case "UNFOLD_HEADER_GROUP":
|
|
59955
59996
|
case "FOLD_ALL_HEADER_GROUPS":
|
|
59956
59997
|
case "UNFOLD_ALL_HEADER_GROUPS":
|
|
59998
|
+
case "FOLD_HEADER_GROUPS_IN_ZONE":
|
|
59999
|
+
case "UNFOLD_HEADER_GROUPS_IN_ZONE":
|
|
59957
60000
|
this.updateHiddenRows(cmd.sheetId);
|
|
59958
60001
|
break;
|
|
59959
60002
|
case "UPDATE_FILTER":
|
|
@@ -65900,7 +65943,9 @@ class StateObserver {
|
|
|
65900
65943
|
* The value does not matter, it can be hardcoded.
|
|
65901
65944
|
*/
|
|
65902
65945
|
const catAxId = 17781237;
|
|
65946
|
+
const secondaryCatAxId = 17781238;
|
|
65903
65947
|
const valAxId = 88853993;
|
|
65948
|
+
const secondaryValAxId = 88853994;
|
|
65904
65949
|
function createChart(chart, chartSheetIndex, data) {
|
|
65905
65950
|
const namespaces = [
|
|
65906
65951
|
["xmlns:r", RELATIONSHIP_NSR],
|
|
@@ -66216,8 +66261,8 @@ function addComboChart(chart) {
|
|
|
66216
66261
|
<!-- each data marker in the series does not have a different color -->
|
|
66217
66262
|
<c:varyColors val="0"/>
|
|
66218
66263
|
${barDataSetNode}
|
|
66219
|
-
<c:axId val="${
|
|
66220
|
-
<c:axId val="${
|
|
66264
|
+
<c:axId val="${useRightAxisForBarSerie ? secondaryCatAxId : catAxId}" />
|
|
66265
|
+
<c:axId val="${useRightAxisForBarSerie ? secondaryValAxId : valAxId}" />
|
|
66221
66266
|
</c:barChart>
|
|
66222
66267
|
${leftDataSetsNodes.length
|
|
66223
66268
|
? escapeXml /*xml*/ `
|
|
@@ -66238,21 +66283,21 @@ function addComboChart(chart) {
|
|
|
66238
66283
|
<!-- each data marker in the series does not have a different color -->
|
|
66239
66284
|
<c:varyColors val="0"/>
|
|
66240
66285
|
${joinXmlNodes(rightDataSetsNodes)}
|
|
66241
|
-
<c:axId val="${
|
|
66242
|
-
<c:axId val="${
|
|
66286
|
+
<c:axId val="${secondaryCatAxId}" />
|
|
66287
|
+
<c:axId val="${secondaryValAxId}" />
|
|
66243
66288
|
</c:lineChart>
|
|
66244
66289
|
`
|
|
66245
66290
|
: ""}
|
|
66246
66291
|
${!useRightAxisForBarSerie || leftDataSetsNodes.length
|
|
66247
66292
|
? escapeXml /*xml*/ `
|
|
66248
|
-
${addAx("b", "c:catAx", catAxId
|
|
66249
|
-
${addAx("
|
|
66293
|
+
${addAx("b", "c:catAx", catAxId, valAxId, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length ? 1 : 0)}
|
|
66294
|
+
${addAx("l", "c:valAx", valAxId, catAxId, chart.axesDesign?.y?.title, chart.fontColor)}
|
|
66250
66295
|
`
|
|
66251
66296
|
: ""}
|
|
66252
66297
|
${useRightAxisForBarSerie || rightDataSetsNodes.length
|
|
66253
66298
|
? escapeXml /*xml*/ `
|
|
66254
|
-
${addAx("b", "c:catAx",
|
|
66255
|
-
${addAx("
|
|
66299
|
+
${addAx("b", "c:catAx", secondaryCatAxId, secondaryValAxId, chart.axesDesign?.x?.title, chart.fontColor, leftDataSetsNodes.length || !useRightAxisForBarSerie ? 1 : 0)}
|
|
66300
|
+
${addAx("r", "c:valAx", secondaryValAxId, secondaryCatAxId, chart.axesDesign?.y1?.title, chart.fontColor)}
|
|
66256
66301
|
`
|
|
66257
66302
|
: ""}
|
|
66258
66303
|
`;
|
|
@@ -67273,6 +67318,15 @@ function addTableColumns(table, sheetData) {
|
|
|
67273
67318
|
["id", i + 1], // id cannot be 0
|
|
67274
67319
|
["name", colName],
|
|
67275
67320
|
];
|
|
67321
|
+
if (table.config.totalRow) {
|
|
67322
|
+
// Note: To be 100% complete, we could also add a `totalsRowLabel` attribute for total strings, and a tag
|
|
67323
|
+
// `<totalsRowFormula>` for the formula of the total. But those doesn't seem to be mandatory for Excel.
|
|
67324
|
+
const colTotalXc = toXC(tableZone.left + i, tableZone.bottom);
|
|
67325
|
+
const colTotalContent = sheetData.cells[colTotalXc]?.content;
|
|
67326
|
+
if (colTotalContent?.startsWith("=")) {
|
|
67327
|
+
colAttributes.push(["totalsRowFunction", "custom"]);
|
|
67328
|
+
}
|
|
67329
|
+
}
|
|
67276
67330
|
columns.push(escapeXml /*xml*/ `<tableColumn ${formatAttributes(colAttributes)}/>`);
|
|
67277
67331
|
}
|
|
67278
67332
|
return escapeXml /*xml*/ `
|
|
@@ -67367,8 +67421,9 @@ function addRows(construct, data, sheet) {
|
|
|
67367
67421
|
}
|
|
67368
67422
|
else if (cell.content && cell.content !== "") {
|
|
67369
67423
|
const isTableHeader = isCellTableHeader(c, r, sheet);
|
|
67424
|
+
const isTableTotal = isCellTableTotal(c, r, sheet);
|
|
67370
67425
|
const isPlainText = !!(cell.format && data.formats[cell.format] === PLAIN_TEXT_FORMAT);
|
|
67371
|
-
({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader || isPlainText));
|
|
67426
|
+
({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader || isTableTotal || isPlainText));
|
|
67372
67427
|
}
|
|
67373
67428
|
attributes.push(...additionalAttrs);
|
|
67374
67429
|
// prettier-ignore
|
|
@@ -67402,6 +67457,16 @@ function isCellTableHeader(col, row, sheet) {
|
|
|
67402
67457
|
return isInside(col, row, headerZone);
|
|
67403
67458
|
});
|
|
67404
67459
|
}
|
|
67460
|
+
function isCellTableTotal(col, row, sheet) {
|
|
67461
|
+
return sheet.tables.some((table) => {
|
|
67462
|
+
if (!table.config.totalRow) {
|
|
67463
|
+
return false;
|
|
67464
|
+
}
|
|
67465
|
+
const zone = toZone(table.range);
|
|
67466
|
+
const totalZone = { ...zone, top: zone.bottom };
|
|
67467
|
+
return isInside(col, row, totalZone);
|
|
67468
|
+
});
|
|
67469
|
+
}
|
|
67405
67470
|
function addHyperlinks(construct, data, sheetIndex) {
|
|
67406
67471
|
const sheet = data.sheets[sheetIndex];
|
|
67407
67472
|
const cells = sheet.cells;
|
|
@@ -67880,7 +67945,6 @@ class Model extends EventBus {
|
|
|
67880
67945
|
isReadonly: () => this.config.mode === "readonly" || this.config.mode === "dashboard",
|
|
67881
67946
|
isDashboard: () => this.config.mode === "dashboard",
|
|
67882
67947
|
};
|
|
67883
|
-
this.uuidGenerator.setIsFastStrategy(true);
|
|
67884
67948
|
// Initiate stream processor
|
|
67885
67949
|
this.selection = new SelectionStreamProcessorImpl(this.getters);
|
|
67886
67950
|
this.coreHandlers.push(this.range);
|
|
@@ -68413,6 +68477,7 @@ const helpers = {
|
|
|
68413
68477
|
UNDO_REDO_PIVOT_COMMANDS,
|
|
68414
68478
|
createPivotFormula,
|
|
68415
68479
|
areDomainArgsFieldsValid,
|
|
68480
|
+
formatTickValue,
|
|
68416
68481
|
};
|
|
68417
68482
|
const links = {
|
|
68418
68483
|
isMarkdownLink,
|
|
@@ -68500,6 +68565,6 @@ const constants = {
|
|
|
68500
68565
|
export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
|
|
68501
68566
|
|
|
68502
68567
|
|
|
68503
|
-
__info__.version = "17.4.
|
|
68504
|
-
__info__.date = "2024-
|
|
68505
|
-
__info__.hash = "
|
|
68568
|
+
__info__.version = "17.4.9";
|
|
68569
|
+
__info__.date = "2024-10-14T07:53:51.633Z";
|
|
68570
|
+
__info__.hash = "b7015b7";
|