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