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