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