@odoo/o-spreadsheet 18.2.11 → 18.2.12
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 +280 -155
- package/dist/o-spreadsheet.esm.js +458 -41
- package/dist/o-spreadsheet.iife.js +458 -41
- package/dist/o-spreadsheet.iife.min.js +422 -386
- 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.2.
|
|
6
|
-
* @date 2025-05-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.2.12
|
|
6
|
+
* @date 2025-05-13T17:52:23.989Z
|
|
7
|
+
* @hash ba2ba9b
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -3358,7 +3358,7 @@
|
|
|
3358
3358
|
*/
|
|
3359
3359
|
const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
|
|
3360
3360
|
decimalSeparator = escapeRegExp(decimalSeparator);
|
|
3361
|
-
return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e
|
|
3361
|
+
return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e(\\+|-)?\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
|
|
3362
3362
|
});
|
|
3363
3363
|
const getNumberRegex = memoize(function getNumberRegex(locale) {
|
|
3364
3364
|
const decimalSeparator = escapeRegExp(locale.decimalSeparator);
|
|
@@ -6300,6 +6300,13 @@
|
|
|
6300
6300
|
}
|
|
6301
6301
|
return name;
|
|
6302
6302
|
}
|
|
6303
|
+
function isSheetNameEqual(name1, name2) {
|
|
6304
|
+
if (name1 === undefined || name2 === undefined) {
|
|
6305
|
+
return false;
|
|
6306
|
+
}
|
|
6307
|
+
return (getUnquotedSheetName(name1.trim().toUpperCase()) ===
|
|
6308
|
+
getUnquotedSheetName(name2.trim().toUpperCase()));
|
|
6309
|
+
}
|
|
6303
6310
|
|
|
6304
6311
|
function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
|
|
6305
6312
|
return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
|
|
@@ -8163,10 +8170,9 @@
|
|
|
8163
8170
|
avg: _t("Average"),
|
|
8164
8171
|
sum: _t("Sum"),
|
|
8165
8172
|
};
|
|
8166
|
-
const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
|
|
8167
8173
|
const AGGREGATORS_BY_FIELD_TYPE = {
|
|
8168
|
-
integer:
|
|
8169
|
-
char:
|
|
8174
|
+
integer: ["max", "min", "avg", "sum", "count_distinct", "count"],
|
|
8175
|
+
char: ["count_distinct", "count"],
|
|
8170
8176
|
boolean: ["count_distinct", "count", "bool_and", "bool_or"],
|
|
8171
8177
|
datetime: ["max", "min", "count_distinct", "count"],
|
|
8172
8178
|
};
|
|
@@ -9519,7 +9525,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9519
9525
|
const functionProxy = new Proxy(value, {
|
|
9520
9526
|
// trap the function call
|
|
9521
9527
|
apply(target, thisArg, argArray) {
|
|
9522
|
-
Reflect.apply(target, thisStore, argArray);
|
|
9528
|
+
const res = Reflect.apply(target, thisStore, argArray);
|
|
9529
|
+
if (res === "noStateChange") {
|
|
9530
|
+
return;
|
|
9531
|
+
}
|
|
9523
9532
|
callback();
|
|
9524
9533
|
},
|
|
9525
9534
|
});
|
|
@@ -9541,7 +9550,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9541
9550
|
const ModelStore = createAbstractStore("Model");
|
|
9542
9551
|
|
|
9543
9552
|
class RendererStore {
|
|
9544
|
-
mutators = ["register", "unRegister"];
|
|
9553
|
+
mutators = ["register", "unRegister", "drawLayer"];
|
|
9545
9554
|
renderers = {};
|
|
9546
9555
|
register(renderer) {
|
|
9547
9556
|
if (!renderer.renderingLayers.length) {
|
|
@@ -9561,14 +9570,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9561
9570
|
}
|
|
9562
9571
|
drawLayer(context, layer) {
|
|
9563
9572
|
const renderers = this.renderers[layer];
|
|
9564
|
-
if (
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
|
|
9568
|
-
|
|
9569
|
-
|
|
9570
|
-
context.ctx.restore();
|
|
9573
|
+
if (renderers) {
|
|
9574
|
+
for (const renderer of renderers) {
|
|
9575
|
+
context.ctx.save();
|
|
9576
|
+
renderer.drawLayer(context, layer);
|
|
9577
|
+
context.ctx.restore();
|
|
9578
|
+
}
|
|
9571
9579
|
}
|
|
9580
|
+
return "noStateChange";
|
|
9572
9581
|
}
|
|
9573
9582
|
}
|
|
9574
9583
|
|
|
@@ -9621,16 +9630,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9621
9630
|
focusComposer(listener, args) {
|
|
9622
9631
|
this.activeComposer = listener;
|
|
9623
9632
|
if (this.getters.isReadonly()) {
|
|
9624
|
-
return;
|
|
9633
|
+
return "noStateChange";
|
|
9625
9634
|
}
|
|
9626
9635
|
this._focusMode = args.focusMode || "contentFocus";
|
|
9627
9636
|
if (this._focusMode !== "inactive") {
|
|
9628
9637
|
this.setComposerContent(args);
|
|
9629
9638
|
}
|
|
9639
|
+
return;
|
|
9630
9640
|
}
|
|
9631
9641
|
focusActiveComposer(args) {
|
|
9632
9642
|
if (this.getters.isReadonly()) {
|
|
9633
|
-
return;
|
|
9643
|
+
return "noStateChange";
|
|
9634
9644
|
}
|
|
9635
9645
|
if (!this.activeComposer) {
|
|
9636
9646
|
throw new Error("No composer is registered");
|
|
@@ -9639,6 +9649,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9639
9649
|
if (this._focusMode !== "inactive") {
|
|
9640
9650
|
this.setComposerContent(args);
|
|
9641
9651
|
}
|
|
9652
|
+
return;
|
|
9642
9653
|
}
|
|
9643
9654
|
/**
|
|
9644
9655
|
* Start the edition or update the content if it's already started.
|
|
@@ -10132,7 +10143,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
10132
10143
|
}
|
|
10133
10144
|
function formatChartDatasetValue(axisFormats, locale) {
|
|
10134
10145
|
return (value, axisId) => {
|
|
10135
|
-
const format =
|
|
10146
|
+
const format = axisFormats?.[axisId];
|
|
10136
10147
|
return formatTickValue({ format, locale })(value);
|
|
10137
10148
|
};
|
|
10138
10149
|
}
|
|
@@ -10306,7 +10317,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
10306
10317
|
const y = bar.y + midRadius * Math.sin(midAngle) + 7;
|
|
10307
10318
|
ctx.fillStyle = chartFontColor(options.background);
|
|
10308
10319
|
ctx.strokeStyle = options.background || "#ffffff";
|
|
10309
|
-
const displayValue = options.callback(value);
|
|
10320
|
+
const displayValue = options.callback(value, "y");
|
|
10310
10321
|
drawTextWithBackground(displayValue, x, y, ctx);
|
|
10311
10322
|
}
|
|
10312
10323
|
}
|
|
@@ -19205,6 +19216,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19205
19216
|
};
|
|
19206
19217
|
}
|
|
19207
19218
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
19219
|
+
if (this.getters.getActiveSheetId() === this.__originSheetId) {
|
|
19220
|
+
this.getters.getPivotPresenceTracker(pivotId)?.trackValue(_measure, domain);
|
|
19221
|
+
}
|
|
19208
19222
|
return pivot.getPivotCellValueAndFormat(_measure, domain);
|
|
19209
19223
|
},
|
|
19210
19224
|
};
|
|
@@ -19236,6 +19250,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19236
19250
|
};
|
|
19237
19251
|
}
|
|
19238
19252
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
19253
|
+
if (this.getters.getActiveSheetId() === this.__originSheetId) {
|
|
19254
|
+
this.getters.getPivotPresenceTracker(_pivotId)?.trackHeader(domain);
|
|
19255
|
+
}
|
|
19239
19256
|
const lastNode = domain.at(-1);
|
|
19240
19257
|
if (lastNode?.field === "measure") {
|
|
19241
19258
|
return pivot.getPivotMeasureValue(toString(lastNode.value), domain);
|
|
@@ -19458,6 +19475,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19458
19475
|
return data === undefined || data.value === null;
|
|
19459
19476
|
}
|
|
19460
19477
|
const getNeutral = { number: 0, string: "", boolean: false };
|
|
19478
|
+
function areAlmostEqual(value1, value2, epsilon = 2e-16) {
|
|
19479
|
+
return Math.abs(value1 - value2) < epsilon;
|
|
19480
|
+
}
|
|
19461
19481
|
const EQ = {
|
|
19462
19482
|
description: _t("Equal."),
|
|
19463
19483
|
args: [
|
|
@@ -19479,6 +19499,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19479
19499
|
if (typeof _value2 === "string") {
|
|
19480
19500
|
_value2 = _value2.toUpperCase();
|
|
19481
19501
|
}
|
|
19502
|
+
if (typeof _value1 === "number" && typeof _value2 === "number") {
|
|
19503
|
+
return { value: areAlmostEqual(_value1, _value2) };
|
|
19504
|
+
}
|
|
19482
19505
|
return { value: _value1 === _value2 };
|
|
19483
19506
|
},
|
|
19484
19507
|
};
|
|
@@ -19518,6 +19541,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19518
19541
|
],
|
|
19519
19542
|
compute: function (value1, value2) {
|
|
19520
19543
|
return applyRelationalOperator(value1, value2, (v1, v2) => {
|
|
19544
|
+
if (typeof v1 === "number" && typeof v2 === "number") {
|
|
19545
|
+
return !areAlmostEqual(v1, v2) && v1 > v2;
|
|
19546
|
+
}
|
|
19521
19547
|
return v1 > v2;
|
|
19522
19548
|
});
|
|
19523
19549
|
},
|
|
@@ -19533,6 +19559,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19533
19559
|
],
|
|
19534
19560
|
compute: function (value1, value2) {
|
|
19535
19561
|
return applyRelationalOperator(value1, value2, (v1, v2) => {
|
|
19562
|
+
if (typeof v1 === "number" && typeof v2 === "number") {
|
|
19563
|
+
return areAlmostEqual(v1, v2) || v1 > v2;
|
|
19564
|
+
}
|
|
19536
19565
|
return v1 >= v2;
|
|
19537
19566
|
});
|
|
19538
19567
|
},
|
|
@@ -21139,7 +21168,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21139
21168
|
.find((token) => {
|
|
21140
21169
|
const { xc, sheetName: sheet } = splitReference(token.value);
|
|
21141
21170
|
const sheetName = sheet || this.getters.getSheetName(this.sheetId);
|
|
21142
|
-
if (this.getters.getSheetName(activeSheetId)
|
|
21171
|
+
if (!isSheetNameEqual(this.getters.getSheetName(activeSheetId), sheetName)) {
|
|
21143
21172
|
return false;
|
|
21144
21173
|
}
|
|
21145
21174
|
const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
|
|
@@ -24601,7 +24630,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24601
24630
|
({ xc, sheetName } = splitReference(reference));
|
|
24602
24631
|
let rangeSheetIndex;
|
|
24603
24632
|
if (sheetName) {
|
|
24604
|
-
const index = data.sheets.findIndex((sheet) => sheet.name
|
|
24633
|
+
const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
|
|
24605
24634
|
if (index < 0) {
|
|
24606
24635
|
throw new Error("Unable to find a sheet with the name " + sheetName);
|
|
24607
24636
|
}
|
|
@@ -24942,7 +24971,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24942
24971
|
formula = formula.replace(externalReferenceRegex, (match, externalRefId, sheetName, cellRef) => {
|
|
24943
24972
|
externalRefId = Number(externalRefId) - 1;
|
|
24944
24973
|
cellRef = cellRef.replace(/\$/g, "");
|
|
24945
|
-
const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => name
|
|
24974
|
+
const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => isSheetNameEqual(name, sheetName));
|
|
24946
24975
|
if (sheetIndex === -1) {
|
|
24947
24976
|
return match;
|
|
24948
24977
|
}
|
|
@@ -25593,7 +25622,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25593
25622
|
*/
|
|
25594
25623
|
function convertTableFormulaReferences(convertedSheets, xlsxSheets) {
|
|
25595
25624
|
for (let tableSheet of convertedSheets) {
|
|
25596
|
-
const tables = xlsxSheets.find((s) => s.sheetName
|
|
25625
|
+
const tables = xlsxSheets.find((s) => isSheetNameEqual(s.sheetName, tableSheet.name)).tables;
|
|
25597
25626
|
for (let table of tables) {
|
|
25598
25627
|
const tabRef = table.name + "[";
|
|
25599
25628
|
for (let sheet of convertedSheets) {
|
|
@@ -32585,12 +32614,20 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32585
32614
|
}
|
|
32586
32615
|
}
|
|
32587
32616
|
hover(position) {
|
|
32617
|
+
if (position.col === this.col && position.row === this.row) {
|
|
32618
|
+
return "noStateChange";
|
|
32619
|
+
}
|
|
32588
32620
|
this.col = position.col;
|
|
32589
32621
|
this.row = position.row;
|
|
32622
|
+
return;
|
|
32590
32623
|
}
|
|
32591
32624
|
clear() {
|
|
32625
|
+
if (this.col === undefined && this.row === undefined) {
|
|
32626
|
+
return "noStateChange";
|
|
32627
|
+
}
|
|
32592
32628
|
this.col = undefined;
|
|
32593
32629
|
this.row = undefined;
|
|
32630
|
+
return;
|
|
32594
32631
|
}
|
|
32595
32632
|
}
|
|
32596
32633
|
|
|
@@ -32612,7 +32649,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32612
32649
|
this.persistentPopover = { col, row, sheetId, type };
|
|
32613
32650
|
}
|
|
32614
32651
|
close() {
|
|
32652
|
+
if (!this.persistentPopover) {
|
|
32653
|
+
return "noStateChange";
|
|
32654
|
+
}
|
|
32615
32655
|
this.persistentPopover = undefined;
|
|
32656
|
+
return;
|
|
32616
32657
|
}
|
|
32617
32658
|
get persistentCellPopover() {
|
|
32618
32659
|
return ((this.persistentPopover && { isOpen: true, ...this.persistentPopover }) || { isOpen: false });
|
|
@@ -40068,10 +40109,18 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40068
40109
|
}
|
|
40069
40110
|
|
|
40070
40111
|
class DOMFocusableElementStore {
|
|
40071
|
-
mutators = ["setFocusableElement"];
|
|
40112
|
+
mutators = ["setFocusableElement", "focus"];
|
|
40072
40113
|
focusableElement = undefined;
|
|
40073
40114
|
setFocusableElement(element) {
|
|
40074
40115
|
this.focusableElement = element;
|
|
40116
|
+
return "noStateChange";
|
|
40117
|
+
}
|
|
40118
|
+
focus() {
|
|
40119
|
+
if (this.focusableElement === document.activeElement) {
|
|
40120
|
+
return "noStateChange";
|
|
40121
|
+
}
|
|
40122
|
+
this.focusableElement?.focus();
|
|
40123
|
+
return;
|
|
40075
40124
|
}
|
|
40076
40125
|
}
|
|
40077
40126
|
|
|
@@ -40659,7 +40708,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40659
40708
|
if (document.activeElement === this.contentHelper.el &&
|
|
40660
40709
|
this.props.composerStore.editionMode === "inactive" &&
|
|
40661
40710
|
!this.props.isDefaultFocus) {
|
|
40662
|
-
this.DOMFocusableElementStore.
|
|
40711
|
+
this.DOMFocusableElementStore.focus();
|
|
40663
40712
|
}
|
|
40664
40713
|
});
|
|
40665
40714
|
owl.useEffect(() => {
|
|
@@ -46943,7 +46992,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46943
46992
|
entry[field.name] = { value: null, type: CellValueType.empty, formattedValue: "" };
|
|
46944
46993
|
}
|
|
46945
46994
|
else {
|
|
46946
|
-
|
|
46995
|
+
if (field.type === "char") {
|
|
46996
|
+
entry[field.name] = { ...cell, value: cell.formattedValue || null };
|
|
46997
|
+
}
|
|
46998
|
+
else {
|
|
46999
|
+
entry[field.name] = cell;
|
|
47000
|
+
}
|
|
46947
47001
|
}
|
|
46948
47002
|
}
|
|
46949
47003
|
entry["__count"] = { value: 1, type: CellValueType.number, formattedValue: "1" };
|
|
@@ -52081,10 +52135,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52081
52135
|
ctx.scale(dpr, dpr);
|
|
52082
52136
|
for (const layer of OrderedLayers()) {
|
|
52083
52137
|
model.drawLayer(renderingContext, layer);
|
|
52084
|
-
// @ts-ignore 'drawLayer' is not declated as a mutator because:
|
|
52085
|
-
// it does not mutate anything. Most importantly it's used
|
|
52086
|
-
// during rendering. Invoking a mutator during rendering would
|
|
52087
|
-
// trigger another rendering, ultimately resulting in an infinite loop.
|
|
52088
52138
|
rendererStore.drawLayer(renderingContext, layer);
|
|
52089
52139
|
}
|
|
52090
52140
|
}
|
|
@@ -52775,7 +52825,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52775
52825
|
this.cellPopovers = useStore(CellPopoverStore);
|
|
52776
52826
|
owl.useEffect(() => {
|
|
52777
52827
|
if (!this.sidePanel.isOpen) {
|
|
52778
|
-
this.DOMFocusableElementStore.
|
|
52828
|
+
this.DOMFocusableElementStore.focus();
|
|
52779
52829
|
}
|
|
52780
52830
|
}, () => [this.sidePanel.isOpen]);
|
|
52781
52831
|
useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
|
|
@@ -52985,7 +53035,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52985
53035
|
focusDefaultElement() {
|
|
52986
53036
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
52987
53037
|
this.composerFocusStore.activeComposer.editionMode === "inactive") {
|
|
52988
|
-
this.DOMFocusableElementStore.
|
|
53038
|
+
this.DOMFocusableElementStore.focus();
|
|
52989
53039
|
}
|
|
52990
53040
|
}
|
|
52991
53041
|
get gridEl() {
|
|
@@ -53330,6 +53380,322 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
53330
53380
|
}
|
|
53331
53381
|
}
|
|
53332
53382
|
|
|
53383
|
+
css /* scss */ `
|
|
53384
|
+
.o_pivot_html_renderer {
|
|
53385
|
+
width: 100%;
|
|
53386
|
+
border-collapse: collapse;
|
|
53387
|
+
|
|
53388
|
+
&:hover {
|
|
53389
|
+
cursor: pointer;
|
|
53390
|
+
}
|
|
53391
|
+
|
|
53392
|
+
td,
|
|
53393
|
+
th {
|
|
53394
|
+
border: 1px solid #dee2e6;
|
|
53395
|
+
background-color: #fff;
|
|
53396
|
+
padding: 0.3rem;
|
|
53397
|
+
white-space: nowrap;
|
|
53398
|
+
|
|
53399
|
+
&:hover {
|
|
53400
|
+
filter: brightness(0.9);
|
|
53401
|
+
}
|
|
53402
|
+
}
|
|
53403
|
+
|
|
53404
|
+
td {
|
|
53405
|
+
text-align: right;
|
|
53406
|
+
}
|
|
53407
|
+
|
|
53408
|
+
th {
|
|
53409
|
+
background-color: #f5f5f5;
|
|
53410
|
+
font-weight: bold;
|
|
53411
|
+
color: black;
|
|
53412
|
+
}
|
|
53413
|
+
|
|
53414
|
+
.o_missing_value {
|
|
53415
|
+
color: #46646d;
|
|
53416
|
+
background: #e7f2f6;
|
|
53417
|
+
}
|
|
53418
|
+
}
|
|
53419
|
+
`;
|
|
53420
|
+
class PivotHTMLRenderer extends owl.Component {
|
|
53421
|
+
static template = "o_spreadsheet.PivotHTMLRenderer";
|
|
53422
|
+
static components = { Checkbox };
|
|
53423
|
+
static props = {
|
|
53424
|
+
pivotId: String,
|
|
53425
|
+
onCellClicked: Function,
|
|
53426
|
+
};
|
|
53427
|
+
pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
53428
|
+
data = {
|
|
53429
|
+
columns: [],
|
|
53430
|
+
rows: [],
|
|
53431
|
+
values: [],
|
|
53432
|
+
};
|
|
53433
|
+
state = owl.useState({
|
|
53434
|
+
showMissingValuesOnly: false,
|
|
53435
|
+
});
|
|
53436
|
+
setup() {
|
|
53437
|
+
const table = this.pivot.getTableStructure();
|
|
53438
|
+
const formulaId = this.env.model.getters.getPivotFormulaId(this.props.pivotId);
|
|
53439
|
+
this.data = {
|
|
53440
|
+
columns: this._buildColHeaders(formulaId, table),
|
|
53441
|
+
rows: this._buildRowHeaders(formulaId, table),
|
|
53442
|
+
values: this._buildValues(formulaId, table),
|
|
53443
|
+
};
|
|
53444
|
+
}
|
|
53445
|
+
get tracker() {
|
|
53446
|
+
return this.env.model.getters.getPivotPresenceTracker(this.props.pivotId);
|
|
53447
|
+
}
|
|
53448
|
+
// ---------------------------------------------------------------------
|
|
53449
|
+
// Missing values building
|
|
53450
|
+
// ---------------------------------------------------------------------
|
|
53451
|
+
/**
|
|
53452
|
+
* Retrieve the data to display in the Pivot Table
|
|
53453
|
+
* In the case when showMissingValuesOnly is false, the returned value
|
|
53454
|
+
* is the complete data
|
|
53455
|
+
* In the case when showMissingValuesOnly is true, the returned value is
|
|
53456
|
+
* the data which contains only missing values in the rows and cols. In
|
|
53457
|
+
* the rows, we also return the parent rows of rows which contains missing
|
|
53458
|
+
* values, to give context to the user.
|
|
53459
|
+
*
|
|
53460
|
+
*/
|
|
53461
|
+
getTableData() {
|
|
53462
|
+
if (!this.state.showMissingValuesOnly) {
|
|
53463
|
+
return this.data;
|
|
53464
|
+
}
|
|
53465
|
+
const colIndexes = this.getColumnsIndexes();
|
|
53466
|
+
const rowIndexes = this.getRowsIndexes();
|
|
53467
|
+
const columns = this.buildColumnsMissing(colIndexes);
|
|
53468
|
+
const rows = this.buildRowsMissing(rowIndexes);
|
|
53469
|
+
const values = this.buildValuesMissing(colIndexes, rowIndexes);
|
|
53470
|
+
return { columns, rows, values };
|
|
53471
|
+
}
|
|
53472
|
+
/**
|
|
53473
|
+
* Retrieve the parents of the given row
|
|
53474
|
+
* ex:
|
|
53475
|
+
* Australia
|
|
53476
|
+
* January
|
|
53477
|
+
* February
|
|
53478
|
+
* The parent of "January" is "Australia"
|
|
53479
|
+
*/
|
|
53480
|
+
addRecursiveRow(index) {
|
|
53481
|
+
const rows = this.pivot.getTableStructure().rows;
|
|
53482
|
+
const row = [...rows[index].values];
|
|
53483
|
+
if (row.length <= 1) {
|
|
53484
|
+
return [index];
|
|
53485
|
+
}
|
|
53486
|
+
row.pop();
|
|
53487
|
+
const parentRowIndex = rows.findIndex((r) => JSON.stringify(r.values) === JSON.stringify(row));
|
|
53488
|
+
return [index].concat(this.addRecursiveRow(parentRowIndex));
|
|
53489
|
+
}
|
|
53490
|
+
/**
|
|
53491
|
+
* Create the columns to be used, based on the indexes of the columns in
|
|
53492
|
+
* which a missing value is present
|
|
53493
|
+
*
|
|
53494
|
+
*/
|
|
53495
|
+
buildColumnsMissing(indexes) {
|
|
53496
|
+
// columnsMap explode the columns in an array of array of the same
|
|
53497
|
+
// size with the index of each column, repeated 'span' times.
|
|
53498
|
+
// ex:
|
|
53499
|
+
// | A | B |
|
|
53500
|
+
// | 1 | 2 | 3 |
|
|
53501
|
+
// => [
|
|
53502
|
+
// [0, 0, 1]
|
|
53503
|
+
// [0, 1, 2]
|
|
53504
|
+
// ]
|
|
53505
|
+
const columnsMap = [];
|
|
53506
|
+
for (const column of this.data.columns) {
|
|
53507
|
+
const columnMap = [];
|
|
53508
|
+
for (const index in column) {
|
|
53509
|
+
for (let i = 0; i < column[index].span; i++) {
|
|
53510
|
+
columnMap.push(parseInt(index, 10));
|
|
53511
|
+
}
|
|
53512
|
+
}
|
|
53513
|
+
columnsMap.push(columnMap);
|
|
53514
|
+
}
|
|
53515
|
+
// Remove the columns that are not present in indexes
|
|
53516
|
+
for (let i = columnsMap[columnsMap.length - 1].length; i >= 0; i--) {
|
|
53517
|
+
if (!indexes.includes(i)) {
|
|
53518
|
+
for (const columnMap of columnsMap) {
|
|
53519
|
+
columnMap.splice(i, 1);
|
|
53520
|
+
}
|
|
53521
|
+
}
|
|
53522
|
+
}
|
|
53523
|
+
// Build the columns
|
|
53524
|
+
const columns = [];
|
|
53525
|
+
for (const mapIndex in columnsMap) {
|
|
53526
|
+
const column = [];
|
|
53527
|
+
let index = undefined;
|
|
53528
|
+
let span = 1;
|
|
53529
|
+
for (let i = 0; i < columnsMap[mapIndex].length; i++) {
|
|
53530
|
+
if (index !== columnsMap[mapIndex][i]) {
|
|
53531
|
+
if (index !== undefined) {
|
|
53532
|
+
column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
|
|
53533
|
+
}
|
|
53534
|
+
index = columnsMap[mapIndex][i];
|
|
53535
|
+
span = 1;
|
|
53536
|
+
}
|
|
53537
|
+
else {
|
|
53538
|
+
span++;
|
|
53539
|
+
}
|
|
53540
|
+
}
|
|
53541
|
+
if (index !== undefined) {
|
|
53542
|
+
column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
|
|
53543
|
+
}
|
|
53544
|
+
columns.push(column);
|
|
53545
|
+
}
|
|
53546
|
+
return columns;
|
|
53547
|
+
}
|
|
53548
|
+
/**
|
|
53549
|
+
* Create the rows to be used, based on the indexes of the rows in
|
|
53550
|
+
* which a missing value is present.
|
|
53551
|
+
*/
|
|
53552
|
+
buildRowsMissing(indexes) {
|
|
53553
|
+
return indexes.map((index) => this.data.rows[index]);
|
|
53554
|
+
}
|
|
53555
|
+
/**
|
|
53556
|
+
* Create the value to be used, based on the indexes of the columns and
|
|
53557
|
+
* rows in which a missing value is present.
|
|
53558
|
+
*/
|
|
53559
|
+
buildValuesMissing(colIndexes, rowIndexes) {
|
|
53560
|
+
const values = colIndexes.map(() => []);
|
|
53561
|
+
for (const row of rowIndexes) {
|
|
53562
|
+
for (const col in colIndexes) {
|
|
53563
|
+
values[col].push(this.data.values[colIndexes[col]][row]);
|
|
53564
|
+
}
|
|
53565
|
+
}
|
|
53566
|
+
return values;
|
|
53567
|
+
}
|
|
53568
|
+
getColumnsIndexes() {
|
|
53569
|
+
const indexes = new Set();
|
|
53570
|
+
for (let i = 0; i < this.data.columns.length; i++) {
|
|
53571
|
+
const exploded = [];
|
|
53572
|
+
for (let y = 0; y < this.data.columns[i].length; y++) {
|
|
53573
|
+
for (let x = 0; x < this.data.columns[i][y].span; x++) {
|
|
53574
|
+
exploded.push(this.data.columns[i][y]);
|
|
53575
|
+
}
|
|
53576
|
+
}
|
|
53577
|
+
for (let y = 0; y < exploded.length; y++) {
|
|
53578
|
+
if (exploded[y].isMissing) {
|
|
53579
|
+
indexes.add(y);
|
|
53580
|
+
}
|
|
53581
|
+
}
|
|
53582
|
+
}
|
|
53583
|
+
for (let i = 0; i < this.data.columns[this.data.columns.length - 1].length; i++) {
|
|
53584
|
+
const values = this.data.values[i];
|
|
53585
|
+
if (values.find((x) => x.isMissing)) {
|
|
53586
|
+
indexes.add(i);
|
|
53587
|
+
}
|
|
53588
|
+
}
|
|
53589
|
+
return Array.from(indexes).sort((a, b) => a - b);
|
|
53590
|
+
}
|
|
53591
|
+
getRowsIndexes() {
|
|
53592
|
+
const rowIndexes = new Set();
|
|
53593
|
+
for (let i = 0; i < this.data.rows.length; i++) {
|
|
53594
|
+
if (this.data.rows[i].isMissing) {
|
|
53595
|
+
rowIndexes.add(i);
|
|
53596
|
+
}
|
|
53597
|
+
for (const col of this.data.values) {
|
|
53598
|
+
if (col[i].isMissing) {
|
|
53599
|
+
this.addRecursiveRow(i).forEach((x) => rowIndexes.add(x));
|
|
53600
|
+
}
|
|
53601
|
+
}
|
|
53602
|
+
}
|
|
53603
|
+
return Array.from(rowIndexes).sort((a, b) => a - b);
|
|
53604
|
+
}
|
|
53605
|
+
// ---------------------------------------------------------------------
|
|
53606
|
+
// Data table creation
|
|
53607
|
+
// ---------------------------------------------------------------------
|
|
53608
|
+
_buildColHeaders(id, table) {
|
|
53609
|
+
const headers = [];
|
|
53610
|
+
for (const row of table.columns) {
|
|
53611
|
+
const current = [];
|
|
53612
|
+
for (const cell of row) {
|
|
53613
|
+
const args = [];
|
|
53614
|
+
for (let i = 0; i < cell.fields.length; i++) {
|
|
53615
|
+
args.push({ value: cell.fields[i] }, { value: cell.values[i] });
|
|
53616
|
+
}
|
|
53617
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
53618
|
+
const locale = this.env.model.getters.getLocale();
|
|
53619
|
+
if (domain.at(-1)?.field === "measure") {
|
|
53620
|
+
const { value, format } = this.pivot.getPivotMeasureValue(toString(domain.at(-1).value), domain);
|
|
53621
|
+
current.push({
|
|
53622
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
53623
|
+
value: formatValue(value, { format, locale }),
|
|
53624
|
+
span: cell.width,
|
|
53625
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
53626
|
+
});
|
|
53627
|
+
}
|
|
53628
|
+
else {
|
|
53629
|
+
const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
|
|
53630
|
+
current.push({
|
|
53631
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
53632
|
+
value: formatValue(value, { format, locale }),
|
|
53633
|
+
span: cell.width,
|
|
53634
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
53635
|
+
});
|
|
53636
|
+
}
|
|
53637
|
+
}
|
|
53638
|
+
headers.push(current);
|
|
53639
|
+
}
|
|
53640
|
+
const last = headers[headers.length - 1];
|
|
53641
|
+
headers[headers.length - 1] = last.map((cell) => {
|
|
53642
|
+
if (!cell.isMissing) {
|
|
53643
|
+
cell.style = "color: #756f6f;";
|
|
53644
|
+
}
|
|
53645
|
+
return cell;
|
|
53646
|
+
});
|
|
53647
|
+
return headers;
|
|
53648
|
+
}
|
|
53649
|
+
_buildRowHeaders(id, table) {
|
|
53650
|
+
const headers = [];
|
|
53651
|
+
for (const row of table.rows) {
|
|
53652
|
+
const args = [];
|
|
53653
|
+
for (let i = 0; i < row.fields.length; i++) {
|
|
53654
|
+
args.push({ value: row.fields[i] }, { value: row.values[i] });
|
|
53655
|
+
}
|
|
53656
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
53657
|
+
const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
|
|
53658
|
+
const locale = this.env.model.getters.getLocale();
|
|
53659
|
+
const cell = {
|
|
53660
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
53661
|
+
value: formatValue(value, { format, locale }),
|
|
53662
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
53663
|
+
};
|
|
53664
|
+
if (row.indent > 1) {
|
|
53665
|
+
cell.style = `padding-left: ${row.indent - 1 * 10}px`;
|
|
53666
|
+
}
|
|
53667
|
+
headers.push(cell);
|
|
53668
|
+
}
|
|
53669
|
+
return headers;
|
|
53670
|
+
}
|
|
53671
|
+
_buildValues(id, table) {
|
|
53672
|
+
const values = [];
|
|
53673
|
+
for (const col of table.columns.at(-1) || []) {
|
|
53674
|
+
const current = [];
|
|
53675
|
+
const measure = toString(col.values[col.values.length - 1]);
|
|
53676
|
+
for (const row of table.rows) {
|
|
53677
|
+
const args = [];
|
|
53678
|
+
for (let i = 0; i < row.fields.length; i++) {
|
|
53679
|
+
args.push({ value: row.fields[i] }, { value: row.values[i] });
|
|
53680
|
+
}
|
|
53681
|
+
for (let i = 0; i < col.fields.length - 1; i++) {
|
|
53682
|
+
args.push({ value: col.fields[i] }, { value: col.values[i] });
|
|
53683
|
+
}
|
|
53684
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
53685
|
+
const { value, format } = this.pivot.getPivotCellValueAndFormat(measure, domain);
|
|
53686
|
+
const locale = this.env.model.getters.getLocale();
|
|
53687
|
+
current.push({
|
|
53688
|
+
formula: `=PIVOT.VALUE(${generatePivotArgs(id, domain, measure).join(",")})`,
|
|
53689
|
+
value: formatValue(value, { format, locale }),
|
|
53690
|
+
isMissing: !this.tracker?.isValuePresent(measure, domain),
|
|
53691
|
+
});
|
|
53692
|
+
}
|
|
53693
|
+
values.push(current);
|
|
53694
|
+
}
|
|
53695
|
+
return values;
|
|
53696
|
+
}
|
|
53697
|
+
}
|
|
53698
|
+
|
|
53333
53699
|
/**
|
|
53334
53700
|
* BasePlugin
|
|
53335
53701
|
*
|
|
@@ -56789,7 +57155,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56789
57155
|
if (range.sheetId === cmd.sheetId) {
|
|
56790
57156
|
return { changeType: "CHANGE", range };
|
|
56791
57157
|
}
|
|
56792
|
-
if (
|
|
57158
|
+
if (isSheetNameEqual(range.invalidSheetName, cmd.name)) {
|
|
56793
57159
|
const invalidSheetName = undefined;
|
|
56794
57160
|
const sheetId = cmd.sheetId;
|
|
56795
57161
|
const newRange = range.clone({ sheetId, invalidSheetName });
|
|
@@ -57406,7 +57772,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57406
57772
|
if (name) {
|
|
57407
57773
|
const unquotedName = getUnquotedSheetName(name);
|
|
57408
57774
|
for (const key in this.sheetIdsMapName) {
|
|
57409
|
-
if (key
|
|
57775
|
+
if (isSheetNameEqual(key, unquotedName)) {
|
|
57410
57776
|
return this.sheetIdsMapName[key];
|
|
57411
57777
|
}
|
|
57412
57778
|
}
|
|
@@ -57654,7 +58020,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57654
58020
|
}
|
|
57655
58021
|
const { orderedSheetIds, sheets } = this;
|
|
57656
58022
|
const name = cmd.name && cmd.name.trim().toLowerCase();
|
|
57657
|
-
if (orderedSheetIds.find((id) => sheets[id]?.name
|
|
58023
|
+
if (orderedSheetIds.find((id) => isSheetNameEqual(sheets[id]?.name, name) && id !== cmd.sheetId)) {
|
|
57658
58024
|
return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
|
|
57659
58025
|
}
|
|
57660
58026
|
if (FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX.test(name)) {
|
|
@@ -66547,6 +66913,55 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66547
66913
|
}
|
|
66548
66914
|
}
|
|
66549
66915
|
|
|
66916
|
+
class PivotPresenceTracker {
|
|
66917
|
+
trackedValues = new Set();
|
|
66918
|
+
domainToArray(domain) {
|
|
66919
|
+
return domain.flatMap((node) => [node.field, toString(node.value)]);
|
|
66920
|
+
}
|
|
66921
|
+
isValuePresent(measure, domain) {
|
|
66922
|
+
const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
|
|
66923
|
+
return this.trackedValues.has(key);
|
|
66924
|
+
}
|
|
66925
|
+
isHeaderPresent(domain) {
|
|
66926
|
+
const key = JSON.stringify({ domain: this.domainToArray(domain) });
|
|
66927
|
+
return this.trackedValues.has(key);
|
|
66928
|
+
}
|
|
66929
|
+
trackValue(measure, domain) {
|
|
66930
|
+
const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
|
|
66931
|
+
this.trackedValues.add(key);
|
|
66932
|
+
}
|
|
66933
|
+
trackHeader(domain) {
|
|
66934
|
+
const key = JSON.stringify({ domain: this.domainToArray(domain) });
|
|
66935
|
+
this.trackedValues.add(key);
|
|
66936
|
+
}
|
|
66937
|
+
}
|
|
66938
|
+
|
|
66939
|
+
class PivotPresencePlugin extends UIPlugin {
|
|
66940
|
+
static getters = ["getPivotPresenceTracker"];
|
|
66941
|
+
trackPresencePivotId;
|
|
66942
|
+
tracker;
|
|
66943
|
+
handle(cmd) {
|
|
66944
|
+
switch (cmd.type) {
|
|
66945
|
+
case "PIVOT_START_PRESENCE_TRACKING":
|
|
66946
|
+
this.tracker = new PivotPresenceTracker();
|
|
66947
|
+
this.trackPresencePivotId = cmd.pivotId;
|
|
66948
|
+
break;
|
|
66949
|
+
case "PIVOT_STOP_PRESENCE_TRACKING":
|
|
66950
|
+
this.trackPresencePivotId = undefined;
|
|
66951
|
+
break;
|
|
66952
|
+
}
|
|
66953
|
+
}
|
|
66954
|
+
getPivotPresenceTracker(pivotId) {
|
|
66955
|
+
if (this.trackPresencePivotId !== pivotId) {
|
|
66956
|
+
return undefined;
|
|
66957
|
+
}
|
|
66958
|
+
if (!this.tracker) {
|
|
66959
|
+
throw new Error("Tracker not initialized");
|
|
66960
|
+
}
|
|
66961
|
+
return this.tracker;
|
|
66962
|
+
}
|
|
66963
|
+
}
|
|
66964
|
+
|
|
66550
66965
|
class SplitToColumnsPlugin extends UIPlugin {
|
|
66551
66966
|
static getters = ["getAutomaticSeparator"];
|
|
66552
66967
|
allowDispatch(cmd) {
|
|
@@ -69297,6 +69712,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
69297
69712
|
.add("automatic_sum", AutomaticSumPlugin)
|
|
69298
69713
|
.add("format", FormatPlugin)
|
|
69299
69714
|
.add("insert_pivot", InsertPivotPlugin)
|
|
69715
|
+
.add("pivot_presence", PivotPresencePlugin)
|
|
69300
69716
|
.add("split_to_columns", SplitToColumnsPlugin)
|
|
69301
69717
|
.add("collaborative", CollaborativePlugin)
|
|
69302
69718
|
.add("history", HistoryPlugin)
|
|
@@ -69677,11 +70093,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
69677
70093
|
if (ev.key === "Enter") {
|
|
69678
70094
|
ev.preventDefault();
|
|
69679
70095
|
this.stopEdition();
|
|
69680
|
-
this.DOMFocusableElementStore.
|
|
70096
|
+
this.DOMFocusableElementStore.focus();
|
|
69681
70097
|
}
|
|
69682
70098
|
if (ev.key === "Escape") {
|
|
69683
70099
|
this.cancelEdition();
|
|
69684
|
-
this.DOMFocusableElementStore.
|
|
70100
|
+
this.DOMFocusableElementStore.focus();
|
|
69685
70101
|
}
|
|
69686
70102
|
}
|
|
69687
70103
|
onMouseEventSheetName(ev) {
|
|
@@ -76292,6 +76708,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76292
76708
|
PivotDimensionOrder,
|
|
76293
76709
|
PivotDimension,
|
|
76294
76710
|
PivotLayoutConfigurator,
|
|
76711
|
+
PivotHTMLRenderer,
|
|
76295
76712
|
PivotDeferUpdate,
|
|
76296
76713
|
PivotTitleSection,
|
|
76297
76714
|
CogWheelMenu,
|
|
@@ -76386,9 +76803,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76386
76803
|
exports.tokenize = tokenize;
|
|
76387
76804
|
|
|
76388
76805
|
|
|
76389
|
-
__info__.version = "18.2.
|
|
76390
|
-
__info__.date = "2025-05-
|
|
76391
|
-
__info__.hash = "
|
|
76806
|
+
__info__.version = "18.2.12";
|
|
76807
|
+
__info__.date = "2025-05-13T17:52:23.989Z";
|
|
76808
|
+
__info__.hash = "ba2ba9b";
|
|
76392
76809
|
|
|
76393
76810
|
|
|
76394
76811
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|