@odoo/o-spreadsheet 18.0.27 → 18.0.28
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 +456 -39
- package/dist/o-spreadsheet.d.ts +267 -142
- package/dist/o-spreadsheet.esm.js +456 -39
- package/dist/o-spreadsheet.iife.js +456 -39
- package/dist/o-spreadsheet.iife.min.js +301 -265
- package/dist/o_spreadsheet.xml +60 -13
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 18.0.
|
|
6
|
-
* @date 2025-05-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.0.28
|
|
6
|
+
* @date 2025-05-13T17:53:12.402Z
|
|
7
|
+
* @hash b3088aa
|
|
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';
|
|
@@ -3180,7 +3180,7 @@ function isDateAfter(date, dateAfter) {
|
|
|
3180
3180
|
*/
|
|
3181
3181
|
const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
|
|
3182
3182
|
decimalSeparator = escapeRegExp(decimalSeparator);
|
|
3183
|
-
return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e
|
|
3183
|
+
return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e(\\+|-)?\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
|
|
3184
3184
|
});
|
|
3185
3185
|
const getNumberRegex = memoize(function getNumberRegex(locale) {
|
|
3186
3186
|
const decimalSeparator = escapeRegExp(locale.decimalSeparator);
|
|
@@ -6121,6 +6121,13 @@ function getDuplicateSheetName(nameToDuplicate, existingNames) {
|
|
|
6121
6121
|
}
|
|
6122
6122
|
return name;
|
|
6123
6123
|
}
|
|
6124
|
+
function isSheetNameEqual(name1, name2) {
|
|
6125
|
+
if (name1 === undefined || name2 === undefined) {
|
|
6126
|
+
return false;
|
|
6127
|
+
}
|
|
6128
|
+
return (getUnquotedSheetName(name1.trim().toUpperCase()) ===
|
|
6129
|
+
getUnquotedSheetName(name2.trim().toUpperCase()));
|
|
6130
|
+
}
|
|
6124
6131
|
|
|
6125
6132
|
function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
|
|
6126
6133
|
return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
|
|
@@ -7974,10 +7981,9 @@ const AGGREGATOR_NAMES = {
|
|
|
7974
7981
|
avg: _t("Average"),
|
|
7975
7982
|
sum: _t("Sum"),
|
|
7976
7983
|
};
|
|
7977
|
-
const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
|
|
7978
7984
|
const AGGREGATORS_BY_FIELD_TYPE = {
|
|
7979
|
-
integer:
|
|
7980
|
-
char:
|
|
7985
|
+
integer: ["max", "min", "avg", "sum", "count_distinct", "count"],
|
|
7986
|
+
char: ["count_distinct", "count"],
|
|
7981
7987
|
boolean: ["count_distinct", "count", "bool_and", "bool_or"],
|
|
7982
7988
|
};
|
|
7983
7989
|
const AGGREGATORS = {};
|
|
@@ -9310,7 +9316,10 @@ function proxifyStoreMutation(store, callback) {
|
|
|
9310
9316
|
const functionProxy = new Proxy(value, {
|
|
9311
9317
|
// trap the function call
|
|
9312
9318
|
apply(target, thisArg, argArray) {
|
|
9313
|
-
Reflect.apply(target, thisStore, argArray);
|
|
9319
|
+
const res = Reflect.apply(target, thisStore, argArray);
|
|
9320
|
+
if (res === "noStateChange") {
|
|
9321
|
+
return;
|
|
9322
|
+
}
|
|
9314
9323
|
callback();
|
|
9315
9324
|
},
|
|
9316
9325
|
});
|
|
@@ -9332,7 +9341,7 @@ function getDependencyContainer(env) {
|
|
|
9332
9341
|
const ModelStore = createAbstractStore("Model");
|
|
9333
9342
|
|
|
9334
9343
|
class RendererStore {
|
|
9335
|
-
mutators = ["register", "unRegister"];
|
|
9344
|
+
mutators = ["register", "unRegister", "drawLayer"];
|
|
9336
9345
|
renderers = {};
|
|
9337
9346
|
register(renderer) {
|
|
9338
9347
|
if (!renderer.renderingLayers.length) {
|
|
@@ -9352,14 +9361,14 @@ class RendererStore {
|
|
|
9352
9361
|
}
|
|
9353
9362
|
drawLayer(context, layer) {
|
|
9354
9363
|
const renderers = this.renderers[layer];
|
|
9355
|
-
if (
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
context.ctx.restore();
|
|
9364
|
+
if (renderers) {
|
|
9365
|
+
for (const renderer of renderers) {
|
|
9366
|
+
context.ctx.save();
|
|
9367
|
+
renderer.drawLayer(context, layer);
|
|
9368
|
+
context.ctx.restore();
|
|
9369
|
+
}
|
|
9362
9370
|
}
|
|
9371
|
+
return "noStateChange";
|
|
9363
9372
|
}
|
|
9364
9373
|
}
|
|
9365
9374
|
|
|
@@ -9412,16 +9421,17 @@ class ComposerFocusStore extends SpreadsheetStore {
|
|
|
9412
9421
|
focusComposer(listener, args) {
|
|
9413
9422
|
this.activeComposer = listener;
|
|
9414
9423
|
if (this.getters.isReadonly()) {
|
|
9415
|
-
return;
|
|
9424
|
+
return "noStateChange";
|
|
9416
9425
|
}
|
|
9417
9426
|
this._focusMode = args.focusMode || "contentFocus";
|
|
9418
9427
|
if (this._focusMode !== "inactive") {
|
|
9419
9428
|
this.setComposerContent(args);
|
|
9420
9429
|
}
|
|
9430
|
+
return;
|
|
9421
9431
|
}
|
|
9422
9432
|
focusActiveComposer(args) {
|
|
9423
9433
|
if (this.getters.isReadonly()) {
|
|
9424
|
-
return;
|
|
9434
|
+
return "noStateChange";
|
|
9425
9435
|
}
|
|
9426
9436
|
if (!this.activeComposer) {
|
|
9427
9437
|
throw new Error("No composer is registered");
|
|
@@ -9430,6 +9440,7 @@ class ComposerFocusStore extends SpreadsheetStore {
|
|
|
9430
9440
|
if (this._focusMode !== "inactive") {
|
|
9431
9441
|
this.setComposerContent(args);
|
|
9432
9442
|
}
|
|
9443
|
+
return;
|
|
9433
9444
|
}
|
|
9434
9445
|
/**
|
|
9435
9446
|
* Start the edition or update the content if it's already started.
|
|
@@ -11744,7 +11755,7 @@ function getRangeSize(reference, defaultSheetIndex, data) {
|
|
|
11744
11755
|
({ xc, sheetName } = splitReference(reference));
|
|
11745
11756
|
let rangeSheetIndex;
|
|
11746
11757
|
if (sheetName) {
|
|
11747
|
-
const index = data.sheets.findIndex((sheet) => sheet.name
|
|
11758
|
+
const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
|
|
11748
11759
|
if (index < 0) {
|
|
11749
11760
|
throw new Error("Unable to find a sheet with the name " + sheetName);
|
|
11750
11761
|
}
|
|
@@ -12085,7 +12096,7 @@ function convertFormula(formula, data) {
|
|
|
12085
12096
|
formula = formula.replace(externalReferenceRegex, (match, externalRefId, sheetName, cellRef) => {
|
|
12086
12097
|
externalRefId = Number(externalRefId) - 1;
|
|
12087
12098
|
cellRef = cellRef.replace(/\$/g, "");
|
|
12088
|
-
const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => name
|
|
12099
|
+
const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => isSheetNameEqual(name, sheetName));
|
|
12089
12100
|
if (sheetIndex === -1) {
|
|
12090
12101
|
return match;
|
|
12091
12102
|
}
|
|
@@ -12748,7 +12759,7 @@ function convertPivotTableConfig(pivotTable) {
|
|
|
12748
12759
|
*/
|
|
12749
12760
|
function convertTableFormulaReferences(convertedSheets, xlsxSheets) {
|
|
12750
12761
|
for (let tableSheet of convertedSheets) {
|
|
12751
|
-
const tables = xlsxSheets.find((s) => s.sheetName
|
|
12762
|
+
const tables = xlsxSheets.find((s) => isSheetNameEqual(s.sheetName, tableSheet.name)).tables;
|
|
12752
12763
|
for (let table of tables) {
|
|
12753
12764
|
const tabRef = table.name + "[";
|
|
12754
12765
|
for (let sheet of convertedSheets) {
|
|
@@ -25071,6 +25082,9 @@ const PIVOT_VALUE = {
|
|
|
25071
25082
|
};
|
|
25072
25083
|
}
|
|
25073
25084
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
25085
|
+
if (this.getters.getActiveSheetId() === this.__originSheetId) {
|
|
25086
|
+
this.getters.getPivotPresenceTracker(pivotId)?.trackValue(_measure, domain);
|
|
25087
|
+
}
|
|
25074
25088
|
return pivot.getPivotCellValueAndFormat(_measure, domain);
|
|
25075
25089
|
},
|
|
25076
25090
|
};
|
|
@@ -25102,6 +25116,9 @@ const PIVOT_HEADER = {
|
|
|
25102
25116
|
};
|
|
25103
25117
|
}
|
|
25104
25118
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
25119
|
+
if (this.getters.getActiveSheetId() === this.__originSheetId) {
|
|
25120
|
+
this.getters.getPivotPresenceTracker(_pivotId)?.trackHeader(domain);
|
|
25121
|
+
}
|
|
25105
25122
|
const lastNode = domain.at(-1);
|
|
25106
25123
|
if (lastNode?.field === "measure") {
|
|
25107
25124
|
return pivot.getPivotMeasureValue(toString(lastNode.value), domain);
|
|
@@ -25324,6 +25341,9 @@ function isEmpty(data) {
|
|
|
25324
25341
|
return data === undefined || data.value === null;
|
|
25325
25342
|
}
|
|
25326
25343
|
const getNeutral = { number: 0, string: "", boolean: false };
|
|
25344
|
+
function areAlmostEqual(value1, value2, epsilon = 2e-16) {
|
|
25345
|
+
return Math.abs(value1 - value2) < epsilon;
|
|
25346
|
+
}
|
|
25327
25347
|
const EQ = {
|
|
25328
25348
|
description: _t("Equal."),
|
|
25329
25349
|
args: [
|
|
@@ -25339,6 +25359,9 @@ const EQ = {
|
|
|
25339
25359
|
if (typeof _value2 === "string") {
|
|
25340
25360
|
_value2 = _value2.toUpperCase();
|
|
25341
25361
|
}
|
|
25362
|
+
if (typeof _value1 === "number" && typeof _value2 === "number") {
|
|
25363
|
+
return areAlmostEqual(_value1, _value2);
|
|
25364
|
+
}
|
|
25342
25365
|
return _value1 === _value2;
|
|
25343
25366
|
},
|
|
25344
25367
|
};
|
|
@@ -25378,6 +25401,9 @@ const GT = {
|
|
|
25378
25401
|
],
|
|
25379
25402
|
compute: function (value1, value2) {
|
|
25380
25403
|
return applyRelationalOperator(value1, value2, (v1, v2) => {
|
|
25404
|
+
if (typeof v1 === "number" && typeof v2 === "number") {
|
|
25405
|
+
return !areAlmostEqual(v1, v2) && v1 > v2;
|
|
25406
|
+
}
|
|
25381
25407
|
return v1 > v2;
|
|
25382
25408
|
});
|
|
25383
25409
|
},
|
|
@@ -25393,6 +25419,9 @@ const GTE = {
|
|
|
25393
25419
|
],
|
|
25394
25420
|
compute: function (value1, value2) {
|
|
25395
25421
|
return applyRelationalOperator(value1, value2, (v1, v2) => {
|
|
25422
|
+
if (typeof v1 === "number" && typeof v2 === "number") {
|
|
25423
|
+
return areAlmostEqual(v1, v2) || v1 > v2;
|
|
25424
|
+
}
|
|
25396
25425
|
return v1 >= v2;
|
|
25397
25426
|
});
|
|
25398
25427
|
},
|
|
@@ -26515,10 +26544,18 @@ autoCompleteProviders.add("functions", {
|
|
|
26515
26544
|
});
|
|
26516
26545
|
|
|
26517
26546
|
class DOMFocusableElementStore {
|
|
26518
|
-
mutators = ["setFocusableElement"];
|
|
26547
|
+
mutators = ["setFocusableElement", "focus"];
|
|
26519
26548
|
focusableElement = undefined;
|
|
26520
26549
|
setFocusableElement(element) {
|
|
26521
26550
|
this.focusableElement = element;
|
|
26551
|
+
return "noStateChange";
|
|
26552
|
+
}
|
|
26553
|
+
focus() {
|
|
26554
|
+
if (this.focusableElement === document.activeElement) {
|
|
26555
|
+
return "noStateChange";
|
|
26556
|
+
}
|
|
26557
|
+
this.focusableElement?.focus();
|
|
26558
|
+
return;
|
|
26522
26559
|
}
|
|
26523
26560
|
}
|
|
26524
26561
|
|
|
@@ -27361,7 +27398,7 @@ class Composer extends Component {
|
|
|
27361
27398
|
if (document.activeElement === this.contentHelper.el &&
|
|
27362
27399
|
this.props.composerStore.editionMode === "inactive" &&
|
|
27363
27400
|
!this.props.isDefaultFocus) {
|
|
27364
|
-
this.DOMFocusableElementStore.
|
|
27401
|
+
this.DOMFocusableElementStore.focus();
|
|
27365
27402
|
}
|
|
27366
27403
|
});
|
|
27367
27404
|
useEffect(() => {
|
|
@@ -31833,12 +31870,20 @@ class HoveredCellStore extends SpreadsheetStore {
|
|
|
31833
31870
|
}
|
|
31834
31871
|
}
|
|
31835
31872
|
hover(position) {
|
|
31873
|
+
if (position.col === this.col && position.row === this.row) {
|
|
31874
|
+
return "noStateChange";
|
|
31875
|
+
}
|
|
31836
31876
|
this.col = position.col;
|
|
31837
31877
|
this.row = position.row;
|
|
31878
|
+
return;
|
|
31838
31879
|
}
|
|
31839
31880
|
clear() {
|
|
31881
|
+
if (this.col === undefined && this.row === undefined) {
|
|
31882
|
+
return "noStateChange";
|
|
31883
|
+
}
|
|
31840
31884
|
this.col = undefined;
|
|
31841
31885
|
this.row = undefined;
|
|
31886
|
+
return;
|
|
31842
31887
|
}
|
|
31843
31888
|
}
|
|
31844
31889
|
|
|
@@ -31860,7 +31905,11 @@ class CellPopoverStore extends SpreadsheetStore {
|
|
|
31860
31905
|
this.persistentPopover = { col, row, sheetId, type };
|
|
31861
31906
|
}
|
|
31862
31907
|
close() {
|
|
31908
|
+
if (!this.persistentPopover) {
|
|
31909
|
+
return "noStateChange";
|
|
31910
|
+
}
|
|
31863
31911
|
this.persistentPopover = undefined;
|
|
31912
|
+
return;
|
|
31864
31913
|
}
|
|
31865
31914
|
get persistentCellPopover() {
|
|
31866
31915
|
return ((this.persistentPopover && { isOpen: true, ...this.persistentPopover }) || { isOpen: false });
|
|
@@ -39213,7 +39262,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
39213
39262
|
.find((token) => {
|
|
39214
39263
|
const { xc, sheetName: sheet } = splitReference(token.value);
|
|
39215
39264
|
const sheetName = sheet || this.getters.getSheetName(this.sheetId);
|
|
39216
|
-
if (this.getters.getSheetName(activeSheetId)
|
|
39265
|
+
if (!isSheetNameEqual(this.getters.getSheetName(activeSheetId), sheetName)) {
|
|
39217
39266
|
return false;
|
|
39218
39267
|
}
|
|
39219
39268
|
const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
|
|
@@ -44510,7 +44559,12 @@ class SpreadsheetPivot {
|
|
|
44510
44559
|
entry[field.name] = { value: null, type: CellValueType.empty, formattedValue: "" };
|
|
44511
44560
|
}
|
|
44512
44561
|
else {
|
|
44513
|
-
|
|
44562
|
+
if (field.type === "char") {
|
|
44563
|
+
entry[field.name] = { ...cell, value: cell.formattedValue || null };
|
|
44564
|
+
}
|
|
44565
|
+
else {
|
|
44566
|
+
entry[field.name] = cell;
|
|
44567
|
+
}
|
|
44514
44568
|
}
|
|
44515
44569
|
}
|
|
44516
44570
|
entry["__count"] = { value: 1, type: CellValueType.number, formattedValue: "1" };
|
|
@@ -49506,10 +49560,6 @@ function useGridDrawing(refName, model, canvasSize) {
|
|
|
49506
49560
|
ctx.scale(dpr, dpr);
|
|
49507
49561
|
for (const layer of OrderedLayers()) {
|
|
49508
49562
|
model.drawLayer(renderingContext, layer);
|
|
49509
|
-
// @ts-ignore 'drawLayer' is not declated as a mutator because:
|
|
49510
|
-
// it does not mutate anything. Most importantly it's used
|
|
49511
|
-
// during rendering. Invoking a mutator during rendering would
|
|
49512
|
-
// trigger another rendering, ultimately resulting in an infinite loop.
|
|
49513
49563
|
rendererStore.drawLayer(renderingContext, layer);
|
|
49514
49564
|
}
|
|
49515
49565
|
}
|
|
@@ -50199,7 +50249,7 @@ class Grid extends Component {
|
|
|
50199
50249
|
this.cellPopovers = useStore(CellPopoverStore);
|
|
50200
50250
|
useEffect(() => {
|
|
50201
50251
|
if (!this.sidePanel.isOpen) {
|
|
50202
|
-
this.DOMFocusableElementStore.
|
|
50252
|
+
this.DOMFocusableElementStore.focus();
|
|
50203
50253
|
}
|
|
50204
50254
|
}, () => [this.sidePanel.isOpen]);
|
|
50205
50255
|
useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
|
|
@@ -50407,7 +50457,7 @@ class Grid extends Component {
|
|
|
50407
50457
|
focusDefaultElement() {
|
|
50408
50458
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
50409
50459
|
this.composerFocusStore.activeComposer.editionMode === "inactive") {
|
|
50410
|
-
this.DOMFocusableElementStore.
|
|
50460
|
+
this.DOMFocusableElementStore.focus();
|
|
50411
50461
|
}
|
|
50412
50462
|
}
|
|
50413
50463
|
get gridEl() {
|
|
@@ -50777,6 +50827,322 @@ class EditableName extends Component {
|
|
|
50777
50827
|
}
|
|
50778
50828
|
}
|
|
50779
50829
|
|
|
50830
|
+
css /* scss */ `
|
|
50831
|
+
.o_pivot_html_renderer {
|
|
50832
|
+
width: 100%;
|
|
50833
|
+
border-collapse: collapse;
|
|
50834
|
+
|
|
50835
|
+
&:hover {
|
|
50836
|
+
cursor: pointer;
|
|
50837
|
+
}
|
|
50838
|
+
|
|
50839
|
+
td,
|
|
50840
|
+
th {
|
|
50841
|
+
border: 1px solid #dee2e6;
|
|
50842
|
+
background-color: #fff;
|
|
50843
|
+
padding: 0.3rem;
|
|
50844
|
+
white-space: nowrap;
|
|
50845
|
+
|
|
50846
|
+
&:hover {
|
|
50847
|
+
filter: brightness(0.9);
|
|
50848
|
+
}
|
|
50849
|
+
}
|
|
50850
|
+
|
|
50851
|
+
td {
|
|
50852
|
+
text-align: right;
|
|
50853
|
+
}
|
|
50854
|
+
|
|
50855
|
+
th {
|
|
50856
|
+
background-color: #f5f5f5;
|
|
50857
|
+
font-weight: bold;
|
|
50858
|
+
color: black;
|
|
50859
|
+
}
|
|
50860
|
+
|
|
50861
|
+
.o_missing_value {
|
|
50862
|
+
color: #46646d;
|
|
50863
|
+
background: #e7f2f6;
|
|
50864
|
+
}
|
|
50865
|
+
}
|
|
50866
|
+
`;
|
|
50867
|
+
class PivotHTMLRenderer extends Component {
|
|
50868
|
+
static template = "o_spreadsheet.PivotHTMLRenderer";
|
|
50869
|
+
static components = { Checkbox };
|
|
50870
|
+
static props = {
|
|
50871
|
+
pivotId: String,
|
|
50872
|
+
onCellClicked: Function,
|
|
50873
|
+
};
|
|
50874
|
+
pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
50875
|
+
data = {
|
|
50876
|
+
columns: [],
|
|
50877
|
+
rows: [],
|
|
50878
|
+
values: [],
|
|
50879
|
+
};
|
|
50880
|
+
state = useState({
|
|
50881
|
+
showMissingValuesOnly: false,
|
|
50882
|
+
});
|
|
50883
|
+
setup() {
|
|
50884
|
+
const table = this.pivot.getTableStructure();
|
|
50885
|
+
const formulaId = this.env.model.getters.getPivotFormulaId(this.props.pivotId);
|
|
50886
|
+
this.data = {
|
|
50887
|
+
columns: this._buildColHeaders(formulaId, table),
|
|
50888
|
+
rows: this._buildRowHeaders(formulaId, table),
|
|
50889
|
+
values: this._buildValues(formulaId, table),
|
|
50890
|
+
};
|
|
50891
|
+
}
|
|
50892
|
+
get tracker() {
|
|
50893
|
+
return this.env.model.getters.getPivotPresenceTracker(this.props.pivotId);
|
|
50894
|
+
}
|
|
50895
|
+
// ---------------------------------------------------------------------
|
|
50896
|
+
// Missing values building
|
|
50897
|
+
// ---------------------------------------------------------------------
|
|
50898
|
+
/**
|
|
50899
|
+
* Retrieve the data to display in the Pivot Table
|
|
50900
|
+
* In the case when showMissingValuesOnly is false, the returned value
|
|
50901
|
+
* is the complete data
|
|
50902
|
+
* In the case when showMissingValuesOnly is true, the returned value is
|
|
50903
|
+
* the data which contains only missing values in the rows and cols. In
|
|
50904
|
+
* the rows, we also return the parent rows of rows which contains missing
|
|
50905
|
+
* values, to give context to the user.
|
|
50906
|
+
*
|
|
50907
|
+
*/
|
|
50908
|
+
getTableData() {
|
|
50909
|
+
if (!this.state.showMissingValuesOnly) {
|
|
50910
|
+
return this.data;
|
|
50911
|
+
}
|
|
50912
|
+
const colIndexes = this.getColumnsIndexes();
|
|
50913
|
+
const rowIndexes = this.getRowsIndexes();
|
|
50914
|
+
const columns = this.buildColumnsMissing(colIndexes);
|
|
50915
|
+
const rows = this.buildRowsMissing(rowIndexes);
|
|
50916
|
+
const values = this.buildValuesMissing(colIndexes, rowIndexes);
|
|
50917
|
+
return { columns, rows, values };
|
|
50918
|
+
}
|
|
50919
|
+
/**
|
|
50920
|
+
* Retrieve the parents of the given row
|
|
50921
|
+
* ex:
|
|
50922
|
+
* Australia
|
|
50923
|
+
* January
|
|
50924
|
+
* February
|
|
50925
|
+
* The parent of "January" is "Australia"
|
|
50926
|
+
*/
|
|
50927
|
+
addRecursiveRow(index) {
|
|
50928
|
+
const rows = this.pivot.getTableStructure().rows;
|
|
50929
|
+
const row = [...rows[index].values];
|
|
50930
|
+
if (row.length <= 1) {
|
|
50931
|
+
return [index];
|
|
50932
|
+
}
|
|
50933
|
+
row.pop();
|
|
50934
|
+
const parentRowIndex = rows.findIndex((r) => JSON.stringify(r.values) === JSON.stringify(row));
|
|
50935
|
+
return [index].concat(this.addRecursiveRow(parentRowIndex));
|
|
50936
|
+
}
|
|
50937
|
+
/**
|
|
50938
|
+
* Create the columns to be used, based on the indexes of the columns in
|
|
50939
|
+
* which a missing value is present
|
|
50940
|
+
*
|
|
50941
|
+
*/
|
|
50942
|
+
buildColumnsMissing(indexes) {
|
|
50943
|
+
// columnsMap explode the columns in an array of array of the same
|
|
50944
|
+
// size with the index of each column, repeated 'span' times.
|
|
50945
|
+
// ex:
|
|
50946
|
+
// | A | B |
|
|
50947
|
+
// | 1 | 2 | 3 |
|
|
50948
|
+
// => [
|
|
50949
|
+
// [0, 0, 1]
|
|
50950
|
+
// [0, 1, 2]
|
|
50951
|
+
// ]
|
|
50952
|
+
const columnsMap = [];
|
|
50953
|
+
for (const column of this.data.columns) {
|
|
50954
|
+
const columnMap = [];
|
|
50955
|
+
for (const index in column) {
|
|
50956
|
+
for (let i = 0; i < column[index].span; i++) {
|
|
50957
|
+
columnMap.push(parseInt(index, 10));
|
|
50958
|
+
}
|
|
50959
|
+
}
|
|
50960
|
+
columnsMap.push(columnMap);
|
|
50961
|
+
}
|
|
50962
|
+
// Remove the columns that are not present in indexes
|
|
50963
|
+
for (let i = columnsMap[columnsMap.length - 1].length; i >= 0; i--) {
|
|
50964
|
+
if (!indexes.includes(i)) {
|
|
50965
|
+
for (const columnMap of columnsMap) {
|
|
50966
|
+
columnMap.splice(i, 1);
|
|
50967
|
+
}
|
|
50968
|
+
}
|
|
50969
|
+
}
|
|
50970
|
+
// Build the columns
|
|
50971
|
+
const columns = [];
|
|
50972
|
+
for (const mapIndex in columnsMap) {
|
|
50973
|
+
const column = [];
|
|
50974
|
+
let index = undefined;
|
|
50975
|
+
let span = 1;
|
|
50976
|
+
for (let i = 0; i < columnsMap[mapIndex].length; i++) {
|
|
50977
|
+
if (index !== columnsMap[mapIndex][i]) {
|
|
50978
|
+
if (index !== undefined) {
|
|
50979
|
+
column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
|
|
50980
|
+
}
|
|
50981
|
+
index = columnsMap[mapIndex][i];
|
|
50982
|
+
span = 1;
|
|
50983
|
+
}
|
|
50984
|
+
else {
|
|
50985
|
+
span++;
|
|
50986
|
+
}
|
|
50987
|
+
}
|
|
50988
|
+
if (index !== undefined) {
|
|
50989
|
+
column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
|
|
50990
|
+
}
|
|
50991
|
+
columns.push(column);
|
|
50992
|
+
}
|
|
50993
|
+
return columns;
|
|
50994
|
+
}
|
|
50995
|
+
/**
|
|
50996
|
+
* Create the rows to be used, based on the indexes of the rows in
|
|
50997
|
+
* which a missing value is present.
|
|
50998
|
+
*/
|
|
50999
|
+
buildRowsMissing(indexes) {
|
|
51000
|
+
return indexes.map((index) => this.data.rows[index]);
|
|
51001
|
+
}
|
|
51002
|
+
/**
|
|
51003
|
+
* Create the value to be used, based on the indexes of the columns and
|
|
51004
|
+
* rows in which a missing value is present.
|
|
51005
|
+
*/
|
|
51006
|
+
buildValuesMissing(colIndexes, rowIndexes) {
|
|
51007
|
+
const values = colIndexes.map(() => []);
|
|
51008
|
+
for (const row of rowIndexes) {
|
|
51009
|
+
for (const col in colIndexes) {
|
|
51010
|
+
values[col].push(this.data.values[colIndexes[col]][row]);
|
|
51011
|
+
}
|
|
51012
|
+
}
|
|
51013
|
+
return values;
|
|
51014
|
+
}
|
|
51015
|
+
getColumnsIndexes() {
|
|
51016
|
+
const indexes = new Set();
|
|
51017
|
+
for (let i = 0; i < this.data.columns.length; i++) {
|
|
51018
|
+
const exploded = [];
|
|
51019
|
+
for (let y = 0; y < this.data.columns[i].length; y++) {
|
|
51020
|
+
for (let x = 0; x < this.data.columns[i][y].span; x++) {
|
|
51021
|
+
exploded.push(this.data.columns[i][y]);
|
|
51022
|
+
}
|
|
51023
|
+
}
|
|
51024
|
+
for (let y = 0; y < exploded.length; y++) {
|
|
51025
|
+
if (exploded[y].isMissing) {
|
|
51026
|
+
indexes.add(y);
|
|
51027
|
+
}
|
|
51028
|
+
}
|
|
51029
|
+
}
|
|
51030
|
+
for (let i = 0; i < this.data.columns[this.data.columns.length - 1].length; i++) {
|
|
51031
|
+
const values = this.data.values[i];
|
|
51032
|
+
if (values.find((x) => x.isMissing)) {
|
|
51033
|
+
indexes.add(i);
|
|
51034
|
+
}
|
|
51035
|
+
}
|
|
51036
|
+
return Array.from(indexes).sort((a, b) => a - b);
|
|
51037
|
+
}
|
|
51038
|
+
getRowsIndexes() {
|
|
51039
|
+
const rowIndexes = new Set();
|
|
51040
|
+
for (let i = 0; i < this.data.rows.length; i++) {
|
|
51041
|
+
if (this.data.rows[i].isMissing) {
|
|
51042
|
+
rowIndexes.add(i);
|
|
51043
|
+
}
|
|
51044
|
+
for (const col of this.data.values) {
|
|
51045
|
+
if (col[i].isMissing) {
|
|
51046
|
+
this.addRecursiveRow(i).forEach((x) => rowIndexes.add(x));
|
|
51047
|
+
}
|
|
51048
|
+
}
|
|
51049
|
+
}
|
|
51050
|
+
return Array.from(rowIndexes).sort((a, b) => a - b);
|
|
51051
|
+
}
|
|
51052
|
+
// ---------------------------------------------------------------------
|
|
51053
|
+
// Data table creation
|
|
51054
|
+
// ---------------------------------------------------------------------
|
|
51055
|
+
_buildColHeaders(id, table) {
|
|
51056
|
+
const headers = [];
|
|
51057
|
+
for (const row of table.columns) {
|
|
51058
|
+
const current = [];
|
|
51059
|
+
for (const cell of row) {
|
|
51060
|
+
const args = [];
|
|
51061
|
+
for (let i = 0; i < cell.fields.length; i++) {
|
|
51062
|
+
args.push({ value: cell.fields[i] }, { value: cell.values[i] });
|
|
51063
|
+
}
|
|
51064
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
51065
|
+
const locale = this.env.model.getters.getLocale();
|
|
51066
|
+
if (domain.at(-1)?.field === "measure") {
|
|
51067
|
+
const { value, format } = this.pivot.getPivotMeasureValue(toString(domain.at(-1).value), domain);
|
|
51068
|
+
current.push({
|
|
51069
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
51070
|
+
value: formatValue(value, { format, locale }),
|
|
51071
|
+
span: cell.width,
|
|
51072
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
51073
|
+
});
|
|
51074
|
+
}
|
|
51075
|
+
else {
|
|
51076
|
+
const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
|
|
51077
|
+
current.push({
|
|
51078
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
51079
|
+
value: formatValue(value, { format, locale }),
|
|
51080
|
+
span: cell.width,
|
|
51081
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
51082
|
+
});
|
|
51083
|
+
}
|
|
51084
|
+
}
|
|
51085
|
+
headers.push(current);
|
|
51086
|
+
}
|
|
51087
|
+
const last = headers[headers.length - 1];
|
|
51088
|
+
headers[headers.length - 1] = last.map((cell) => {
|
|
51089
|
+
if (!cell.isMissing) {
|
|
51090
|
+
cell.style = "color: #756f6f;";
|
|
51091
|
+
}
|
|
51092
|
+
return cell;
|
|
51093
|
+
});
|
|
51094
|
+
return headers;
|
|
51095
|
+
}
|
|
51096
|
+
_buildRowHeaders(id, table) {
|
|
51097
|
+
const headers = [];
|
|
51098
|
+
for (const row of table.rows) {
|
|
51099
|
+
const args = [];
|
|
51100
|
+
for (let i = 0; i < row.fields.length; i++) {
|
|
51101
|
+
args.push({ value: row.fields[i] }, { value: row.values[i] });
|
|
51102
|
+
}
|
|
51103
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
51104
|
+
const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
|
|
51105
|
+
const locale = this.env.model.getters.getLocale();
|
|
51106
|
+
const cell = {
|
|
51107
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
51108
|
+
value: formatValue(value, { format, locale }),
|
|
51109
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
51110
|
+
};
|
|
51111
|
+
if (row.indent > 1) {
|
|
51112
|
+
cell.style = `padding-left: ${row.indent - 1 * 10}px`;
|
|
51113
|
+
}
|
|
51114
|
+
headers.push(cell);
|
|
51115
|
+
}
|
|
51116
|
+
return headers;
|
|
51117
|
+
}
|
|
51118
|
+
_buildValues(id, table) {
|
|
51119
|
+
const values = [];
|
|
51120
|
+
for (const col of table.columns.at(-1) || []) {
|
|
51121
|
+
const current = [];
|
|
51122
|
+
const measure = toString(col.values[col.values.length - 1]);
|
|
51123
|
+
for (const row of table.rows) {
|
|
51124
|
+
const args = [];
|
|
51125
|
+
for (let i = 0; i < row.fields.length; i++) {
|
|
51126
|
+
args.push({ value: row.fields[i] }, { value: row.values[i] });
|
|
51127
|
+
}
|
|
51128
|
+
for (let i = 0; i < col.fields.length - 1; i++) {
|
|
51129
|
+
args.push({ value: col.fields[i] }, { value: col.values[i] });
|
|
51130
|
+
}
|
|
51131
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
51132
|
+
const { value, format } = this.pivot.getPivotCellValueAndFormat(measure, domain);
|
|
51133
|
+
const locale = this.env.model.getters.getLocale();
|
|
51134
|
+
current.push({
|
|
51135
|
+
formula: `=PIVOT.VALUE(${generatePivotArgs(id, domain, measure).join(",")})`,
|
|
51136
|
+
value: formatValue(value, { format, locale }),
|
|
51137
|
+
isMissing: !this.tracker?.isValuePresent(measure, domain),
|
|
51138
|
+
});
|
|
51139
|
+
}
|
|
51140
|
+
values.push(current);
|
|
51141
|
+
}
|
|
51142
|
+
return values;
|
|
51143
|
+
}
|
|
51144
|
+
}
|
|
51145
|
+
|
|
50780
51146
|
/**
|
|
50781
51147
|
* BasePlugin
|
|
50782
51148
|
*
|
|
@@ -54285,7 +54651,7 @@ class RangeAdapter {
|
|
|
54285
54651
|
if (range.sheetId === cmd.sheetId) {
|
|
54286
54652
|
return { changeType: "CHANGE", range };
|
|
54287
54653
|
}
|
|
54288
|
-
if (
|
|
54654
|
+
if (isSheetNameEqual(range.invalidSheetName, cmd.name)) {
|
|
54289
54655
|
const invalidSheetName = undefined;
|
|
54290
54656
|
const sheetId = cmd.sheetId;
|
|
54291
54657
|
const newRange = range.clone({ sheetId, invalidSheetName });
|
|
@@ -54870,7 +55236,7 @@ class SheetPlugin extends CorePlugin {
|
|
|
54870
55236
|
if (name) {
|
|
54871
55237
|
const unquotedName = getUnquotedSheetName(name);
|
|
54872
55238
|
for (const key in this.sheetIdsMapName) {
|
|
54873
|
-
if (key
|
|
55239
|
+
if (isSheetNameEqual(key, unquotedName)) {
|
|
54874
55240
|
return this.sheetIdsMapName[key];
|
|
54875
55241
|
}
|
|
54876
55242
|
}
|
|
@@ -55118,7 +55484,7 @@ class SheetPlugin extends CorePlugin {
|
|
|
55118
55484
|
}
|
|
55119
55485
|
const { orderedSheetIds, sheets } = this;
|
|
55120
55486
|
const name = cmd.name && cmd.name.trim().toLowerCase();
|
|
55121
|
-
if (orderedSheetIds.find((id) => sheets[id]?.name
|
|
55487
|
+
if (orderedSheetIds.find((id) => isSheetNameEqual(sheets[id]?.name, name) && id !== cmd.sheetId)) {
|
|
55122
55488
|
return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
|
|
55123
55489
|
}
|
|
55124
55490
|
if (FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX.test(name)) {
|
|
@@ -64005,6 +64371,55 @@ class HistoryPlugin extends UIPlugin {
|
|
|
64005
64371
|
}
|
|
64006
64372
|
}
|
|
64007
64373
|
|
|
64374
|
+
class PivotPresenceTracker {
|
|
64375
|
+
trackedValues = new Set();
|
|
64376
|
+
domainToArray(domain) {
|
|
64377
|
+
return domain.flatMap((node) => [node.field, toString(node.value)]);
|
|
64378
|
+
}
|
|
64379
|
+
isValuePresent(measure, domain) {
|
|
64380
|
+
const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
|
|
64381
|
+
return this.trackedValues.has(key);
|
|
64382
|
+
}
|
|
64383
|
+
isHeaderPresent(domain) {
|
|
64384
|
+
const key = JSON.stringify({ domain: this.domainToArray(domain) });
|
|
64385
|
+
return this.trackedValues.has(key);
|
|
64386
|
+
}
|
|
64387
|
+
trackValue(measure, domain) {
|
|
64388
|
+
const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
|
|
64389
|
+
this.trackedValues.add(key);
|
|
64390
|
+
}
|
|
64391
|
+
trackHeader(domain) {
|
|
64392
|
+
const key = JSON.stringify({ domain: this.domainToArray(domain) });
|
|
64393
|
+
this.trackedValues.add(key);
|
|
64394
|
+
}
|
|
64395
|
+
}
|
|
64396
|
+
|
|
64397
|
+
class PivotPresencePlugin extends UIPlugin {
|
|
64398
|
+
static getters = ["getPivotPresenceTracker"];
|
|
64399
|
+
trackPresencePivotId;
|
|
64400
|
+
tracker;
|
|
64401
|
+
handle(cmd) {
|
|
64402
|
+
switch (cmd.type) {
|
|
64403
|
+
case "PIVOT_START_PRESENCE_TRACKING":
|
|
64404
|
+
this.tracker = new PivotPresenceTracker();
|
|
64405
|
+
this.trackPresencePivotId = cmd.pivotId;
|
|
64406
|
+
break;
|
|
64407
|
+
case "PIVOT_STOP_PRESENCE_TRACKING":
|
|
64408
|
+
this.trackPresencePivotId = undefined;
|
|
64409
|
+
break;
|
|
64410
|
+
}
|
|
64411
|
+
}
|
|
64412
|
+
getPivotPresenceTracker(pivotId) {
|
|
64413
|
+
if (this.trackPresencePivotId !== pivotId) {
|
|
64414
|
+
return undefined;
|
|
64415
|
+
}
|
|
64416
|
+
if (!this.tracker) {
|
|
64417
|
+
throw new Error("Tracker not initialized");
|
|
64418
|
+
}
|
|
64419
|
+
return this.tracker;
|
|
64420
|
+
}
|
|
64421
|
+
}
|
|
64422
|
+
|
|
64008
64423
|
class SplitToColumnsPlugin extends UIPlugin {
|
|
64009
64424
|
static getters = ["getAutomaticSeparator"];
|
|
64010
64425
|
allowDispatch(cmd) {
|
|
@@ -66788,6 +67203,7 @@ const featurePluginRegistry = new Registry()
|
|
|
66788
67203
|
.add("automatic_sum", AutomaticSumPlugin)
|
|
66789
67204
|
.add("format", FormatPlugin)
|
|
66790
67205
|
.add("insert_pivot", InsertPivotPlugin)
|
|
67206
|
+
.add("pivot_presence", PivotPresencePlugin)
|
|
66791
67207
|
.add("split_to_columns", SplitToColumnsPlugin)
|
|
66792
67208
|
.add("collaborative", CollaborativePlugin)
|
|
66793
67209
|
.add("history", HistoryPlugin)
|
|
@@ -67167,11 +67583,11 @@ class BottomBarSheet extends Component {
|
|
|
67167
67583
|
if (ev.key === "Enter") {
|
|
67168
67584
|
ev.preventDefault();
|
|
67169
67585
|
this.stopEdition();
|
|
67170
|
-
this.DOMFocusableElementStore.
|
|
67586
|
+
this.DOMFocusableElementStore.focus();
|
|
67171
67587
|
}
|
|
67172
67588
|
if (ev.key === "Escape") {
|
|
67173
67589
|
this.cancelEdition();
|
|
67174
|
-
this.DOMFocusableElementStore.
|
|
67590
|
+
this.DOMFocusableElementStore.focus();
|
|
67175
67591
|
}
|
|
67176
67592
|
}
|
|
67177
67593
|
onMouseEventSheetName(ev) {
|
|
@@ -73781,6 +74197,7 @@ const components = {
|
|
|
73781
74197
|
PivotDimensionOrder,
|
|
73782
74198
|
PivotDimension,
|
|
73783
74199
|
PivotLayoutConfigurator,
|
|
74200
|
+
PivotHTMLRenderer,
|
|
73784
74201
|
EditableName,
|
|
73785
74202
|
PivotDeferUpdate,
|
|
73786
74203
|
PivotTitleSection,
|
|
@@ -73831,6 +74248,6 @@ const constants = {
|
|
|
73831
74248
|
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 };
|
|
73832
74249
|
|
|
73833
74250
|
|
|
73834
|
-
__info__.version = "18.0.
|
|
73835
|
-
__info__.date = "2025-05-
|
|
73836
|
-
__info__.hash = "
|
|
74251
|
+
__info__.version = "18.0.28";
|
|
74252
|
+
__info__.date = "2025-05-13T17:53:12.402Z";
|
|
74253
|
+
__info__.hash = "b3088aa";
|