@odoo/o-spreadsheet 17.4.0-alpha.7 → 17.4.0-alpha.8
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 +802 -736
- package/dist/o-spreadsheet.d.ts +38 -28
- package/dist/o-spreadsheet.esm.js +802 -736
- package/dist/o-spreadsheet.iife.js +802 -736
- 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.8
|
|
6
|
+
* @date 2024-06-24T19:51:16.144Z
|
|
7
|
+
* @hash ccd30df
|
|
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",
|
|
@@ -34553,6 +34564,7 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
34553
34564
|
currentSearchRegex = null;
|
|
34554
34565
|
isSearchDirty = false;
|
|
34555
34566
|
initialShowFormulaState;
|
|
34567
|
+
preserveSelectedMatchIndex = false;
|
|
34556
34568
|
// fixme: why do we make selectedMatchIndex on top of a selected
|
|
34557
34569
|
// property in the matches?
|
|
34558
34570
|
selectedMatchIndex = null;
|
|
@@ -34666,7 +34678,9 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
34666
34678
|
* refresh the matches according to the current search options
|
|
34667
34679
|
*/
|
|
34668
34680
|
refreshSearch(jumpToMatchSheet = true) {
|
|
34669
|
-
this.
|
|
34681
|
+
if (!this.preserveSelectedMatchIndex) {
|
|
34682
|
+
this.selectedMatchIndex = null;
|
|
34683
|
+
}
|
|
34670
34684
|
this.findMatches();
|
|
34671
34685
|
this.selectNextCell(Direction.current, jumpToMatchSheet);
|
|
34672
34686
|
}
|
|
@@ -34765,10 +34779,16 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
34765
34779
|
const selectedMatch = matches[nextIndex];
|
|
34766
34780
|
// Switch to the sheet where the match is located
|
|
34767
34781
|
if (jumpToMatchSheet && this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
34782
|
+
// We set `preserveSelectedMatchIndex` to true to avoid resetting the selected search
|
|
34783
|
+
// index in the `refreshSearch` function when a new sheet is activated. The reason being
|
|
34784
|
+
// that, when we automatically go back to previous sheet while performing a search, the
|
|
34785
|
+
// search index is reset to the first occurrence each time.
|
|
34786
|
+
this.preserveSelectedMatchIndex = true;
|
|
34768
34787
|
this.model.dispatch("ACTIVATE_SHEET", {
|
|
34769
34788
|
sheetIdFrom: this.getters.getActiveSheetId(),
|
|
34770
34789
|
sheetIdTo: selectedMatch.sheetId,
|
|
34771
34790
|
});
|
|
34791
|
+
this.preserveSelectedMatchIndex = false;
|
|
34772
34792
|
// We do not want to reset the selection at finalize in this case
|
|
34773
34793
|
this.isSearchDirty = false;
|
|
34774
34794
|
}
|
|
@@ -35409,6 +35429,10 @@ class CogWheelMenu extends Component {
|
|
|
35409
35429
|
}
|
|
35410
35430
|
});
|
|
35411
35431
|
}
|
|
35432
|
+
onClick(item) {
|
|
35433
|
+
item.onClick();
|
|
35434
|
+
this.popover.isOpen = false;
|
|
35435
|
+
}
|
|
35412
35436
|
get popoverProps() {
|
|
35413
35437
|
const { x, y, width, height } = this.buttonRef.el.getBoundingClientRect();
|
|
35414
35438
|
return {
|
|
@@ -35451,16 +35475,22 @@ class PivotTitleSection extends Component {
|
|
|
35451
35475
|
static components = { CogWheelMenu, Section, EditableName };
|
|
35452
35476
|
static props = {
|
|
35453
35477
|
pivotId: String,
|
|
35478
|
+
flipAxis: Function,
|
|
35454
35479
|
};
|
|
35455
35480
|
get cogWheelMenuItems() {
|
|
35456
35481
|
return [
|
|
35457
35482
|
{
|
|
35458
|
-
name: "
|
|
35483
|
+
name: _t("Flip axes"),
|
|
35484
|
+
icon: "fa-exchange",
|
|
35485
|
+
onClick: this.props.flipAxis,
|
|
35486
|
+
},
|
|
35487
|
+
{
|
|
35488
|
+
name: _t("Duplicate"),
|
|
35459
35489
|
icon: "fa-copy",
|
|
35460
35490
|
onClick: () => this.duplicatePivot(),
|
|
35461
35491
|
},
|
|
35462
35492
|
{
|
|
35463
|
-
name: "Delete",
|
|
35493
|
+
name: _t("Delete"),
|
|
35464
35494
|
icon: "fa-trash",
|
|
35465
35495
|
onClick: () => this.delete(),
|
|
35466
35496
|
},
|
|
@@ -35657,9 +35687,10 @@ class SpreadsheetPivotTable {
|
|
|
35657
35687
|
columns;
|
|
35658
35688
|
rows;
|
|
35659
35689
|
measures;
|
|
35690
|
+
fieldsType;
|
|
35660
35691
|
maxIndent;
|
|
35661
35692
|
pivotCells = {};
|
|
35662
|
-
constructor(columns, rows, measures) {
|
|
35693
|
+
constructor(columns, rows, measures, fieldsType) {
|
|
35663
35694
|
this.columns = columns.map((row) => {
|
|
35664
35695
|
// offset in the pivot table
|
|
35665
35696
|
// starts at 1 because the first column is the row title
|
|
@@ -35672,6 +35703,7 @@ class SpreadsheetPivotTable {
|
|
|
35672
35703
|
});
|
|
35673
35704
|
this.rows = rows;
|
|
35674
35705
|
this.measures = measures;
|
|
35706
|
+
this.fieldsType = fieldsType;
|
|
35675
35707
|
this.maxIndent = Math.max(...this.rows.map((row) => row.indent));
|
|
35676
35708
|
}
|
|
35677
35709
|
/**
|
|
@@ -35718,7 +35750,7 @@ class SpreadsheetPivotTable {
|
|
|
35718
35750
|
if (!domain) {
|
|
35719
35751
|
return EMPTY_PIVOT_CELL;
|
|
35720
35752
|
}
|
|
35721
|
-
const measure = domain.at(-1)?.value
|
|
35753
|
+
const measure = domain.at(-1)?.value?.toString() || "";
|
|
35722
35754
|
return { type: "MEASURE_HEADER", domain: domain.slice(0, -1), measure };
|
|
35723
35755
|
}
|
|
35724
35756
|
else if (row <= colHeadersHeight - 1) {
|
|
@@ -35750,9 +35782,13 @@ class SpreadsheetPivotTable {
|
|
|
35750
35782
|
return undefined;
|
|
35751
35783
|
}
|
|
35752
35784
|
for (let i = 0; i < pivotCol.fields.length; i++) {
|
|
35785
|
+
const fieldWithGranularity = pivotCol.fields[i];
|
|
35786
|
+
const { name, granularity } = parseDimension(fieldWithGranularity);
|
|
35787
|
+
const type = this.fieldsType[name] || "char";
|
|
35753
35788
|
domain.push({
|
|
35754
|
-
|
|
35755
|
-
|
|
35789
|
+
type,
|
|
35790
|
+
field: fieldWithGranularity,
|
|
35791
|
+
value: toNormalizedPivotValue({ displayName: name, type, granularity }, pivotCol.values[i]),
|
|
35756
35792
|
});
|
|
35757
35793
|
}
|
|
35758
35794
|
return domain;
|
|
@@ -35764,17 +35800,21 @@ class SpreadsheetPivotTable {
|
|
|
35764
35800
|
getColMeasure(col) {
|
|
35765
35801
|
const domain = this.getColHeaderDomain(col, this.columns.length - 1);
|
|
35766
35802
|
const measure = domain?.at(-1)?.value;
|
|
35767
|
-
if (measure === undefined) {
|
|
35768
|
-
throw new Error("Measure
|
|
35803
|
+
if (measure === undefined || measure === null) {
|
|
35804
|
+
throw new Error("Measure is missing");
|
|
35769
35805
|
}
|
|
35770
35806
|
return measure.toString();
|
|
35771
35807
|
}
|
|
35772
35808
|
getRowDomain(row) {
|
|
35773
35809
|
const domain = [];
|
|
35774
35810
|
for (let i = 0; i < this.rows[row].fields.length; i++) {
|
|
35811
|
+
const fieldWithGranularity = this.rows[row].fields[i];
|
|
35812
|
+
const { name, granularity } = parseDimension(fieldWithGranularity);
|
|
35813
|
+
const type = this.fieldsType[name] || "char";
|
|
35775
35814
|
domain.push({
|
|
35776
|
-
|
|
35777
|
-
|
|
35815
|
+
type,
|
|
35816
|
+
field: fieldWithGranularity,
|
|
35817
|
+
value: toNormalizedPivotValue({ displayName: name, type, granularity }, this.rows[row].values[i]),
|
|
35778
35818
|
});
|
|
35779
35819
|
}
|
|
35780
35820
|
return domain;
|
|
@@ -35784,6 +35824,7 @@ class SpreadsheetPivotTable {
|
|
|
35784
35824
|
cols: this.columns,
|
|
35785
35825
|
rows: this.rows,
|
|
35786
35826
|
measures: this.measures,
|
|
35827
|
+
fieldsType: this.fieldsType,
|
|
35787
35828
|
};
|
|
35788
35829
|
}
|
|
35789
35830
|
}
|
|
@@ -35804,7 +35845,14 @@ function dataEntriesToSpreadsheetPivotTable(dataEntries, definition) {
|
|
|
35804
35845
|
indent: 0,
|
|
35805
35846
|
});
|
|
35806
35847
|
const measureNames = definition.measures.map((m) => m.name);
|
|
35807
|
-
|
|
35848
|
+
const fieldsType = {};
|
|
35849
|
+
for (const columns of definition.columns) {
|
|
35850
|
+
fieldsType[columns.name] = columns.type;
|
|
35851
|
+
}
|
|
35852
|
+
for (const row of definition.rows) {
|
|
35853
|
+
fieldsType[row.name] = row.type;
|
|
35854
|
+
}
|
|
35855
|
+
return new SpreadsheetPivotTable(cols, rows, measureNames, fieldsType);
|
|
35808
35856
|
}
|
|
35809
35857
|
// -----------------------------------------------------------------------------
|
|
35810
35858
|
// ROWS
|
|
@@ -35980,41 +36028,42 @@ function compareDimensionValues(dimension, a, b) {
|
|
|
35980
36028
|
return dimension.order === "asc" ? a.localeCompare(b) : b.localeCompare(a);
|
|
35981
36029
|
}
|
|
35982
36030
|
|
|
36031
|
+
const NULL_SYMBOL = Symbol("NULL");
|
|
35983
36032
|
function createDate(dimension, value, locale) {
|
|
35984
36033
|
const granularity = dimension.granularity;
|
|
35985
36034
|
if (!granularity || !(granularity in MAP_VALUE_DIMENSION_DATE)) {
|
|
35986
36035
|
throw new Error(`Unknown date granularity: ${granularity}`);
|
|
35987
36036
|
}
|
|
35988
|
-
|
|
35989
|
-
return null;
|
|
35990
|
-
}
|
|
36037
|
+
const keyInMap = typeof value === "number" || typeof value === "string" ? value : NULL_SYMBOL;
|
|
35991
36038
|
if (!MAP_VALUE_DIMENSION_DATE[granularity].set.has(value)) {
|
|
35992
36039
|
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
|
-
|
|
36040
|
+
let number = null;
|
|
36041
|
+
if (typeof value === "number" || typeof value === "string") {
|
|
36042
|
+
const date = toJsDate(value, locale);
|
|
36043
|
+
switch (granularity) {
|
|
36044
|
+
case "year_number":
|
|
36045
|
+
number = date.getFullYear();
|
|
36046
|
+
break;
|
|
36047
|
+
case "quarter_number":
|
|
36048
|
+
number = Math.floor(date.getMonth() / 3) + 1;
|
|
36049
|
+
break;
|
|
36050
|
+
case "month_number":
|
|
36051
|
+
number = date.getMonth() + 1;
|
|
36052
|
+
break;
|
|
36053
|
+
case "iso_week_number":
|
|
36054
|
+
number = date.getIsoWeek();
|
|
36055
|
+
break;
|
|
36056
|
+
case "day_of_month":
|
|
36057
|
+
number = date.getDate();
|
|
36058
|
+
break;
|
|
36059
|
+
case "day":
|
|
36060
|
+
number = Math.floor(toNumber(value, locale));
|
|
36061
|
+
break;
|
|
36062
|
+
}
|
|
36014
36063
|
}
|
|
36015
|
-
MAP_VALUE_DIMENSION_DATE[granularity].values[
|
|
36064
|
+
MAP_VALUE_DIMENSION_DATE[granularity].values[keyInMap] = toNormalizedPivotValue(dimension, number);
|
|
36016
36065
|
}
|
|
36017
|
-
return MAP_VALUE_DIMENSION_DATE[granularity].values[
|
|
36066
|
+
return MAP_VALUE_DIMENSION_DATE[granularity].values[keyInMap];
|
|
36018
36067
|
}
|
|
36019
36068
|
/**
|
|
36020
36069
|
* This map is used to cache the different values of a pivot date value
|
|
@@ -36196,6 +36245,25 @@ class SpreadsheetPivot {
|
|
|
36196
36245
|
}
|
|
36197
36246
|
return undefined;
|
|
36198
36247
|
}
|
|
36248
|
+
areDomainArgsFieldsValid(args) {
|
|
36249
|
+
let dimensions = args.filter((_, index) => index % 2 === 0).map(toString);
|
|
36250
|
+
if (dimensions.length && dimensions.at(-1) === "measure") {
|
|
36251
|
+
dimensions = dimensions.slice(0, -1);
|
|
36252
|
+
}
|
|
36253
|
+
return areDomainArgsFieldsValid(dimensions, this.definition);
|
|
36254
|
+
}
|
|
36255
|
+
parseArgsToPivotDomain(args) {
|
|
36256
|
+
const domain = [];
|
|
36257
|
+
for (let i = 0; i < args.length - 1; i += 2) {
|
|
36258
|
+
const fieldWithGranularity = toString(args[i]);
|
|
36259
|
+
const type = this.getTypeOfDimension(fieldWithGranularity);
|
|
36260
|
+
const normalizedValue = fieldWithGranularity === "measure"
|
|
36261
|
+
? toString(args[i + 1])
|
|
36262
|
+
: toNormalizedPivotValue(this.getDimension(fieldWithGranularity), args[i + 1]);
|
|
36263
|
+
domain.push({ field: fieldWithGranularity, value: normalizedValue, type });
|
|
36264
|
+
}
|
|
36265
|
+
return domain;
|
|
36266
|
+
}
|
|
36199
36267
|
markAsDirtyForEvaluation() {
|
|
36200
36268
|
this.needsReevaluation = true;
|
|
36201
36269
|
}
|
|
@@ -36217,18 +36285,12 @@ class SpreadsheetPivot {
|
|
|
36217
36285
|
const finalCell = cells[0]?.[dimension.nameWithGranularity];
|
|
36218
36286
|
if (dimension.type === "date") {
|
|
36219
36287
|
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
|
-
};
|
|
36288
|
+
return adapter.toValueAndFormat(lastNode.value, this.getters.getLocale());
|
|
36226
36289
|
}
|
|
36227
36290
|
if (!finalCell) {
|
|
36228
36291
|
return { value: "" };
|
|
36229
36292
|
}
|
|
36230
|
-
|
|
36231
|
-
if (finalCell.value === null || finalCell.value === `${null}`) {
|
|
36293
|
+
if (finalCell.value === null) {
|
|
36232
36294
|
return { value: _t("(Undefined)") };
|
|
36233
36295
|
}
|
|
36234
36296
|
return {
|
|
@@ -36279,14 +36341,24 @@ class SpreadsheetPivot {
|
|
|
36279
36341
|
getFields() {
|
|
36280
36342
|
return this.fields;
|
|
36281
36343
|
}
|
|
36344
|
+
getTypeOfDimension(fieldWithGranularity) {
|
|
36345
|
+
if (fieldWithGranularity === "measure") {
|
|
36346
|
+
return "char";
|
|
36347
|
+
}
|
|
36348
|
+
const { name } = parseDimension(fieldWithGranularity);
|
|
36349
|
+
const type = this.fields[name]?.type;
|
|
36350
|
+
if (!type) {
|
|
36351
|
+
throw new Error(`Field ${name} does not exist`);
|
|
36352
|
+
}
|
|
36353
|
+
return type;
|
|
36354
|
+
}
|
|
36282
36355
|
filterDataEntriesFromDomain(dataEntries, domain) {
|
|
36283
36356
|
return domain.reduce((current, acc) => this.filterDataEntriesFromDomainNode(current, acc), dataEntries);
|
|
36284
36357
|
}
|
|
36285
36358
|
filterDataEntriesFromDomainNode(dataEntries, domain) {
|
|
36286
36359
|
const { field, value } = domain;
|
|
36287
|
-
const
|
|
36288
|
-
return dataEntries.filter((entry) =>
|
|
36289
|
-
`${toNormalizedPivotValue(dimension, value)}`);
|
|
36360
|
+
const { nameWithGranularity } = this.getDimension(field);
|
|
36361
|
+
return dataEntries.filter((entry) => entry[nameWithGranularity]?.value === value);
|
|
36290
36362
|
}
|
|
36291
36363
|
getDimension(nameWithGranularity) {
|
|
36292
36364
|
return this.definition.getDimension(nameWithGranularity);
|
|
@@ -36391,7 +36463,7 @@ class SpreadsheetPivot {
|
|
|
36391
36463
|
for (const entry of dataEntries) {
|
|
36392
36464
|
for (const dimension of dateDimensions) {
|
|
36393
36465
|
entry[dimension.nameWithGranularity] = {
|
|
36394
|
-
value:
|
|
36466
|
+
value: createDate(dimension, entry[dimension.name]?.value || null, this.getters.getLocale()),
|
|
36395
36467
|
type: entry[dimension.name]?.type || CellValueType.empty,
|
|
36396
36468
|
format: entry[dimension.name]?.format,
|
|
36397
36469
|
};
|
|
@@ -36438,11 +36510,7 @@ class PivotSidePanelStore extends SpreadsheetStore {
|
|
|
36438
36510
|
}
|
|
36439
36511
|
}
|
|
36440
36512
|
get fields() {
|
|
36441
|
-
|
|
36442
|
-
if (!fields) {
|
|
36443
|
-
throw new Error("Fields not found");
|
|
36444
|
-
}
|
|
36445
|
-
return fields;
|
|
36513
|
+
return this.pivot.getFields();
|
|
36446
36514
|
}
|
|
36447
36515
|
get pivot() {
|
|
36448
36516
|
return this.getters.getPivot(this.pivotId);
|
|
@@ -36676,6 +36744,13 @@ class PivotSpreadsheetSidePanel extends Component {
|
|
|
36676
36744
|
this.store.applyUpdate();
|
|
36677
36745
|
}
|
|
36678
36746
|
}
|
|
36747
|
+
flipAxis() {
|
|
36748
|
+
const { rows, columns } = this.definition;
|
|
36749
|
+
this.onDimensionsUpdated({
|
|
36750
|
+
rows: columns,
|
|
36751
|
+
columns: rows,
|
|
36752
|
+
});
|
|
36753
|
+
}
|
|
36679
36754
|
onDimensionsUpdated(definition) {
|
|
36680
36755
|
this.store.update(definition);
|
|
36681
36756
|
}
|
|
@@ -51547,8 +51622,8 @@ class PivotCorePlugin extends CorePlugin {
|
|
|
51547
51622
|
case "INSERT_PIVOT": {
|
|
51548
51623
|
const { sheetId, col, row, pivotId, table } = cmd;
|
|
51549
51624
|
const position = { sheetId, col, row };
|
|
51550
|
-
const { cols, rows, measures } = table;
|
|
51551
|
-
const spTable = new SpreadsheetPivotTable(cols, rows, measures);
|
|
51625
|
+
const { cols, rows, measures, fieldsType } = table;
|
|
51626
|
+
const spTable = new SpreadsheetPivotTable(cols, rows, measures, fieldsType || {});
|
|
51552
51627
|
const formulaId = this.getPivotFormulaId(pivotId);
|
|
51553
51628
|
this.insertPivot(position, formulaId, spTable);
|
|
51554
51629
|
break;
|
|
@@ -51629,7 +51704,7 @@ class PivotCorePlugin extends CorePlugin {
|
|
|
51629
51704
|
sheetId: position.sheetId,
|
|
51630
51705
|
col: position.col + col,
|
|
51631
51706
|
row: position.row + row,
|
|
51632
|
-
content:
|
|
51707
|
+
content: createPivotFormula(formulaId, pivotCell),
|
|
51633
51708
|
});
|
|
51634
51709
|
}
|
|
51635
51710
|
}
|
|
@@ -54895,7 +54970,6 @@ class PivotUIPlugin extends UIPlugin {
|
|
|
54895
54970
|
"getPivotIdFromPosition",
|
|
54896
54971
|
"getPivotCellFromPosition",
|
|
54897
54972
|
"isPivotUnused",
|
|
54898
|
-
"areDomainArgsFieldsValid",
|
|
54899
54973
|
"isSpillPivotFormula",
|
|
54900
54974
|
];
|
|
54901
54975
|
pivots = {};
|
|
@@ -55027,19 +55101,19 @@ class PivotUIPlugin extends UIPlugin {
|
|
|
55027
55101
|
return EMPTY_PIVOT_CELL;
|
|
55028
55102
|
}
|
|
55029
55103
|
const { functionName, args } = result;
|
|
55104
|
+
const formulaId = args[0];
|
|
55105
|
+
if (!formulaId) {
|
|
55106
|
+
return EMPTY_PIVOT_CELL;
|
|
55107
|
+
}
|
|
55108
|
+
const pivotId = this.getters.getPivotId(formulaId.toString());
|
|
55109
|
+
if (!pivotId) {
|
|
55110
|
+
return EMPTY_PIVOT_CELL;
|
|
55111
|
+
}
|
|
55112
|
+
const pivot = this.getPivot(pivotId);
|
|
55113
|
+
if (!pivot.isValid()) {
|
|
55114
|
+
return EMPTY_PIVOT_CELL;
|
|
55115
|
+
}
|
|
55030
55116
|
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
55117
|
const includeTotal = args[2] === false ? false : undefined;
|
|
55044
55118
|
const includeColumnHeaders = args[3] === false ? false : undefined;
|
|
55045
55119
|
const pivotCells = pivot
|
|
@@ -55050,7 +55124,7 @@ class PivotUIPlugin extends UIPlugin {
|
|
|
55050
55124
|
return pivotCells[pivotCol][pivotRow];
|
|
55051
55125
|
}
|
|
55052
55126
|
if (functionName === "PIVOT.HEADER" && args.at(-2) === "measure") {
|
|
55053
|
-
const domain =
|
|
55127
|
+
const domain = pivot.parseArgsToPivotDomain(args.slice(1, -2).map((value) => ({ value })));
|
|
55054
55128
|
return {
|
|
55055
55129
|
type: "MEASURE_HEADER",
|
|
55056
55130
|
domain,
|
|
@@ -55058,15 +55132,17 @@ class PivotUIPlugin extends UIPlugin {
|
|
|
55058
55132
|
};
|
|
55059
55133
|
}
|
|
55060
55134
|
else if (functionName === "PIVOT.HEADER") {
|
|
55135
|
+
const domain = pivot.parseArgsToPivotDomain(args.slice(1).map((value) => ({ value })));
|
|
55061
55136
|
return {
|
|
55062
55137
|
type: "HEADER",
|
|
55063
|
-
domain
|
|
55138
|
+
domain,
|
|
55064
55139
|
};
|
|
55065
55140
|
}
|
|
55066
55141
|
const [measure, ...domainArgs] = args.slice(1);
|
|
55142
|
+
const domain = pivot.parseArgsToPivotDomain(domainArgs.map((value) => ({ value })));
|
|
55067
55143
|
return {
|
|
55068
55144
|
type: "VALUE",
|
|
55069
|
-
domain
|
|
55145
|
+
domain,
|
|
55070
55146
|
measure: measure?.toString() || "",
|
|
55071
55147
|
};
|
|
55072
55148
|
}
|
|
@@ -55076,32 +55152,6 @@ class PivotUIPlugin extends UIPlugin {
|
|
|
55076
55152
|
isPivotUnused(pivotId) {
|
|
55077
55153
|
return this._getUnusedPivots().includes(pivotId);
|
|
55078
55154
|
}
|
|
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
55155
|
// ---------------------------------------------------------------------
|
|
55106
55156
|
// Private
|
|
55107
55157
|
// ---------------------------------------------------------------------
|
|
@@ -58584,32 +58634,32 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
58584
58634
|
}
|
|
58585
58635
|
}
|
|
58586
58636
|
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)));
|
|
58637
|
+
const handlers = this.selectClipboardHandlers({ figureId: true }).concat(this.selectClipboardHandlers({}));
|
|
58593
58638
|
let copiedData = {};
|
|
58594
|
-
for (const handler of handlers) {
|
|
58639
|
+
for (const { handlerName, handler } of handlers) {
|
|
58595
58640
|
const data = handler.convertOSClipboardData(clipboardData);
|
|
58596
|
-
copiedData =
|
|
58641
|
+
copiedData[handlerName] = data;
|
|
58642
|
+
const minimalKeys = ["sheetId", "cells", "zones", "figureId"];
|
|
58643
|
+
for (const key of minimalKeys) {
|
|
58644
|
+
if (data && key in data) {
|
|
58645
|
+
copiedData[key] = data[key];
|
|
58646
|
+
}
|
|
58647
|
+
}
|
|
58597
58648
|
}
|
|
58598
58649
|
return copiedData;
|
|
58599
58650
|
}
|
|
58600
58651
|
selectClipboardHandlers(data) {
|
|
58601
|
-
|
|
58602
|
-
|
|
58603
|
-
|
|
58604
|
-
|
|
58605
|
-
|
|
58606
|
-
|
|
58607
|
-
|
|
58608
|
-
.map((handler) => new handler(this.getters, this.dispatch));
|
|
58652
|
+
const handlersRegistry = "figureId" in data
|
|
58653
|
+
? clipboardHandlersRegistries.figureHandlers
|
|
58654
|
+
: clipboardHandlersRegistries.cellHandlers;
|
|
58655
|
+
return handlersRegistry.getKeys().map((handlerName) => {
|
|
58656
|
+
const Handler = handlersRegistry.get(handlerName);
|
|
58657
|
+
return { handlerName, handler: new Handler(this.getters, this.dispatch) };
|
|
58658
|
+
});
|
|
58609
58659
|
}
|
|
58610
58660
|
isCutAllowedOn(zones) {
|
|
58611
58661
|
const clipboardData = this.getClipboardData(zones);
|
|
58612
|
-
for (const handler of this.selectClipboardHandlers(clipboardData)) {
|
|
58662
|
+
for (const { handler } of this.selectClipboardHandlers(clipboardData)) {
|
|
58613
58663
|
const result = handler.isCutAllowed(clipboardData);
|
|
58614
58664
|
if (result !== "Success" /* CommandResult.Success */) {
|
|
58615
58665
|
return result;
|
|
@@ -58618,7 +58668,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
58618
58668
|
return "Success" /* CommandResult.Success */;
|
|
58619
58669
|
}
|
|
58620
58670
|
isPasteAllowed(target, copiedData, options) {
|
|
58621
|
-
for (const handler of this.selectClipboardHandlers(copiedData)) {
|
|
58671
|
+
for (const { handler } of this.selectClipboardHandlers(copiedData)) {
|
|
58622
58672
|
const result = handler.isPasteAllowed(this.getters.getActiveSheetId(), target, copiedData, {
|
|
58623
58673
|
...options,
|
|
58624
58674
|
});
|
|
@@ -58646,9 +58696,15 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
58646
58696
|
copy(zones) {
|
|
58647
58697
|
let copiedData = {};
|
|
58648
58698
|
const clipboardData = this.getClipboardData(zones);
|
|
58649
|
-
for (const handler of this.selectClipboardHandlers(clipboardData)) {
|
|
58699
|
+
for (const { handlerName, handler } of this.selectClipboardHandlers(clipboardData)) {
|
|
58650
58700
|
const data = handler.copy(clipboardData);
|
|
58651
|
-
copiedData =
|
|
58701
|
+
copiedData[handlerName] = data;
|
|
58702
|
+
const minimalKeys = ["sheetId", "cells", "zones", "figureId"];
|
|
58703
|
+
for (const key of minimalKeys) {
|
|
58704
|
+
if (data && key in data) {
|
|
58705
|
+
copiedData[key] = data[key];
|
|
58706
|
+
}
|
|
58707
|
+
}
|
|
58652
58708
|
}
|
|
58653
58709
|
return copiedData;
|
|
58654
58710
|
}
|
|
@@ -58664,8 +58720,12 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
58664
58720
|
zones,
|
|
58665
58721
|
};
|
|
58666
58722
|
const handlers = this.selectClipboardHandlers(copiedData);
|
|
58667
|
-
for (const handler of handlers) {
|
|
58668
|
-
const
|
|
58723
|
+
for (const { handlerName, handler } of handlers) {
|
|
58724
|
+
const handlerData = copiedData[handlerName];
|
|
58725
|
+
if (!handlerData) {
|
|
58726
|
+
continue;
|
|
58727
|
+
}
|
|
58728
|
+
const currentTarget = handler.getPasteTarget(sheetId, zones, handlerData, options);
|
|
58669
58729
|
if (currentTarget.figureId) {
|
|
58670
58730
|
target.figureId = currentTarget.figureId;
|
|
58671
58731
|
}
|
|
@@ -58681,7 +58741,12 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
58681
58741
|
if (zone !== undefined) {
|
|
58682
58742
|
this.addMissingDimensions(this.getters.getActiveSheetId(), zone.right - zone.left + 1, zone.bottom - zone.top + 1, zone.left, zone.top);
|
|
58683
58743
|
}
|
|
58684
|
-
handlers.forEach((handler) =>
|
|
58744
|
+
handlers.forEach(({ handlerName, handler }) => {
|
|
58745
|
+
const handlerData = copiedData[handlerName];
|
|
58746
|
+
if (handlerData) {
|
|
58747
|
+
handler.paste(target, handlerData, options);
|
|
58748
|
+
}
|
|
58749
|
+
});
|
|
58685
58750
|
if (!options?.selectTarget) {
|
|
58686
58751
|
return;
|
|
58687
58752
|
}
|
|
@@ -66801,6 +66866,7 @@ class Model extends EventBus {
|
|
|
66801
66866
|
const start = performance.now();
|
|
66802
66867
|
console.group("Model creation");
|
|
66803
66868
|
super();
|
|
66869
|
+
setDefaultTranslationMethod();
|
|
66804
66870
|
stateUpdateMessages = repairInitialMessages(data, stateUpdateMessages);
|
|
66805
66871
|
const workbookData = load(data, verboseImport);
|
|
66806
66872
|
this.state = new StateObserver();
|
|
@@ -67296,6 +67362,7 @@ const registries = {
|
|
|
67296
67362
|
pivotSidePanelRegistry,
|
|
67297
67363
|
pivotNormalizationValueRegistry,
|
|
67298
67364
|
supportedPivotPositionalFormulaRegistry,
|
|
67365
|
+
pivotToFunctionValueRegistry,
|
|
67299
67366
|
};
|
|
67300
67367
|
const helpers = {
|
|
67301
67368
|
arg,
|
|
@@ -67341,7 +67408,6 @@ const helpers = {
|
|
|
67341
67408
|
expandZoneOnInsertion,
|
|
67342
67409
|
reduceZoneOnDeletion,
|
|
67343
67410
|
unquote,
|
|
67344
|
-
makePivotFormula,
|
|
67345
67411
|
getMaxObjectId,
|
|
67346
67412
|
getFunctionsFromTokens,
|
|
67347
67413
|
getFirstPivotFunction,
|
|
@@ -67353,10 +67419,10 @@ const helpers = {
|
|
|
67353
67419
|
insertTokenAfterLeftParenthesis,
|
|
67354
67420
|
mergeContiguousZones,
|
|
67355
67421
|
getPivotHighlights,
|
|
67356
|
-
toPivotDomain,
|
|
67357
|
-
flatPivotDomain,
|
|
67358
67422
|
pivotTimeAdapter,
|
|
67359
67423
|
UNDO_REDO_PIVOT_COMMANDS,
|
|
67424
|
+
createPivotFormula,
|
|
67425
|
+
areDomainArgsFieldsValid,
|
|
67360
67426
|
};
|
|
67361
67427
|
const links = {
|
|
67362
67428
|
isMarkdownLink,
|
|
@@ -67444,6 +67510,6 @@ const constants = {
|
|
|
67444
67510
|
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
67511
|
|
|
67446
67512
|
|
|
67447
|
-
__info__.version = "17.4.0-alpha.
|
|
67448
|
-
__info__.date = "2024-06-
|
|
67449
|
-
__info__.hash = "
|
|
67513
|
+
__info__.version = "17.4.0-alpha.8";
|
|
67514
|
+
__info__.date = "2024-06-24T19:51:16.144Z";
|
|
67515
|
+
__info__.hash = "ccd30df";
|