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