@odoo/o-spreadsheet 18.0.26 → 18.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/o-spreadsheet.cjs.js +580 -81
- package/dist/o-spreadsheet.d.ts +271 -144
- package/dist/o-spreadsheet.esm.js +580 -81
- package/dist/o-spreadsheet.iife.js +580 -81
- package/dist/o-spreadsheet.iife.min.js +405 -369
- package/dist/o_spreadsheet.xml +64 -16
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 18.0.
|
|
6
|
-
* @date 2025-05-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.0.28
|
|
6
|
+
* @date 2025-05-13T17:53:12.402Z
|
|
7
|
+
* @hash b3088aa
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -3181,7 +3181,7 @@
|
|
|
3181
3181
|
*/
|
|
3182
3182
|
const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
|
|
3183
3183
|
decimalSeparator = escapeRegExp(decimalSeparator);
|
|
3184
|
-
return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e
|
|
3184
|
+
return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e(\\+|-)?\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
|
|
3185
3185
|
});
|
|
3186
3186
|
const getNumberRegex = memoize(function getNumberRegex(locale) {
|
|
3187
3187
|
const decimalSeparator = escapeRegExp(locale.decimalSeparator);
|
|
@@ -6103,6 +6103,32 @@
|
|
|
6103
6103
|
})
|
|
6104
6104
|
.filter(isDefined);
|
|
6105
6105
|
}
|
|
6106
|
+
function getNextSheetName(existingNames, baseName = "Sheet") {
|
|
6107
|
+
let i = 1;
|
|
6108
|
+
let name = `${baseName}${i}`;
|
|
6109
|
+
while (existingNames.includes(name)) {
|
|
6110
|
+
name = `${baseName}${i}`;
|
|
6111
|
+
i++;
|
|
6112
|
+
}
|
|
6113
|
+
return name;
|
|
6114
|
+
}
|
|
6115
|
+
function getDuplicateSheetName(nameToDuplicate, existingNames) {
|
|
6116
|
+
let i = 1;
|
|
6117
|
+
const baseName = _t("Copy of %s", nameToDuplicate);
|
|
6118
|
+
let name = baseName.toString();
|
|
6119
|
+
while (existingNames.includes(name)) {
|
|
6120
|
+
name = `${baseName} (${i})`;
|
|
6121
|
+
i++;
|
|
6122
|
+
}
|
|
6123
|
+
return name;
|
|
6124
|
+
}
|
|
6125
|
+
function isSheetNameEqual(name1, name2) {
|
|
6126
|
+
if (name1 === undefined || name2 === undefined) {
|
|
6127
|
+
return false;
|
|
6128
|
+
}
|
|
6129
|
+
return (getUnquotedSheetName(name1.trim().toUpperCase()) ===
|
|
6130
|
+
getUnquotedSheetName(name2.trim().toUpperCase()));
|
|
6131
|
+
}
|
|
6106
6132
|
|
|
6107
6133
|
function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
|
|
6108
6134
|
return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
|
|
@@ -7791,6 +7817,24 @@
|
|
|
7791
7817
|
return `${normalizedValue}`;
|
|
7792
7818
|
},
|
|
7793
7819
|
};
|
|
7820
|
+
/**
|
|
7821
|
+
* normalizes month number + year
|
|
7822
|
+
*/
|
|
7823
|
+
const monthAdapter = {
|
|
7824
|
+
normalizeFunctionValue(value) {
|
|
7825
|
+
const date = toNumber(value, DEFAULT_LOCALE);
|
|
7826
|
+
return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
|
|
7827
|
+
},
|
|
7828
|
+
toValueAndFormat(normalizedValue) {
|
|
7829
|
+
return {
|
|
7830
|
+
value: toNumber(normalizedValue, DEFAULT_LOCALE),
|
|
7831
|
+
format: "mmmm yyyy",
|
|
7832
|
+
};
|
|
7833
|
+
},
|
|
7834
|
+
toFunctionValue(normalizedValue) {
|
|
7835
|
+
return `"${normalizedValue}"`;
|
|
7836
|
+
},
|
|
7837
|
+
};
|
|
7794
7838
|
/**
|
|
7795
7839
|
* normalizes quarter number
|
|
7796
7840
|
*/
|
|
@@ -7921,6 +7965,7 @@
|
|
|
7921
7965
|
.add("day_of_month", nullHandlerDecorator(dayOfMonthAdapter))
|
|
7922
7966
|
.add("iso_week_number", nullHandlerDecorator(isoWeekNumberAdapter))
|
|
7923
7967
|
.add("month_number", nullHandlerDecorator(monthNumberAdapter))
|
|
7968
|
+
.add("month", nullHandlerDecorator(monthAdapter))
|
|
7924
7969
|
.add("quarter_number", nullHandlerDecorator(quarterNumberAdapter))
|
|
7925
7970
|
.add("day_of_week", nullHandlerDecorator(dayOfWeekAdapter))
|
|
7926
7971
|
.add("hour_number", nullHandlerDecorator(hourNumberAdapter))
|
|
@@ -7937,10 +7982,9 @@
|
|
|
7937
7982
|
avg: _t("Average"),
|
|
7938
7983
|
sum: _t("Sum"),
|
|
7939
7984
|
};
|
|
7940
|
-
const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
|
|
7941
7985
|
const AGGREGATORS_BY_FIELD_TYPE = {
|
|
7942
|
-
integer:
|
|
7943
|
-
char:
|
|
7986
|
+
integer: ["max", "min", "avg", "sum", "count_distinct", "count"],
|
|
7987
|
+
char: ["count_distinct", "count"],
|
|
7944
7988
|
boolean: ["count_distinct", "count", "bool_and", "bool_or"],
|
|
7945
7989
|
};
|
|
7946
7990
|
const AGGREGATORS = {};
|
|
@@ -8101,10 +8145,7 @@
|
|
|
8101
8145
|
return normalizer(groupValueString, dimension.granularity);
|
|
8102
8146
|
}
|
|
8103
8147
|
function normalizeDateTime(value, granularity) {
|
|
8104
|
-
|
|
8105
|
-
throw new Error("Missing granularity");
|
|
8106
|
-
}
|
|
8107
|
-
return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
|
|
8148
|
+
return pivotTimeAdapter(granularity ?? "month").normalizeFunctionValue(value);
|
|
8108
8149
|
}
|
|
8109
8150
|
function toFunctionPivotValue(value, dimension) {
|
|
8110
8151
|
if (value === null) {
|
|
@@ -8116,10 +8157,7 @@
|
|
|
8116
8157
|
return pivotToFunctionValueRegistry.get(dimension.type)(value, dimension.granularity);
|
|
8117
8158
|
}
|
|
8118
8159
|
function toFunctionValueDateTime(value, granularity) {
|
|
8119
|
-
|
|
8120
|
-
throw new Error("Missing granularity");
|
|
8121
|
-
}
|
|
8122
|
-
return pivotTimeAdapter(granularity).toFunctionValue(value);
|
|
8160
|
+
return pivotTimeAdapter(granularity ?? "month").toFunctionValue(value);
|
|
8123
8161
|
}
|
|
8124
8162
|
const pivotNormalizationValueRegistry = new Registry();
|
|
8125
8163
|
pivotNormalizationValueRegistry
|
|
@@ -9279,7 +9317,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9279
9317
|
const functionProxy = new Proxy(value, {
|
|
9280
9318
|
// trap the function call
|
|
9281
9319
|
apply(target, thisArg, argArray) {
|
|
9282
|
-
Reflect.apply(target, thisStore, argArray);
|
|
9320
|
+
const res = Reflect.apply(target, thisStore, argArray);
|
|
9321
|
+
if (res === "noStateChange") {
|
|
9322
|
+
return;
|
|
9323
|
+
}
|
|
9283
9324
|
callback();
|
|
9284
9325
|
},
|
|
9285
9326
|
});
|
|
@@ -9301,7 +9342,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9301
9342
|
const ModelStore = createAbstractStore("Model");
|
|
9302
9343
|
|
|
9303
9344
|
class RendererStore {
|
|
9304
|
-
mutators = ["register", "unRegister"];
|
|
9345
|
+
mutators = ["register", "unRegister", "drawLayer"];
|
|
9305
9346
|
renderers = {};
|
|
9306
9347
|
register(renderer) {
|
|
9307
9348
|
if (!renderer.renderingLayers.length) {
|
|
@@ -9321,14 +9362,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9321
9362
|
}
|
|
9322
9363
|
drawLayer(context, layer) {
|
|
9323
9364
|
const renderers = this.renderers[layer];
|
|
9324
|
-
if (
|
|
9325
|
-
|
|
9326
|
-
|
|
9327
|
-
|
|
9328
|
-
|
|
9329
|
-
|
|
9330
|
-
context.ctx.restore();
|
|
9365
|
+
if (renderers) {
|
|
9366
|
+
for (const renderer of renderers) {
|
|
9367
|
+
context.ctx.save();
|
|
9368
|
+
renderer.drawLayer(context, layer);
|
|
9369
|
+
context.ctx.restore();
|
|
9370
|
+
}
|
|
9331
9371
|
}
|
|
9372
|
+
return "noStateChange";
|
|
9332
9373
|
}
|
|
9333
9374
|
}
|
|
9334
9375
|
|
|
@@ -9381,16 +9422,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9381
9422
|
focusComposer(listener, args) {
|
|
9382
9423
|
this.activeComposer = listener;
|
|
9383
9424
|
if (this.getters.isReadonly()) {
|
|
9384
|
-
return;
|
|
9425
|
+
return "noStateChange";
|
|
9385
9426
|
}
|
|
9386
9427
|
this._focusMode = args.focusMode || "contentFocus";
|
|
9387
9428
|
if (this._focusMode !== "inactive") {
|
|
9388
9429
|
this.setComposerContent(args);
|
|
9389
9430
|
}
|
|
9431
|
+
return;
|
|
9390
9432
|
}
|
|
9391
9433
|
focusActiveComposer(args) {
|
|
9392
9434
|
if (this.getters.isReadonly()) {
|
|
9393
|
-
return;
|
|
9435
|
+
return "noStateChange";
|
|
9394
9436
|
}
|
|
9395
9437
|
if (!this.activeComposer) {
|
|
9396
9438
|
throw new Error("No composer is registered");
|
|
@@ -9399,6 +9441,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9399
9441
|
if (this._focusMode !== "inactive") {
|
|
9400
9442
|
this.setComposerContent(args);
|
|
9401
9443
|
}
|
|
9444
|
+
return;
|
|
9402
9445
|
}
|
|
9403
9446
|
/**
|
|
9404
9447
|
* Start the edition or update the content if it's already started.
|
|
@@ -11713,7 +11756,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
11713
11756
|
({ xc, sheetName } = splitReference(reference));
|
|
11714
11757
|
let rangeSheetIndex;
|
|
11715
11758
|
if (sheetName) {
|
|
11716
|
-
const index = data.sheets.findIndex((sheet) => sheet.name
|
|
11759
|
+
const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
|
|
11717
11760
|
if (index < 0) {
|
|
11718
11761
|
throw new Error("Unable to find a sheet with the name " + sheetName);
|
|
11719
11762
|
}
|
|
@@ -12054,7 +12097,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
12054
12097
|
formula = formula.replace(externalReferenceRegex, (match, externalRefId, sheetName, cellRef) => {
|
|
12055
12098
|
externalRefId = Number(externalRefId) - 1;
|
|
12056
12099
|
cellRef = cellRef.replace(/\$/g, "");
|
|
12057
|
-
const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => name
|
|
12100
|
+
const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => isSheetNameEqual(name, sheetName));
|
|
12058
12101
|
if (sheetIndex === -1) {
|
|
12059
12102
|
return match;
|
|
12060
12103
|
}
|
|
@@ -12717,7 +12760,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
12717
12760
|
*/
|
|
12718
12761
|
function convertTableFormulaReferences(convertedSheets, xlsxSheets) {
|
|
12719
12762
|
for (let tableSheet of convertedSheets) {
|
|
12720
|
-
const tables = xlsxSheets.find((s) => s.sheetName
|
|
12763
|
+
const tables = xlsxSheets.find((s) => isSheetNameEqual(s.sheetName, tableSheet.name)).tables;
|
|
12721
12764
|
for (let table of tables) {
|
|
12722
12765
|
const tabRef = table.name + "[";
|
|
12723
12766
|
for (let sheet of convertedSheets) {
|
|
@@ -15252,6 +15295,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
15252
15295
|
initialMessages = dropCommands(initialMessages, "SORT_CELLS");
|
|
15253
15296
|
initialMessages = dropCommands(initialMessages, "SET_DECIMAL");
|
|
15254
15297
|
initialMessages = fixChartDefinitions(data, initialMessages);
|
|
15298
|
+
initialMessages = fixTranslatedDuplicateSheetName(data, initialMessages);
|
|
15255
15299
|
return initialMessages;
|
|
15256
15300
|
}
|
|
15257
15301
|
/**
|
|
@@ -15351,6 +15395,40 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
15351
15395
|
}
|
|
15352
15396
|
return messages;
|
|
15353
15397
|
}
|
|
15398
|
+
function fixTranslatedDuplicateSheetName(data, initialMessages) {
|
|
15399
|
+
const sheetNames = {};
|
|
15400
|
+
for (const sheet of data.sheets || []) {
|
|
15401
|
+
sheetNames[sheet.id] = sheet.name;
|
|
15402
|
+
}
|
|
15403
|
+
const messages = [];
|
|
15404
|
+
for (const message of initialMessages) {
|
|
15405
|
+
if (message.type === "REMOTE_REVISION") {
|
|
15406
|
+
const commands = [];
|
|
15407
|
+
for (const cmd of message.commands) {
|
|
15408
|
+
switch (cmd.type) {
|
|
15409
|
+
case "DUPLICATE_SHEET":
|
|
15410
|
+
cmd.sheetNameTo =
|
|
15411
|
+
cmd.sheetNameTo ??
|
|
15412
|
+
getDuplicateSheetName(sheetNames[cmd.sheetId], Object.values(sheetNames));
|
|
15413
|
+
break;
|
|
15414
|
+
case "CREATE_SHEET":
|
|
15415
|
+
case "RENAME_SHEET":
|
|
15416
|
+
sheetNames[cmd.sheetId] = cmd.name || getNextSheetName(Object.values(sheetNames));
|
|
15417
|
+
break;
|
|
15418
|
+
}
|
|
15419
|
+
commands.push(cmd);
|
|
15420
|
+
}
|
|
15421
|
+
messages.push({
|
|
15422
|
+
...message,
|
|
15423
|
+
commands,
|
|
15424
|
+
});
|
|
15425
|
+
}
|
|
15426
|
+
else {
|
|
15427
|
+
messages.push(message);
|
|
15428
|
+
}
|
|
15429
|
+
}
|
|
15430
|
+
return initialMessages;
|
|
15431
|
+
}
|
|
15354
15432
|
// -----------------------------------------------------------------------------
|
|
15355
15433
|
// Helpers
|
|
15356
15434
|
// -----------------------------------------------------------------------------
|
|
@@ -24366,7 +24444,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24366
24444
|
return { value: "" };
|
|
24367
24445
|
}
|
|
24368
24446
|
if (result.value === null) {
|
|
24369
|
-
result
|
|
24447
|
+
return { ...result, value: "" };
|
|
24370
24448
|
}
|
|
24371
24449
|
return result;
|
|
24372
24450
|
},
|
|
@@ -24387,7 +24465,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24387
24465
|
return { value: "" };
|
|
24388
24466
|
}
|
|
24389
24467
|
if (result.value === null) {
|
|
24390
|
-
result
|
|
24468
|
+
return { ...result, value: "" };
|
|
24391
24469
|
}
|
|
24392
24470
|
return result;
|
|
24393
24471
|
},
|
|
@@ -24408,7 +24486,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24408
24486
|
return { value: "" };
|
|
24409
24487
|
}
|
|
24410
24488
|
if (result.value === null) {
|
|
24411
|
-
result
|
|
24489
|
+
return { ...result, value: "" };
|
|
24412
24490
|
}
|
|
24413
24491
|
return result;
|
|
24414
24492
|
},
|
|
@@ -24434,7 +24512,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24434
24512
|
return { value: "" };
|
|
24435
24513
|
}
|
|
24436
24514
|
if (result.value === null) {
|
|
24437
|
-
result
|
|
24515
|
+
return { ...result, value: "" };
|
|
24438
24516
|
}
|
|
24439
24517
|
return result;
|
|
24440
24518
|
}
|
|
@@ -24552,6 +24630,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24552
24630
|
if (range === undefined || range.invalidXc || range.invalidSheetName) {
|
|
24553
24631
|
throw new InvalidReferenceError();
|
|
24554
24632
|
}
|
|
24633
|
+
if (evalContext.__originCellPosition &&
|
|
24634
|
+
range.sheetId === evalContext.__originSheetId &&
|
|
24635
|
+
isZoneInside(positionToZone(evalContext.__originCellPosition), zone)) {
|
|
24636
|
+
throw new CircularDependencyError();
|
|
24637
|
+
}
|
|
24555
24638
|
dependencies.push(range);
|
|
24556
24639
|
}
|
|
24557
24640
|
for (const measure of forMeasures) {
|
|
@@ -25000,6 +25083,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25000
25083
|
};
|
|
25001
25084
|
}
|
|
25002
25085
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
25086
|
+
if (this.getters.getActiveSheetId() === this.__originSheetId) {
|
|
25087
|
+
this.getters.getPivotPresenceTracker(pivotId)?.trackValue(_measure, domain);
|
|
25088
|
+
}
|
|
25003
25089
|
return pivot.getPivotCellValueAndFormat(_measure, domain);
|
|
25004
25090
|
},
|
|
25005
25091
|
};
|
|
@@ -25031,6 +25117,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25031
25117
|
};
|
|
25032
25118
|
}
|
|
25033
25119
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
25120
|
+
if (this.getters.getActiveSheetId() === this.__originSheetId) {
|
|
25121
|
+
this.getters.getPivotPresenceTracker(_pivotId)?.trackHeader(domain);
|
|
25122
|
+
}
|
|
25034
25123
|
const lastNode = domain.at(-1);
|
|
25035
25124
|
if (lastNode?.field === "measure") {
|
|
25036
25125
|
return pivot.getPivotMeasureValue(toString(lastNode.value), domain);
|
|
@@ -25253,6 +25342,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25253
25342
|
return data === undefined || data.value === null;
|
|
25254
25343
|
}
|
|
25255
25344
|
const getNeutral = { number: 0, string: "", boolean: false };
|
|
25345
|
+
function areAlmostEqual(value1, value2, epsilon = 2e-16) {
|
|
25346
|
+
return Math.abs(value1 - value2) < epsilon;
|
|
25347
|
+
}
|
|
25256
25348
|
const EQ = {
|
|
25257
25349
|
description: _t("Equal."),
|
|
25258
25350
|
args: [
|
|
@@ -25268,6 +25360,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25268
25360
|
if (typeof _value2 === "string") {
|
|
25269
25361
|
_value2 = _value2.toUpperCase();
|
|
25270
25362
|
}
|
|
25363
|
+
if (typeof _value1 === "number" && typeof _value2 === "number") {
|
|
25364
|
+
return areAlmostEqual(_value1, _value2);
|
|
25365
|
+
}
|
|
25271
25366
|
return _value1 === _value2;
|
|
25272
25367
|
},
|
|
25273
25368
|
};
|
|
@@ -25307,6 +25402,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25307
25402
|
],
|
|
25308
25403
|
compute: function (value1, value2) {
|
|
25309
25404
|
return applyRelationalOperator(value1, value2, (v1, v2) => {
|
|
25405
|
+
if (typeof v1 === "number" && typeof v2 === "number") {
|
|
25406
|
+
return !areAlmostEqual(v1, v2) && v1 > v2;
|
|
25407
|
+
}
|
|
25310
25408
|
return v1 > v2;
|
|
25311
25409
|
});
|
|
25312
25410
|
},
|
|
@@ -25322,6 +25420,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25322
25420
|
],
|
|
25323
25421
|
compute: function (value1, value2) {
|
|
25324
25422
|
return applyRelationalOperator(value1, value2, (v1, v2) => {
|
|
25423
|
+
if (typeof v1 === "number" && typeof v2 === "number") {
|
|
25424
|
+
return areAlmostEqual(v1, v2) || v1 > v2;
|
|
25425
|
+
}
|
|
25325
25426
|
return v1 >= v2;
|
|
25326
25427
|
});
|
|
25327
25428
|
},
|
|
@@ -26444,10 +26545,18 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
26444
26545
|
});
|
|
26445
26546
|
|
|
26446
26547
|
class DOMFocusableElementStore {
|
|
26447
|
-
mutators = ["setFocusableElement"];
|
|
26548
|
+
mutators = ["setFocusableElement", "focus"];
|
|
26448
26549
|
focusableElement = undefined;
|
|
26449
26550
|
setFocusableElement(element) {
|
|
26450
26551
|
this.focusableElement = element;
|
|
26552
|
+
return "noStateChange";
|
|
26553
|
+
}
|
|
26554
|
+
focus() {
|
|
26555
|
+
if (this.focusableElement === document.activeElement) {
|
|
26556
|
+
return "noStateChange";
|
|
26557
|
+
}
|
|
26558
|
+
this.focusableElement?.focus();
|
|
26559
|
+
return;
|
|
26451
26560
|
}
|
|
26452
26561
|
}
|
|
26453
26562
|
|
|
@@ -27290,7 +27399,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27290
27399
|
if (document.activeElement === this.contentHelper.el &&
|
|
27291
27400
|
this.props.composerStore.editionMode === "inactive" &&
|
|
27292
27401
|
!this.props.isDefaultFocus) {
|
|
27293
|
-
this.DOMFocusableElementStore.
|
|
27402
|
+
this.DOMFocusableElementStore.focus();
|
|
27294
27403
|
}
|
|
27295
27404
|
});
|
|
27296
27405
|
owl.useEffect(() => {
|
|
@@ -27559,6 +27668,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27559
27668
|
openAssistant() {
|
|
27560
27669
|
this.assistant.forcedClosed = false;
|
|
27561
27670
|
}
|
|
27671
|
+
onWheel(event) {
|
|
27672
|
+
// detect if scrollbar is available
|
|
27673
|
+
if (this.composerRef.el &&
|
|
27674
|
+
this.composerRef.el.scrollHeight > this.composerRef.el.clientHeight) {
|
|
27675
|
+
event.stopPropagation();
|
|
27676
|
+
}
|
|
27677
|
+
}
|
|
27562
27678
|
// ---------------------------------------------------------------------------
|
|
27563
27679
|
// Private
|
|
27564
27680
|
// ---------------------------------------------------------------------------
|
|
@@ -31755,12 +31871,20 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31755
31871
|
}
|
|
31756
31872
|
}
|
|
31757
31873
|
hover(position) {
|
|
31874
|
+
if (position.col === this.col && position.row === this.row) {
|
|
31875
|
+
return "noStateChange";
|
|
31876
|
+
}
|
|
31758
31877
|
this.col = position.col;
|
|
31759
31878
|
this.row = position.row;
|
|
31879
|
+
return;
|
|
31760
31880
|
}
|
|
31761
31881
|
clear() {
|
|
31882
|
+
if (this.col === undefined && this.row === undefined) {
|
|
31883
|
+
return "noStateChange";
|
|
31884
|
+
}
|
|
31762
31885
|
this.col = undefined;
|
|
31763
31886
|
this.row = undefined;
|
|
31887
|
+
return;
|
|
31764
31888
|
}
|
|
31765
31889
|
}
|
|
31766
31890
|
|
|
@@ -31782,7 +31906,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31782
31906
|
this.persistentPopover = { col, row, sheetId, type };
|
|
31783
31907
|
}
|
|
31784
31908
|
close() {
|
|
31909
|
+
if (!this.persistentPopover) {
|
|
31910
|
+
return "noStateChange";
|
|
31911
|
+
}
|
|
31785
31912
|
this.persistentPopover = undefined;
|
|
31913
|
+
return;
|
|
31786
31914
|
}
|
|
31787
31915
|
get persistentCellPopover() {
|
|
31788
31916
|
return ((this.persistentPopover && { isOpen: true, ...this.persistentPopover }) || { isOpen: false });
|
|
@@ -32558,10 +32686,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32558
32686
|
name: _t("Duplicate"),
|
|
32559
32687
|
execute: (env) => {
|
|
32560
32688
|
const sheetIdFrom = env.model.getters.getActiveSheetId();
|
|
32689
|
+
const sheetNameFrom = env.model.getters.getSheetName(sheetIdFrom);
|
|
32561
32690
|
const sheetIdTo = env.model.uuidGenerator.smallUuid();
|
|
32691
|
+
const sheetNameTo = env.model.getters.getDuplicateSheetName(sheetNameFrom);
|
|
32562
32692
|
env.model.dispatch("DUPLICATE_SHEET", {
|
|
32563
32693
|
sheetId: sheetIdFrom,
|
|
32564
32694
|
sheetIdTo,
|
|
32695
|
+
sheetNameTo,
|
|
32565
32696
|
});
|
|
32566
32697
|
env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
|
|
32567
32698
|
},
|
|
@@ -39132,7 +39263,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
39132
39263
|
.find((token) => {
|
|
39133
39264
|
const { xc, sheetName: sheet } = splitReference(token.value);
|
|
39134
39265
|
const sheetName = sheet || this.getters.getSheetName(this.sheetId);
|
|
39135
|
-
if (this.getters.getSheetName(activeSheetId)
|
|
39266
|
+
if (!isSheetNameEqual(this.getters.getSheetName(activeSheetId), sheetName)) {
|
|
39136
39267
|
return false;
|
|
39137
39268
|
}
|
|
39138
39269
|
const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
|
|
@@ -43900,8 +44031,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43900
44031
|
|
|
43901
44032
|
const NULL_SYMBOL = Symbol("NULL");
|
|
43902
44033
|
function createDate(dimension, value, locale) {
|
|
43903
|
-
const granularity = dimension.granularity;
|
|
43904
|
-
if (!
|
|
44034
|
+
const granularity = dimension.granularity || "month";
|
|
44035
|
+
if (!(granularity in MAP_VALUE_DIMENSION_DATE)) {
|
|
43905
44036
|
throw new Error(`Unknown date granularity: ${granularity}`);
|
|
43906
44037
|
}
|
|
43907
44038
|
const keyInMap = typeof value === "number" || typeof value === "string" ? value : NULL_SYMBOL;
|
|
@@ -43920,6 +44051,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43920
44051
|
case "month_number":
|
|
43921
44052
|
number = date.getMonth() + 1;
|
|
43922
44053
|
break;
|
|
44054
|
+
case "month":
|
|
44055
|
+
number = Math.floor(toNumber(value, locale));
|
|
44056
|
+
break;
|
|
43923
44057
|
case "iso_week_number":
|
|
43924
44058
|
number = date.getIsoWeek();
|
|
43925
44059
|
break;
|
|
@@ -44013,6 +44147,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44013
44147
|
set: new Set(),
|
|
44014
44148
|
values: {},
|
|
44015
44149
|
},
|
|
44150
|
+
month: {
|
|
44151
|
+
set: new Set(),
|
|
44152
|
+
values: {},
|
|
44153
|
+
},
|
|
44016
44154
|
iso_week_number: {
|
|
44017
44155
|
set: new Set(),
|
|
44018
44156
|
values: {},
|
|
@@ -44223,7 +44361,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44223
44361
|
const cells = this.filterDataEntriesFromDomain(this.dataEntries, domain);
|
|
44224
44362
|
const finalCell = cells[0]?.[dimension.nameWithGranularity];
|
|
44225
44363
|
if (dimension.type === "datetime") {
|
|
44226
|
-
const adapter = pivotTimeAdapter(dimension.granularity);
|
|
44364
|
+
const adapter = pivotTimeAdapter((dimension.granularity || "month"));
|
|
44227
44365
|
return adapter.toValueAndFormat(lastNode.value, this.getters.getLocale());
|
|
44228
44366
|
}
|
|
44229
44367
|
if (!finalCell) {
|
|
@@ -44341,7 +44479,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44341
44479
|
if (nonEmptyCells.length === 0) {
|
|
44342
44480
|
return "integer";
|
|
44343
44481
|
}
|
|
44344
|
-
if (nonEmptyCells.every((cell) => cell.format && isDateTimeFormat(cell.format))) {
|
|
44482
|
+
if (nonEmptyCells.every((cell) => cell.type === CellValueType.number && cell.format && isDateTimeFormat(cell.format))) {
|
|
44345
44483
|
return "datetime";
|
|
44346
44484
|
}
|
|
44347
44485
|
if (nonEmptyCells.every((cell) => cell.type === CellValueType.boolean)) {
|
|
@@ -44422,7 +44560,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44422
44560
|
entry[field.name] = { value: null, type: CellValueType.empty, formattedValue: "" };
|
|
44423
44561
|
}
|
|
44424
44562
|
else {
|
|
44425
|
-
|
|
44563
|
+
if (field.type === "char") {
|
|
44564
|
+
entry[field.name] = { ...cell, value: cell.formattedValue || null };
|
|
44565
|
+
}
|
|
44566
|
+
else {
|
|
44567
|
+
entry[field.name] = cell;
|
|
44568
|
+
}
|
|
44426
44569
|
}
|
|
44427
44570
|
}
|
|
44428
44571
|
entry["__count"] = { value: 1, type: CellValueType.number, formattedValue: "1" };
|
|
@@ -44436,7 +44579,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44436
44579
|
for (const entry of dataEntries) {
|
|
44437
44580
|
for (const dimension of dateDimensions) {
|
|
44438
44581
|
const value = createDate(dimension, entry[dimension.fieldName]?.value || null, this.getters.getLocale());
|
|
44439
|
-
const adapter = pivotTimeAdapter(dimension.granularity);
|
|
44582
|
+
const adapter = pivotTimeAdapter((dimension.granularity || "month"));
|
|
44440
44583
|
const { format, value: valueToFormat } = adapter.toValueAndFormat(value, locale);
|
|
44441
44584
|
entry[dimension.nameWithGranularity] = {
|
|
44442
44585
|
value,
|
|
@@ -44456,6 +44599,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44456
44599
|
"year",
|
|
44457
44600
|
"quarter_number",
|
|
44458
44601
|
"month_number",
|
|
44602
|
+
"month",
|
|
44459
44603
|
"iso_week_number",
|
|
44460
44604
|
"day_of_month",
|
|
44461
44605
|
"day",
|
|
@@ -44696,7 +44840,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44696
44840
|
: this.datetimeGranularities);
|
|
44697
44841
|
}
|
|
44698
44842
|
for (const field of dateFields) {
|
|
44699
|
-
granularitiesPerFields[field.fieldName].delete(field.granularity);
|
|
44843
|
+
granularitiesPerFields[field.fieldName].delete(field.granularity || "month");
|
|
44700
44844
|
}
|
|
44701
44845
|
return granularitiesPerFields;
|
|
44702
44846
|
}
|
|
@@ -46854,6 +46998,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46854
46998
|
}
|
|
46855
46999
|
get composerProps() {
|
|
46856
47000
|
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
47001
|
+
// Remove the wrapper border width
|
|
47002
|
+
const maxHeight = this.props.gridDims.height - this.rect.y - 2 * COMPOSER_BORDER_WIDTH;
|
|
46857
47003
|
return {
|
|
46858
47004
|
rect: { ...this.rect },
|
|
46859
47005
|
delimitation: {
|
|
@@ -46871,6 +47017,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46871
47017
|
}),
|
|
46872
47018
|
onInputContextMenu: this.props.onInputContextMenu,
|
|
46873
47019
|
composerStore: this.composerStore,
|
|
47020
|
+
inputStyle: `max-height: ${maxHeight}px;`,
|
|
46874
47021
|
};
|
|
46875
47022
|
}
|
|
46876
47023
|
get containerStyle() {
|
|
@@ -49414,10 +49561,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49414
49561
|
ctx.scale(dpr, dpr);
|
|
49415
49562
|
for (const layer of OrderedLayers()) {
|
|
49416
49563
|
model.drawLayer(renderingContext, layer);
|
|
49417
|
-
// @ts-ignore 'drawLayer' is not declated as a mutator because:
|
|
49418
|
-
// it does not mutate anything. Most importantly it's used
|
|
49419
|
-
// during rendering. Invoking a mutator during rendering would
|
|
49420
|
-
// trigger another rendering, ultimately resulting in an infinite loop.
|
|
49421
49564
|
rendererStore.drawLayer(renderingContext, layer);
|
|
49422
49565
|
}
|
|
49423
49566
|
}
|
|
@@ -50107,7 +50250,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
50107
50250
|
this.cellPopovers = useStore(CellPopoverStore);
|
|
50108
50251
|
owl.useEffect(() => {
|
|
50109
50252
|
if (!this.sidePanel.isOpen) {
|
|
50110
|
-
this.DOMFocusableElementStore.
|
|
50253
|
+
this.DOMFocusableElementStore.focus();
|
|
50111
50254
|
}
|
|
50112
50255
|
}, () => [this.sidePanel.isOpen]);
|
|
50113
50256
|
useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
|
|
@@ -50315,7 +50458,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
50315
50458
|
focusDefaultElement() {
|
|
50316
50459
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
50317
50460
|
this.composerFocusStore.activeComposer.editionMode === "inactive") {
|
|
50318
|
-
this.DOMFocusableElementStore.
|
|
50461
|
+
this.DOMFocusableElementStore.focus();
|
|
50319
50462
|
}
|
|
50320
50463
|
}
|
|
50321
50464
|
get gridEl() {
|
|
@@ -50685,6 +50828,322 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
50685
50828
|
}
|
|
50686
50829
|
}
|
|
50687
50830
|
|
|
50831
|
+
css /* scss */ `
|
|
50832
|
+
.o_pivot_html_renderer {
|
|
50833
|
+
width: 100%;
|
|
50834
|
+
border-collapse: collapse;
|
|
50835
|
+
|
|
50836
|
+
&:hover {
|
|
50837
|
+
cursor: pointer;
|
|
50838
|
+
}
|
|
50839
|
+
|
|
50840
|
+
td,
|
|
50841
|
+
th {
|
|
50842
|
+
border: 1px solid #dee2e6;
|
|
50843
|
+
background-color: #fff;
|
|
50844
|
+
padding: 0.3rem;
|
|
50845
|
+
white-space: nowrap;
|
|
50846
|
+
|
|
50847
|
+
&:hover {
|
|
50848
|
+
filter: brightness(0.9);
|
|
50849
|
+
}
|
|
50850
|
+
}
|
|
50851
|
+
|
|
50852
|
+
td {
|
|
50853
|
+
text-align: right;
|
|
50854
|
+
}
|
|
50855
|
+
|
|
50856
|
+
th {
|
|
50857
|
+
background-color: #f5f5f5;
|
|
50858
|
+
font-weight: bold;
|
|
50859
|
+
color: black;
|
|
50860
|
+
}
|
|
50861
|
+
|
|
50862
|
+
.o_missing_value {
|
|
50863
|
+
color: #46646d;
|
|
50864
|
+
background: #e7f2f6;
|
|
50865
|
+
}
|
|
50866
|
+
}
|
|
50867
|
+
`;
|
|
50868
|
+
class PivotHTMLRenderer extends owl.Component {
|
|
50869
|
+
static template = "o_spreadsheet.PivotHTMLRenderer";
|
|
50870
|
+
static components = { Checkbox };
|
|
50871
|
+
static props = {
|
|
50872
|
+
pivotId: String,
|
|
50873
|
+
onCellClicked: Function,
|
|
50874
|
+
};
|
|
50875
|
+
pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
50876
|
+
data = {
|
|
50877
|
+
columns: [],
|
|
50878
|
+
rows: [],
|
|
50879
|
+
values: [],
|
|
50880
|
+
};
|
|
50881
|
+
state = owl.useState({
|
|
50882
|
+
showMissingValuesOnly: false,
|
|
50883
|
+
});
|
|
50884
|
+
setup() {
|
|
50885
|
+
const table = this.pivot.getTableStructure();
|
|
50886
|
+
const formulaId = this.env.model.getters.getPivotFormulaId(this.props.pivotId);
|
|
50887
|
+
this.data = {
|
|
50888
|
+
columns: this._buildColHeaders(formulaId, table),
|
|
50889
|
+
rows: this._buildRowHeaders(formulaId, table),
|
|
50890
|
+
values: this._buildValues(formulaId, table),
|
|
50891
|
+
};
|
|
50892
|
+
}
|
|
50893
|
+
get tracker() {
|
|
50894
|
+
return this.env.model.getters.getPivotPresenceTracker(this.props.pivotId);
|
|
50895
|
+
}
|
|
50896
|
+
// ---------------------------------------------------------------------
|
|
50897
|
+
// Missing values building
|
|
50898
|
+
// ---------------------------------------------------------------------
|
|
50899
|
+
/**
|
|
50900
|
+
* Retrieve the data to display in the Pivot Table
|
|
50901
|
+
* In the case when showMissingValuesOnly is false, the returned value
|
|
50902
|
+
* is the complete data
|
|
50903
|
+
* In the case when showMissingValuesOnly is true, the returned value is
|
|
50904
|
+
* the data which contains only missing values in the rows and cols. In
|
|
50905
|
+
* the rows, we also return the parent rows of rows which contains missing
|
|
50906
|
+
* values, to give context to the user.
|
|
50907
|
+
*
|
|
50908
|
+
*/
|
|
50909
|
+
getTableData() {
|
|
50910
|
+
if (!this.state.showMissingValuesOnly) {
|
|
50911
|
+
return this.data;
|
|
50912
|
+
}
|
|
50913
|
+
const colIndexes = this.getColumnsIndexes();
|
|
50914
|
+
const rowIndexes = this.getRowsIndexes();
|
|
50915
|
+
const columns = this.buildColumnsMissing(colIndexes);
|
|
50916
|
+
const rows = this.buildRowsMissing(rowIndexes);
|
|
50917
|
+
const values = this.buildValuesMissing(colIndexes, rowIndexes);
|
|
50918
|
+
return { columns, rows, values };
|
|
50919
|
+
}
|
|
50920
|
+
/**
|
|
50921
|
+
* Retrieve the parents of the given row
|
|
50922
|
+
* ex:
|
|
50923
|
+
* Australia
|
|
50924
|
+
* January
|
|
50925
|
+
* February
|
|
50926
|
+
* The parent of "January" is "Australia"
|
|
50927
|
+
*/
|
|
50928
|
+
addRecursiveRow(index) {
|
|
50929
|
+
const rows = this.pivot.getTableStructure().rows;
|
|
50930
|
+
const row = [...rows[index].values];
|
|
50931
|
+
if (row.length <= 1) {
|
|
50932
|
+
return [index];
|
|
50933
|
+
}
|
|
50934
|
+
row.pop();
|
|
50935
|
+
const parentRowIndex = rows.findIndex((r) => JSON.stringify(r.values) === JSON.stringify(row));
|
|
50936
|
+
return [index].concat(this.addRecursiveRow(parentRowIndex));
|
|
50937
|
+
}
|
|
50938
|
+
/**
|
|
50939
|
+
* Create the columns to be used, based on the indexes of the columns in
|
|
50940
|
+
* which a missing value is present
|
|
50941
|
+
*
|
|
50942
|
+
*/
|
|
50943
|
+
buildColumnsMissing(indexes) {
|
|
50944
|
+
// columnsMap explode the columns in an array of array of the same
|
|
50945
|
+
// size with the index of each column, repeated 'span' times.
|
|
50946
|
+
// ex:
|
|
50947
|
+
// | A | B |
|
|
50948
|
+
// | 1 | 2 | 3 |
|
|
50949
|
+
// => [
|
|
50950
|
+
// [0, 0, 1]
|
|
50951
|
+
// [0, 1, 2]
|
|
50952
|
+
// ]
|
|
50953
|
+
const columnsMap = [];
|
|
50954
|
+
for (const column of this.data.columns) {
|
|
50955
|
+
const columnMap = [];
|
|
50956
|
+
for (const index in column) {
|
|
50957
|
+
for (let i = 0; i < column[index].span; i++) {
|
|
50958
|
+
columnMap.push(parseInt(index, 10));
|
|
50959
|
+
}
|
|
50960
|
+
}
|
|
50961
|
+
columnsMap.push(columnMap);
|
|
50962
|
+
}
|
|
50963
|
+
// Remove the columns that are not present in indexes
|
|
50964
|
+
for (let i = columnsMap[columnsMap.length - 1].length; i >= 0; i--) {
|
|
50965
|
+
if (!indexes.includes(i)) {
|
|
50966
|
+
for (const columnMap of columnsMap) {
|
|
50967
|
+
columnMap.splice(i, 1);
|
|
50968
|
+
}
|
|
50969
|
+
}
|
|
50970
|
+
}
|
|
50971
|
+
// Build the columns
|
|
50972
|
+
const columns = [];
|
|
50973
|
+
for (const mapIndex in columnsMap) {
|
|
50974
|
+
const column = [];
|
|
50975
|
+
let index = undefined;
|
|
50976
|
+
let span = 1;
|
|
50977
|
+
for (let i = 0; i < columnsMap[mapIndex].length; i++) {
|
|
50978
|
+
if (index !== columnsMap[mapIndex][i]) {
|
|
50979
|
+
if (index !== undefined) {
|
|
50980
|
+
column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
|
|
50981
|
+
}
|
|
50982
|
+
index = columnsMap[mapIndex][i];
|
|
50983
|
+
span = 1;
|
|
50984
|
+
}
|
|
50985
|
+
else {
|
|
50986
|
+
span++;
|
|
50987
|
+
}
|
|
50988
|
+
}
|
|
50989
|
+
if (index !== undefined) {
|
|
50990
|
+
column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
|
|
50991
|
+
}
|
|
50992
|
+
columns.push(column);
|
|
50993
|
+
}
|
|
50994
|
+
return columns;
|
|
50995
|
+
}
|
|
50996
|
+
/**
|
|
50997
|
+
* Create the rows to be used, based on the indexes of the rows in
|
|
50998
|
+
* which a missing value is present.
|
|
50999
|
+
*/
|
|
51000
|
+
buildRowsMissing(indexes) {
|
|
51001
|
+
return indexes.map((index) => this.data.rows[index]);
|
|
51002
|
+
}
|
|
51003
|
+
/**
|
|
51004
|
+
* Create the value to be used, based on the indexes of the columns and
|
|
51005
|
+
* rows in which a missing value is present.
|
|
51006
|
+
*/
|
|
51007
|
+
buildValuesMissing(colIndexes, rowIndexes) {
|
|
51008
|
+
const values = colIndexes.map(() => []);
|
|
51009
|
+
for (const row of rowIndexes) {
|
|
51010
|
+
for (const col in colIndexes) {
|
|
51011
|
+
values[col].push(this.data.values[colIndexes[col]][row]);
|
|
51012
|
+
}
|
|
51013
|
+
}
|
|
51014
|
+
return values;
|
|
51015
|
+
}
|
|
51016
|
+
getColumnsIndexes() {
|
|
51017
|
+
const indexes = new Set();
|
|
51018
|
+
for (let i = 0; i < this.data.columns.length; i++) {
|
|
51019
|
+
const exploded = [];
|
|
51020
|
+
for (let y = 0; y < this.data.columns[i].length; y++) {
|
|
51021
|
+
for (let x = 0; x < this.data.columns[i][y].span; x++) {
|
|
51022
|
+
exploded.push(this.data.columns[i][y]);
|
|
51023
|
+
}
|
|
51024
|
+
}
|
|
51025
|
+
for (let y = 0; y < exploded.length; y++) {
|
|
51026
|
+
if (exploded[y].isMissing) {
|
|
51027
|
+
indexes.add(y);
|
|
51028
|
+
}
|
|
51029
|
+
}
|
|
51030
|
+
}
|
|
51031
|
+
for (let i = 0; i < this.data.columns[this.data.columns.length - 1].length; i++) {
|
|
51032
|
+
const values = this.data.values[i];
|
|
51033
|
+
if (values.find((x) => x.isMissing)) {
|
|
51034
|
+
indexes.add(i);
|
|
51035
|
+
}
|
|
51036
|
+
}
|
|
51037
|
+
return Array.from(indexes).sort((a, b) => a - b);
|
|
51038
|
+
}
|
|
51039
|
+
getRowsIndexes() {
|
|
51040
|
+
const rowIndexes = new Set();
|
|
51041
|
+
for (let i = 0; i < this.data.rows.length; i++) {
|
|
51042
|
+
if (this.data.rows[i].isMissing) {
|
|
51043
|
+
rowIndexes.add(i);
|
|
51044
|
+
}
|
|
51045
|
+
for (const col of this.data.values) {
|
|
51046
|
+
if (col[i].isMissing) {
|
|
51047
|
+
this.addRecursiveRow(i).forEach((x) => rowIndexes.add(x));
|
|
51048
|
+
}
|
|
51049
|
+
}
|
|
51050
|
+
}
|
|
51051
|
+
return Array.from(rowIndexes).sort((a, b) => a - b);
|
|
51052
|
+
}
|
|
51053
|
+
// ---------------------------------------------------------------------
|
|
51054
|
+
// Data table creation
|
|
51055
|
+
// ---------------------------------------------------------------------
|
|
51056
|
+
_buildColHeaders(id, table) {
|
|
51057
|
+
const headers = [];
|
|
51058
|
+
for (const row of table.columns) {
|
|
51059
|
+
const current = [];
|
|
51060
|
+
for (const cell of row) {
|
|
51061
|
+
const args = [];
|
|
51062
|
+
for (let i = 0; i < cell.fields.length; i++) {
|
|
51063
|
+
args.push({ value: cell.fields[i] }, { value: cell.values[i] });
|
|
51064
|
+
}
|
|
51065
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
51066
|
+
const locale = this.env.model.getters.getLocale();
|
|
51067
|
+
if (domain.at(-1)?.field === "measure") {
|
|
51068
|
+
const { value, format } = this.pivot.getPivotMeasureValue(toString(domain.at(-1).value), domain);
|
|
51069
|
+
current.push({
|
|
51070
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
51071
|
+
value: formatValue(value, { format, locale }),
|
|
51072
|
+
span: cell.width,
|
|
51073
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
51074
|
+
});
|
|
51075
|
+
}
|
|
51076
|
+
else {
|
|
51077
|
+
const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
|
|
51078
|
+
current.push({
|
|
51079
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
51080
|
+
value: formatValue(value, { format, locale }),
|
|
51081
|
+
span: cell.width,
|
|
51082
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
51083
|
+
});
|
|
51084
|
+
}
|
|
51085
|
+
}
|
|
51086
|
+
headers.push(current);
|
|
51087
|
+
}
|
|
51088
|
+
const last = headers[headers.length - 1];
|
|
51089
|
+
headers[headers.length - 1] = last.map((cell) => {
|
|
51090
|
+
if (!cell.isMissing) {
|
|
51091
|
+
cell.style = "color: #756f6f;";
|
|
51092
|
+
}
|
|
51093
|
+
return cell;
|
|
51094
|
+
});
|
|
51095
|
+
return headers;
|
|
51096
|
+
}
|
|
51097
|
+
_buildRowHeaders(id, table) {
|
|
51098
|
+
const headers = [];
|
|
51099
|
+
for (const row of table.rows) {
|
|
51100
|
+
const args = [];
|
|
51101
|
+
for (let i = 0; i < row.fields.length; i++) {
|
|
51102
|
+
args.push({ value: row.fields[i] }, { value: row.values[i] });
|
|
51103
|
+
}
|
|
51104
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
51105
|
+
const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
|
|
51106
|
+
const locale = this.env.model.getters.getLocale();
|
|
51107
|
+
const cell = {
|
|
51108
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
51109
|
+
value: formatValue(value, { format, locale }),
|
|
51110
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
51111
|
+
};
|
|
51112
|
+
if (row.indent > 1) {
|
|
51113
|
+
cell.style = `padding-left: ${row.indent - 1 * 10}px`;
|
|
51114
|
+
}
|
|
51115
|
+
headers.push(cell);
|
|
51116
|
+
}
|
|
51117
|
+
return headers;
|
|
51118
|
+
}
|
|
51119
|
+
_buildValues(id, table) {
|
|
51120
|
+
const values = [];
|
|
51121
|
+
for (const col of table.columns.at(-1) || []) {
|
|
51122
|
+
const current = [];
|
|
51123
|
+
const measure = toString(col.values[col.values.length - 1]);
|
|
51124
|
+
for (const row of table.rows) {
|
|
51125
|
+
const args = [];
|
|
51126
|
+
for (let i = 0; i < row.fields.length; i++) {
|
|
51127
|
+
args.push({ value: row.fields[i] }, { value: row.values[i] });
|
|
51128
|
+
}
|
|
51129
|
+
for (let i = 0; i < col.fields.length - 1; i++) {
|
|
51130
|
+
args.push({ value: col.fields[i] }, { value: col.values[i] });
|
|
51131
|
+
}
|
|
51132
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
51133
|
+
const { value, format } = this.pivot.getPivotCellValueAndFormat(measure, domain);
|
|
51134
|
+
const locale = this.env.model.getters.getLocale();
|
|
51135
|
+
current.push({
|
|
51136
|
+
formula: `=PIVOT.VALUE(${generatePivotArgs(id, domain, measure).join(",")})`,
|
|
51137
|
+
value: formatValue(value, { format, locale }),
|
|
51138
|
+
isMissing: !this.tracker?.isValuePresent(measure, domain),
|
|
51139
|
+
});
|
|
51140
|
+
}
|
|
51141
|
+
values.push(current);
|
|
51142
|
+
}
|
|
51143
|
+
return values;
|
|
51144
|
+
}
|
|
51145
|
+
}
|
|
51146
|
+
|
|
50688
51147
|
/**
|
|
50689
51148
|
* BasePlugin
|
|
50690
51149
|
*
|
|
@@ -52270,9 +52729,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52270
52729
|
: "Success" /* CommandResult.Success */;
|
|
52271
52730
|
}
|
|
52272
52731
|
checkChartExists(cmd) {
|
|
52273
|
-
return this.
|
|
52274
|
-
? "Success" /* CommandResult.Success */
|
|
52275
|
-
: "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
|
|
52732
|
+
return this.isChartDefined(cmd.id) ? "Success" /* CommandResult.Success */ : "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
|
|
52276
52733
|
}
|
|
52277
52734
|
}
|
|
52278
52735
|
|
|
@@ -54195,7 +54652,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54195
54652
|
if (range.sheetId === cmd.sheetId) {
|
|
54196
54653
|
return { changeType: "CHANGE", range };
|
|
54197
54654
|
}
|
|
54198
|
-
if (
|
|
54655
|
+
if (isSheetNameEqual(range.invalidSheetName, cmd.name)) {
|
|
54199
54656
|
const invalidSheetName = undefined;
|
|
54200
54657
|
const sheetId = cmd.sheetId;
|
|
54201
54658
|
const newRange = range.clone({ sheetId, invalidSheetName });
|
|
@@ -54533,6 +54990,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54533
54990
|
"getCommandZones",
|
|
54534
54991
|
"getUnboundedZone",
|
|
54535
54992
|
"checkElementsIncludeAllNonFrozenHeaders",
|
|
54993
|
+
"getDuplicateSheetName",
|
|
54536
54994
|
];
|
|
54537
54995
|
sheetIdsMapName = {};
|
|
54538
54996
|
orderedSheetIds = [];
|
|
@@ -54557,7 +55015,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54557
55015
|
return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
|
|
54558
55016
|
}
|
|
54559
55017
|
case "DUPLICATE_SHEET": {
|
|
54560
|
-
|
|
55018
|
+
if (this.sheets[cmd.sheetIdTo])
|
|
55019
|
+
return "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */;
|
|
55020
|
+
if (this.orderedSheetIds.map(this.getSheetName.bind(this)).includes(cmd.sheetNameTo))
|
|
55021
|
+
return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
|
|
55022
|
+
return "Success" /* CommandResult.Success */;
|
|
54561
55023
|
}
|
|
54562
55024
|
case "MOVE_SHEET":
|
|
54563
55025
|
try {
|
|
@@ -54634,7 +55096,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54634
55096
|
this.showSheet(cmd.sheetId);
|
|
54635
55097
|
break;
|
|
54636
55098
|
case "DUPLICATE_SHEET":
|
|
54637
|
-
this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo);
|
|
55099
|
+
this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo, cmd.sheetNameTo);
|
|
54638
55100
|
break;
|
|
54639
55101
|
case "DELETE_SHEET":
|
|
54640
55102
|
this.deleteSheet(this.sheets[cmd.sheetId]);
|
|
@@ -54775,7 +55237,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54775
55237
|
if (name) {
|
|
54776
55238
|
const unquotedName = getUnquotedSheetName(name);
|
|
54777
55239
|
for (const key in this.sheetIdsMapName) {
|
|
54778
|
-
if (key
|
|
55240
|
+
if (isSheetNameEqual(key, unquotedName)) {
|
|
54779
55241
|
return this.sheetIdsMapName[key];
|
|
54780
55242
|
}
|
|
54781
55243
|
}
|
|
@@ -54840,14 +55302,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54840
55302
|
return dimension === "COL" ? this.getNumberCols(sheetId) : this.getNumberRows(sheetId);
|
|
54841
55303
|
}
|
|
54842
55304
|
getNextSheetName(baseName = "Sheet") {
|
|
54843
|
-
let i = 1;
|
|
54844
55305
|
const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
|
|
54845
|
-
|
|
54846
|
-
while (names.includes(name)) {
|
|
54847
|
-
name = `${baseName}${i}`;
|
|
54848
|
-
i++;
|
|
54849
|
-
}
|
|
54850
|
-
return name;
|
|
55306
|
+
return getNextSheetName(names, baseName);
|
|
54851
55307
|
}
|
|
54852
55308
|
getSheetSize(sheetId) {
|
|
54853
55309
|
return {
|
|
@@ -55029,7 +55485,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55029
55485
|
}
|
|
55030
55486
|
const { orderedSheetIds, sheets } = this;
|
|
55031
55487
|
const name = cmd.name && cmd.name.trim().toLowerCase();
|
|
55032
|
-
if (orderedSheetIds.find((id) => sheets[id]?.name
|
|
55488
|
+
if (orderedSheetIds.find((id) => isSheetNameEqual(sheets[id]?.name, name) && id !== cmd.sheetId)) {
|
|
55033
55489
|
return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
|
|
55034
55490
|
}
|
|
55035
55491
|
if (FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX.test(name)) {
|
|
@@ -55093,9 +55549,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55093
55549
|
showSheet(sheetId) {
|
|
55094
55550
|
this.history.update("sheets", sheetId, "isVisible", true);
|
|
55095
55551
|
}
|
|
55096
|
-
duplicateSheet(fromId, toId) {
|
|
55552
|
+
duplicateSheet(fromId, toId, toName) {
|
|
55097
55553
|
const sheet = this.getSheet(fromId);
|
|
55098
|
-
const toName = this.getDuplicateSheetName(sheet.name);
|
|
55099
55554
|
const newSheet = deepCopy(sheet);
|
|
55100
55555
|
newSheet.id = toId;
|
|
55101
55556
|
newSheet.name = toName;
|
|
@@ -55127,15 +55582,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55127
55582
|
this.history.update("sheetIdsMapName", sheetIdsMapName);
|
|
55128
55583
|
}
|
|
55129
55584
|
getDuplicateSheetName(sheetName) {
|
|
55130
|
-
let i = 1;
|
|
55131
55585
|
const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
|
|
55132
|
-
|
|
55133
|
-
let name = baseName.toString();
|
|
55134
|
-
while (names.includes(name)) {
|
|
55135
|
-
name = `${baseName} (${i})`;
|
|
55136
|
-
i++;
|
|
55137
|
-
}
|
|
55138
|
-
return name;
|
|
55586
|
+
return getDuplicateSheetName(sheetName, names);
|
|
55139
55587
|
}
|
|
55140
55588
|
deleteSheet(sheet) {
|
|
55141
55589
|
const name = sheet.name;
|
|
@@ -57961,8 +58409,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57961
58409
|
const EMPTY_ARRAY = [];
|
|
57962
58410
|
|
|
57963
58411
|
const MAX_ITERATION = 30;
|
|
57964
|
-
const ERROR_CYCLE_CELL = createEvaluatedCell(new CircularDependencyError());
|
|
57965
|
-
const EMPTY_CELL = createEvaluatedCell({ value: null });
|
|
58412
|
+
const ERROR_CYCLE_CELL = Object.freeze(createEvaluatedCell(new CircularDependencyError()));
|
|
58413
|
+
const EMPTY_CELL = Object.freeze(createEvaluatedCell({ value: null }));
|
|
57966
58414
|
class Evaluator {
|
|
57967
58415
|
context;
|
|
57968
58416
|
getters;
|
|
@@ -63924,6 +64372,55 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
63924
64372
|
}
|
|
63925
64373
|
}
|
|
63926
64374
|
|
|
64375
|
+
class PivotPresenceTracker {
|
|
64376
|
+
trackedValues = new Set();
|
|
64377
|
+
domainToArray(domain) {
|
|
64378
|
+
return domain.flatMap((node) => [node.field, toString(node.value)]);
|
|
64379
|
+
}
|
|
64380
|
+
isValuePresent(measure, domain) {
|
|
64381
|
+
const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
|
|
64382
|
+
return this.trackedValues.has(key);
|
|
64383
|
+
}
|
|
64384
|
+
isHeaderPresent(domain) {
|
|
64385
|
+
const key = JSON.stringify({ domain: this.domainToArray(domain) });
|
|
64386
|
+
return this.trackedValues.has(key);
|
|
64387
|
+
}
|
|
64388
|
+
trackValue(measure, domain) {
|
|
64389
|
+
const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
|
|
64390
|
+
this.trackedValues.add(key);
|
|
64391
|
+
}
|
|
64392
|
+
trackHeader(domain) {
|
|
64393
|
+
const key = JSON.stringify({ domain: this.domainToArray(domain) });
|
|
64394
|
+
this.trackedValues.add(key);
|
|
64395
|
+
}
|
|
64396
|
+
}
|
|
64397
|
+
|
|
64398
|
+
class PivotPresencePlugin extends UIPlugin {
|
|
64399
|
+
static getters = ["getPivotPresenceTracker"];
|
|
64400
|
+
trackPresencePivotId;
|
|
64401
|
+
tracker;
|
|
64402
|
+
handle(cmd) {
|
|
64403
|
+
switch (cmd.type) {
|
|
64404
|
+
case "PIVOT_START_PRESENCE_TRACKING":
|
|
64405
|
+
this.tracker = new PivotPresenceTracker();
|
|
64406
|
+
this.trackPresencePivotId = cmd.pivotId;
|
|
64407
|
+
break;
|
|
64408
|
+
case "PIVOT_STOP_PRESENCE_TRACKING":
|
|
64409
|
+
this.trackPresencePivotId = undefined;
|
|
64410
|
+
break;
|
|
64411
|
+
}
|
|
64412
|
+
}
|
|
64413
|
+
getPivotPresenceTracker(pivotId) {
|
|
64414
|
+
if (this.trackPresencePivotId !== pivotId) {
|
|
64415
|
+
return undefined;
|
|
64416
|
+
}
|
|
64417
|
+
if (!this.tracker) {
|
|
64418
|
+
throw new Error("Tracker not initialized");
|
|
64419
|
+
}
|
|
64420
|
+
return this.tracker;
|
|
64421
|
+
}
|
|
64422
|
+
}
|
|
64423
|
+
|
|
63927
64424
|
class SplitToColumnsPlugin extends UIPlugin {
|
|
63928
64425
|
static getters = ["getAutomaticSeparator"];
|
|
63929
64426
|
allowDispatch(cmd) {
|
|
@@ -66707,6 +67204,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66707
67204
|
.add("automatic_sum", AutomaticSumPlugin)
|
|
66708
67205
|
.add("format", FormatPlugin)
|
|
66709
67206
|
.add("insert_pivot", InsertPivotPlugin)
|
|
67207
|
+
.add("pivot_presence", PivotPresencePlugin)
|
|
66710
67208
|
.add("split_to_columns", SplitToColumnsPlugin)
|
|
66711
67209
|
.add("collaborative", CollaborativePlugin)
|
|
66712
67210
|
.add("history", HistoryPlugin)
|
|
@@ -67086,11 +67584,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
67086
67584
|
if (ev.key === "Enter") {
|
|
67087
67585
|
ev.preventDefault();
|
|
67088
67586
|
this.stopEdition();
|
|
67089
|
-
this.DOMFocusableElementStore.
|
|
67587
|
+
this.DOMFocusableElementStore.focus();
|
|
67090
67588
|
}
|
|
67091
67589
|
if (ev.key === "Escape") {
|
|
67092
67590
|
this.cancelEdition();
|
|
67093
|
-
this.DOMFocusableElementStore.
|
|
67591
|
+
this.DOMFocusableElementStore.focus();
|
|
67094
67592
|
}
|
|
67095
67593
|
}
|
|
67096
67594
|
onMouseEventSheetName(ev) {
|
|
@@ -73700,6 +74198,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73700
74198
|
PivotDimensionOrder,
|
|
73701
74199
|
PivotDimension,
|
|
73702
74200
|
PivotLayoutConfigurator,
|
|
74201
|
+
PivotHTMLRenderer,
|
|
73703
74202
|
EditableName,
|
|
73704
74203
|
PivotDeferUpdate,
|
|
73705
74204
|
PivotTitleSection,
|
|
@@ -73793,9 +74292,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73793
74292
|
exports.tokenize = tokenize;
|
|
73794
74293
|
|
|
73795
74294
|
|
|
73796
|
-
__info__.version = "18.0.
|
|
73797
|
-
__info__.date = "2025-05-
|
|
73798
|
-
__info__.hash = "
|
|
74295
|
+
__info__.version = "18.0.28";
|
|
74296
|
+
__info__.date = "2025-05-13T17:53:12.402Z";
|
|
74297
|
+
__info__.hash = "b3088aa";
|
|
73799
74298
|
|
|
73800
74299
|
|
|
73801
74300
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|