@odoo/o-spreadsheet 17.4.0-alpha.7 → 17.4.0-alpha.9
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 +811 -742
- package/dist/o-spreadsheet.d.ts +47 -31
- package/dist/o-spreadsheet.esm.js +811 -742
- package/dist/o-spreadsheet.iife.js +811 -742
- package/dist/o-spreadsheet.iife.min.js +345 -345
- package/dist/o_spreadsheet.xml +5 -5
- 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 17.4.0-alpha.
|
|
6
|
-
* @date 2024-06-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.4.0-alpha.9
|
|
6
|
+
* @date 2024-06-26T11:09:20.284Z
|
|
7
|
+
* @hash 526be20
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -1902,9 +1902,10 @@
|
|
|
1902
1902
|
sortedValues[indexLow] * (indexSup - percentIndex));
|
|
1903
1903
|
}
|
|
1904
1904
|
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
let
|
|
1905
|
+
const defaultTranslate = (s) => s;
|
|
1906
|
+
const defaultLoaded = () => false;
|
|
1907
|
+
let _translate = defaultTranslate;
|
|
1908
|
+
let _loaded = defaultLoaded;
|
|
1908
1909
|
function sprintf(s, ...values) {
|
|
1909
1910
|
if (values.length === 1 && typeof values[0] === "object" && !(values[0] instanceof String)) {
|
|
1910
1911
|
const valuesDict = values[0];
|
|
@@ -1916,7 +1917,8 @@
|
|
|
1916
1917
|
return s;
|
|
1917
1918
|
}
|
|
1918
1919
|
/***
|
|
1919
|
-
* Allow to inject a translation function from outside o-spreadsheet.
|
|
1920
|
+
* Allow to inject a translation function from outside o-spreadsheet. This should be called before instantiating
|
|
1921
|
+
* a model.
|
|
1920
1922
|
* @param tfn the function that will do the translation
|
|
1921
1923
|
* @param loaded a function that returns true when the translation is loaded
|
|
1922
1924
|
*/
|
|
@@ -1924,6 +1926,18 @@
|
|
|
1924
1926
|
_translate = tfn;
|
|
1925
1927
|
_loaded = loaded;
|
|
1926
1928
|
}
|
|
1929
|
+
/**
|
|
1930
|
+
* If no translation function has been set, this will mark the translation are loaded.
|
|
1931
|
+
*
|
|
1932
|
+
* By default, the translations should not be set as loaded, otherwise top-level translated constants will never be
|
|
1933
|
+
* translated. But if by the time the model is instantiated no custom translation function has been set, we can set
|
|
1934
|
+
* the default translation function as loaded so o-spreadsheet can be run in standalone with no translations.
|
|
1935
|
+
*/
|
|
1936
|
+
function setDefaultTranslationMethod() {
|
|
1937
|
+
if (_translate === defaultTranslate && _loaded === defaultLoaded) {
|
|
1938
|
+
_loaded = () => true;
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1927
1941
|
const _t = function (s, ...values) {
|
|
1928
1942
|
if (!_loaded()) {
|
|
1929
1943
|
return new LazyTranslatedString(s, values);
|
|
@@ -5619,18 +5633,12 @@
|
|
|
5619
5633
|
return { borders };
|
|
5620
5634
|
}
|
|
5621
5635
|
paste(target, content, options) {
|
|
5622
|
-
if (!content) {
|
|
5623
|
-
return;
|
|
5624
|
-
}
|
|
5625
5636
|
const sheetId = target.sheetId;
|
|
5626
|
-
if (options
|
|
5627
|
-
return;
|
|
5628
|
-
}
|
|
5629
|
-
if (!("borders" in content) || !("zones" in target) || !target.zones.length) {
|
|
5637
|
+
if (options.pasteOption === "asValue") {
|
|
5630
5638
|
return;
|
|
5631
5639
|
}
|
|
5632
5640
|
const zones = target.zones;
|
|
5633
|
-
if (!options
|
|
5641
|
+
if (!options.isCutOperation) {
|
|
5634
5642
|
this.pasteFromCopy(sheetId, zones, content.borders);
|
|
5635
5643
|
}
|
|
5636
5644
|
else {
|
|
@@ -6141,6 +6149,530 @@
|
|
|
6141
6149
|
return localizedFormula;
|
|
6142
6150
|
}
|
|
6143
6151
|
|
|
6152
|
+
function boolAnd(args) {
|
|
6153
|
+
let foundBoolean = false;
|
|
6154
|
+
let acc = true;
|
|
6155
|
+
conditionalVisitBoolean(args, (arg) => {
|
|
6156
|
+
foundBoolean = true;
|
|
6157
|
+
acc = acc && arg;
|
|
6158
|
+
return acc;
|
|
6159
|
+
});
|
|
6160
|
+
return {
|
|
6161
|
+
foundBoolean,
|
|
6162
|
+
result: acc,
|
|
6163
|
+
};
|
|
6164
|
+
}
|
|
6165
|
+
function boolOr(args) {
|
|
6166
|
+
let foundBoolean = false;
|
|
6167
|
+
let acc = false;
|
|
6168
|
+
conditionalVisitBoolean(args, (arg) => {
|
|
6169
|
+
foundBoolean = true;
|
|
6170
|
+
acc = acc || arg;
|
|
6171
|
+
return !acc;
|
|
6172
|
+
});
|
|
6173
|
+
return {
|
|
6174
|
+
foundBoolean,
|
|
6175
|
+
result: acc,
|
|
6176
|
+
};
|
|
6177
|
+
}
|
|
6178
|
+
|
|
6179
|
+
function sum(values, locale) {
|
|
6180
|
+
return reduceNumbers(values, (acc, a) => acc + a, 0, locale);
|
|
6181
|
+
}
|
|
6182
|
+
function countUnique(args) {
|
|
6183
|
+
return reduceAny(args, (acc, a) => (isDataNonEmpty(a) ? acc.add(a?.value) : acc), new Set()).size;
|
|
6184
|
+
}
|
|
6185
|
+
|
|
6186
|
+
function assertSameNumberOfElements(...args) {
|
|
6187
|
+
const dims = args[0].length;
|
|
6188
|
+
args.forEach((arg, i) => assert(() => arg.length === dims, _t("[[FUNCTION_NAME]] has mismatched dimensions for argument %s (%s vs %s).", i.toString(), dims.toString(), arg.length.toString())));
|
|
6189
|
+
}
|
|
6190
|
+
function average(values, locale) {
|
|
6191
|
+
let count = 0;
|
|
6192
|
+
const sum = reduceNumbers(values, (acc, a) => {
|
|
6193
|
+
count += 1;
|
|
6194
|
+
return acc + a;
|
|
6195
|
+
}, 0, locale);
|
|
6196
|
+
assertNotZero(count);
|
|
6197
|
+
return sum / count;
|
|
6198
|
+
}
|
|
6199
|
+
function countNumbers(values, locale) {
|
|
6200
|
+
let count = 0;
|
|
6201
|
+
for (let n of values) {
|
|
6202
|
+
if (isMatrix(n)) {
|
|
6203
|
+
for (let i of n) {
|
|
6204
|
+
for (let j of i) {
|
|
6205
|
+
if (typeof j.value === "number") {
|
|
6206
|
+
count += 1;
|
|
6207
|
+
}
|
|
6208
|
+
}
|
|
6209
|
+
}
|
|
6210
|
+
}
|
|
6211
|
+
else {
|
|
6212
|
+
const value = n?.value;
|
|
6213
|
+
if (!isEvaluationError(value) &&
|
|
6214
|
+
(typeof value !== "string" || isNumber(value, locale) || parseDateTime(value, locale))) {
|
|
6215
|
+
count += 1;
|
|
6216
|
+
}
|
|
6217
|
+
}
|
|
6218
|
+
}
|
|
6219
|
+
return count;
|
|
6220
|
+
}
|
|
6221
|
+
function countAny(values) {
|
|
6222
|
+
return reduceAny(values, (acc, a) => (a !== undefined && a.value !== null ? acc + 1 : acc), 0);
|
|
6223
|
+
}
|
|
6224
|
+
function max(values, locale) {
|
|
6225
|
+
const result = reduceNumbers(values, (acc, a) => (acc < a ? a : acc), -Infinity, locale);
|
|
6226
|
+
return result === -Infinity ? 0 : result;
|
|
6227
|
+
}
|
|
6228
|
+
function min(values, locale) {
|
|
6229
|
+
const result = reduceNumbers(values, (acc, a) => (a < acc ? a : acc), Infinity, locale);
|
|
6230
|
+
return result === Infinity ? 0 : result;
|
|
6231
|
+
}
|
|
6232
|
+
|
|
6233
|
+
const pivotTimeAdapterRegistry = new Registry();
|
|
6234
|
+
function pivotTimeAdapter(granularity) {
|
|
6235
|
+
return pivotTimeAdapterRegistry.get(granularity);
|
|
6236
|
+
}
|
|
6237
|
+
/**
|
|
6238
|
+
* The Time Adapter: Managing Time Periods for Pivot Functions
|
|
6239
|
+
*
|
|
6240
|
+
* Overview:
|
|
6241
|
+
* A time adapter is responsible for managing time periods associated with pivot functions.
|
|
6242
|
+
* Each type of period (day, week, month, quarter, etc.) has its own dedicated adapter.
|
|
6243
|
+
* The adapter's primary role is to normalize period values between spreadsheet functions,
|
|
6244
|
+
* and the pivot.
|
|
6245
|
+
* By normalizing the period value, it can be stored consistently in the pivot.
|
|
6246
|
+
*
|
|
6247
|
+
* Normalization Process:
|
|
6248
|
+
* When working with functions in the spreadsheet, the time adapter normalizes
|
|
6249
|
+
* the provided period to facilitate accurate lookup of values in the pivot.
|
|
6250
|
+
* For instance, if the spreadsheet function represents a day period as a number generated
|
|
6251
|
+
* by the DATE function (DATE(2023, 12, 25)), the time adapter will normalize it accordingly.
|
|
6252
|
+
*
|
|
6253
|
+
*/
|
|
6254
|
+
/**
|
|
6255
|
+
* Normalized value: "12/25/2023"
|
|
6256
|
+
*
|
|
6257
|
+
* Note: Those two format are equivalent:
|
|
6258
|
+
* - "MM/dd/yyyy" (luxon format)
|
|
6259
|
+
* - "mm/dd/yyyy" (spreadsheet format)
|
|
6260
|
+
**/
|
|
6261
|
+
const dayAdapter = {
|
|
6262
|
+
normalizeFunctionValue(value) {
|
|
6263
|
+
return toNumber(value, DEFAULT_LOCALE);
|
|
6264
|
+
},
|
|
6265
|
+
toValueAndFormat(normalizedValue, locale) {
|
|
6266
|
+
return {
|
|
6267
|
+
value: toNumber(normalizedValue, DEFAULT_LOCALE),
|
|
6268
|
+
format: (locale ?? DEFAULT_LOCALE).dateFormat,
|
|
6269
|
+
};
|
|
6270
|
+
},
|
|
6271
|
+
toFunctionValue(normalizedValue) {
|
|
6272
|
+
const date = toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
6273
|
+
return `"${formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/dd/yyyy" })}"`;
|
|
6274
|
+
},
|
|
6275
|
+
};
|
|
6276
|
+
/**
|
|
6277
|
+
* normalizes day of month number
|
|
6278
|
+
*/
|
|
6279
|
+
const dayOfMonthAdapter = {
|
|
6280
|
+
normalizeFunctionValue(value) {
|
|
6281
|
+
const day = toNumber(value, DEFAULT_LOCALE);
|
|
6282
|
+
if (day < 1 || day > 31) {
|
|
6283
|
+
throw new EvaluationError(_t("%s is not a valid day of month (it should be a number between 1 and 31)", day));
|
|
6284
|
+
}
|
|
6285
|
+
return day;
|
|
6286
|
+
},
|
|
6287
|
+
toValueAndFormat(normalizedValue) {
|
|
6288
|
+
return {
|
|
6289
|
+
value: toNumber(normalizedValue, DEFAULT_LOCALE),
|
|
6290
|
+
format: "0",
|
|
6291
|
+
};
|
|
6292
|
+
},
|
|
6293
|
+
toFunctionValue(normalizedValue) {
|
|
6294
|
+
return `${normalizedValue}`;
|
|
6295
|
+
},
|
|
6296
|
+
};
|
|
6297
|
+
/**
|
|
6298
|
+
* Normalized value: "2/2023" for week 2 of 2023
|
|
6299
|
+
*/
|
|
6300
|
+
const weekAdapter = {
|
|
6301
|
+
normalizeFunctionValue(value) {
|
|
6302
|
+
const [week, year] = toString(value).split("/");
|
|
6303
|
+
return `${Number(week)}/${Number(year)}`;
|
|
6304
|
+
},
|
|
6305
|
+
toValueAndFormat(normalizedValue, locale) {
|
|
6306
|
+
const [week, year] = normalizedValue.split("/");
|
|
6307
|
+
return {
|
|
6308
|
+
value: _t("W%(week)s %(year)s", { week, year }),
|
|
6309
|
+
};
|
|
6310
|
+
},
|
|
6311
|
+
toFunctionValue(normalizedValue) {
|
|
6312
|
+
return `"${normalizedValue}"`;
|
|
6313
|
+
},
|
|
6314
|
+
};
|
|
6315
|
+
/**
|
|
6316
|
+
* normalizes iso week number
|
|
6317
|
+
*/
|
|
6318
|
+
const isoWeekNumberAdapter = {
|
|
6319
|
+
normalizeFunctionValue(value) {
|
|
6320
|
+
const isoWeek = toNumber(value, DEFAULT_LOCALE);
|
|
6321
|
+
if (isoWeek < 0 || isoWeek > 53) {
|
|
6322
|
+
throw new EvaluationError(_t("%s is not a valid week (it should be a number between 0 and 53)", isoWeek));
|
|
6323
|
+
}
|
|
6324
|
+
return isoWeek;
|
|
6325
|
+
},
|
|
6326
|
+
toValueAndFormat(normalizedValue) {
|
|
6327
|
+
return {
|
|
6328
|
+
value: toNumber(normalizedValue, DEFAULT_LOCALE),
|
|
6329
|
+
format: "0",
|
|
6330
|
+
};
|
|
6331
|
+
},
|
|
6332
|
+
toFunctionValue(normalizedValue) {
|
|
6333
|
+
return `${normalizedValue}`;
|
|
6334
|
+
},
|
|
6335
|
+
};
|
|
6336
|
+
/**
|
|
6337
|
+
* normalized month value is a string formatted as "MM/yyyy" (luxon format)
|
|
6338
|
+
* e.g. "01/2020" for January 2020
|
|
6339
|
+
*/
|
|
6340
|
+
const monthAdapter = {
|
|
6341
|
+
normalizeFunctionValue(value) {
|
|
6342
|
+
const date = toNumber(value, DEFAULT_LOCALE);
|
|
6343
|
+
return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
|
|
6344
|
+
},
|
|
6345
|
+
toValueAndFormat(normalizedValue) {
|
|
6346
|
+
return {
|
|
6347
|
+
value: toNumber(normalizedValue, DEFAULT_LOCALE),
|
|
6348
|
+
format: "mmmm yyyy",
|
|
6349
|
+
};
|
|
6350
|
+
},
|
|
6351
|
+
toFunctionValue(normalizedValue) {
|
|
6352
|
+
return `"${normalizedValue}"`;
|
|
6353
|
+
},
|
|
6354
|
+
};
|
|
6355
|
+
/**
|
|
6356
|
+
* normalizes month number
|
|
6357
|
+
*/
|
|
6358
|
+
const monthNumberAdapter = {
|
|
6359
|
+
normalizeFunctionValue(value) {
|
|
6360
|
+
const month = toNumber(value, DEFAULT_LOCALE);
|
|
6361
|
+
if (month < 1 || month > 12) {
|
|
6362
|
+
throw new EvaluationError(_t("%s is not a valid month (it should be a number between 1 and 12)", month));
|
|
6363
|
+
}
|
|
6364
|
+
return month;
|
|
6365
|
+
},
|
|
6366
|
+
toValueAndFormat(normalizedValue) {
|
|
6367
|
+
return {
|
|
6368
|
+
value: MONTHS[toNumber(normalizedValue, DEFAULT_LOCALE) - 1].toString(),
|
|
6369
|
+
format: "0",
|
|
6370
|
+
};
|
|
6371
|
+
},
|
|
6372
|
+
toFunctionValue(normalizedValue) {
|
|
6373
|
+
return `${normalizedValue}`;
|
|
6374
|
+
},
|
|
6375
|
+
};
|
|
6376
|
+
/**
|
|
6377
|
+
* normalized quarter value is "quarter/year"
|
|
6378
|
+
* e.g. "1/2020" for Q1 2020
|
|
6379
|
+
*/
|
|
6380
|
+
const quarterAdapter = {
|
|
6381
|
+
normalizeFunctionValue(value) {
|
|
6382
|
+
const [quarter, year] = toString(value).split("/");
|
|
6383
|
+
return `${quarter}/${year}`;
|
|
6384
|
+
},
|
|
6385
|
+
toValueAndFormat(normalizedValue) {
|
|
6386
|
+
const [quarter, year] = normalizedValue.split("/");
|
|
6387
|
+
return {
|
|
6388
|
+
value: _t("Q%(quarter)s %(year)s", { quarter, year }),
|
|
6389
|
+
};
|
|
6390
|
+
},
|
|
6391
|
+
toFunctionValue(normalizedValue) {
|
|
6392
|
+
return `"${normalizedValue}"`;
|
|
6393
|
+
},
|
|
6394
|
+
};
|
|
6395
|
+
/**
|
|
6396
|
+
* normalizes quarter number
|
|
6397
|
+
*/
|
|
6398
|
+
const quarterNumberAdapter = {
|
|
6399
|
+
normalizeFunctionValue(value) {
|
|
6400
|
+
const quarter = toNumber(value, DEFAULT_LOCALE);
|
|
6401
|
+
if (quarter < 1 || quarter > 4) {
|
|
6402
|
+
throw new EvaluationError(_t("%s is not a valid quarter (it should be a number between 1 and 4)", quarter));
|
|
6403
|
+
}
|
|
6404
|
+
return quarter;
|
|
6405
|
+
},
|
|
6406
|
+
toValueAndFormat(normalizedValue) {
|
|
6407
|
+
return {
|
|
6408
|
+
value: toNumber(normalizedValue, DEFAULT_LOCALE),
|
|
6409
|
+
format: "0",
|
|
6410
|
+
};
|
|
6411
|
+
},
|
|
6412
|
+
toFunctionValue(normalizedValue) {
|
|
6413
|
+
return `${normalizedValue}`;
|
|
6414
|
+
},
|
|
6415
|
+
};
|
|
6416
|
+
const yearAdapter = {
|
|
6417
|
+
normalizeFunctionValue(value) {
|
|
6418
|
+
return toNumber(value, DEFAULT_LOCALE);
|
|
6419
|
+
},
|
|
6420
|
+
toValueAndFormat(normalizedValue) {
|
|
6421
|
+
return {
|
|
6422
|
+
value: toNumber(normalizedValue, DEFAULT_LOCALE),
|
|
6423
|
+
format: "0",
|
|
6424
|
+
};
|
|
6425
|
+
},
|
|
6426
|
+
toFunctionValue(normalizedValue) {
|
|
6427
|
+
return `${normalizedValue}`;
|
|
6428
|
+
},
|
|
6429
|
+
};
|
|
6430
|
+
/**
|
|
6431
|
+
* This function takes an adapter and wraps it with a null handler.
|
|
6432
|
+
* null value means that the value is not set.
|
|
6433
|
+
*/
|
|
6434
|
+
function nullHandlerDecorator(adapter) {
|
|
6435
|
+
return {
|
|
6436
|
+
normalizeFunctionValue(value) {
|
|
6437
|
+
if (value === null) {
|
|
6438
|
+
return null;
|
|
6439
|
+
}
|
|
6440
|
+
return adapter.normalizeFunctionValue(value);
|
|
6441
|
+
},
|
|
6442
|
+
toValueAndFormat(normalizedValue, locale) {
|
|
6443
|
+
if (normalizedValue === null) {
|
|
6444
|
+
return { value: _t("(Undefined)") }; //TODO Return NA ?
|
|
6445
|
+
}
|
|
6446
|
+
return adapter.toValueAndFormat(normalizedValue, locale);
|
|
6447
|
+
},
|
|
6448
|
+
toFunctionValue(normalizedValue) {
|
|
6449
|
+
if (normalizedValue === null) {
|
|
6450
|
+
return "false"; //TODO Return NA ?
|
|
6451
|
+
}
|
|
6452
|
+
return adapter.toFunctionValue(normalizedValue);
|
|
6453
|
+
},
|
|
6454
|
+
};
|
|
6455
|
+
}
|
|
6456
|
+
pivotTimeAdapterRegistry
|
|
6457
|
+
.add("day", nullHandlerDecorator(dayAdapter))
|
|
6458
|
+
.add("week", nullHandlerDecorator(weekAdapter))
|
|
6459
|
+
.add("month", nullHandlerDecorator(monthAdapter))
|
|
6460
|
+
.add("quarter", nullHandlerDecorator(quarterAdapter))
|
|
6461
|
+
.add("year", nullHandlerDecorator(yearAdapter))
|
|
6462
|
+
.add("day_of_month", nullHandlerDecorator(dayOfMonthAdapter))
|
|
6463
|
+
.add("iso_week_number", nullHandlerDecorator(isoWeekNumberAdapter))
|
|
6464
|
+
.add("month_number", nullHandlerDecorator(monthNumberAdapter))
|
|
6465
|
+
.add("quarter_number", nullHandlerDecorator(quarterNumberAdapter))
|
|
6466
|
+
.add("year_number", nullHandlerDecorator(yearAdapter));
|
|
6467
|
+
|
|
6468
|
+
const AGGREGATOR_NAMES = {
|
|
6469
|
+
count: _t("Count"),
|
|
6470
|
+
count_distinct: _t("Count Distinct"),
|
|
6471
|
+
bool_and: _t("Boolean And"),
|
|
6472
|
+
bool_or: _t("Boolean Or"),
|
|
6473
|
+
max: _t("Maximum"),
|
|
6474
|
+
min: _t("Minimum"),
|
|
6475
|
+
avg: _t("Average"),
|
|
6476
|
+
sum: _t("Sum"),
|
|
6477
|
+
};
|
|
6478
|
+
const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
|
|
6479
|
+
const AGGREGATORS_BY_FIELD_TYPE = {
|
|
6480
|
+
integer: NUMBER_CHAR_AGGREGATORS,
|
|
6481
|
+
char: NUMBER_CHAR_AGGREGATORS,
|
|
6482
|
+
boolean: ["count_distinct", "count", "bool_and", "bool_or"],
|
|
6483
|
+
};
|
|
6484
|
+
const AGGREGATORS = {};
|
|
6485
|
+
for (const type in AGGREGATORS_BY_FIELD_TYPE) {
|
|
6486
|
+
AGGREGATORS[type] = {};
|
|
6487
|
+
for (const aggregator of AGGREGATORS_BY_FIELD_TYPE[type]) {
|
|
6488
|
+
AGGREGATORS[type][aggregator] = AGGREGATOR_NAMES[aggregator];
|
|
6489
|
+
}
|
|
6490
|
+
}
|
|
6491
|
+
const AGGREGATORS_FN = {
|
|
6492
|
+
count: {
|
|
6493
|
+
fn: (args) => countAny([args]),
|
|
6494
|
+
format: () => "0",
|
|
6495
|
+
},
|
|
6496
|
+
count_distinct: {
|
|
6497
|
+
fn: (args) => countUnique([args]),
|
|
6498
|
+
format: () => "0",
|
|
6499
|
+
},
|
|
6500
|
+
bool_and: {
|
|
6501
|
+
fn: (args) => boolAnd([args]).result,
|
|
6502
|
+
format: () => undefined,
|
|
6503
|
+
},
|
|
6504
|
+
bool_or: {
|
|
6505
|
+
fn: (args) => boolOr([args]).result,
|
|
6506
|
+
format: () => undefined,
|
|
6507
|
+
},
|
|
6508
|
+
max: {
|
|
6509
|
+
fn: (args, locale) => max([args], locale),
|
|
6510
|
+
format: inferFormat,
|
|
6511
|
+
},
|
|
6512
|
+
min: {
|
|
6513
|
+
fn: (args, locale) => min([args], locale),
|
|
6514
|
+
format: inferFormat,
|
|
6515
|
+
},
|
|
6516
|
+
avg: {
|
|
6517
|
+
fn: (args, locale) => average([args], locale),
|
|
6518
|
+
format: inferFormat,
|
|
6519
|
+
},
|
|
6520
|
+
sum: {
|
|
6521
|
+
fn: (args, locale) => sum([args], locale),
|
|
6522
|
+
format: inferFormat,
|
|
6523
|
+
},
|
|
6524
|
+
};
|
|
6525
|
+
/**
|
|
6526
|
+
* Given an object of form {"1": {...}, "2": {...}, ...} get the maximum ID used
|
|
6527
|
+
* in this object
|
|
6528
|
+
* If the object has no keys, return 0
|
|
6529
|
+
*
|
|
6530
|
+
*/
|
|
6531
|
+
function getMaxObjectId(o) {
|
|
6532
|
+
const keys = Object.keys(o);
|
|
6533
|
+
if (!keys.length) {
|
|
6534
|
+
return 0;
|
|
6535
|
+
}
|
|
6536
|
+
const nums = keys.map((id) => parseInt(id, 10));
|
|
6537
|
+
const max = Math.max(...nums);
|
|
6538
|
+
return max;
|
|
6539
|
+
}
|
|
6540
|
+
const ALL_PERIODS = {
|
|
6541
|
+
year: _t("Year"),
|
|
6542
|
+
quarter: _t("Quarter"),
|
|
6543
|
+
month: _t("Month"),
|
|
6544
|
+
week: _t("Week"),
|
|
6545
|
+
day: _t("Day"),
|
|
6546
|
+
year_number: _t("Year"),
|
|
6547
|
+
quarter_number: _t("Quarter"),
|
|
6548
|
+
month_number: _t("Month"),
|
|
6549
|
+
iso_week_number: _t("Week"),
|
|
6550
|
+
day_of_month: _t("Day of Month"),
|
|
6551
|
+
};
|
|
6552
|
+
const DATE_FIELDS = ["date", "datetime"];
|
|
6553
|
+
/**
|
|
6554
|
+
* Parse a dimension string into a pivot dimension definition.
|
|
6555
|
+
* e.g "create_date:month" => { name: "create_date", granularity: "month" }
|
|
6556
|
+
*/
|
|
6557
|
+
function parseDimension(dimension) {
|
|
6558
|
+
const [name, granularity] = dimension.split(":");
|
|
6559
|
+
if (granularity) {
|
|
6560
|
+
return { name, granularity };
|
|
6561
|
+
}
|
|
6562
|
+
return { name };
|
|
6563
|
+
}
|
|
6564
|
+
function isDateField(field) {
|
|
6565
|
+
return DATE_FIELDS.includes(field.type);
|
|
6566
|
+
}
|
|
6567
|
+
function generatePivotArgs(formulaId, domain, measure) {
|
|
6568
|
+
const args = [formulaId];
|
|
6569
|
+
if (measure) {
|
|
6570
|
+
args.push(`"${measure}"`);
|
|
6571
|
+
}
|
|
6572
|
+
for (const { field, value, type } of domain) {
|
|
6573
|
+
if (field === "measure") {
|
|
6574
|
+
args.push(`"measure"`, `"${value}"`);
|
|
6575
|
+
continue;
|
|
6576
|
+
}
|
|
6577
|
+
const { granularity } = parseDimension(field);
|
|
6578
|
+
const formattedValue = toFunctionPivotValue(value, { type, granularity });
|
|
6579
|
+
args.push(`"${field}"`, formattedValue);
|
|
6580
|
+
}
|
|
6581
|
+
return args;
|
|
6582
|
+
}
|
|
6583
|
+
/**
|
|
6584
|
+
* Check if the fields in the domain part of
|
|
6585
|
+
* a pivot function are valid according to the pivot definition.
|
|
6586
|
+
* e.g. =PIVOT.VALUE(1,"revenue","country_id",...,"create_date:month",...,"source_id",...)
|
|
6587
|
+
*/
|
|
6588
|
+
function areDomainArgsFieldsValid(dimensions, definition) {
|
|
6589
|
+
let argIndex = 0;
|
|
6590
|
+
let definitionIndex = 0;
|
|
6591
|
+
const cols = definition.columns.map((col) => col.nameWithGranularity);
|
|
6592
|
+
const rows = definition.rows.map((row) => row.nameWithGranularity);
|
|
6593
|
+
while (dimensions[argIndex] !== undefined && dimensions[argIndex] === rows[definitionIndex]) {
|
|
6594
|
+
argIndex++;
|
|
6595
|
+
definitionIndex++;
|
|
6596
|
+
}
|
|
6597
|
+
definitionIndex = 0;
|
|
6598
|
+
while (dimensions[argIndex] !== undefined && dimensions[argIndex] === cols[definitionIndex]) {
|
|
6599
|
+
argIndex++;
|
|
6600
|
+
definitionIndex++;
|
|
6601
|
+
}
|
|
6602
|
+
return dimensions.length === argIndex;
|
|
6603
|
+
}
|
|
6604
|
+
function createPivotFormula(formulaId, cell) {
|
|
6605
|
+
switch (cell.type) {
|
|
6606
|
+
case "HEADER":
|
|
6607
|
+
return `=PIVOT.HEADER(${generatePivotArgs(formulaId, cell.domain).join(",")})`;
|
|
6608
|
+
case "VALUE":
|
|
6609
|
+
return `=PIVOT.VALUE(${generatePivotArgs(formulaId, cell.domain, cell.measure).join(",")})`;
|
|
6610
|
+
case "MEASURE_HEADER":
|
|
6611
|
+
return `=PIVOT.HEADER(${generatePivotArgs(formulaId, [
|
|
6612
|
+
...cell.domain,
|
|
6613
|
+
{ field: "measure", value: cell.measure, type: "char" },
|
|
6614
|
+
]).join(",")})`;
|
|
6615
|
+
}
|
|
6616
|
+
return "";
|
|
6617
|
+
}
|
|
6618
|
+
/**
|
|
6619
|
+
* Parses the value defining a pivot group in a PIVOT formula
|
|
6620
|
+
* e.g. given the following formula PIVOT.VALUE("1", "stage_id", "42", "status", "won"),
|
|
6621
|
+
* the two group values are "42" and "won".
|
|
6622
|
+
*/
|
|
6623
|
+
function toNormalizedPivotValue(dimension, groupValue) {
|
|
6624
|
+
if (groupValue === null || groupValue === "null") {
|
|
6625
|
+
return null;
|
|
6626
|
+
}
|
|
6627
|
+
const groupValueString = typeof groupValue === "boolean"
|
|
6628
|
+
? toString(groupValue).toLocaleLowerCase()
|
|
6629
|
+
: toString(groupValue);
|
|
6630
|
+
if (!pivotNormalizationValueRegistry.contains(dimension.type)) {
|
|
6631
|
+
throw new EvaluationError(_t("Field %(field)s is not supported because of its type (%(type)s)", {
|
|
6632
|
+
field: dimension.displayName,
|
|
6633
|
+
type: dimension.type,
|
|
6634
|
+
}));
|
|
6635
|
+
}
|
|
6636
|
+
// represents a field which is not set (=False server side)
|
|
6637
|
+
if (groupValueString.toLowerCase() === "false") {
|
|
6638
|
+
return false;
|
|
6639
|
+
}
|
|
6640
|
+
const normalizer = pivotNormalizationValueRegistry.get(dimension.type);
|
|
6641
|
+
return normalizer(groupValueString, dimension.granularity);
|
|
6642
|
+
}
|
|
6643
|
+
function normalizeDateTime(value, granularity) {
|
|
6644
|
+
if (!granularity) {
|
|
6645
|
+
throw new Error("Missing granularity");
|
|
6646
|
+
}
|
|
6647
|
+
return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
|
|
6648
|
+
}
|
|
6649
|
+
function toFunctionPivotValue(value, dimension) {
|
|
6650
|
+
if (!pivotToFunctionValueRegistry.contains(dimension.type)) {
|
|
6651
|
+
return `"${value}"`;
|
|
6652
|
+
}
|
|
6653
|
+
return pivotToFunctionValueRegistry.get(dimension.type)(value, dimension.granularity);
|
|
6654
|
+
}
|
|
6655
|
+
function toFunctionValueDateTime(value, granularity) {
|
|
6656
|
+
if (!granularity) {
|
|
6657
|
+
throw new Error("Missing granularity");
|
|
6658
|
+
}
|
|
6659
|
+
return pivotTimeAdapter(granularity).toFunctionValue(value);
|
|
6660
|
+
}
|
|
6661
|
+
const pivotNormalizationValueRegistry = new Registry();
|
|
6662
|
+
pivotNormalizationValueRegistry
|
|
6663
|
+
.add("date", normalizeDateTime)
|
|
6664
|
+
.add("datetime", normalizeDateTime)
|
|
6665
|
+
.add("integer", (value) => toNumber(value, DEFAULT_LOCALE))
|
|
6666
|
+
.add("boolean", (value) => toBoolean(value))
|
|
6667
|
+
.add("char", (value) => toString(value));
|
|
6668
|
+
const pivotToFunctionValueRegistry = new Registry();
|
|
6669
|
+
pivotToFunctionValueRegistry
|
|
6670
|
+
.add("date", toFunctionValueDateTime)
|
|
6671
|
+
.add("datetime", toFunctionValueDateTime)
|
|
6672
|
+
.add("integer", (value) => `${toNumber(value, DEFAULT_LOCALE)}`)
|
|
6673
|
+
.add("boolean", (value) => (toBoolean(value) ? "TRUE" : "FALSE"))
|
|
6674
|
+
.add("char", (value) => `"${toString(value).replace(/"/g, '\\"')}"`);
|
|
6675
|
+
|
|
6144
6676
|
class CellClipboardHandler extends AbstractCellClipboardHandler {
|
|
6145
6677
|
isCutAllowed(data) {
|
|
6146
6678
|
if (data.zones.length !== 1) {
|
|
@@ -6149,40 +6681,48 @@
|
|
|
6149
6681
|
return "Success" /* CommandResult.Success */;
|
|
6150
6682
|
}
|
|
6151
6683
|
copy(data) {
|
|
6152
|
-
if (!("zones" in data) || !data.zones.length) {
|
|
6153
|
-
return;
|
|
6154
|
-
}
|
|
6155
6684
|
const sheetId = data.sheetId;
|
|
6156
|
-
const zones = data.zones;
|
|
6157
|
-
if (!zones.length) {
|
|
6158
|
-
return {
|
|
6159
|
-
cells: [[]],
|
|
6160
|
-
zones: [],
|
|
6161
|
-
sheetId,
|
|
6162
|
-
};
|
|
6163
|
-
}
|
|
6164
6685
|
const { clippedZones, rowsIndexes, columnsIndexes } = data;
|
|
6165
6686
|
const clippedCells = [];
|
|
6687
|
+
const isCopyingOneCell = rowsIndexes.length == 1 && columnsIndexes.length == 1;
|
|
6166
6688
|
for (let row of rowsIndexes) {
|
|
6167
6689
|
let cellsInRow = [];
|
|
6168
6690
|
for (let col of columnsIndexes) {
|
|
6169
6691
|
const position = { col, row, sheetId };
|
|
6170
|
-
const spreader = this.getters.getArrayFormulaSpreadingOn(position);
|
|
6171
6692
|
let cell = this.getters.getCell(position);
|
|
6172
6693
|
const evaluatedCell = this.getters.getEvaluatedCell(position);
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6694
|
+
const pivotId = this.getters.getPivotIdFromPosition(position);
|
|
6695
|
+
const spreader = this.getters.getArrayFormulaSpreadingOn(position);
|
|
6696
|
+
if (pivotId) {
|
|
6697
|
+
if (!deepEquals(spreader, position) || !isCopyingOneCell) {
|
|
6698
|
+
const pivotCell = this.getters.getPivotCellFromPosition(position);
|
|
6699
|
+
const formulaPivotId = this.getters.getPivotFormulaId(pivotId);
|
|
6700
|
+
const pivotFormula = createPivotFormula(formulaPivotId, pivotCell);
|
|
6701
|
+
cell = {
|
|
6702
|
+
id: cell?.id || "",
|
|
6703
|
+
style: cell?.style,
|
|
6704
|
+
format: evaluatedCell.format,
|
|
6705
|
+
content: pivotFormula,
|
|
6706
|
+
isFormula: false,
|
|
6707
|
+
parsedValue: evaluatedCell.value,
|
|
6708
|
+
};
|
|
6709
|
+
}
|
|
6710
|
+
}
|
|
6711
|
+
else {
|
|
6712
|
+
if (spreader && !deepEquals(spreader, position)) {
|
|
6713
|
+
const isSpreaderCopied = rowsIndexes.includes(spreader.row) && columnsIndexes.includes(spreader.col);
|
|
6714
|
+
const content = isSpreaderCopied
|
|
6715
|
+
? ""
|
|
6716
|
+
: formatValue(evaluatedCell.value, { locale: this.getters.getLocale() });
|
|
6717
|
+
cell = {
|
|
6718
|
+
id: cell?.id || "",
|
|
6719
|
+
style: cell?.style,
|
|
6720
|
+
format: evaluatedCell.format,
|
|
6721
|
+
content,
|
|
6722
|
+
isFormula: false,
|
|
6723
|
+
parsedValue: evaluatedCell.value,
|
|
6724
|
+
};
|
|
6725
|
+
}
|
|
6186
6726
|
}
|
|
6187
6727
|
cellsInRow.push({
|
|
6188
6728
|
cell,
|
|
@@ -6231,12 +6771,9 @@
|
|
|
6231
6771
|
* Paste the clipboard content in the given target
|
|
6232
6772
|
*/
|
|
6233
6773
|
paste(target, content, options) {
|
|
6234
|
-
if (!("cells" in content) || !("zones" in target) || !target.zones.length) {
|
|
6235
|
-
return;
|
|
6236
|
-
}
|
|
6237
6774
|
const zones = target.zones;
|
|
6238
6775
|
const sheetId = target.sheetId;
|
|
6239
|
-
if (!options
|
|
6776
|
+
if (!options.isCutOperation) {
|
|
6240
6777
|
this.pasteFromCopy(sheetId, zones, content.cells, options);
|
|
6241
6778
|
}
|
|
6242
6779
|
else {
|
|
@@ -6406,14 +6943,11 @@
|
|
|
6406
6943
|
};
|
|
6407
6944
|
}
|
|
6408
6945
|
getPasteTarget(sheetId, target, content, options) {
|
|
6409
|
-
if (!content?.copiedFigure || !content?.copiedChart) {
|
|
6410
|
-
return { zones: [], sheetId };
|
|
6411
|
-
}
|
|
6412
6946
|
const newId = new UuidGenerator().uuidv4();
|
|
6413
6947
|
return { zones: [], figureId: newId, sheetId };
|
|
6414
6948
|
}
|
|
6415
6949
|
paste(target, clippedContent, options) {
|
|
6416
|
-
if (!
|
|
6950
|
+
if (!target.figureId) {
|
|
6417
6951
|
return;
|
|
6418
6952
|
}
|
|
6419
6953
|
const { zones, figureId } = target;
|
|
@@ -6437,7 +6971,7 @@
|
|
|
6437
6971
|
size: { height, width },
|
|
6438
6972
|
definition: copy.getDefinition(),
|
|
6439
6973
|
});
|
|
6440
|
-
if (options
|
|
6974
|
+
if (options.isCutOperation) {
|
|
6441
6975
|
this.dispatch("DELETE_FIGURE", {
|
|
6442
6976
|
sheetId: clippedContent.copiedChart.sheetId,
|
|
6443
6977
|
id: clippedContent.copiedFigure.id,
|
|
@@ -6479,15 +7013,12 @@
|
|
|
6479
7013
|
return { cfRules };
|
|
6480
7014
|
}
|
|
6481
7015
|
paste(target, clippedContent, options) {
|
|
6482
|
-
if (
|
|
6483
|
-
options?.pasteOption === "asValue" ||
|
|
6484
|
-
!("zones" in target) ||
|
|
6485
|
-
!target.zones.length) {
|
|
7016
|
+
if (options.pasteOption === "asValue") {
|
|
6486
7017
|
return;
|
|
6487
7018
|
}
|
|
6488
7019
|
const zones = target.zones;
|
|
6489
7020
|
const sheetId = target.sheetId;
|
|
6490
|
-
if (!options
|
|
7021
|
+
if (!options.isCutOperation) {
|
|
6491
7022
|
this.pasteFromCopy(sheetId, zones, clippedContent.cfRules, options);
|
|
6492
7023
|
}
|
|
6493
7024
|
else {
|
|
@@ -6561,9 +7092,6 @@
|
|
|
6561
7092
|
class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
|
|
6562
7093
|
uuidGenerator = new UuidGenerator();
|
|
6563
7094
|
copy(data) {
|
|
6564
|
-
if (!data.zones.length) {
|
|
6565
|
-
return;
|
|
6566
|
-
}
|
|
6567
7095
|
const { rowsIndexes, columnsIndexes } = data;
|
|
6568
7096
|
const sheetId = data.sheetId;
|
|
6569
7097
|
const dvRules = [];
|
|
@@ -6579,18 +7107,12 @@
|
|
|
6579
7107
|
return { dvRules };
|
|
6580
7108
|
}
|
|
6581
7109
|
paste(target, clippedContent, options) {
|
|
6582
|
-
if (
|
|
6583
|
-
return;
|
|
6584
|
-
}
|
|
6585
|
-
if (options?.pasteOption) {
|
|
6586
|
-
return;
|
|
6587
|
-
}
|
|
6588
|
-
if (!("zones" in target) || !target.zones.length) {
|
|
7110
|
+
if (options.pasteOption) {
|
|
6589
7111
|
return;
|
|
6590
7112
|
}
|
|
6591
7113
|
const zones = target.zones;
|
|
6592
7114
|
const sheetId = target.sheetId;
|
|
6593
|
-
if (!options
|
|
7115
|
+
if (!options.isCutOperation) {
|
|
6594
7116
|
this.pasteFromCopy(sheetId, zones, clippedContent.dvRules);
|
|
6595
7117
|
}
|
|
6596
7118
|
else {
|
|
@@ -6689,14 +7211,11 @@
|
|
|
6689
7211
|
};
|
|
6690
7212
|
}
|
|
6691
7213
|
getPasteTarget(sheetId, target, content, options) {
|
|
6692
|
-
if (!content?.copiedFigure || !content?.copiedImage) {
|
|
6693
|
-
return { zones: [], sheetId };
|
|
6694
|
-
}
|
|
6695
7214
|
const newId = new UuidGenerator().uuidv4();
|
|
6696
7215
|
return { sheetId, zones: [], figureId: newId };
|
|
6697
7216
|
}
|
|
6698
7217
|
paste(target, clippedContent, options) {
|
|
6699
|
-
if (!
|
|
7218
|
+
if (!target.figureId) {
|
|
6700
7219
|
return;
|
|
6701
7220
|
}
|
|
6702
7221
|
const { zones, figureId } = target;
|
|
@@ -6720,7 +7239,7 @@
|
|
|
6720
7239
|
size: { height, width },
|
|
6721
7240
|
definition: copy,
|
|
6722
7241
|
});
|
|
6723
|
-
if (options
|
|
7242
|
+
if (options.isCutOperation) {
|
|
6724
7243
|
this.dispatch("DELETE_FIGURE", {
|
|
6725
7244
|
sheetId: clippedContent.sheetId,
|
|
6726
7245
|
id: clippedContent.copiedFigure.id,
|
|
@@ -6741,9 +7260,6 @@
|
|
|
6741
7260
|
|
|
6742
7261
|
class MergeClipboardHandler extends AbstractCellClipboardHandler {
|
|
6743
7262
|
copy(data) {
|
|
6744
|
-
if (!data.zones.length) {
|
|
6745
|
-
return;
|
|
6746
|
-
}
|
|
6747
7263
|
const sheetId = this.getters.getActiveSheetId();
|
|
6748
7264
|
const { rowsIndexes, columnsIndexes } = data;
|
|
6749
7265
|
const merges = [];
|
|
@@ -6761,10 +7277,7 @@
|
|
|
6761
7277
|
* Paste the clipboard content in the given target
|
|
6762
7278
|
*/
|
|
6763
7279
|
paste(target, content, options) {
|
|
6764
|
-
if (
|
|
6765
|
-
options?.isCutOperation ||
|
|
6766
|
-
!("zones" in target) ||
|
|
6767
|
-
!target.zones.length) {
|
|
7280
|
+
if (options.isCutOperation) {
|
|
6768
7281
|
return;
|
|
6769
7282
|
}
|
|
6770
7283
|
this.pasteFromCopy(target.sheetId, target.zones, content.merges, options);
|
|
@@ -6820,9 +7333,6 @@
|
|
|
6820
7333
|
copy(data) {
|
|
6821
7334
|
const sheetId = data.sheetId;
|
|
6822
7335
|
const { rowsIndexes, columnsIndexes, zones } = data;
|
|
6823
|
-
if (!zones || !rowsIndexes.length || !columnsIndexes.length) {
|
|
6824
|
-
return { tableCells: [[]], sheetId };
|
|
6825
|
-
}
|
|
6826
7336
|
const copiedTablesIds = new Set();
|
|
6827
7337
|
const tableCells = [];
|
|
6828
7338
|
for (let row of rowsIndexes) {
|
|
@@ -6878,12 +7388,9 @@
|
|
|
6878
7388
|
};
|
|
6879
7389
|
}
|
|
6880
7390
|
paste(target, content, options) {
|
|
6881
|
-
if (!content || !content.tableCells) {
|
|
6882
|
-
return;
|
|
6883
|
-
}
|
|
6884
7391
|
const zones = target.zones;
|
|
6885
7392
|
const sheetId = target.sheetId;
|
|
6886
|
-
if (!options
|
|
7393
|
+
if (!options.isCutOperation) {
|
|
6887
7394
|
this.pasteFromCopy(sheetId, zones, content.tableCells, options);
|
|
6888
7395
|
}
|
|
6889
7396
|
else {
|
|
@@ -7776,486 +8283,6 @@
|
|
|
7776
8283
|
};
|
|
7777
8284
|
}
|
|
7778
8285
|
|
|
7779
|
-
function boolAnd(args) {
|
|
7780
|
-
let foundBoolean = false;
|
|
7781
|
-
let acc = true;
|
|
7782
|
-
conditionalVisitBoolean(args, (arg) => {
|
|
7783
|
-
foundBoolean = true;
|
|
7784
|
-
acc = acc && arg;
|
|
7785
|
-
return acc;
|
|
7786
|
-
});
|
|
7787
|
-
return {
|
|
7788
|
-
foundBoolean,
|
|
7789
|
-
result: acc,
|
|
7790
|
-
};
|
|
7791
|
-
}
|
|
7792
|
-
function boolOr(args) {
|
|
7793
|
-
let foundBoolean = false;
|
|
7794
|
-
let acc = false;
|
|
7795
|
-
conditionalVisitBoolean(args, (arg) => {
|
|
7796
|
-
foundBoolean = true;
|
|
7797
|
-
acc = acc || arg;
|
|
7798
|
-
return !acc;
|
|
7799
|
-
});
|
|
7800
|
-
return {
|
|
7801
|
-
foundBoolean,
|
|
7802
|
-
result: acc,
|
|
7803
|
-
};
|
|
7804
|
-
}
|
|
7805
|
-
|
|
7806
|
-
function sum(values, locale) {
|
|
7807
|
-
return reduceNumbers(values, (acc, a) => acc + a, 0, locale);
|
|
7808
|
-
}
|
|
7809
|
-
function countUnique(args) {
|
|
7810
|
-
return reduceAny(args, (acc, a) => (isDataNonEmpty(a) ? acc.add(a?.value) : acc), new Set()).size;
|
|
7811
|
-
}
|
|
7812
|
-
|
|
7813
|
-
function assertSameNumberOfElements(...args) {
|
|
7814
|
-
const dims = args[0].length;
|
|
7815
|
-
args.forEach((arg, i) => assert(() => arg.length === dims, _t("[[FUNCTION_NAME]] has mismatched dimensions for argument %s (%s vs %s).", i.toString(), dims.toString(), arg.length.toString())));
|
|
7816
|
-
}
|
|
7817
|
-
function average(values, locale) {
|
|
7818
|
-
let count = 0;
|
|
7819
|
-
const sum = reduceNumbers(values, (acc, a) => {
|
|
7820
|
-
count += 1;
|
|
7821
|
-
return acc + a;
|
|
7822
|
-
}, 0, locale);
|
|
7823
|
-
assertNotZero(count);
|
|
7824
|
-
return sum / count;
|
|
7825
|
-
}
|
|
7826
|
-
function countNumbers(values, locale) {
|
|
7827
|
-
let count = 0;
|
|
7828
|
-
for (let n of values) {
|
|
7829
|
-
if (isMatrix(n)) {
|
|
7830
|
-
for (let i of n) {
|
|
7831
|
-
for (let j of i) {
|
|
7832
|
-
if (typeof j.value === "number") {
|
|
7833
|
-
count += 1;
|
|
7834
|
-
}
|
|
7835
|
-
}
|
|
7836
|
-
}
|
|
7837
|
-
}
|
|
7838
|
-
else {
|
|
7839
|
-
const value = n?.value;
|
|
7840
|
-
if (!isEvaluationError(value) &&
|
|
7841
|
-
(typeof value !== "string" || isNumber(value, locale) || parseDateTime(value, locale))) {
|
|
7842
|
-
count += 1;
|
|
7843
|
-
}
|
|
7844
|
-
}
|
|
7845
|
-
}
|
|
7846
|
-
return count;
|
|
7847
|
-
}
|
|
7848
|
-
function countAny(values) {
|
|
7849
|
-
return reduceAny(values, (acc, a) => (a !== undefined && a.value !== null ? acc + 1 : acc), 0);
|
|
7850
|
-
}
|
|
7851
|
-
function max(values, locale) {
|
|
7852
|
-
const result = reduceNumbers(values, (acc, a) => (acc < a ? a : acc), -Infinity, locale);
|
|
7853
|
-
return result === -Infinity ? 0 : result;
|
|
7854
|
-
}
|
|
7855
|
-
function min(values, locale) {
|
|
7856
|
-
const result = reduceNumbers(values, (acc, a) => (a < acc ? a : acc), Infinity, locale);
|
|
7857
|
-
return result === Infinity ? 0 : result;
|
|
7858
|
-
}
|
|
7859
|
-
|
|
7860
|
-
const pivotTimeAdapterRegistry = new Registry();
|
|
7861
|
-
function pivotTimeAdapter(granularity) {
|
|
7862
|
-
return pivotTimeAdapterRegistry.get(granularity);
|
|
7863
|
-
}
|
|
7864
|
-
/**
|
|
7865
|
-
* The Time Adapter: Managing Time Periods for Pivot Functions
|
|
7866
|
-
*
|
|
7867
|
-
* Overview:
|
|
7868
|
-
* A time adapter is responsible for managing time periods associated with pivot functions.
|
|
7869
|
-
* Each type of period (day, week, month, quarter, etc.) has its own dedicated adapter.
|
|
7870
|
-
* The adapter's primary role is to normalize period values between spreadsheet functions,
|
|
7871
|
-
* and the pivot.
|
|
7872
|
-
* By normalizing the period value, it can be stored consistently in the pivot.
|
|
7873
|
-
*
|
|
7874
|
-
* Normalization Process:
|
|
7875
|
-
* When working with functions in the spreadsheet, the time adapter normalizes
|
|
7876
|
-
* the provided period to facilitate accurate lookup of values in the pivot.
|
|
7877
|
-
* For instance, if the spreadsheet function represents a day period as a number generated
|
|
7878
|
-
* by the DATE function (DATE(2023, 12, 25)), the time adapter will normalize it accordingly.
|
|
7879
|
-
*
|
|
7880
|
-
*/
|
|
7881
|
-
/**
|
|
7882
|
-
* Normalized value: "12/25/2023"
|
|
7883
|
-
*
|
|
7884
|
-
* Note: Those two format are equivalent:
|
|
7885
|
-
* - "MM/dd/yyyy" (luxon format)
|
|
7886
|
-
* - "mm/dd/yyyy" (spreadsheet format)
|
|
7887
|
-
**/
|
|
7888
|
-
const dayAdapter = {
|
|
7889
|
-
normalizeFunctionValue(value) {
|
|
7890
|
-
const date = toNumber(value, DEFAULT_LOCALE);
|
|
7891
|
-
return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/dd/yyyy" });
|
|
7892
|
-
},
|
|
7893
|
-
getFormat(locale) {
|
|
7894
|
-
return (locale ?? DEFAULT_LOCALE).dateFormat;
|
|
7895
|
-
},
|
|
7896
|
-
formatValue(normalizedValue, locale) {
|
|
7897
|
-
locale = locale ?? DEFAULT_LOCALE;
|
|
7898
|
-
const value = toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
7899
|
-
return formatValue(value, { locale, format: this.getFormat(locale) });
|
|
7900
|
-
},
|
|
7901
|
-
toCellValue(normalizedValue) {
|
|
7902
|
-
return toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
7903
|
-
},
|
|
7904
|
-
};
|
|
7905
|
-
/**
|
|
7906
|
-
* normalizes day of month number
|
|
7907
|
-
*/
|
|
7908
|
-
const dayOfMonthAdapter = {
|
|
7909
|
-
normalizeFunctionValue(value) {
|
|
7910
|
-
const day = toNumber(value, DEFAULT_LOCALE);
|
|
7911
|
-
if (day < 1 || day > 31) {
|
|
7912
|
-
throw new EvaluationError(_t("%s is not a valid day of month (it should be a number between 1 and 31)", day));
|
|
7913
|
-
}
|
|
7914
|
-
return day;
|
|
7915
|
-
},
|
|
7916
|
-
getFormat() {
|
|
7917
|
-
return "0";
|
|
7918
|
-
},
|
|
7919
|
-
formatValue(normalizedValue, locale) {
|
|
7920
|
-
locale = locale ?? DEFAULT_LOCALE;
|
|
7921
|
-
const value = toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
7922
|
-
return formatValue(value, { locale, format: this.getFormat(locale) });
|
|
7923
|
-
},
|
|
7924
|
-
toCellValue(normalizedValue) {
|
|
7925
|
-
return toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
7926
|
-
},
|
|
7927
|
-
};
|
|
7928
|
-
/**
|
|
7929
|
-
* Normalized value: "2/2023" for week 2 of 2023
|
|
7930
|
-
*/
|
|
7931
|
-
const weekAdapter = {
|
|
7932
|
-
normalizeFunctionValue(value) {
|
|
7933
|
-
const [week, year] = value.split("/");
|
|
7934
|
-
return `${Number(week)}/${Number(year)}`;
|
|
7935
|
-
},
|
|
7936
|
-
getFormat() {
|
|
7937
|
-
return undefined;
|
|
7938
|
-
},
|
|
7939
|
-
formatValue(normalizedValue) {
|
|
7940
|
-
const [week, year] = normalizedValue.split("/");
|
|
7941
|
-
return _t("W%(week)s %(year)s", { week, year });
|
|
7942
|
-
},
|
|
7943
|
-
toCellValue(normalizedValue) {
|
|
7944
|
-
return this.formatValue(normalizedValue);
|
|
7945
|
-
},
|
|
7946
|
-
};
|
|
7947
|
-
/**
|
|
7948
|
-
* normalizes iso week number
|
|
7949
|
-
*/
|
|
7950
|
-
const isoWeekNumberAdapter = {
|
|
7951
|
-
normalizeFunctionValue(value) {
|
|
7952
|
-
const isoWeek = toNumber(value, DEFAULT_LOCALE);
|
|
7953
|
-
if (isoWeek < 0 || isoWeek > 53) {
|
|
7954
|
-
throw new EvaluationError(_t("%s is not a valid week (it should be a number between 0 and 53)", isoWeek));
|
|
7955
|
-
}
|
|
7956
|
-
return isoWeek;
|
|
7957
|
-
},
|
|
7958
|
-
getFormat() {
|
|
7959
|
-
return "0";
|
|
7960
|
-
},
|
|
7961
|
-
formatValue(normalizedValue, locale) {
|
|
7962
|
-
locale = locale ?? DEFAULT_LOCALE;
|
|
7963
|
-
const value = toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
7964
|
-
return formatValue(value, { locale, format: this.getFormat(locale) });
|
|
7965
|
-
},
|
|
7966
|
-
toCellValue(normalizedValue) {
|
|
7967
|
-
return toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
7968
|
-
},
|
|
7969
|
-
};
|
|
7970
|
-
/**
|
|
7971
|
-
* normalized month value is a string formatted as "MM/yyyy" (luxon format)
|
|
7972
|
-
* e.g. "01/2020" for January 2020
|
|
7973
|
-
*/
|
|
7974
|
-
const monthAdapter = {
|
|
7975
|
-
normalizeFunctionValue(value) {
|
|
7976
|
-
const date = toNumber(value, DEFAULT_LOCALE);
|
|
7977
|
-
return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
|
|
7978
|
-
},
|
|
7979
|
-
getFormat() {
|
|
7980
|
-
return "mmmm yyyy";
|
|
7981
|
-
},
|
|
7982
|
-
formatValue(normalizedValue, locale) {
|
|
7983
|
-
locale = locale ?? DEFAULT_LOCALE;
|
|
7984
|
-
const value = toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
7985
|
-
return formatValue(value, { locale, format: this.getFormat(locale) });
|
|
7986
|
-
},
|
|
7987
|
-
toCellValue(normalizedValue) {
|
|
7988
|
-
return toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
7989
|
-
},
|
|
7990
|
-
};
|
|
7991
|
-
/**
|
|
7992
|
-
* normalizes month number
|
|
7993
|
-
*/
|
|
7994
|
-
const monthNumberAdapter = {
|
|
7995
|
-
normalizeFunctionValue(value) {
|
|
7996
|
-
const month = toNumber(value, DEFAULT_LOCALE);
|
|
7997
|
-
if (month < 1 || month > 12) {
|
|
7998
|
-
throw new EvaluationError(_t("%s is not a valid month (it should be a number between 1 and 12)", month));
|
|
7999
|
-
}
|
|
8000
|
-
return month;
|
|
8001
|
-
},
|
|
8002
|
-
getFormat() {
|
|
8003
|
-
return "0";
|
|
8004
|
-
},
|
|
8005
|
-
formatValue(normalizedValue, locale) {
|
|
8006
|
-
locale = locale ?? DEFAULT_LOCALE;
|
|
8007
|
-
const value = toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
8008
|
-
return formatValue(value, { locale, format: this.getFormat(locale) });
|
|
8009
|
-
},
|
|
8010
|
-
toCellValue(normalizedValue) {
|
|
8011
|
-
return MONTHS[toNumber(normalizedValue, DEFAULT_LOCALE) - 1].toString();
|
|
8012
|
-
},
|
|
8013
|
-
};
|
|
8014
|
-
/**
|
|
8015
|
-
* normalized quarter value is "quarter/year"
|
|
8016
|
-
* e.g. "1/2020" for Q1 2020
|
|
8017
|
-
*/
|
|
8018
|
-
const quarterAdapter = {
|
|
8019
|
-
normalizeFunctionValue(value) {
|
|
8020
|
-
const [quarter, year] = value.split("/");
|
|
8021
|
-
return `${quarter}/${year}`;
|
|
8022
|
-
},
|
|
8023
|
-
getFormat() {
|
|
8024
|
-
return undefined;
|
|
8025
|
-
},
|
|
8026
|
-
formatValue(normalizedValue) {
|
|
8027
|
-
const [quarter, year] = normalizedValue.split("/");
|
|
8028
|
-
return _t("Q%(quarter)s %(year)s", { quarter, year });
|
|
8029
|
-
},
|
|
8030
|
-
toCellValue(normalizedValue) {
|
|
8031
|
-
return this.formatValue(normalizedValue);
|
|
8032
|
-
},
|
|
8033
|
-
};
|
|
8034
|
-
/**
|
|
8035
|
-
* normalizes quarter number
|
|
8036
|
-
*/
|
|
8037
|
-
const quarterNumberAdapter = {
|
|
8038
|
-
normalizeFunctionValue(value) {
|
|
8039
|
-
const quarter = toNumber(value, DEFAULT_LOCALE);
|
|
8040
|
-
if (quarter < 1 || quarter > 4) {
|
|
8041
|
-
throw new EvaluationError(_t("%s is not a valid quarter (it should be a number between 1 and 4)", quarter));
|
|
8042
|
-
}
|
|
8043
|
-
return quarter;
|
|
8044
|
-
},
|
|
8045
|
-
getFormat() {
|
|
8046
|
-
return "0";
|
|
8047
|
-
},
|
|
8048
|
-
formatValue(normalizedValue, locale) {
|
|
8049
|
-
locale = locale ?? DEFAULT_LOCALE;
|
|
8050
|
-
const value = toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
8051
|
-
return formatValue(value, { locale, format: this.getFormat(locale) });
|
|
8052
|
-
},
|
|
8053
|
-
toCellValue(normalizedValue) {
|
|
8054
|
-
return toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
8055
|
-
},
|
|
8056
|
-
};
|
|
8057
|
-
const yearAdapter = {
|
|
8058
|
-
normalizeFunctionValue(value) {
|
|
8059
|
-
return toNumber(value, DEFAULT_LOCALE);
|
|
8060
|
-
},
|
|
8061
|
-
getFormat() {
|
|
8062
|
-
return "0";
|
|
8063
|
-
},
|
|
8064
|
-
formatValue(normalizedValue, locale) {
|
|
8065
|
-
locale = locale ?? DEFAULT_LOCALE;
|
|
8066
|
-
return formatValue(normalizedValue, { locale, format: "0" });
|
|
8067
|
-
},
|
|
8068
|
-
toCellValue(normalizedValue) {
|
|
8069
|
-
return toNumber(normalizedValue, DEFAULT_LOCALE);
|
|
8070
|
-
},
|
|
8071
|
-
};
|
|
8072
|
-
pivotTimeAdapterRegistry
|
|
8073
|
-
.add("day", dayAdapter)
|
|
8074
|
-
.add("week", weekAdapter)
|
|
8075
|
-
.add("month", monthAdapter)
|
|
8076
|
-
.add("quarter", quarterAdapter)
|
|
8077
|
-
.add("year", yearAdapter)
|
|
8078
|
-
.add("day_of_month", dayOfMonthAdapter)
|
|
8079
|
-
.add("iso_week_number", isoWeekNumberAdapter)
|
|
8080
|
-
.add("month_number", monthNumberAdapter)
|
|
8081
|
-
.add("quarter_number", quarterNumberAdapter)
|
|
8082
|
-
.add("year_number", yearAdapter);
|
|
8083
|
-
|
|
8084
|
-
const AGGREGATOR_NAMES = {
|
|
8085
|
-
count: _t("Count"),
|
|
8086
|
-
count_distinct: _t("Count Distinct"),
|
|
8087
|
-
bool_and: _t("Boolean And"),
|
|
8088
|
-
bool_or: _t("Boolean Or"),
|
|
8089
|
-
max: _t("Maximum"),
|
|
8090
|
-
min: _t("Minimum"),
|
|
8091
|
-
avg: _t("Average"),
|
|
8092
|
-
sum: _t("Sum"),
|
|
8093
|
-
};
|
|
8094
|
-
const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
|
|
8095
|
-
const AGGREGATORS_BY_FIELD_TYPE = {
|
|
8096
|
-
integer: NUMBER_CHAR_AGGREGATORS,
|
|
8097
|
-
char: NUMBER_CHAR_AGGREGATORS,
|
|
8098
|
-
boolean: ["count_distinct", "count", "bool_and", "bool_or"],
|
|
8099
|
-
};
|
|
8100
|
-
const AGGREGATORS = {};
|
|
8101
|
-
for (const type in AGGREGATORS_BY_FIELD_TYPE) {
|
|
8102
|
-
AGGREGATORS[type] = {};
|
|
8103
|
-
for (const aggregator of AGGREGATORS_BY_FIELD_TYPE[type]) {
|
|
8104
|
-
AGGREGATORS[type][aggregator] = AGGREGATOR_NAMES[aggregator];
|
|
8105
|
-
}
|
|
8106
|
-
}
|
|
8107
|
-
const AGGREGATORS_FN = {
|
|
8108
|
-
count: {
|
|
8109
|
-
fn: (args) => countAny([args]),
|
|
8110
|
-
format: () => "0",
|
|
8111
|
-
},
|
|
8112
|
-
count_distinct: {
|
|
8113
|
-
fn: (args) => countUnique([args]),
|
|
8114
|
-
format: () => "0",
|
|
8115
|
-
},
|
|
8116
|
-
bool_and: {
|
|
8117
|
-
fn: (args) => boolAnd([args]).result,
|
|
8118
|
-
format: () => undefined,
|
|
8119
|
-
},
|
|
8120
|
-
bool_or: {
|
|
8121
|
-
fn: (args) => boolOr([args]).result,
|
|
8122
|
-
format: () => undefined,
|
|
8123
|
-
},
|
|
8124
|
-
max: {
|
|
8125
|
-
fn: (args, locale) => max([args], locale),
|
|
8126
|
-
format: inferFormat,
|
|
8127
|
-
},
|
|
8128
|
-
min: {
|
|
8129
|
-
fn: (args, locale) => min([args], locale),
|
|
8130
|
-
format: inferFormat,
|
|
8131
|
-
},
|
|
8132
|
-
avg: {
|
|
8133
|
-
fn: (args, locale) => average([args], locale),
|
|
8134
|
-
format: inferFormat,
|
|
8135
|
-
},
|
|
8136
|
-
sum: {
|
|
8137
|
-
fn: (args, locale) => sum([args], locale),
|
|
8138
|
-
format: inferFormat,
|
|
8139
|
-
},
|
|
8140
|
-
};
|
|
8141
|
-
function makePivotFormulaFromPivotCell(pivotFormulaId, pivotCell) {
|
|
8142
|
-
switch (pivotCell.type) {
|
|
8143
|
-
case "HEADER":
|
|
8144
|
-
return makePivotFormula("PIVOT.HEADER", [pivotFormulaId, ...flatPivotDomain(pivotCell.domain)].filter(isDefined));
|
|
8145
|
-
case "MEASURE_HEADER":
|
|
8146
|
-
return makePivotFormula("PIVOT.HEADER", [pivotFormulaId, ...flatPivotDomain(pivotCell.domain), "measure", pivotCell.measure].filter(isDefined));
|
|
8147
|
-
case "VALUE":
|
|
8148
|
-
return makePivotFormula("PIVOT.VALUE", [pivotFormulaId, pivotCell.measure, ...flatPivotDomain(pivotCell.domain)].filter(isDefined));
|
|
8149
|
-
case "EMPTY":
|
|
8150
|
-
return "";
|
|
8151
|
-
}
|
|
8152
|
-
}
|
|
8153
|
-
/**
|
|
8154
|
-
* Build a pivot formula expression
|
|
8155
|
-
*/
|
|
8156
|
-
function makePivotFormula(formula, args) {
|
|
8157
|
-
return `=${formula}(${args
|
|
8158
|
-
.map((arg) => {
|
|
8159
|
-
const stringIsNumber = typeof arg == "string" && !isNaN(Number(arg)) && Number(arg).toString() === arg;
|
|
8160
|
-
const convertToNumber = typeof arg == "number" || stringIsNumber;
|
|
8161
|
-
return convertToNumber ? `${arg}` : `"${arg.toString().replace(/"/g, '\\"')}"`;
|
|
8162
|
-
})
|
|
8163
|
-
.join(",")})`;
|
|
8164
|
-
}
|
|
8165
|
-
/**
|
|
8166
|
-
* Given an object of form {"1": {...}, "2": {...}, ...} get the maximum ID used
|
|
8167
|
-
* in this object
|
|
8168
|
-
* If the object has no keys, return 0
|
|
8169
|
-
*
|
|
8170
|
-
*/
|
|
8171
|
-
function getMaxObjectId(o) {
|
|
8172
|
-
const keys = Object.keys(o);
|
|
8173
|
-
if (!keys.length) {
|
|
8174
|
-
return 0;
|
|
8175
|
-
}
|
|
8176
|
-
const nums = keys.map((id) => parseInt(id, 10));
|
|
8177
|
-
const max = Math.max(...nums);
|
|
8178
|
-
return max;
|
|
8179
|
-
}
|
|
8180
|
-
const ALL_PERIODS = {
|
|
8181
|
-
year: _t("Year"),
|
|
8182
|
-
quarter: _t("Quarter"),
|
|
8183
|
-
month: _t("Month"),
|
|
8184
|
-
week: _t("Week"),
|
|
8185
|
-
day: _t("Day"),
|
|
8186
|
-
year_number: _t("Year"),
|
|
8187
|
-
quarter_number: _t("Quarter"),
|
|
8188
|
-
month_number: _t("Month"),
|
|
8189
|
-
iso_week_number: _t("Week"),
|
|
8190
|
-
day_of_month: _t("Day of Month"),
|
|
8191
|
-
};
|
|
8192
|
-
const DATE_FIELDS = ["date", "datetime"];
|
|
8193
|
-
/**
|
|
8194
|
-
* Parse a dimension string into a pivot dimension definition.
|
|
8195
|
-
* e.g "create_date:month" => { name: "create_date", granularity: "month" }
|
|
8196
|
-
*/
|
|
8197
|
-
function parseDimension(dimension) {
|
|
8198
|
-
const [name, granularity] = dimension.split(":");
|
|
8199
|
-
if (granularity) {
|
|
8200
|
-
return { name, granularity };
|
|
8201
|
-
}
|
|
8202
|
-
return { name };
|
|
8203
|
-
}
|
|
8204
|
-
function isDateField(field) {
|
|
8205
|
-
return DATE_FIELDS.includes(field.type);
|
|
8206
|
-
}
|
|
8207
|
-
function toPivotDomain(domainStr) {
|
|
8208
|
-
if (domainStr.length % 2 !== 0) {
|
|
8209
|
-
throw new Error("Invalid domain: odd number of elements");
|
|
8210
|
-
}
|
|
8211
|
-
const domain = [];
|
|
8212
|
-
for (let i = 0; i < domainStr.length - 1; i += 2) {
|
|
8213
|
-
domain.push({ field: domainStr[i], value: domainStr[i + 1] });
|
|
8214
|
-
}
|
|
8215
|
-
return domain;
|
|
8216
|
-
}
|
|
8217
|
-
function flatPivotDomain(domain) {
|
|
8218
|
-
return domain.flatMap((arg) => [arg.field, arg.value]);
|
|
8219
|
-
}
|
|
8220
|
-
/**
|
|
8221
|
-
* Parses the value defining a pivot group in a PIVOT formula
|
|
8222
|
-
* e.g. given the following formula PIVOT.VALUE("1", "stage_id", "42", "status", "won"),
|
|
8223
|
-
* the two group values are "42" and "won".
|
|
8224
|
-
*/
|
|
8225
|
-
function toNormalizedPivotValue(dimension, groupValue) {
|
|
8226
|
-
if (groupValue === null || groupValue === "null") {
|
|
8227
|
-
return null;
|
|
8228
|
-
}
|
|
8229
|
-
const groupValueString = typeof groupValue === "boolean"
|
|
8230
|
-
? toString(groupValue).toLocaleLowerCase()
|
|
8231
|
-
: toString(groupValue);
|
|
8232
|
-
if (!pivotNormalizationValueRegistry.contains(dimension.type)) {
|
|
8233
|
-
throw new EvaluationError(_t("Field %(field)s is not supported because of its type (%(type)s)", {
|
|
8234
|
-
field: dimension.displayName,
|
|
8235
|
-
type: dimension.type,
|
|
8236
|
-
}));
|
|
8237
|
-
}
|
|
8238
|
-
// represents a field which is not set (=False server side)
|
|
8239
|
-
if (groupValueString === "false") {
|
|
8240
|
-
return false;
|
|
8241
|
-
}
|
|
8242
|
-
const normalizer = pivotNormalizationValueRegistry.get(dimension.type);
|
|
8243
|
-
return normalizer(groupValueString, dimension.granularity);
|
|
8244
|
-
}
|
|
8245
|
-
function normalizeDateTime(value, granularity) {
|
|
8246
|
-
if (!granularity) {
|
|
8247
|
-
throw "";
|
|
8248
|
-
}
|
|
8249
|
-
return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
|
|
8250
|
-
}
|
|
8251
|
-
const pivotNormalizationValueRegistry = new Registry();
|
|
8252
|
-
pivotNormalizationValueRegistry
|
|
8253
|
-
.add("date", normalizeDateTime)
|
|
8254
|
-
.add("datetime", normalizeDateTime)
|
|
8255
|
-
.add("integer", (value) => toNumber(value, DEFAULT_LOCALE))
|
|
8256
|
-
.add("boolean", (value) => toBoolean(value))
|
|
8257
|
-
.add("char", (value) => toString(value));
|
|
8258
|
-
|
|
8259
8286
|
/**
|
|
8260
8287
|
* Change the reference types inside the given token, if the token represent a range or a cell
|
|
8261
8288
|
*
|
|
@@ -9995,7 +10022,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9995
10022
|
const cell = this.getters.getCell(position);
|
|
9996
10023
|
if (pivotId && pivotCell.type !== "EMPTY" && !cell?.isFormula) {
|
|
9997
10024
|
const formulaPivotId = this.getters.getPivotFormulaId(pivotId);
|
|
9998
|
-
const formula =
|
|
10025
|
+
const formula = createPivotFormula(formulaPivotId, pivotCell);
|
|
9999
10026
|
return formula.slice(1); // strip leading =
|
|
10000
10027
|
}
|
|
10001
10028
|
}
|
|
@@ -19087,10 +19114,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19087
19114
|
compute: function (formulaId, measureName, ...domainArgs) {
|
|
19088
19115
|
const _pivotFormulaId = toString(formulaId);
|
|
19089
19116
|
const _measure = toString(measureName);
|
|
19090
|
-
const _domainArgs = domainArgs.map(toString);
|
|
19091
19117
|
const pivotId = getPivotId(_pivotFormulaId, this.getters);
|
|
19092
19118
|
assertMeasureExist(pivotId, _measure, this.getters);
|
|
19093
|
-
assertDomainLength(
|
|
19119
|
+
assertDomainLength(domainArgs);
|
|
19094
19120
|
const pivot = this.getters.getPivot(pivotId);
|
|
19095
19121
|
const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
|
|
19096
19122
|
addPivotDependencies(this, coreDefinition);
|
|
@@ -19098,15 +19124,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19098
19124
|
if (error) {
|
|
19099
19125
|
return error;
|
|
19100
19126
|
}
|
|
19101
|
-
|
|
19102
|
-
const { value, format } = pivot.getPivotCellValueAndFormat(_measure, domain);
|
|
19103
|
-
if (!value && !this.getters.areDomainArgsFieldsValid(pivotId, domain)) {
|
|
19127
|
+
if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
|
|
19104
19128
|
return {
|
|
19105
19129
|
value: CellErrorType.GenericError,
|
|
19106
19130
|
message: _t("Dimensions don't match the pivot definition"),
|
|
19107
19131
|
};
|
|
19108
19132
|
}
|
|
19109
|
-
|
|
19133
|
+
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
19134
|
+
return pivot.getPivotCellValueAndFormat(_measure, domain);
|
|
19110
19135
|
},
|
|
19111
19136
|
};
|
|
19112
19137
|
const PIVOT_HEADER = {
|
|
@@ -19118,9 +19143,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19118
19143
|
],
|
|
19119
19144
|
compute: function (pivotId, ...domainArgs) {
|
|
19120
19145
|
const _pivotFormulaId = toString(pivotId);
|
|
19121
|
-
const _domainArgs = domainArgs.map(toString);
|
|
19122
19146
|
const _pivotId = getPivotId(_pivotFormulaId, this.getters);
|
|
19123
|
-
assertDomainLength(
|
|
19147
|
+
assertDomainLength(domainArgs);
|
|
19124
19148
|
const pivot = this.getters.getPivot(_pivotId);
|
|
19125
19149
|
const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
|
|
19126
19150
|
addPivotDependencies(this, coreDefinition);
|
|
@@ -19128,14 +19152,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19128
19152
|
if (error) {
|
|
19129
19153
|
return error;
|
|
19130
19154
|
}
|
|
19131
|
-
|
|
19132
|
-
const lastNode = domain.at(-1);
|
|
19133
|
-
if (!this.getters.areDomainArgsFieldsValid(_pivotId, lastNode?.field === "measure" ? domain.slice(0, -1) : domain)) {
|
|
19155
|
+
if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
|
|
19134
19156
|
return {
|
|
19135
19157
|
value: CellErrorType.GenericError,
|
|
19136
19158
|
message: _t("Dimensions don't match the pivot definition"),
|
|
19137
19159
|
};
|
|
19138
19160
|
}
|
|
19161
|
+
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
19162
|
+
const lastNode = domain.at(-1);
|
|
19139
19163
|
if (lastNode?.field === "measure") {
|
|
19140
19164
|
return pivot.getPivotMeasureValue(toString(lastNode.value), domain);
|
|
19141
19165
|
}
|
|
@@ -19152,13 +19176,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19152
19176
|
description: _t("Get a pivot table."),
|
|
19153
19177
|
args: [
|
|
19154
19178
|
arg("pivot_id (string)", _t("ID of the pivot.")),
|
|
19155
|
-
arg("row_count (number, optional
|
|
19179
|
+
arg("row_count (number, optional)", _t("number of rows")),
|
|
19156
19180
|
arg("include_total (boolean, default=TRUE)", _t("Whether to include total/sub-totals or not.")),
|
|
19157
19181
|
arg("include_column_titles (boolean, default=TRUE)", _t("Whether to include the column titles or not.")),
|
|
19182
|
+
arg("column_count (number, optional)", _t("number of columns")),
|
|
19158
19183
|
],
|
|
19159
|
-
compute: function (pivotFormulaId, rowCount = { value:
|
|
19184
|
+
compute: function (pivotFormulaId, rowCount = { value: Number.MAX_VALUE }, includeTotal = { value: true }, includeColumnHeaders = { value: true }, columnCount = { value: Number.MAX_VALUE }) {
|
|
19160
19185
|
const _pivotFormulaId = toString(pivotFormulaId);
|
|
19161
19186
|
const _rowCount = toNumber(rowCount, this.locale);
|
|
19187
|
+
if (_rowCount < 0) {
|
|
19188
|
+
throw new EvaluationError(_t("The number of rows must be positive."));
|
|
19189
|
+
}
|
|
19190
|
+
const _columnCount = toNumber(columnCount, this.locale);
|
|
19191
|
+
if (_columnCount < 0) {
|
|
19192
|
+
throw new EvaluationError(_t("The number of columns must be positive."));
|
|
19193
|
+
}
|
|
19162
19194
|
const _includeColumnHeaders = toBoolean(includeColumnHeaders);
|
|
19163
19195
|
const _includedTotal = toBoolean(includeTotal);
|
|
19164
19196
|
const pivotId = getPivotId(_pivotFormulaId, this.getters);
|
|
@@ -19174,19 +19206,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19174
19206
|
const cells = table.getPivotCells(_includedTotal, _includeColumnHeaders);
|
|
19175
19207
|
const headerRows = _includeColumnHeaders ? table.columns.length : 0;
|
|
19176
19208
|
const pivotTitle = this.getters.getPivotDisplayName(pivotId);
|
|
19177
|
-
|
|
19178
|
-
|
|
19179
|
-
}
|
|
19180
|
-
const end = Math.min(headerRows + _rowCount, cells[0].length);
|
|
19181
|
-
if (end === 0) {
|
|
19209
|
+
const tableHeight = Math.min(headerRows + _rowCount, cells[0].length);
|
|
19210
|
+
if (tableHeight === 0) {
|
|
19182
19211
|
return [[{ value: pivotTitle }]];
|
|
19183
19212
|
}
|
|
19184
|
-
const tableWidth = cells.length;
|
|
19185
|
-
const tableRows = range(0, end);
|
|
19213
|
+
const tableWidth = Math.min(1 + _columnCount, cells.length);
|
|
19186
19214
|
const result = [];
|
|
19187
19215
|
for (const col of range(0, tableWidth)) {
|
|
19188
19216
|
result[col] = [];
|
|
19189
|
-
for (const row of
|
|
19217
|
+
for (const row of range(0, tableHeight)) {
|
|
19190
19218
|
const pivotCell = cells[col][row];
|
|
19191
19219
|
switch (pivotCell.type) {
|
|
19192
19220
|
case "EMPTY":
|
|
@@ -21876,9 +21904,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21876
21904
|
const pivot = this.getters.getPivot(pivotId);
|
|
21877
21905
|
pivot.init();
|
|
21878
21906
|
const fields = pivot.getFields();
|
|
21879
|
-
if (!fields) {
|
|
21880
|
-
return [];
|
|
21881
|
-
}
|
|
21882
21907
|
const definition = this.getters.getPivotCoreDefinition(pivotId);
|
|
21883
21908
|
return definition.measures
|
|
21884
21909
|
.map((measure) => {
|
|
@@ -21918,9 +21943,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21918
21943
|
const pivot = this.getters.getPivot(pivotId);
|
|
21919
21944
|
pivot.init();
|
|
21920
21945
|
const fields = pivot.getFields();
|
|
21921
|
-
if (!fields) {
|
|
21922
|
-
return;
|
|
21923
|
-
}
|
|
21924
21946
|
const { columns, rows } = pivot.definition;
|
|
21925
21947
|
let args = functionContext.args;
|
|
21926
21948
|
if (functionContext?.parent.toUpperCase() === "PIVOT.VALUE") {
|
|
@@ -27069,7 +27091,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27069
27091
|
if (getZoneArea(zone) === 1 && topLeftCell?.content) {
|
|
27070
27092
|
return {
|
|
27071
27093
|
type: "scorecard",
|
|
27072
|
-
title: {
|
|
27094
|
+
title: {},
|
|
27073
27095
|
background: topLeftCell.style?.fillColor || undefined,
|
|
27074
27096
|
keyValue: zoneToXc(zone),
|
|
27075
27097
|
baselineMode: DEFAULT_SCORECARD_BASELINE_MODE,
|
|
@@ -27077,22 +27099,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27077
27099
|
baselineColorDown: DEFAULT_SCORECARD_BASELINE_COLOR_DOWN,
|
|
27078
27100
|
};
|
|
27079
27101
|
}
|
|
27080
|
-
let title = "";
|
|
27081
27102
|
const cellsInFirstRow = getters.getEvaluatedCellsInZone(sheetId, {
|
|
27082
27103
|
...dataSetZone,
|
|
27083
27104
|
bottom: dataSetZone.top,
|
|
27084
27105
|
});
|
|
27085
27106
|
const dataSetsHaveTitle = !!cellsInFirstRow.find((cell) => cell.type !== CellValueType.empty && cell.type !== CellValueType.number);
|
|
27086
|
-
if (dataSetsHaveTitle) {
|
|
27087
|
-
const texts = cellsInFirstRow
|
|
27088
|
-
.filter((cell) => cell.type !== CellValueType.error && cell.type !== CellValueType.empty)
|
|
27089
|
-
.map((cell) => cell.formattedValue);
|
|
27090
|
-
const lastElement = texts.splice(-1)[0];
|
|
27091
|
-
title = texts.join(", ");
|
|
27092
|
-
if (lastElement) {
|
|
27093
|
-
title += (title ? " " + _t("and") + " " : "") + lastElement;
|
|
27094
|
-
}
|
|
27095
|
-
}
|
|
27096
27107
|
let labelRangeXc;
|
|
27097
27108
|
if (!singleColumn) {
|
|
27098
27109
|
labelRangeXc = zoneToXc({
|
|
@@ -27105,7 +27116,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27105
27116
|
const labelRange = labelRangeXc ? getters.getRangeFromSheetXC(sheetId, labelRangeXc) : undefined;
|
|
27106
27117
|
if (canChartParseLabels(labelRange, getters)) {
|
|
27107
27118
|
return {
|
|
27108
|
-
title: {
|
|
27119
|
+
title: {},
|
|
27109
27120
|
dataSets,
|
|
27110
27121
|
labelsAsText: false,
|
|
27111
27122
|
stacked: false,
|
|
@@ -27121,7 +27132,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27121
27132
|
if (singleColumn &&
|
|
27122
27133
|
getData(getters, _dataSets[0]).every((e) => typeof e === "string" && !isEvaluationError(e))) {
|
|
27123
27134
|
return {
|
|
27124
|
-
title: {
|
|
27135
|
+
title: {},
|
|
27125
27136
|
dataSets: [{ dataRange }],
|
|
27126
27137
|
aggregated: true,
|
|
27127
27138
|
labelRange: dataRange,
|
|
@@ -27131,7 +27142,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27131
27142
|
};
|
|
27132
27143
|
}
|
|
27133
27144
|
return {
|
|
27134
|
-
title: {
|
|
27145
|
+
title: {},
|
|
27135
27146
|
dataSets,
|
|
27136
27147
|
labelRange: labelRangeXc,
|
|
27137
27148
|
type: "bar",
|
|
@@ -31674,7 +31685,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31674
31685
|
static template = "o-spreadsheet.ChartTitle";
|
|
31675
31686
|
static components = { Section, ColorPickerWidget };
|
|
31676
31687
|
static props = {
|
|
31677
|
-
title: String,
|
|
31688
|
+
title: { type: String, optional: true },
|
|
31678
31689
|
updateTitle: Function,
|
|
31679
31690
|
name: { type: String, optional: true },
|
|
31680
31691
|
toggleItalic: { type: Function, optional: true },
|
|
@@ -31683,6 +31694,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31683
31694
|
updateColor: { type: Function, optional: true },
|
|
31684
31695
|
style: { type: Object, optional: true },
|
|
31685
31696
|
};
|
|
31697
|
+
static defaultProps = {
|
|
31698
|
+
title: "",
|
|
31699
|
+
};
|
|
31686
31700
|
openedEl = null;
|
|
31687
31701
|
setup() {
|
|
31688
31702
|
owl.useExternalListener(window, "click", this.onExternalClick);
|
|
@@ -34554,6 +34568,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34554
34568
|
currentSearchRegex = null;
|
|
34555
34569
|
isSearchDirty = false;
|
|
34556
34570
|
initialShowFormulaState;
|
|
34571
|
+
preserveSelectedMatchIndex = false;
|
|
34557
34572
|
// fixme: why do we make selectedMatchIndex on top of a selected
|
|
34558
34573
|
// property in the matches?
|
|
34559
34574
|
selectedMatchIndex = null;
|
|
@@ -34667,7 +34682,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34667
34682
|
* refresh the matches according to the current search options
|
|
34668
34683
|
*/
|
|
34669
34684
|
refreshSearch(jumpToMatchSheet = true) {
|
|
34670
|
-
this.
|
|
34685
|
+
if (!this.preserveSelectedMatchIndex) {
|
|
34686
|
+
this.selectedMatchIndex = null;
|
|
34687
|
+
}
|
|
34671
34688
|
this.findMatches();
|
|
34672
34689
|
this.selectNextCell(Direction.current, jumpToMatchSheet);
|
|
34673
34690
|
}
|
|
@@ -34766,10 +34783,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34766
34783
|
const selectedMatch = matches[nextIndex];
|
|
34767
34784
|
// Switch to the sheet where the match is located
|
|
34768
34785
|
if (jumpToMatchSheet && this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
34786
|
+
// We set `preserveSelectedMatchIndex` to true to avoid resetting the selected search
|
|
34787
|
+
// index in the `refreshSearch` function when a new sheet is activated. The reason being
|
|
34788
|
+
// that, when we automatically go back to previous sheet while performing a search, the
|
|
34789
|
+
// search index is reset to the first occurrence each time.
|
|
34790
|
+
this.preserveSelectedMatchIndex = true;
|
|
34769
34791
|
this.model.dispatch("ACTIVATE_SHEET", {
|
|
34770
34792
|
sheetIdFrom: this.getters.getActiveSheetId(),
|
|
34771
34793
|
sheetIdTo: selectedMatch.sheetId,
|
|
34772
34794
|
});
|
|
34795
|
+
this.preserveSelectedMatchIndex = false;
|
|
34773
34796
|
// We do not want to reset the selection at finalize in this case
|
|
34774
34797
|
this.isSearchDirty = false;
|
|
34775
34798
|
}
|
|
@@ -35410,6 +35433,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35410
35433
|
}
|
|
35411
35434
|
});
|
|
35412
35435
|
}
|
|
35436
|
+
onClick(item) {
|
|
35437
|
+
item.onClick();
|
|
35438
|
+
this.popover.isOpen = false;
|
|
35439
|
+
}
|
|
35413
35440
|
get popoverProps() {
|
|
35414
35441
|
const { x, y, width, height } = this.buttonRef.el.getBoundingClientRect();
|
|
35415
35442
|
return {
|
|
@@ -35452,16 +35479,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35452
35479
|
static components = { CogWheelMenu, Section, EditableName };
|
|
35453
35480
|
static props = {
|
|
35454
35481
|
pivotId: String,
|
|
35482
|
+
flipAxis: Function,
|
|
35455
35483
|
};
|
|
35456
35484
|
get cogWheelMenuItems() {
|
|
35457
35485
|
return [
|
|
35458
35486
|
{
|
|
35459
|
-
name: "
|
|
35487
|
+
name: _t("Flip axes"),
|
|
35488
|
+
icon: "fa-exchange",
|
|
35489
|
+
onClick: this.props.flipAxis,
|
|
35490
|
+
},
|
|
35491
|
+
{
|
|
35492
|
+
name: _t("Duplicate"),
|
|
35460
35493
|
icon: "fa-copy",
|
|
35461
35494
|
onClick: () => this.duplicatePivot(),
|
|
35462
35495
|
},
|
|
35463
35496
|
{
|
|
35464
|
-
name: "Delete",
|
|
35497
|
+
name: _t("Delete"),
|
|
35465
35498
|
icon: "fa-trash",
|
|
35466
35499
|
onClick: () => this.delete(),
|
|
35467
35500
|
},
|
|
@@ -35658,9 +35691,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35658
35691
|
columns;
|
|
35659
35692
|
rows;
|
|
35660
35693
|
measures;
|
|
35694
|
+
fieldsType;
|
|
35661
35695
|
maxIndent;
|
|
35662
35696
|
pivotCells = {};
|
|
35663
|
-
constructor(columns, rows, measures) {
|
|
35697
|
+
constructor(columns, rows, measures, fieldsType) {
|
|
35664
35698
|
this.columns = columns.map((row) => {
|
|
35665
35699
|
// offset in the pivot table
|
|
35666
35700
|
// starts at 1 because the first column is the row title
|
|
@@ -35673,6 +35707,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35673
35707
|
});
|
|
35674
35708
|
this.rows = rows;
|
|
35675
35709
|
this.measures = measures;
|
|
35710
|
+
this.fieldsType = fieldsType;
|
|
35676
35711
|
this.maxIndent = Math.max(...this.rows.map((row) => row.indent));
|
|
35677
35712
|
}
|
|
35678
35713
|
/**
|
|
@@ -35719,7 +35754,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35719
35754
|
if (!domain) {
|
|
35720
35755
|
return EMPTY_PIVOT_CELL;
|
|
35721
35756
|
}
|
|
35722
|
-
const measure = domain.at(-1)?.value
|
|
35757
|
+
const measure = domain.at(-1)?.value?.toString() || "";
|
|
35723
35758
|
return { type: "MEASURE_HEADER", domain: domain.slice(0, -1), measure };
|
|
35724
35759
|
}
|
|
35725
35760
|
else if (row <= colHeadersHeight - 1) {
|
|
@@ -35751,9 +35786,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35751
35786
|
return undefined;
|
|
35752
35787
|
}
|
|
35753
35788
|
for (let i = 0; i < pivotCol.fields.length; i++) {
|
|
35789
|
+
const fieldWithGranularity = pivotCol.fields[i];
|
|
35790
|
+
const { name, granularity } = parseDimension(fieldWithGranularity);
|
|
35791
|
+
const type = this.fieldsType[name] || "char";
|
|
35754
35792
|
domain.push({
|
|
35755
|
-
|
|
35756
|
-
|
|
35793
|
+
type,
|
|
35794
|
+
field: fieldWithGranularity,
|
|
35795
|
+
value: toNormalizedPivotValue({ displayName: name, type, granularity }, pivotCol.values[i]),
|
|
35757
35796
|
});
|
|
35758
35797
|
}
|
|
35759
35798
|
return domain;
|
|
@@ -35765,17 +35804,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35765
35804
|
getColMeasure(col) {
|
|
35766
35805
|
const domain = this.getColHeaderDomain(col, this.columns.length - 1);
|
|
35767
35806
|
const measure = domain?.at(-1)?.value;
|
|
35768
|
-
if (measure === undefined) {
|
|
35769
|
-
throw new Error("Measure
|
|
35807
|
+
if (measure === undefined || measure === null) {
|
|
35808
|
+
throw new Error("Measure is missing");
|
|
35770
35809
|
}
|
|
35771
35810
|
return measure.toString();
|
|
35772
35811
|
}
|
|
35773
35812
|
getRowDomain(row) {
|
|
35774
35813
|
const domain = [];
|
|
35775
35814
|
for (let i = 0; i < this.rows[row].fields.length; i++) {
|
|
35815
|
+
const fieldWithGranularity = this.rows[row].fields[i];
|
|
35816
|
+
const { name, granularity } = parseDimension(fieldWithGranularity);
|
|
35817
|
+
const type = this.fieldsType[name] || "char";
|
|
35776
35818
|
domain.push({
|
|
35777
|
-
|
|
35778
|
-
|
|
35819
|
+
type,
|
|
35820
|
+
field: fieldWithGranularity,
|
|
35821
|
+
value: toNormalizedPivotValue({ displayName: name, type, granularity }, this.rows[row].values[i]),
|
|
35779
35822
|
});
|
|
35780
35823
|
}
|
|
35781
35824
|
return domain;
|
|
@@ -35785,6 +35828,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35785
35828
|
cols: this.columns,
|
|
35786
35829
|
rows: this.rows,
|
|
35787
35830
|
measures: this.measures,
|
|
35831
|
+
fieldsType: this.fieldsType,
|
|
35788
35832
|
};
|
|
35789
35833
|
}
|
|
35790
35834
|
}
|
|
@@ -35805,7 +35849,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35805
35849
|
indent: 0,
|
|
35806
35850
|
});
|
|
35807
35851
|
const measureNames = definition.measures.map((m) => m.name);
|
|
35808
|
-
|
|
35852
|
+
const fieldsType = {};
|
|
35853
|
+
for (const columns of definition.columns) {
|
|
35854
|
+
fieldsType[columns.name] = columns.type;
|
|
35855
|
+
}
|
|
35856
|
+
for (const row of definition.rows) {
|
|
35857
|
+
fieldsType[row.name] = row.type;
|
|
35858
|
+
}
|
|
35859
|
+
return new SpreadsheetPivotTable(cols, rows, measureNames, fieldsType);
|
|
35809
35860
|
}
|
|
35810
35861
|
// -----------------------------------------------------------------------------
|
|
35811
35862
|
// ROWS
|
|
@@ -35981,41 +36032,42 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35981
36032
|
return dimension.order === "asc" ? a.localeCompare(b) : b.localeCompare(a);
|
|
35982
36033
|
}
|
|
35983
36034
|
|
|
36035
|
+
const NULL_SYMBOL = Symbol("NULL");
|
|
35984
36036
|
function createDate(dimension, value, locale) {
|
|
35985
36037
|
const granularity = dimension.granularity;
|
|
35986
36038
|
if (!granularity || !(granularity in MAP_VALUE_DIMENSION_DATE)) {
|
|
35987
36039
|
throw new Error(`Unknown date granularity: ${granularity}`);
|
|
35988
36040
|
}
|
|
35989
|
-
|
|
35990
|
-
return null;
|
|
35991
|
-
}
|
|
36041
|
+
const keyInMap = typeof value === "number" || typeof value === "string" ? value : NULL_SYMBOL;
|
|
35992
36042
|
if (!MAP_VALUE_DIMENSION_DATE[granularity].set.has(value)) {
|
|
35993
36043
|
MAP_VALUE_DIMENSION_DATE[granularity].set.add(value);
|
|
35994
|
-
|
|
35995
|
-
|
|
35996
|
-
|
|
35997
|
-
|
|
35998
|
-
|
|
35999
|
-
|
|
36000
|
-
|
|
36001
|
-
|
|
36002
|
-
|
|
36003
|
-
|
|
36004
|
-
|
|
36005
|
-
|
|
36006
|
-
|
|
36007
|
-
|
|
36008
|
-
|
|
36009
|
-
|
|
36010
|
-
|
|
36011
|
-
|
|
36012
|
-
|
|
36013
|
-
|
|
36014
|
-
|
|
36044
|
+
let number = null;
|
|
36045
|
+
if (typeof value === "number" || typeof value === "string") {
|
|
36046
|
+
const date = toJsDate(value, locale);
|
|
36047
|
+
switch (granularity) {
|
|
36048
|
+
case "year_number":
|
|
36049
|
+
number = date.getFullYear();
|
|
36050
|
+
break;
|
|
36051
|
+
case "quarter_number":
|
|
36052
|
+
number = Math.floor(date.getMonth() / 3) + 1;
|
|
36053
|
+
break;
|
|
36054
|
+
case "month_number":
|
|
36055
|
+
number = date.getMonth() + 1;
|
|
36056
|
+
break;
|
|
36057
|
+
case "iso_week_number":
|
|
36058
|
+
number = date.getIsoWeek();
|
|
36059
|
+
break;
|
|
36060
|
+
case "day_of_month":
|
|
36061
|
+
number = date.getDate();
|
|
36062
|
+
break;
|
|
36063
|
+
case "day":
|
|
36064
|
+
number = Math.floor(toNumber(value, locale));
|
|
36065
|
+
break;
|
|
36066
|
+
}
|
|
36015
36067
|
}
|
|
36016
|
-
MAP_VALUE_DIMENSION_DATE[granularity].values[
|
|
36068
|
+
MAP_VALUE_DIMENSION_DATE[granularity].values[keyInMap] = toNormalizedPivotValue(dimension, number);
|
|
36017
36069
|
}
|
|
36018
|
-
return MAP_VALUE_DIMENSION_DATE[granularity].values[
|
|
36070
|
+
return MAP_VALUE_DIMENSION_DATE[granularity].values[keyInMap];
|
|
36019
36071
|
}
|
|
36020
36072
|
/**
|
|
36021
36073
|
* This map is used to cache the different values of a pivot date value
|
|
@@ -36197,6 +36249,25 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36197
36249
|
}
|
|
36198
36250
|
return undefined;
|
|
36199
36251
|
}
|
|
36252
|
+
areDomainArgsFieldsValid(args) {
|
|
36253
|
+
let dimensions = args.filter((_, index) => index % 2 === 0).map(toString);
|
|
36254
|
+
if (dimensions.length && dimensions.at(-1) === "measure") {
|
|
36255
|
+
dimensions = dimensions.slice(0, -1);
|
|
36256
|
+
}
|
|
36257
|
+
return areDomainArgsFieldsValid(dimensions, this.definition);
|
|
36258
|
+
}
|
|
36259
|
+
parseArgsToPivotDomain(args) {
|
|
36260
|
+
const domain = [];
|
|
36261
|
+
for (let i = 0; i < args.length - 1; i += 2) {
|
|
36262
|
+
const fieldWithGranularity = toString(args[i]);
|
|
36263
|
+
const type = this.getTypeOfDimension(fieldWithGranularity);
|
|
36264
|
+
const normalizedValue = fieldWithGranularity === "measure"
|
|
36265
|
+
? toString(args[i + 1])
|
|
36266
|
+
: toNormalizedPivotValue(this.getDimension(fieldWithGranularity), args[i + 1]);
|
|
36267
|
+
domain.push({ field: fieldWithGranularity, value: normalizedValue, type });
|
|
36268
|
+
}
|
|
36269
|
+
return domain;
|
|
36270
|
+
}
|
|
36200
36271
|
markAsDirtyForEvaluation() {
|
|
36201
36272
|
this.needsReevaluation = true;
|
|
36202
36273
|
}
|
|
@@ -36218,18 +36289,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36218
36289
|
const finalCell = cells[0]?.[dimension.nameWithGranularity];
|
|
36219
36290
|
if (dimension.type === "date") {
|
|
36220
36291
|
const adapter = pivotTimeAdapter(dimension.granularity);
|
|
36221
|
-
return
|
|
36222
|
-
value: lastNode.value !== "null"
|
|
36223
|
-
? adapter.toCellValue(toNormalizedPivotValue(dimension, lastNode.value))
|
|
36224
|
-
: _t("(Undefined)"),
|
|
36225
|
-
format: adapter.getFormat(this.getters.getLocale()),
|
|
36226
|
-
};
|
|
36292
|
+
return adapter.toValueAndFormat(lastNode.value, this.getters.getLocale());
|
|
36227
36293
|
}
|
|
36228
36294
|
if (!finalCell) {
|
|
36229
36295
|
return { value: "" };
|
|
36230
36296
|
}
|
|
36231
|
-
|
|
36232
|
-
if (finalCell.value === null || finalCell.value === `${null}`) {
|
|
36297
|
+
if (finalCell.value === null) {
|
|
36233
36298
|
return { value: _t("(Undefined)") };
|
|
36234
36299
|
}
|
|
36235
36300
|
return {
|
|
@@ -36280,14 +36345,24 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36280
36345
|
getFields() {
|
|
36281
36346
|
return this.fields;
|
|
36282
36347
|
}
|
|
36348
|
+
getTypeOfDimension(fieldWithGranularity) {
|
|
36349
|
+
if (fieldWithGranularity === "measure") {
|
|
36350
|
+
return "char";
|
|
36351
|
+
}
|
|
36352
|
+
const { name } = parseDimension(fieldWithGranularity);
|
|
36353
|
+
const type = this.fields[name]?.type;
|
|
36354
|
+
if (!type) {
|
|
36355
|
+
throw new Error(`Field ${name} does not exist`);
|
|
36356
|
+
}
|
|
36357
|
+
return type;
|
|
36358
|
+
}
|
|
36283
36359
|
filterDataEntriesFromDomain(dataEntries, domain) {
|
|
36284
36360
|
return domain.reduce((current, acc) => this.filterDataEntriesFromDomainNode(current, acc), dataEntries);
|
|
36285
36361
|
}
|
|
36286
36362
|
filterDataEntriesFromDomainNode(dataEntries, domain) {
|
|
36287
36363
|
const { field, value } = domain;
|
|
36288
|
-
const
|
|
36289
|
-
return dataEntries.filter((entry) =>
|
|
36290
|
-
`${toNormalizedPivotValue(dimension, value)}`);
|
|
36364
|
+
const { nameWithGranularity } = this.getDimension(field);
|
|
36365
|
+
return dataEntries.filter((entry) => entry[nameWithGranularity]?.value === value);
|
|
36291
36366
|
}
|
|
36292
36367
|
getDimension(nameWithGranularity) {
|
|
36293
36368
|
return this.definition.getDimension(nameWithGranularity);
|
|
@@ -36392,7 +36467,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36392
36467
|
for (const entry of dataEntries) {
|
|
36393
36468
|
for (const dimension of dateDimensions) {
|
|
36394
36469
|
entry[dimension.nameWithGranularity] = {
|
|
36395
|
-
value:
|
|
36470
|
+
value: createDate(dimension, entry[dimension.name]?.value || null, this.getters.getLocale()),
|
|
36396
36471
|
type: entry[dimension.name]?.type || CellValueType.empty,
|
|
36397
36472
|
format: entry[dimension.name]?.format,
|
|
36398
36473
|
};
|
|
@@ -36439,11 +36514,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36439
36514
|
}
|
|
36440
36515
|
}
|
|
36441
36516
|
get fields() {
|
|
36442
|
-
|
|
36443
|
-
if (!fields) {
|
|
36444
|
-
throw new Error("Fields not found");
|
|
36445
|
-
}
|
|
36446
|
-
return fields;
|
|
36517
|
+
return this.pivot.getFields();
|
|
36447
36518
|
}
|
|
36448
36519
|
get pivot() {
|
|
36449
36520
|
return this.getters.getPivot(this.pivotId);
|
|
@@ -36677,6 +36748,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36677
36748
|
this.store.applyUpdate();
|
|
36678
36749
|
}
|
|
36679
36750
|
}
|
|
36751
|
+
flipAxis() {
|
|
36752
|
+
const { rows, columns } = this.definition;
|
|
36753
|
+
this.onDimensionsUpdated({
|
|
36754
|
+
rows: columns,
|
|
36755
|
+
columns: rows,
|
|
36756
|
+
});
|
|
36757
|
+
}
|
|
36680
36758
|
onDimensionsUpdated(definition) {
|
|
36681
36759
|
this.store.update(definition);
|
|
36682
36760
|
}
|
|
@@ -51548,8 +51626,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51548
51626
|
case "INSERT_PIVOT": {
|
|
51549
51627
|
const { sheetId, col, row, pivotId, table } = cmd;
|
|
51550
51628
|
const position = { sheetId, col, row };
|
|
51551
|
-
const { cols, rows, measures } = table;
|
|
51552
|
-
const spTable = new SpreadsheetPivotTable(cols, rows, measures);
|
|
51629
|
+
const { cols, rows, measures, fieldsType } = table;
|
|
51630
|
+
const spTable = new SpreadsheetPivotTable(cols, rows, measures, fieldsType || {});
|
|
51553
51631
|
const formulaId = this.getPivotFormulaId(pivotId);
|
|
51554
51632
|
this.insertPivot(position, formulaId, spTable);
|
|
51555
51633
|
break;
|
|
@@ -51630,7 +51708,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51630
51708
|
sheetId: position.sheetId,
|
|
51631
51709
|
col: position.col + col,
|
|
51632
51710
|
row: position.row + row,
|
|
51633
|
-
content:
|
|
51711
|
+
content: createPivotFormula(formulaId, pivotCell),
|
|
51634
51712
|
});
|
|
51635
51713
|
}
|
|
51636
51714
|
}
|
|
@@ -54896,7 +54974,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54896
54974
|
"getPivotIdFromPosition",
|
|
54897
54975
|
"getPivotCellFromPosition",
|
|
54898
54976
|
"isPivotUnused",
|
|
54899
|
-
"areDomainArgsFieldsValid",
|
|
54900
54977
|
"isSpillPivotFormula",
|
|
54901
54978
|
];
|
|
54902
54979
|
pivots = {};
|
|
@@ -54968,7 +55045,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54968
55045
|
getPivotIdFromPosition(position) {
|
|
54969
55046
|
const cell = this.getters.getCorrespondingFormulaCell(position);
|
|
54970
55047
|
if (cell && cell.isFormula) {
|
|
54971
|
-
const pivotFunction = this.getFirstPivotFunction(cell.compiledFormula.tokens);
|
|
55048
|
+
const pivotFunction = this.getFirstPivotFunction(position.sheetId, cell.compiledFormula.tokens);
|
|
54972
55049
|
if (pivotFunction) {
|
|
54973
55050
|
const pivotId = pivotFunction.args[0]?.toString();
|
|
54974
55051
|
return pivotId && this.getters.getPivotId(pivotId);
|
|
@@ -54979,12 +55056,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54979
55056
|
isSpillPivotFormula(position) {
|
|
54980
55057
|
const cell = this.getters.getCorrespondingFormulaCell(position);
|
|
54981
55058
|
if (cell && cell.isFormula) {
|
|
54982
|
-
const pivotFunction = this.getFirstPivotFunction(cell.compiledFormula.tokens);
|
|
55059
|
+
const pivotFunction = this.getFirstPivotFunction(position.sheetId, cell.compiledFormula.tokens);
|
|
54983
55060
|
return pivotFunction?.functionName === "PIVOT";
|
|
54984
55061
|
}
|
|
54985
55062
|
return false;
|
|
54986
55063
|
}
|
|
54987
|
-
getFirstPivotFunction(tokens) {
|
|
55064
|
+
getFirstPivotFunction(sheetId, tokens) {
|
|
54988
55065
|
const pivotFunction = getFirstPivotFunction(tokens);
|
|
54989
55066
|
if (!pivotFunction) {
|
|
54990
55067
|
return undefined;
|
|
@@ -55000,7 +55077,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55000
55077
|
return argAst.value;
|
|
55001
55078
|
}
|
|
55002
55079
|
const argsString = astToFormula(argAst);
|
|
55003
|
-
return this.getters.evaluateFormula(
|
|
55080
|
+
return this.getters.evaluateFormula(sheetId, argsString);
|
|
55004
55081
|
});
|
|
55005
55082
|
return { functionName, args: evaluatedArgs };
|
|
55006
55083
|
}
|
|
@@ -55023,24 +55100,24 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55023
55100
|
return EMPTY_PIVOT_CELL;
|
|
55024
55101
|
}
|
|
55025
55102
|
const mainPosition = this.getters.getCellPosition(cell.id);
|
|
55026
|
-
const result = this.getters.getFirstPivotFunction(cell.compiledFormula.tokens);
|
|
55103
|
+
const result = this.getters.getFirstPivotFunction(position.sheetId, cell.compiledFormula.tokens);
|
|
55027
55104
|
if (!result) {
|
|
55028
55105
|
return EMPTY_PIVOT_CELL;
|
|
55029
55106
|
}
|
|
55030
55107
|
const { functionName, args } = result;
|
|
55108
|
+
const formulaId = args[0];
|
|
55109
|
+
if (!formulaId) {
|
|
55110
|
+
return EMPTY_PIVOT_CELL;
|
|
55111
|
+
}
|
|
55112
|
+
const pivotId = this.getters.getPivotId(formulaId.toString());
|
|
55113
|
+
if (!pivotId) {
|
|
55114
|
+
return EMPTY_PIVOT_CELL;
|
|
55115
|
+
}
|
|
55116
|
+
const pivot = this.getPivot(pivotId);
|
|
55117
|
+
if (!pivot.isValid()) {
|
|
55118
|
+
return EMPTY_PIVOT_CELL;
|
|
55119
|
+
}
|
|
55031
55120
|
if (functionName === "PIVOT") {
|
|
55032
|
-
const formulaId = args[0];
|
|
55033
|
-
if (!formulaId) {
|
|
55034
|
-
return EMPTY_PIVOT_CELL;
|
|
55035
|
-
}
|
|
55036
|
-
const pivotId = this.getters.getPivotId(formulaId.toString());
|
|
55037
|
-
if (!pivotId) {
|
|
55038
|
-
return EMPTY_PIVOT_CELL;
|
|
55039
|
-
}
|
|
55040
|
-
const pivot = this.getPivot(pivotId);
|
|
55041
|
-
if (!pivot.isValid()) {
|
|
55042
|
-
return EMPTY_PIVOT_CELL;
|
|
55043
|
-
}
|
|
55044
55121
|
const includeTotal = args[2] === false ? false : undefined;
|
|
55045
55122
|
const includeColumnHeaders = args[3] === false ? false : undefined;
|
|
55046
55123
|
const pivotCells = pivot
|
|
@@ -55051,7 +55128,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55051
55128
|
return pivotCells[pivotCol][pivotRow];
|
|
55052
55129
|
}
|
|
55053
55130
|
if (functionName === "PIVOT.HEADER" && args.at(-2) === "measure") {
|
|
55054
|
-
const domain =
|
|
55131
|
+
const domain = pivot.parseArgsToPivotDomain(args.slice(1, -2).map((value) => ({ value })));
|
|
55055
55132
|
return {
|
|
55056
55133
|
type: "MEASURE_HEADER",
|
|
55057
55134
|
domain,
|
|
@@ -55059,15 +55136,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55059
55136
|
};
|
|
55060
55137
|
}
|
|
55061
55138
|
else if (functionName === "PIVOT.HEADER") {
|
|
55139
|
+
const domain = pivot.parseArgsToPivotDomain(args.slice(1).map((value) => ({ value })));
|
|
55062
55140
|
return {
|
|
55063
55141
|
type: "HEADER",
|
|
55064
|
-
domain
|
|
55142
|
+
domain,
|
|
55065
55143
|
};
|
|
55066
55144
|
}
|
|
55067
55145
|
const [measure, ...domainArgs] = args.slice(1);
|
|
55146
|
+
const domain = pivot.parseArgsToPivotDomain(domainArgs.map((value) => ({ value })));
|
|
55068
55147
|
return {
|
|
55069
55148
|
type: "VALUE",
|
|
55070
|
-
domain
|
|
55149
|
+
domain,
|
|
55071
55150
|
measure: measure?.toString() || "",
|
|
55072
55151
|
};
|
|
55073
55152
|
}
|
|
@@ -55077,32 +55156,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55077
55156
|
isPivotUnused(pivotId) {
|
|
55078
55157
|
return this._getUnusedPivots().includes(pivotId);
|
|
55079
55158
|
}
|
|
55080
|
-
/**
|
|
55081
|
-
* Check if the fields in the domain part of
|
|
55082
|
-
* a pivot function are valid according to the pivot definition.
|
|
55083
|
-
* e.g. =PIVOT.VALUE(1,"revenue","country_id",...,"create_date:month",...,"source_id",...)
|
|
55084
|
-
*/
|
|
55085
|
-
areDomainArgsFieldsValid(pivotId, domain) {
|
|
55086
|
-
const dimensions = domain
|
|
55087
|
-
.map((node) => node.field)
|
|
55088
|
-
.map((name) => (name.startsWith("#") ? name.slice(1) : name));
|
|
55089
|
-
let argIndex = 0;
|
|
55090
|
-
let definitionIndex = 0;
|
|
55091
|
-
const pivot = this.getPivot(pivotId);
|
|
55092
|
-
const definition = pivot.definition;
|
|
55093
|
-
const cols = definition.columns.map((col) => col.nameWithGranularity);
|
|
55094
|
-
const rows = definition.rows.map((row) => row.nameWithGranularity);
|
|
55095
|
-
while (dimensions[argIndex] !== undefined && dimensions[argIndex] === rows[definitionIndex]) {
|
|
55096
|
-
argIndex++;
|
|
55097
|
-
definitionIndex++;
|
|
55098
|
-
}
|
|
55099
|
-
definitionIndex = 0;
|
|
55100
|
-
while (dimensions[argIndex] !== undefined && dimensions[argIndex] === cols[definitionIndex]) {
|
|
55101
|
-
argIndex++;
|
|
55102
|
-
definitionIndex++;
|
|
55103
|
-
}
|
|
55104
|
-
return dimensions.length === argIndex;
|
|
55105
|
-
}
|
|
55106
55159
|
// ---------------------------------------------------------------------
|
|
55107
55160
|
// Private
|
|
55108
55161
|
// ---------------------------------------------------------------------
|
|
@@ -58585,32 +58638,32 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58585
58638
|
}
|
|
58586
58639
|
}
|
|
58587
58640
|
convertOSClipboardData(clipboardData) {
|
|
58588
|
-
const handlers =
|
|
58589
|
-
.getAll()
|
|
58590
|
-
.map((handler) => new handler(this.getters, this.dispatch));
|
|
58591
|
-
clipboardHandlersRegistries.cellHandlers
|
|
58592
|
-
.getAll()
|
|
58593
|
-
.forEach((handler) => handlers.push(new handler(this.getters, this.dispatch)));
|
|
58641
|
+
const handlers = this.selectClipboardHandlers({ figureId: true }).concat(this.selectClipboardHandlers({}));
|
|
58594
58642
|
let copiedData = {};
|
|
58595
|
-
for (const handler of handlers) {
|
|
58643
|
+
for (const { handlerName, handler } of handlers) {
|
|
58596
58644
|
const data = handler.convertOSClipboardData(clipboardData);
|
|
58597
|
-
copiedData =
|
|
58645
|
+
copiedData[handlerName] = data;
|
|
58646
|
+
const minimalKeys = ["sheetId", "cells", "zones", "figureId"];
|
|
58647
|
+
for (const key of minimalKeys) {
|
|
58648
|
+
if (data && key in data) {
|
|
58649
|
+
copiedData[key] = data[key];
|
|
58650
|
+
}
|
|
58651
|
+
}
|
|
58598
58652
|
}
|
|
58599
58653
|
return copiedData;
|
|
58600
58654
|
}
|
|
58601
58655
|
selectClipboardHandlers(data) {
|
|
58602
|
-
|
|
58603
|
-
|
|
58604
|
-
|
|
58605
|
-
|
|
58606
|
-
|
|
58607
|
-
|
|
58608
|
-
|
|
58609
|
-
.map((handler) => new handler(this.getters, this.dispatch));
|
|
58656
|
+
const handlersRegistry = "figureId" in data
|
|
58657
|
+
? clipboardHandlersRegistries.figureHandlers
|
|
58658
|
+
: clipboardHandlersRegistries.cellHandlers;
|
|
58659
|
+
return handlersRegistry.getKeys().map((handlerName) => {
|
|
58660
|
+
const Handler = handlersRegistry.get(handlerName);
|
|
58661
|
+
return { handlerName, handler: new Handler(this.getters, this.dispatch) };
|
|
58662
|
+
});
|
|
58610
58663
|
}
|
|
58611
58664
|
isCutAllowedOn(zones) {
|
|
58612
58665
|
const clipboardData = this.getClipboardData(zones);
|
|
58613
|
-
for (const handler of this.selectClipboardHandlers(clipboardData)) {
|
|
58666
|
+
for (const { handler } of this.selectClipboardHandlers(clipboardData)) {
|
|
58614
58667
|
const result = handler.isCutAllowed(clipboardData);
|
|
58615
58668
|
if (result !== "Success" /* CommandResult.Success */) {
|
|
58616
58669
|
return result;
|
|
@@ -58619,7 +58672,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58619
58672
|
return "Success" /* CommandResult.Success */;
|
|
58620
58673
|
}
|
|
58621
58674
|
isPasteAllowed(target, copiedData, options) {
|
|
58622
|
-
for (const handler of this.selectClipboardHandlers(copiedData)) {
|
|
58675
|
+
for (const { handler } of this.selectClipboardHandlers(copiedData)) {
|
|
58623
58676
|
const result = handler.isPasteAllowed(this.getters.getActiveSheetId(), target, copiedData, {
|
|
58624
58677
|
...options,
|
|
58625
58678
|
});
|
|
@@ -58647,9 +58700,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58647
58700
|
copy(zones) {
|
|
58648
58701
|
let copiedData = {};
|
|
58649
58702
|
const clipboardData = this.getClipboardData(zones);
|
|
58650
|
-
for (const handler of this.selectClipboardHandlers(clipboardData)) {
|
|
58703
|
+
for (const { handlerName, handler } of this.selectClipboardHandlers(clipboardData)) {
|
|
58651
58704
|
const data = handler.copy(clipboardData);
|
|
58652
|
-
copiedData =
|
|
58705
|
+
copiedData[handlerName] = data;
|
|
58706
|
+
const minimalKeys = ["sheetId", "cells", "zones", "figureId"];
|
|
58707
|
+
for (const key of minimalKeys) {
|
|
58708
|
+
if (data && key in data) {
|
|
58709
|
+
copiedData[key] = data[key];
|
|
58710
|
+
}
|
|
58711
|
+
}
|
|
58653
58712
|
}
|
|
58654
58713
|
return copiedData;
|
|
58655
58714
|
}
|
|
@@ -58665,8 +58724,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58665
58724
|
zones,
|
|
58666
58725
|
};
|
|
58667
58726
|
const handlers = this.selectClipboardHandlers(copiedData);
|
|
58668
|
-
for (const handler of handlers) {
|
|
58669
|
-
const
|
|
58727
|
+
for (const { handlerName, handler } of handlers) {
|
|
58728
|
+
const handlerData = copiedData[handlerName];
|
|
58729
|
+
if (!handlerData) {
|
|
58730
|
+
continue;
|
|
58731
|
+
}
|
|
58732
|
+
const currentTarget = handler.getPasteTarget(sheetId, zones, handlerData, options);
|
|
58670
58733
|
if (currentTarget.figureId) {
|
|
58671
58734
|
target.figureId = currentTarget.figureId;
|
|
58672
58735
|
}
|
|
@@ -58682,7 +58745,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58682
58745
|
if (zone !== undefined) {
|
|
58683
58746
|
this.addMissingDimensions(this.getters.getActiveSheetId(), zone.right - zone.left + 1, zone.bottom - zone.top + 1, zone.left, zone.top);
|
|
58684
58747
|
}
|
|
58685
|
-
handlers.forEach((handler) =>
|
|
58748
|
+
handlers.forEach(({ handlerName, handler }) => {
|
|
58749
|
+
const handlerData = copiedData[handlerName];
|
|
58750
|
+
if (handlerData) {
|
|
58751
|
+
handler.paste(target, handlerData, options);
|
|
58752
|
+
}
|
|
58753
|
+
});
|
|
58686
58754
|
if (!options?.selectTarget) {
|
|
58687
58755
|
return;
|
|
58688
58756
|
}
|
|
@@ -66802,6 +66870,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66802
66870
|
const start = performance.now();
|
|
66803
66871
|
console.group("Model creation");
|
|
66804
66872
|
super();
|
|
66873
|
+
setDefaultTranslationMethod();
|
|
66805
66874
|
stateUpdateMessages = repairInitialMessages(data, stateUpdateMessages);
|
|
66806
66875
|
const workbookData = load(data, verboseImport);
|
|
66807
66876
|
this.state = new StateObserver();
|
|
@@ -67297,6 +67366,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
67297
67366
|
pivotSidePanelRegistry,
|
|
67298
67367
|
pivotNormalizationValueRegistry,
|
|
67299
67368
|
supportedPivotPositionalFormulaRegistry,
|
|
67369
|
+
pivotToFunctionValueRegistry,
|
|
67300
67370
|
};
|
|
67301
67371
|
const helpers = {
|
|
67302
67372
|
arg,
|
|
@@ -67342,7 +67412,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
67342
67412
|
expandZoneOnInsertion,
|
|
67343
67413
|
reduceZoneOnDeletion,
|
|
67344
67414
|
unquote,
|
|
67345
|
-
makePivotFormula,
|
|
67346
67415
|
getMaxObjectId,
|
|
67347
67416
|
getFunctionsFromTokens,
|
|
67348
67417
|
getFirstPivotFunction,
|
|
@@ -67354,10 +67423,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
67354
67423
|
insertTokenAfterLeftParenthesis,
|
|
67355
67424
|
mergeContiguousZones,
|
|
67356
67425
|
getPivotHighlights,
|
|
67357
|
-
toPivotDomain,
|
|
67358
|
-
flatPivotDomain,
|
|
67359
67426
|
pivotTimeAdapter,
|
|
67360
67427
|
UNDO_REDO_PIVOT_COMMANDS,
|
|
67428
|
+
createPivotFormula,
|
|
67429
|
+
areDomainArgsFieldsValid,
|
|
67361
67430
|
};
|
|
67362
67431
|
const links = {
|
|
67363
67432
|
isMarkdownLink,
|
|
@@ -67488,9 +67557,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
67488
67557
|
exports.tokenize = tokenize;
|
|
67489
67558
|
|
|
67490
67559
|
|
|
67491
|
-
__info__.version = "17.4.0-alpha.
|
|
67492
|
-
__info__.date = "2024-06-
|
|
67493
|
-
__info__.hash = "
|
|
67560
|
+
__info__.version = "17.4.0-alpha.9";
|
|
67561
|
+
__info__.date = "2024-06-26T11:09:20.284Z";
|
|
67562
|
+
__info__.hash = "526be20";
|
|
67494
67563
|
|
|
67495
67564
|
|
|
67496
67565
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|