@odoo/o-spreadsheet 18.1.19 → 18.1.20
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 +458 -41
- package/dist/o-spreadsheet.d.ts +277 -152
- package/dist/o-spreadsheet.esm.js +458 -41
- package/dist/o-spreadsheet.iife.js +458 -41
- package/dist/o-spreadsheet.iife.min.js +420 -384
- 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.1.
|
|
6
|
-
* @date 2025-05-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.1.20
|
|
6
|
+
* @date 2025-05-13T17:52:28.174Z
|
|
7
|
+
* @hash 3e43a46
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -3347,7 +3347,7 @@
|
|
|
3347
3347
|
*/
|
|
3348
3348
|
const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
|
|
3349
3349
|
decimalSeparator = escapeRegExp(decimalSeparator);
|
|
3350
|
-
return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e
|
|
3350
|
+
return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e(\\+|-)?\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
|
|
3351
3351
|
});
|
|
3352
3352
|
const getNumberRegex = memoize(function getNumberRegex(locale) {
|
|
3353
3353
|
const decimalSeparator = escapeRegExp(locale.decimalSeparator);
|
|
@@ -6291,6 +6291,13 @@
|
|
|
6291
6291
|
}
|
|
6292
6292
|
return name;
|
|
6293
6293
|
}
|
|
6294
|
+
function isSheetNameEqual(name1, name2) {
|
|
6295
|
+
if (name1 === undefined || name2 === undefined) {
|
|
6296
|
+
return false;
|
|
6297
|
+
}
|
|
6298
|
+
return (getUnquotedSheetName(name1.trim().toUpperCase()) ===
|
|
6299
|
+
getUnquotedSheetName(name2.trim().toUpperCase()));
|
|
6300
|
+
}
|
|
6294
6301
|
|
|
6295
6302
|
function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
|
|
6296
6303
|
return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
|
|
@@ -8154,10 +8161,9 @@
|
|
|
8154
8161
|
avg: _t("Average"),
|
|
8155
8162
|
sum: _t("Sum"),
|
|
8156
8163
|
};
|
|
8157
|
-
const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
|
|
8158
8164
|
const AGGREGATORS_BY_FIELD_TYPE = {
|
|
8159
|
-
integer:
|
|
8160
|
-
char:
|
|
8165
|
+
integer: ["max", "min", "avg", "sum", "count_distinct", "count"],
|
|
8166
|
+
char: ["count_distinct", "count"],
|
|
8161
8167
|
boolean: ["count_distinct", "count", "bool_and", "bool_or"],
|
|
8162
8168
|
};
|
|
8163
8169
|
const AGGREGATORS = {};
|
|
@@ -9509,7 +9515,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9509
9515
|
const functionProxy = new Proxy(value, {
|
|
9510
9516
|
// trap the function call
|
|
9511
9517
|
apply(target, thisArg, argArray) {
|
|
9512
|
-
Reflect.apply(target, thisStore, argArray);
|
|
9518
|
+
const res = Reflect.apply(target, thisStore, argArray);
|
|
9519
|
+
if (res === "noStateChange") {
|
|
9520
|
+
return;
|
|
9521
|
+
}
|
|
9513
9522
|
callback();
|
|
9514
9523
|
},
|
|
9515
9524
|
});
|
|
@@ -9531,7 +9540,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9531
9540
|
const ModelStore = createAbstractStore("Model");
|
|
9532
9541
|
|
|
9533
9542
|
class RendererStore {
|
|
9534
|
-
mutators = ["register", "unRegister"];
|
|
9543
|
+
mutators = ["register", "unRegister", "drawLayer"];
|
|
9535
9544
|
renderers = {};
|
|
9536
9545
|
register(renderer) {
|
|
9537
9546
|
if (!renderer.renderingLayers.length) {
|
|
@@ -9551,14 +9560,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9551
9560
|
}
|
|
9552
9561
|
drawLayer(context, layer) {
|
|
9553
9562
|
const renderers = this.renderers[layer];
|
|
9554
|
-
if (
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
context.ctx.restore();
|
|
9563
|
+
if (renderers) {
|
|
9564
|
+
for (const renderer of renderers) {
|
|
9565
|
+
context.ctx.save();
|
|
9566
|
+
renderer.drawLayer(context, layer);
|
|
9567
|
+
context.ctx.restore();
|
|
9568
|
+
}
|
|
9561
9569
|
}
|
|
9570
|
+
return "noStateChange";
|
|
9562
9571
|
}
|
|
9563
9572
|
}
|
|
9564
9573
|
|
|
@@ -9611,16 +9620,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9611
9620
|
focusComposer(listener, args) {
|
|
9612
9621
|
this.activeComposer = listener;
|
|
9613
9622
|
if (this.getters.isReadonly()) {
|
|
9614
|
-
return;
|
|
9623
|
+
return "noStateChange";
|
|
9615
9624
|
}
|
|
9616
9625
|
this._focusMode = args.focusMode || "contentFocus";
|
|
9617
9626
|
if (this._focusMode !== "inactive") {
|
|
9618
9627
|
this.setComposerContent(args);
|
|
9619
9628
|
}
|
|
9629
|
+
return;
|
|
9620
9630
|
}
|
|
9621
9631
|
focusActiveComposer(args) {
|
|
9622
9632
|
if (this.getters.isReadonly()) {
|
|
9623
|
-
return;
|
|
9633
|
+
return "noStateChange";
|
|
9624
9634
|
}
|
|
9625
9635
|
if (!this.activeComposer) {
|
|
9626
9636
|
throw new Error("No composer is registered");
|
|
@@ -9629,6 +9639,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9629
9639
|
if (this._focusMode !== "inactive") {
|
|
9630
9640
|
this.setComposerContent(args);
|
|
9631
9641
|
}
|
|
9642
|
+
return;
|
|
9632
9643
|
}
|
|
9633
9644
|
/**
|
|
9634
9645
|
* Start the edition or update the content if it's already started.
|
|
@@ -9978,7 +9989,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9978
9989
|
}
|
|
9979
9990
|
function formatChartDatasetValue(axisFormats, locale) {
|
|
9980
9991
|
return (value, axisId) => {
|
|
9981
|
-
const format =
|
|
9992
|
+
const format = axisFormats?.[axisId];
|
|
9982
9993
|
return formatTickValue({ format, locale })(value);
|
|
9983
9994
|
};
|
|
9984
9995
|
}
|
|
@@ -10142,7 +10153,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
10142
10153
|
const y = bar.y + midRadius * Math.sin(midAngle) + 7;
|
|
10143
10154
|
ctx.fillStyle = chartFontColor(options.background);
|
|
10144
10155
|
ctx.strokeStyle = options.background || "#ffffff";
|
|
10145
|
-
const displayValue = options.callback(value);
|
|
10156
|
+
const displayValue = options.callback(value, "y");
|
|
10146
10157
|
drawTextWithBackground(displayValue, x, y, ctx);
|
|
10147
10158
|
}
|
|
10148
10159
|
}
|
|
@@ -19032,6 +19043,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19032
19043
|
};
|
|
19033
19044
|
}
|
|
19034
19045
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
19046
|
+
if (this.getters.getActiveSheetId() === this.__originSheetId) {
|
|
19047
|
+
this.getters.getPivotPresenceTracker(pivotId)?.trackValue(_measure, domain);
|
|
19048
|
+
}
|
|
19035
19049
|
return pivot.getPivotCellValueAndFormat(_measure, domain);
|
|
19036
19050
|
},
|
|
19037
19051
|
};
|
|
@@ -19063,6 +19077,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19063
19077
|
};
|
|
19064
19078
|
}
|
|
19065
19079
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
19080
|
+
if (this.getters.getActiveSheetId() === this.__originSheetId) {
|
|
19081
|
+
this.getters.getPivotPresenceTracker(_pivotId)?.trackHeader(domain);
|
|
19082
|
+
}
|
|
19066
19083
|
const lastNode = domain.at(-1);
|
|
19067
19084
|
if (lastNode?.field === "measure") {
|
|
19068
19085
|
return pivot.getPivotMeasureValue(toString(lastNode.value), domain);
|
|
@@ -19285,6 +19302,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19285
19302
|
return data === undefined || data.value === null;
|
|
19286
19303
|
}
|
|
19287
19304
|
const getNeutral = { number: 0, string: "", boolean: false };
|
|
19305
|
+
function areAlmostEqual(value1, value2, epsilon = 2e-16) {
|
|
19306
|
+
return Math.abs(value1 - value2) < epsilon;
|
|
19307
|
+
}
|
|
19288
19308
|
const EQ = {
|
|
19289
19309
|
description: _t("Equal."),
|
|
19290
19310
|
args: [
|
|
@@ -19306,6 +19326,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19306
19326
|
if (typeof _value2 === "string") {
|
|
19307
19327
|
_value2 = _value2.toUpperCase();
|
|
19308
19328
|
}
|
|
19329
|
+
if (typeof _value1 === "number" && typeof _value2 === "number") {
|
|
19330
|
+
return { value: areAlmostEqual(_value1, _value2) };
|
|
19331
|
+
}
|
|
19309
19332
|
return { value: _value1 === _value2 };
|
|
19310
19333
|
},
|
|
19311
19334
|
};
|
|
@@ -19345,6 +19368,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19345
19368
|
],
|
|
19346
19369
|
compute: function (value1, value2) {
|
|
19347
19370
|
return applyRelationalOperator(value1, value2, (v1, v2) => {
|
|
19371
|
+
if (typeof v1 === "number" && typeof v2 === "number") {
|
|
19372
|
+
return !areAlmostEqual(v1, v2) && v1 > v2;
|
|
19373
|
+
}
|
|
19348
19374
|
return v1 > v2;
|
|
19349
19375
|
});
|
|
19350
19376
|
},
|
|
@@ -19360,6 +19386,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19360
19386
|
],
|
|
19361
19387
|
compute: function (value1, value2) {
|
|
19362
19388
|
return applyRelationalOperator(value1, value2, (v1, v2) => {
|
|
19389
|
+
if (typeof v1 === "number" && typeof v2 === "number") {
|
|
19390
|
+
return areAlmostEqual(v1, v2) || v1 > v2;
|
|
19391
|
+
}
|
|
19363
19392
|
return v1 >= v2;
|
|
19364
19393
|
});
|
|
19365
19394
|
},
|
|
@@ -20966,7 +20995,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20966
20995
|
.find((token) => {
|
|
20967
20996
|
const { xc, sheetName: sheet } = splitReference(token.value);
|
|
20968
20997
|
const sheetName = sheet || this.getters.getSheetName(this.sheetId);
|
|
20969
|
-
if (this.getters.getSheetName(activeSheetId)
|
|
20998
|
+
if (!isSheetNameEqual(this.getters.getSheetName(activeSheetId), sheetName)) {
|
|
20970
20999
|
return false;
|
|
20971
21000
|
}
|
|
20972
21001
|
const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
|
|
@@ -24577,7 +24606,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24577
24606
|
({ xc, sheetName } = splitReference(reference));
|
|
24578
24607
|
let rangeSheetIndex;
|
|
24579
24608
|
if (sheetName) {
|
|
24580
|
-
const index = data.sheets.findIndex((sheet) => sheet.name
|
|
24609
|
+
const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
|
|
24581
24610
|
if (index < 0) {
|
|
24582
24611
|
throw new Error("Unable to find a sheet with the name " + sheetName);
|
|
24583
24612
|
}
|
|
@@ -24918,7 +24947,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24918
24947
|
formula = formula.replace(externalReferenceRegex, (match, externalRefId, sheetName, cellRef) => {
|
|
24919
24948
|
externalRefId = Number(externalRefId) - 1;
|
|
24920
24949
|
cellRef = cellRef.replace(/\$/g, "");
|
|
24921
|
-
const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => name
|
|
24950
|
+
const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => isSheetNameEqual(name, sheetName));
|
|
24922
24951
|
if (sheetIndex === -1) {
|
|
24923
24952
|
return match;
|
|
24924
24953
|
}
|
|
@@ -25569,7 +25598,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25569
25598
|
*/
|
|
25570
25599
|
function convertTableFormulaReferences(convertedSheets, xlsxSheets) {
|
|
25571
25600
|
for (let tableSheet of convertedSheets) {
|
|
25572
|
-
const tables = xlsxSheets.find((s) => s.sheetName
|
|
25601
|
+
const tables = xlsxSheets.find((s) => isSheetNameEqual(s.sheetName, tableSheet.name)).tables;
|
|
25573
25602
|
for (let table of tables) {
|
|
25574
25603
|
const tabRef = table.name + "[";
|
|
25575
25604
|
for (let sheet of convertedSheets) {
|
|
@@ -32404,12 +32433,20 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32404
32433
|
}
|
|
32405
32434
|
}
|
|
32406
32435
|
hover(position) {
|
|
32436
|
+
if (position.col === this.col && position.row === this.row) {
|
|
32437
|
+
return "noStateChange";
|
|
32438
|
+
}
|
|
32407
32439
|
this.col = position.col;
|
|
32408
32440
|
this.row = position.row;
|
|
32441
|
+
return;
|
|
32409
32442
|
}
|
|
32410
32443
|
clear() {
|
|
32444
|
+
if (this.col === undefined && this.row === undefined) {
|
|
32445
|
+
return "noStateChange";
|
|
32446
|
+
}
|
|
32411
32447
|
this.col = undefined;
|
|
32412
32448
|
this.row = undefined;
|
|
32449
|
+
return;
|
|
32413
32450
|
}
|
|
32414
32451
|
}
|
|
32415
32452
|
|
|
@@ -32431,7 +32468,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32431
32468
|
this.persistentPopover = { col, row, sheetId, type };
|
|
32432
32469
|
}
|
|
32433
32470
|
close() {
|
|
32471
|
+
if (!this.persistentPopover) {
|
|
32472
|
+
return "noStateChange";
|
|
32473
|
+
}
|
|
32434
32474
|
this.persistentPopover = undefined;
|
|
32475
|
+
return;
|
|
32435
32476
|
}
|
|
32436
32477
|
get persistentCellPopover() {
|
|
32437
32478
|
return ((this.persistentPopover && { isOpen: true, ...this.persistentPopover }) || { isOpen: false });
|
|
@@ -40263,10 +40304,18 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40263
40304
|
}
|
|
40264
40305
|
|
|
40265
40306
|
class DOMFocusableElementStore {
|
|
40266
|
-
mutators = ["setFocusableElement"];
|
|
40307
|
+
mutators = ["setFocusableElement", "focus"];
|
|
40267
40308
|
focusableElement = undefined;
|
|
40268
40309
|
setFocusableElement(element) {
|
|
40269
40310
|
this.focusableElement = element;
|
|
40311
|
+
return "noStateChange";
|
|
40312
|
+
}
|
|
40313
|
+
focus() {
|
|
40314
|
+
if (this.focusableElement === document.activeElement) {
|
|
40315
|
+
return "noStateChange";
|
|
40316
|
+
}
|
|
40317
|
+
this.focusableElement?.focus();
|
|
40318
|
+
return;
|
|
40270
40319
|
}
|
|
40271
40320
|
}
|
|
40272
40321
|
|
|
@@ -40856,7 +40905,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40856
40905
|
if (document.activeElement === this.contentHelper.el &&
|
|
40857
40906
|
this.props.composerStore.editionMode === "inactive" &&
|
|
40858
40907
|
!this.props.isDefaultFocus) {
|
|
40859
|
-
this.DOMFocusableElementStore.
|
|
40908
|
+
this.DOMFocusableElementStore.focus();
|
|
40860
40909
|
}
|
|
40861
40910
|
});
|
|
40862
40911
|
owl.useEffect(() => {
|
|
@@ -46603,7 +46652,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46603
46652
|
entry[field.name] = { value: null, type: CellValueType.empty, formattedValue: "" };
|
|
46604
46653
|
}
|
|
46605
46654
|
else {
|
|
46606
|
-
|
|
46655
|
+
if (field.type === "char") {
|
|
46656
|
+
entry[field.name] = { ...cell, value: cell.formattedValue || null };
|
|
46657
|
+
}
|
|
46658
|
+
else {
|
|
46659
|
+
entry[field.name] = cell;
|
|
46660
|
+
}
|
|
46607
46661
|
}
|
|
46608
46662
|
}
|
|
46609
46663
|
entry["__count"] = { value: 1, type: CellValueType.number, formattedValue: "1" };
|
|
@@ -51632,10 +51686,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51632
51686
|
ctx.scale(dpr, dpr);
|
|
51633
51687
|
for (const layer of OrderedLayers()) {
|
|
51634
51688
|
model.drawLayer(renderingContext, layer);
|
|
51635
|
-
// @ts-ignore 'drawLayer' is not declated as a mutator because:
|
|
51636
|
-
// it does not mutate anything. Most importantly it's used
|
|
51637
|
-
// during rendering. Invoking a mutator during rendering would
|
|
51638
|
-
// trigger another rendering, ultimately resulting in an infinite loop.
|
|
51639
51689
|
rendererStore.drawLayer(renderingContext, layer);
|
|
51640
51690
|
}
|
|
51641
51691
|
}
|
|
@@ -52325,7 +52375,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52325
52375
|
this.cellPopovers = useStore(CellPopoverStore);
|
|
52326
52376
|
owl.useEffect(() => {
|
|
52327
52377
|
if (!this.sidePanel.isOpen) {
|
|
52328
|
-
this.DOMFocusableElementStore.
|
|
52378
|
+
this.DOMFocusableElementStore.focus();
|
|
52329
52379
|
}
|
|
52330
52380
|
}, () => [this.sidePanel.isOpen]);
|
|
52331
52381
|
useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
|
|
@@ -52535,7 +52585,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52535
52585
|
focusDefaultElement() {
|
|
52536
52586
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
52537
52587
|
this.composerFocusStore.activeComposer.editionMode === "inactive") {
|
|
52538
|
-
this.DOMFocusableElementStore.
|
|
52588
|
+
this.DOMFocusableElementStore.focus();
|
|
52539
52589
|
}
|
|
52540
52590
|
}
|
|
52541
52591
|
get gridEl() {
|
|
@@ -52880,6 +52930,322 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52880
52930
|
}
|
|
52881
52931
|
}
|
|
52882
52932
|
|
|
52933
|
+
css /* scss */ `
|
|
52934
|
+
.o_pivot_html_renderer {
|
|
52935
|
+
width: 100%;
|
|
52936
|
+
border-collapse: collapse;
|
|
52937
|
+
|
|
52938
|
+
&:hover {
|
|
52939
|
+
cursor: pointer;
|
|
52940
|
+
}
|
|
52941
|
+
|
|
52942
|
+
td,
|
|
52943
|
+
th {
|
|
52944
|
+
border: 1px solid #dee2e6;
|
|
52945
|
+
background-color: #fff;
|
|
52946
|
+
padding: 0.3rem;
|
|
52947
|
+
white-space: nowrap;
|
|
52948
|
+
|
|
52949
|
+
&:hover {
|
|
52950
|
+
filter: brightness(0.9);
|
|
52951
|
+
}
|
|
52952
|
+
}
|
|
52953
|
+
|
|
52954
|
+
td {
|
|
52955
|
+
text-align: right;
|
|
52956
|
+
}
|
|
52957
|
+
|
|
52958
|
+
th {
|
|
52959
|
+
background-color: #f5f5f5;
|
|
52960
|
+
font-weight: bold;
|
|
52961
|
+
color: black;
|
|
52962
|
+
}
|
|
52963
|
+
|
|
52964
|
+
.o_missing_value {
|
|
52965
|
+
color: #46646d;
|
|
52966
|
+
background: #e7f2f6;
|
|
52967
|
+
}
|
|
52968
|
+
}
|
|
52969
|
+
`;
|
|
52970
|
+
class PivotHTMLRenderer extends owl.Component {
|
|
52971
|
+
static template = "o_spreadsheet.PivotHTMLRenderer";
|
|
52972
|
+
static components = { Checkbox };
|
|
52973
|
+
static props = {
|
|
52974
|
+
pivotId: String,
|
|
52975
|
+
onCellClicked: Function,
|
|
52976
|
+
};
|
|
52977
|
+
pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
52978
|
+
data = {
|
|
52979
|
+
columns: [],
|
|
52980
|
+
rows: [],
|
|
52981
|
+
values: [],
|
|
52982
|
+
};
|
|
52983
|
+
state = owl.useState({
|
|
52984
|
+
showMissingValuesOnly: false,
|
|
52985
|
+
});
|
|
52986
|
+
setup() {
|
|
52987
|
+
const table = this.pivot.getTableStructure();
|
|
52988
|
+
const formulaId = this.env.model.getters.getPivotFormulaId(this.props.pivotId);
|
|
52989
|
+
this.data = {
|
|
52990
|
+
columns: this._buildColHeaders(formulaId, table),
|
|
52991
|
+
rows: this._buildRowHeaders(formulaId, table),
|
|
52992
|
+
values: this._buildValues(formulaId, table),
|
|
52993
|
+
};
|
|
52994
|
+
}
|
|
52995
|
+
get tracker() {
|
|
52996
|
+
return this.env.model.getters.getPivotPresenceTracker(this.props.pivotId);
|
|
52997
|
+
}
|
|
52998
|
+
// ---------------------------------------------------------------------
|
|
52999
|
+
// Missing values building
|
|
53000
|
+
// ---------------------------------------------------------------------
|
|
53001
|
+
/**
|
|
53002
|
+
* Retrieve the data to display in the Pivot Table
|
|
53003
|
+
* In the case when showMissingValuesOnly is false, the returned value
|
|
53004
|
+
* is the complete data
|
|
53005
|
+
* In the case when showMissingValuesOnly is true, the returned value is
|
|
53006
|
+
* the data which contains only missing values in the rows and cols. In
|
|
53007
|
+
* the rows, we also return the parent rows of rows which contains missing
|
|
53008
|
+
* values, to give context to the user.
|
|
53009
|
+
*
|
|
53010
|
+
*/
|
|
53011
|
+
getTableData() {
|
|
53012
|
+
if (!this.state.showMissingValuesOnly) {
|
|
53013
|
+
return this.data;
|
|
53014
|
+
}
|
|
53015
|
+
const colIndexes = this.getColumnsIndexes();
|
|
53016
|
+
const rowIndexes = this.getRowsIndexes();
|
|
53017
|
+
const columns = this.buildColumnsMissing(colIndexes);
|
|
53018
|
+
const rows = this.buildRowsMissing(rowIndexes);
|
|
53019
|
+
const values = this.buildValuesMissing(colIndexes, rowIndexes);
|
|
53020
|
+
return { columns, rows, values };
|
|
53021
|
+
}
|
|
53022
|
+
/**
|
|
53023
|
+
* Retrieve the parents of the given row
|
|
53024
|
+
* ex:
|
|
53025
|
+
* Australia
|
|
53026
|
+
* January
|
|
53027
|
+
* February
|
|
53028
|
+
* The parent of "January" is "Australia"
|
|
53029
|
+
*/
|
|
53030
|
+
addRecursiveRow(index) {
|
|
53031
|
+
const rows = this.pivot.getTableStructure().rows;
|
|
53032
|
+
const row = [...rows[index].values];
|
|
53033
|
+
if (row.length <= 1) {
|
|
53034
|
+
return [index];
|
|
53035
|
+
}
|
|
53036
|
+
row.pop();
|
|
53037
|
+
const parentRowIndex = rows.findIndex((r) => JSON.stringify(r.values) === JSON.stringify(row));
|
|
53038
|
+
return [index].concat(this.addRecursiveRow(parentRowIndex));
|
|
53039
|
+
}
|
|
53040
|
+
/**
|
|
53041
|
+
* Create the columns to be used, based on the indexes of the columns in
|
|
53042
|
+
* which a missing value is present
|
|
53043
|
+
*
|
|
53044
|
+
*/
|
|
53045
|
+
buildColumnsMissing(indexes) {
|
|
53046
|
+
// columnsMap explode the columns in an array of array of the same
|
|
53047
|
+
// size with the index of each column, repeated 'span' times.
|
|
53048
|
+
// ex:
|
|
53049
|
+
// | A | B |
|
|
53050
|
+
// | 1 | 2 | 3 |
|
|
53051
|
+
// => [
|
|
53052
|
+
// [0, 0, 1]
|
|
53053
|
+
// [0, 1, 2]
|
|
53054
|
+
// ]
|
|
53055
|
+
const columnsMap = [];
|
|
53056
|
+
for (const column of this.data.columns) {
|
|
53057
|
+
const columnMap = [];
|
|
53058
|
+
for (const index in column) {
|
|
53059
|
+
for (let i = 0; i < column[index].span; i++) {
|
|
53060
|
+
columnMap.push(parseInt(index, 10));
|
|
53061
|
+
}
|
|
53062
|
+
}
|
|
53063
|
+
columnsMap.push(columnMap);
|
|
53064
|
+
}
|
|
53065
|
+
// Remove the columns that are not present in indexes
|
|
53066
|
+
for (let i = columnsMap[columnsMap.length - 1].length; i >= 0; i--) {
|
|
53067
|
+
if (!indexes.includes(i)) {
|
|
53068
|
+
for (const columnMap of columnsMap) {
|
|
53069
|
+
columnMap.splice(i, 1);
|
|
53070
|
+
}
|
|
53071
|
+
}
|
|
53072
|
+
}
|
|
53073
|
+
// Build the columns
|
|
53074
|
+
const columns = [];
|
|
53075
|
+
for (const mapIndex in columnsMap) {
|
|
53076
|
+
const column = [];
|
|
53077
|
+
let index = undefined;
|
|
53078
|
+
let span = 1;
|
|
53079
|
+
for (let i = 0; i < columnsMap[mapIndex].length; i++) {
|
|
53080
|
+
if (index !== columnsMap[mapIndex][i]) {
|
|
53081
|
+
if (index !== undefined) {
|
|
53082
|
+
column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
|
|
53083
|
+
}
|
|
53084
|
+
index = columnsMap[mapIndex][i];
|
|
53085
|
+
span = 1;
|
|
53086
|
+
}
|
|
53087
|
+
else {
|
|
53088
|
+
span++;
|
|
53089
|
+
}
|
|
53090
|
+
}
|
|
53091
|
+
if (index !== undefined) {
|
|
53092
|
+
column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
|
|
53093
|
+
}
|
|
53094
|
+
columns.push(column);
|
|
53095
|
+
}
|
|
53096
|
+
return columns;
|
|
53097
|
+
}
|
|
53098
|
+
/**
|
|
53099
|
+
* Create the rows to be used, based on the indexes of the rows in
|
|
53100
|
+
* which a missing value is present.
|
|
53101
|
+
*/
|
|
53102
|
+
buildRowsMissing(indexes) {
|
|
53103
|
+
return indexes.map((index) => this.data.rows[index]);
|
|
53104
|
+
}
|
|
53105
|
+
/**
|
|
53106
|
+
* Create the value to be used, based on the indexes of the columns and
|
|
53107
|
+
* rows in which a missing value is present.
|
|
53108
|
+
*/
|
|
53109
|
+
buildValuesMissing(colIndexes, rowIndexes) {
|
|
53110
|
+
const values = colIndexes.map(() => []);
|
|
53111
|
+
for (const row of rowIndexes) {
|
|
53112
|
+
for (const col in colIndexes) {
|
|
53113
|
+
values[col].push(this.data.values[colIndexes[col]][row]);
|
|
53114
|
+
}
|
|
53115
|
+
}
|
|
53116
|
+
return values;
|
|
53117
|
+
}
|
|
53118
|
+
getColumnsIndexes() {
|
|
53119
|
+
const indexes = new Set();
|
|
53120
|
+
for (let i = 0; i < this.data.columns.length; i++) {
|
|
53121
|
+
const exploded = [];
|
|
53122
|
+
for (let y = 0; y < this.data.columns[i].length; y++) {
|
|
53123
|
+
for (let x = 0; x < this.data.columns[i][y].span; x++) {
|
|
53124
|
+
exploded.push(this.data.columns[i][y]);
|
|
53125
|
+
}
|
|
53126
|
+
}
|
|
53127
|
+
for (let y = 0; y < exploded.length; y++) {
|
|
53128
|
+
if (exploded[y].isMissing) {
|
|
53129
|
+
indexes.add(y);
|
|
53130
|
+
}
|
|
53131
|
+
}
|
|
53132
|
+
}
|
|
53133
|
+
for (let i = 0; i < this.data.columns[this.data.columns.length - 1].length; i++) {
|
|
53134
|
+
const values = this.data.values[i];
|
|
53135
|
+
if (values.find((x) => x.isMissing)) {
|
|
53136
|
+
indexes.add(i);
|
|
53137
|
+
}
|
|
53138
|
+
}
|
|
53139
|
+
return Array.from(indexes).sort((a, b) => a - b);
|
|
53140
|
+
}
|
|
53141
|
+
getRowsIndexes() {
|
|
53142
|
+
const rowIndexes = new Set();
|
|
53143
|
+
for (let i = 0; i < this.data.rows.length; i++) {
|
|
53144
|
+
if (this.data.rows[i].isMissing) {
|
|
53145
|
+
rowIndexes.add(i);
|
|
53146
|
+
}
|
|
53147
|
+
for (const col of this.data.values) {
|
|
53148
|
+
if (col[i].isMissing) {
|
|
53149
|
+
this.addRecursiveRow(i).forEach((x) => rowIndexes.add(x));
|
|
53150
|
+
}
|
|
53151
|
+
}
|
|
53152
|
+
}
|
|
53153
|
+
return Array.from(rowIndexes).sort((a, b) => a - b);
|
|
53154
|
+
}
|
|
53155
|
+
// ---------------------------------------------------------------------
|
|
53156
|
+
// Data table creation
|
|
53157
|
+
// ---------------------------------------------------------------------
|
|
53158
|
+
_buildColHeaders(id, table) {
|
|
53159
|
+
const headers = [];
|
|
53160
|
+
for (const row of table.columns) {
|
|
53161
|
+
const current = [];
|
|
53162
|
+
for (const cell of row) {
|
|
53163
|
+
const args = [];
|
|
53164
|
+
for (let i = 0; i < cell.fields.length; i++) {
|
|
53165
|
+
args.push({ value: cell.fields[i] }, { value: cell.values[i] });
|
|
53166
|
+
}
|
|
53167
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
53168
|
+
const locale = this.env.model.getters.getLocale();
|
|
53169
|
+
if (domain.at(-1)?.field === "measure") {
|
|
53170
|
+
const { value, format } = this.pivot.getPivotMeasureValue(toString(domain.at(-1).value), domain);
|
|
53171
|
+
current.push({
|
|
53172
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
53173
|
+
value: formatValue(value, { format, locale }),
|
|
53174
|
+
span: cell.width,
|
|
53175
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
53176
|
+
});
|
|
53177
|
+
}
|
|
53178
|
+
else {
|
|
53179
|
+
const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
|
|
53180
|
+
current.push({
|
|
53181
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
53182
|
+
value: formatValue(value, { format, locale }),
|
|
53183
|
+
span: cell.width,
|
|
53184
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
53185
|
+
});
|
|
53186
|
+
}
|
|
53187
|
+
}
|
|
53188
|
+
headers.push(current);
|
|
53189
|
+
}
|
|
53190
|
+
const last = headers[headers.length - 1];
|
|
53191
|
+
headers[headers.length - 1] = last.map((cell) => {
|
|
53192
|
+
if (!cell.isMissing) {
|
|
53193
|
+
cell.style = "color: #756f6f;";
|
|
53194
|
+
}
|
|
53195
|
+
return cell;
|
|
53196
|
+
});
|
|
53197
|
+
return headers;
|
|
53198
|
+
}
|
|
53199
|
+
_buildRowHeaders(id, table) {
|
|
53200
|
+
const headers = [];
|
|
53201
|
+
for (const row of table.rows) {
|
|
53202
|
+
const args = [];
|
|
53203
|
+
for (let i = 0; i < row.fields.length; i++) {
|
|
53204
|
+
args.push({ value: row.fields[i] }, { value: row.values[i] });
|
|
53205
|
+
}
|
|
53206
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
53207
|
+
const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
|
|
53208
|
+
const locale = this.env.model.getters.getLocale();
|
|
53209
|
+
const cell = {
|
|
53210
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
53211
|
+
value: formatValue(value, { format, locale }),
|
|
53212
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
53213
|
+
};
|
|
53214
|
+
if (row.indent > 1) {
|
|
53215
|
+
cell.style = `padding-left: ${row.indent - 1 * 10}px`;
|
|
53216
|
+
}
|
|
53217
|
+
headers.push(cell);
|
|
53218
|
+
}
|
|
53219
|
+
return headers;
|
|
53220
|
+
}
|
|
53221
|
+
_buildValues(id, table) {
|
|
53222
|
+
const values = [];
|
|
53223
|
+
for (const col of table.columns.at(-1) || []) {
|
|
53224
|
+
const current = [];
|
|
53225
|
+
const measure = toString(col.values[col.values.length - 1]);
|
|
53226
|
+
for (const row of table.rows) {
|
|
53227
|
+
const args = [];
|
|
53228
|
+
for (let i = 0; i < row.fields.length; i++) {
|
|
53229
|
+
args.push({ value: row.fields[i] }, { value: row.values[i] });
|
|
53230
|
+
}
|
|
53231
|
+
for (let i = 0; i < col.fields.length - 1; i++) {
|
|
53232
|
+
args.push({ value: col.fields[i] }, { value: col.values[i] });
|
|
53233
|
+
}
|
|
53234
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
53235
|
+
const { value, format } = this.pivot.getPivotCellValueAndFormat(measure, domain);
|
|
53236
|
+
const locale = this.env.model.getters.getLocale();
|
|
53237
|
+
current.push({
|
|
53238
|
+
formula: `=PIVOT.VALUE(${generatePivotArgs(id, domain, measure).join(",")})`,
|
|
53239
|
+
value: formatValue(value, { format, locale }),
|
|
53240
|
+
isMissing: !this.tracker?.isValuePresent(measure, domain),
|
|
53241
|
+
});
|
|
53242
|
+
}
|
|
53243
|
+
values.push(current);
|
|
53244
|
+
}
|
|
53245
|
+
return values;
|
|
53246
|
+
}
|
|
53247
|
+
}
|
|
53248
|
+
|
|
52883
53249
|
/**
|
|
52884
53250
|
* BasePlugin
|
|
52885
53251
|
*
|
|
@@ -56317,7 +56683,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56317
56683
|
if (range.sheetId === cmd.sheetId) {
|
|
56318
56684
|
return { changeType: "CHANGE", range };
|
|
56319
56685
|
}
|
|
56320
|
-
if (
|
|
56686
|
+
if (isSheetNameEqual(range.invalidSheetName, cmd.name)) {
|
|
56321
56687
|
const invalidSheetName = undefined;
|
|
56322
56688
|
const sheetId = cmd.sheetId;
|
|
56323
56689
|
const newRange = range.clone({ sheetId, invalidSheetName });
|
|
@@ -56902,7 +57268,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56902
57268
|
if (name) {
|
|
56903
57269
|
const unquotedName = getUnquotedSheetName(name);
|
|
56904
57270
|
for (const key in this.sheetIdsMapName) {
|
|
56905
|
-
if (key
|
|
57271
|
+
if (isSheetNameEqual(key, unquotedName)) {
|
|
56906
57272
|
return this.sheetIdsMapName[key];
|
|
56907
57273
|
}
|
|
56908
57274
|
}
|
|
@@ -57150,7 +57516,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57150
57516
|
}
|
|
57151
57517
|
const { orderedSheetIds, sheets } = this;
|
|
57152
57518
|
const name = cmd.name && cmd.name.trim().toLowerCase();
|
|
57153
|
-
if (orderedSheetIds.find((id) => sheets[id]?.name
|
|
57519
|
+
if (orderedSheetIds.find((id) => isSheetNameEqual(sheets[id]?.name, name) && id !== cmd.sheetId)) {
|
|
57154
57520
|
return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
|
|
57155
57521
|
}
|
|
57156
57522
|
if (FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX.test(name)) {
|
|
@@ -66053,6 +66419,55 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66053
66419
|
}
|
|
66054
66420
|
}
|
|
66055
66421
|
|
|
66422
|
+
class PivotPresenceTracker {
|
|
66423
|
+
trackedValues = new Set();
|
|
66424
|
+
domainToArray(domain) {
|
|
66425
|
+
return domain.flatMap((node) => [node.field, toString(node.value)]);
|
|
66426
|
+
}
|
|
66427
|
+
isValuePresent(measure, domain) {
|
|
66428
|
+
const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
|
|
66429
|
+
return this.trackedValues.has(key);
|
|
66430
|
+
}
|
|
66431
|
+
isHeaderPresent(domain) {
|
|
66432
|
+
const key = JSON.stringify({ domain: this.domainToArray(domain) });
|
|
66433
|
+
return this.trackedValues.has(key);
|
|
66434
|
+
}
|
|
66435
|
+
trackValue(measure, domain) {
|
|
66436
|
+
const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
|
|
66437
|
+
this.trackedValues.add(key);
|
|
66438
|
+
}
|
|
66439
|
+
trackHeader(domain) {
|
|
66440
|
+
const key = JSON.stringify({ domain: this.domainToArray(domain) });
|
|
66441
|
+
this.trackedValues.add(key);
|
|
66442
|
+
}
|
|
66443
|
+
}
|
|
66444
|
+
|
|
66445
|
+
class PivotPresencePlugin extends UIPlugin {
|
|
66446
|
+
static getters = ["getPivotPresenceTracker"];
|
|
66447
|
+
trackPresencePivotId;
|
|
66448
|
+
tracker;
|
|
66449
|
+
handle(cmd) {
|
|
66450
|
+
switch (cmd.type) {
|
|
66451
|
+
case "PIVOT_START_PRESENCE_TRACKING":
|
|
66452
|
+
this.tracker = new PivotPresenceTracker();
|
|
66453
|
+
this.trackPresencePivotId = cmd.pivotId;
|
|
66454
|
+
break;
|
|
66455
|
+
case "PIVOT_STOP_PRESENCE_TRACKING":
|
|
66456
|
+
this.trackPresencePivotId = undefined;
|
|
66457
|
+
break;
|
|
66458
|
+
}
|
|
66459
|
+
}
|
|
66460
|
+
getPivotPresenceTracker(pivotId) {
|
|
66461
|
+
if (this.trackPresencePivotId !== pivotId) {
|
|
66462
|
+
return undefined;
|
|
66463
|
+
}
|
|
66464
|
+
if (!this.tracker) {
|
|
66465
|
+
throw new Error("Tracker not initialized");
|
|
66466
|
+
}
|
|
66467
|
+
return this.tracker;
|
|
66468
|
+
}
|
|
66469
|
+
}
|
|
66470
|
+
|
|
66056
66471
|
class SplitToColumnsPlugin extends UIPlugin {
|
|
66057
66472
|
static getters = ["getAutomaticSeparator"];
|
|
66058
66473
|
allowDispatch(cmd) {
|
|
@@ -68840,6 +69255,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68840
69255
|
.add("automatic_sum", AutomaticSumPlugin)
|
|
68841
69256
|
.add("format", FormatPlugin)
|
|
68842
69257
|
.add("insert_pivot", InsertPivotPlugin)
|
|
69258
|
+
.add("pivot_presence", PivotPresencePlugin)
|
|
68843
69259
|
.add("split_to_columns", SplitToColumnsPlugin)
|
|
68844
69260
|
.add("collaborative", CollaborativePlugin)
|
|
68845
69261
|
.add("history", HistoryPlugin)
|
|
@@ -69220,11 +69636,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
69220
69636
|
if (ev.key === "Enter") {
|
|
69221
69637
|
ev.preventDefault();
|
|
69222
69638
|
this.stopEdition();
|
|
69223
|
-
this.DOMFocusableElementStore.
|
|
69639
|
+
this.DOMFocusableElementStore.focus();
|
|
69224
69640
|
}
|
|
69225
69641
|
if (ev.key === "Escape") {
|
|
69226
69642
|
this.cancelEdition();
|
|
69227
|
-
this.DOMFocusableElementStore.
|
|
69643
|
+
this.DOMFocusableElementStore.focus();
|
|
69228
69644
|
}
|
|
69229
69645
|
}
|
|
69230
69646
|
onMouseEventSheetName(ev) {
|
|
@@ -75815,6 +76231,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75815
76231
|
PivotDimensionOrder,
|
|
75816
76232
|
PivotDimension,
|
|
75817
76233
|
PivotLayoutConfigurator,
|
|
76234
|
+
PivotHTMLRenderer,
|
|
75818
76235
|
PivotDeferUpdate,
|
|
75819
76236
|
PivotTitleSection,
|
|
75820
76237
|
CogWheelMenu,
|
|
@@ -75908,9 +76325,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75908
76325
|
exports.tokenize = tokenize;
|
|
75909
76326
|
|
|
75910
76327
|
|
|
75911
|
-
__info__.version = "18.1.
|
|
75912
|
-
__info__.date = "2025-05-
|
|
75913
|
-
__info__.hash = "
|
|
76328
|
+
__info__.version = "18.1.20";
|
|
76329
|
+
__info__.date = "2025-05-13T17:52:28.174Z";
|
|
76330
|
+
__info__.hash = "3e43a46";
|
|
75914
76331
|
|
|
75915
76332
|
|
|
75916
76333
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|