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