@odoo/o-spreadsheet 19.2.0-alpha.2 → 19.2.0-alpha.3

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.
@@ -3,8 +3,8 @@
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
5
  * @version 19.1.0-alpha.3
6
- * @date 2026-01-07T16:20:57.293Z
7
- * @hash ac2fa3e
6
+ * @date 2026-01-14T10:01:30.535Z
7
+ * @hash e5cbf18
8
8
  */
9
9
 
10
10
  (function (exports) {
@@ -644,6 +644,7 @@
644
644
  fillColor: "",
645
645
  textColor: "",
646
646
  rotation: 0,
647
+ hideGridLines: false,
647
648
  };
648
649
  const DEFAULT_VERTICAL_ALIGN = DEFAULT_STYLE.verticalAlign;
649
650
  // Fonts
@@ -676,7 +677,7 @@
676
677
  }
677
678
  const NEWLINE = "\n";
678
679
  // Pivot
679
- const PIVOT_TABLE_CONFIG = {
680
+ const PIVOT_STATIC_TABLE_CONFIG = {
680
681
  hasFilters: false,
681
682
  totalRow: false,
682
683
  firstColumn: true,
@@ -687,6 +688,7 @@
687
688
  styleId: "TableStyleMedium5",
688
689
  automaticAutofill: false,
689
690
  };
691
+ const PIVOT_INSERT_TABLE_STYLE_ID = "PivotTableStyleMedium12";
690
692
  const PIVOT_INDENT = 15;
691
693
  const PIVOT_COLLAPSE_ICON_SIZE = 12;
692
694
  const PIVOT_MAX_NUMBER_OF_CELLS = 5e5;
@@ -913,8 +915,9 @@
913
915
  * Check if all the values of an object, and all the values of the objects inside of it, are undefined.
914
916
  */
915
917
  function isObjectEmptyRecursive(argument) {
916
- if (argument === undefined)
918
+ if (argument === undefined) {
917
919
  return true;
920
+ }
918
921
  return Object.values(argument).every((value) => typeof value === "object" ? isObjectEmptyRecursive(value) : !value);
919
922
  }
920
923
  /**
@@ -1031,23 +1034,29 @@
1031
1034
  * Compares n objects.
1032
1035
  */
1033
1036
  function deepEquals(...o) {
1034
- if (o.length <= 1)
1037
+ if (o.length <= 1) {
1035
1038
  return true;
1039
+ }
1036
1040
  for (let index = 1; index < o.length; index++) {
1037
- if (!_deepEquals(o[0], o[index]))
1041
+ if (!_deepEquals(o[0], o[index])) {
1038
1042
  return false;
1043
+ }
1039
1044
  }
1040
1045
  return true;
1041
1046
  }
1042
1047
  function _deepEquals(o1, o2) {
1043
- if (o1 === o2)
1048
+ if (o1 === o2) {
1044
1049
  return true;
1045
- if ((o1 && !o2) || (o2 && !o1))
1050
+ }
1051
+ if ((o1 && !o2) || (o2 && !o1)) {
1046
1052
  return false;
1047
- if (typeof o1 !== typeof o2)
1053
+ }
1054
+ if (typeof o1 !== typeof o2) {
1048
1055
  return false;
1049
- if (typeof o1 !== "object")
1056
+ }
1057
+ if (typeof o1 !== "object") {
1050
1058
  return false;
1059
+ }
1051
1060
  // Objects can have different keys if the values are undefined
1052
1061
  for (const key in o2) {
1053
1062
  if (!(key in o1) && o2[key] !== undefined) {
@@ -1055,15 +1064,18 @@
1055
1064
  }
1056
1065
  }
1057
1066
  for (const key in o1) {
1058
- if (typeof o1[key] !== typeof o2[key])
1067
+ if (typeof o1[key] !== typeof o2[key]) {
1059
1068
  return false;
1069
+ }
1060
1070
  if (typeof o1[key] === "object") {
1061
- if (!_deepEquals(o1[key], o2[key]))
1071
+ if (!_deepEquals(o1[key], o2[key])) {
1062
1072
  return false;
1073
+ }
1063
1074
  }
1064
1075
  else {
1065
- if (o1[key] !== o2[key])
1076
+ if (o1[key] !== o2[key]) {
1066
1077
  return false;
1078
+ }
1067
1079
  }
1068
1080
  }
1069
1081
  return true;
@@ -1099,8 +1111,9 @@
1099
1111
  * Return an object with all the keys in the object that have a falsy value removed.
1100
1112
  */
1101
1113
  function removeFalsyAttributes(obj) {
1102
- if (!obj)
1114
+ if (!obj) {
1103
1115
  return obj;
1116
+ }
1104
1117
  const cleanObject = { ...obj };
1105
1118
  Object.keys(cleanObject).forEach((key) => !cleanObject[key] && delete cleanObject[key]);
1106
1119
  return cleanObject;
@@ -1132,8 +1145,9 @@
1132
1145
  * Replace all different newlines characters by \n.
1133
1146
  */
1134
1147
  function replaceNewLines(text) {
1135
- if (!text)
1148
+ if (!text) {
1136
1149
  return "";
1150
+ }
1137
1151
  return text.replace(newLineRegexp, NEWLINE);
1138
1152
  }
1139
1153
  /**
@@ -1212,8 +1226,9 @@
1212
1226
  */
1213
1227
  function largeMax(array) {
1214
1228
  let len = array.length;
1215
- if (len < 100_000)
1229
+ if (len < 100_000) {
1216
1230
  return Math.max(...array);
1231
+ }
1217
1232
  let max = -Infinity;
1218
1233
  while (len--) {
1219
1234
  max = array[len] > max ? array[len] : max;
@@ -1226,8 +1241,9 @@
1226
1241
  */
1227
1242
  function largeMin(array) {
1228
1243
  let len = array.length;
1229
- if (len < 100_000)
1244
+ if (len < 100_000) {
1230
1245
  return Math.min(...array);
1246
+ }
1231
1247
  let min = +Infinity;
1232
1248
  while (len--) {
1233
1249
  min = array[len] < min ? array[len] : min;
@@ -1328,6 +1344,10 @@
1328
1344
  align: style.align,
1329
1345
  };
1330
1346
  }
1347
+ function doesCellContainFunction(cell, formula) {
1348
+ return (cell.isFormula &&
1349
+ cell.compiledFormula.tokens.some((t) => t.type === "SYMBOL" && t.value.toUpperCase() === formula));
1350
+ }
1331
1351
 
1332
1352
  // -----------------------------------------------------------------------------
1333
1353
  // Date Type
@@ -1744,10 +1764,12 @@
1744
1764
  switch (_dayCountConvention) {
1745
1765
  // 30/360 US convention --------------------------------------------------
1746
1766
  case 0:
1747
- if (dayStart === 31)
1767
+ if (dayStart === 31) {
1748
1768
  dayStart = 30;
1749
- if (dayStart === 30 && dayEnd === 31)
1769
+ }
1770
+ if (dayStart === 30 && dayEnd === 31) {
1750
1771
  dayEnd = 30;
1772
+ }
1751
1773
  // If jsStartDate is the last day of February
1752
1774
  if (monthStart === 1 && dayStart === (isLeapYear(yearStart) ? 29 : 28)) {
1753
1775
  dayStart = 30;
@@ -1821,10 +1843,12 @@
1821
1843
  break;
1822
1844
  // 30/360 European convention --------------------------------------------
1823
1845
  case 4:
1824
- if (dayStart === 31)
1846
+ if (dayStart === 31) {
1825
1847
  dayStart = 30;
1826
- if (dayEnd === 31)
1848
+ }
1849
+ if (dayEnd === 31) {
1827
1850
  dayEnd = 30;
1851
+ }
1828
1852
  yearsStart = yearStart + (monthStart * 30 + dayStart) / 360;
1829
1853
  yearsEnd = yearEnd + (monthEnd * 30 + dayEnd) / 360;
1830
1854
  break;
@@ -1932,8 +1956,9 @@
1932
1956
  * Note that "" (empty string) does not count as a number string
1933
1957
  */
1934
1958
  function isNumber(value, locale) {
1935
- if (!value)
1959
+ if (!value) {
1936
1960
  return false;
1961
+ }
1937
1962
  // TO DO: add regexp for DATE string format (ex match: "28 02 2020")
1938
1963
  return getNumberRegex(locale).test(value.trim());
1939
1964
  }
@@ -2412,15 +2437,17 @@
2412
2437
  const lenCol = arg[0].length;
2413
2438
  for (let y = 0; y < lenCol; y++) {
2414
2439
  for (let x = 0; x < lenRow; x++) {
2415
- if (!cellCb(arg[x][y] ?? undefined))
2440
+ if (!cellCb(arg[x][y] ?? undefined)) {
2416
2441
  return;
2442
+ }
2417
2443
  }
2418
2444
  }
2419
2445
  }
2420
2446
  else {
2421
2447
  // arg is set directly in the formula function
2422
- if (!dataCb(arg))
2448
+ if (!dataCb(arg)) {
2423
2449
  return;
2450
+ }
2424
2451
  }
2425
2452
  }
2426
2453
  }
@@ -3554,8 +3581,9 @@
3554
3581
  if (digitType === "0") {
3555
3582
  digit = digit || "0";
3556
3583
  }
3557
- if (!digit)
3584
+ if (!digit) {
3558
3585
  return;
3586
+ }
3559
3587
  const digitIndex = integerDigits.length - 1 - indexInIntegerString;
3560
3588
  if (thousandsSeparator && digitIndex > 0 && digitIndex % 3 === 0) {
3561
3589
  formattedInteger = digit + thousandsSeparator + formattedInteger;
@@ -3633,8 +3661,9 @@
3633
3661
  **/
3634
3662
  function splitNumber(value, maxDecimals = MAX_DECIMAL_PLACES) {
3635
3663
  const asString = value.toString();
3636
- if (asString.includes("e"))
3664
+ if (asString.includes("e")) {
3637
3665
  return splitNumberIntl(value, maxDecimals);
3666
+ }
3638
3667
  if (Number.isInteger(value)) {
3639
3668
  return { integerDigits: asString, decimalDigits: undefined };
3640
3669
  }
@@ -3822,8 +3851,9 @@
3822
3851
  */
3823
3852
  function createDefaultFormat(value) {
3824
3853
  let { integerDigits, decimalDigits } = splitNumber(value);
3825
- if (!decimalDigits)
3854
+ if (!decimalDigits) {
3826
3855
  return "0";
3856
+ }
3827
3857
  const digitsInIntegerPart = integerDigits.replace("-", "").length;
3828
3858
  // If there's no space for at least the decimal separator + a decimal digit, don't display decimals
3829
3859
  if (digitsInIntegerPart + 2 > DEFAULT_FORMAT_NUMBER_OF_DIGITS) {
@@ -4007,8 +4037,9 @@
4007
4037
  return true;
4008
4038
  }
4009
4039
  function isTextFormat(format) {
4010
- if (!format)
4040
+ if (!format) {
4011
4041
  return false;
4042
+ }
4012
4043
  try {
4013
4044
  const internalFormat = parseFormat(format);
4014
4045
  return internalFormat.positive.type === "text";
@@ -4908,8 +4939,9 @@
4908
4939
  * A1:$B$1 => $A$1:B$1 => A$1:$B1 => $A1:B1 => A1:$B$1
4909
4940
  */
4910
4941
  function loopThroughReferenceType(token) {
4911
- if (token.type !== "REFERENCE")
4942
+ if (token.type !== "REFERENCE") {
4912
4943
  return token;
4944
+ }
4913
4945
  const { xc, sheetName } = splitReference(token.value);
4914
4946
  const [left, right] = xc.split(":");
4915
4947
  const updatedLeft = getTokenNextReferenceType(left);
@@ -4961,16 +4993,19 @@
4961
4993
  const hasRow = indexOfNumber >= 0;
4962
4994
  switch (referenceType) {
4963
4995
  case "col":
4964
- if (!hasCol)
4996
+ if (!hasCol) {
4965
4997
  return xc;
4998
+ }
4966
4999
  return "$" + xc;
4967
5000
  case "row":
4968
- if (!hasRow)
5001
+ if (!hasRow) {
4969
5002
  return xc;
5003
+ }
4970
5004
  return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
4971
5005
  case "colrow":
4972
- if (!hasRow || !hasCol)
5006
+ if (!hasRow || !hasCol) {
4973
5007
  return "$" + xc;
5008
+ }
4974
5009
  return "$" + xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
4975
5010
  case "none":
4976
5011
  return xc;
@@ -5139,8 +5174,9 @@
5139
5174
  }
5140
5175
  }
5141
5176
  function consumeLetters(chars) {
5142
- if (chars.current === "$")
5177
+ if (chars.current === "$") {
5143
5178
  chars.advanceBy(1);
5179
+ }
5144
5180
  if (!chars.current || !isCharALetter(chars.current)) {
5145
5181
  return -1;
5146
5182
  }
@@ -5151,8 +5187,9 @@
5151
5187
  return colCoordinate;
5152
5188
  }
5153
5189
  function consumeDigits(chars) {
5154
- if (chars.current === "$")
5190
+ if (chars.current === "$") {
5155
5191
  chars.advanceBy(1);
5192
+ }
5156
5193
  if (!chars.current || !isCharADigit(chars.current)) {
5157
5194
  return -1;
5158
5195
  }
@@ -5810,8 +5847,9 @@
5810
5847
  for (const removedElement of elements.sort((a, b) => b - a)) {
5811
5848
  if (zone[start] > removedElement) {
5812
5849
  newStart--;
5813
- if (newEnd !== undefined)
5850
+ if (newEnd !== undefined) {
5814
5851
  newEnd--;
5852
+ }
5815
5853
  }
5816
5854
  if (zoneEnd !== undefined &&
5817
5855
  newEnd !== undefined &&
@@ -5881,8 +5919,9 @@
5881
5919
  * Returns the adjacent size of z1 as well as the indexes of the header by which they are adjacent.
5882
5920
  */
5883
5921
  function adjacent(z1, z2) {
5884
- if (intersection(z1, z2))
5922
+ if (intersection(z1, z2)) {
5885
5923
  return undefined;
5924
+ }
5886
5925
  let adjacentEdge = undefined;
5887
5926
  if (z1.left === z2.right + 1) {
5888
5927
  adjacentEdge = {
@@ -6167,14 +6206,16 @@
6167
6206
  * including cells outside the zones
6168
6207
  * */
6169
6208
  function areZonesContinuous(zones) {
6170
- if (zones.length < 2)
6209
+ if (zones.length < 2) {
6171
6210
  return true;
6211
+ }
6172
6212
  return recomputeZones(zones).length === 1;
6173
6213
  }
6174
6214
  function splitIfAdjacent(zone, zoneToRemove) {
6175
6215
  const adjacentEdge = adjacent(zone, zoneToRemove);
6176
- if (!adjacentEdge)
6216
+ if (!adjacentEdge) {
6177
6217
  return [zone];
6218
+ }
6178
6219
  const newZones = [];
6179
6220
  switch (adjacentEdge.position) {
6180
6221
  case "bottom":
@@ -6271,514 +6312,6 @@
6271
6312
  return zones;
6272
6313
  }
6273
6314
 
6274
- function isSheetDependent(cmd) {
6275
- return "sheetId" in cmd;
6276
- }
6277
- function isHeadersDependant(cmd) {
6278
- return "dimension" in cmd && "sheetId" in cmd && "elements" in cmd;
6279
- }
6280
- function isTargetDependent(cmd) {
6281
- return "target" in cmd && "sheetId" in cmd;
6282
- }
6283
- function isRangeDependant(cmd) {
6284
- return "ranges" in cmd;
6285
- }
6286
- function isPositionDependent(cmd) {
6287
- return "col" in cmd && "row" in cmd && "sheetId" in cmd;
6288
- }
6289
- function isZoneDependent(cmd) {
6290
- return "sheetId" in cmd && "zone" in cmd;
6291
- }
6292
- const invalidateEvaluationCommands = new Set([
6293
- "RENAME_SHEET",
6294
- "DELETE_SHEET",
6295
- "CREATE_SHEET",
6296
- "DUPLICATE_SHEET",
6297
- "ADD_COLUMNS_ROWS",
6298
- "REMOVE_COLUMNS_ROWS",
6299
- "UNDO",
6300
- "REDO",
6301
- "ADD_MERGE",
6302
- "REMOVE_MERGE",
6303
- "UPDATE_LOCALE",
6304
- "ADD_PIVOT",
6305
- "UPDATE_PIVOT",
6306
- "INSERT_PIVOT",
6307
- "RENAME_PIVOT",
6308
- "REMOVE_PIVOT",
6309
- "DUPLICATE_PIVOT",
6310
- ]);
6311
- const invalidateChartEvaluationCommands = new Set([
6312
- "EVALUATE_CELLS",
6313
- "EVALUATE_CHARTS",
6314
- "UPDATE_CELL",
6315
- "UNHIDE_COLUMNS_ROWS",
6316
- "HIDE_COLUMNS_ROWS",
6317
- "GROUP_HEADERS",
6318
- "SET_FORMATTING",
6319
- "CLEAR_FORMATTING",
6320
- "UNGROUP_HEADERS",
6321
- "FOLD_ALL_HEADER_GROUPS",
6322
- "FOLD_HEADER_GROUP",
6323
- "FOLD_HEADER_GROUPS_IN_ZONE",
6324
- "UNFOLD_ALL_HEADER_GROUPS",
6325
- "UNFOLD_HEADER_GROUP",
6326
- "UNFOLD_HEADER_GROUPS_IN_ZONE",
6327
- "UPDATE_TABLE",
6328
- "UPDATE_FILTER",
6329
- "UNDO",
6330
- "REDO",
6331
- ]);
6332
- const invalidateDependenciesCommands = new Set(["MOVE_RANGES"]);
6333
- const invalidateCFEvaluationCommands = new Set([
6334
- "EVALUATE_CELLS",
6335
- "ADD_CONDITIONAL_FORMAT",
6336
- "REMOVE_CONDITIONAL_FORMAT",
6337
- "CHANGE_CONDITIONAL_FORMAT_PRIORITY",
6338
- ]);
6339
- const invalidateBordersCommands = new Set([
6340
- "AUTOFILL_CELL",
6341
- "SET_BORDER",
6342
- "SET_ZONE_BORDERS",
6343
- "SET_BORDERS_ON_TARGET",
6344
- ]);
6345
- const invalidSubtotalFormulasCommands = new Set([
6346
- "UNHIDE_COLUMNS_ROWS",
6347
- "HIDE_COLUMNS_ROWS",
6348
- "GROUP_HEADERS",
6349
- "UNGROUP_HEADERS",
6350
- "FOLD_ALL_HEADER_GROUPS",
6351
- "FOLD_HEADER_GROUP",
6352
- "FOLD_HEADER_GROUPS_IN_ZONE",
6353
- "UNFOLD_ALL_HEADER_GROUPS",
6354
- "UNFOLD_HEADER_GROUP",
6355
- "UNFOLD_HEADER_GROUPS_IN_ZONE",
6356
- "UPDATE_TABLE",
6357
- "UPDATE_FILTER",
6358
- ]);
6359
- const readonlyAllowedCommands = new Set([
6360
- "START",
6361
- "ACTIVATE_SHEET",
6362
- "COPY",
6363
- "RESIZE_SHEETVIEW",
6364
- "SET_VIEWPORT_OFFSET",
6365
- "SET_ZOOM",
6366
- "EVALUATE_CELLS",
6367
- "EVALUATE_CHARTS",
6368
- "SET_FORMULA_VISIBILITY",
6369
- "UPDATE_FILTER",
6370
- "UPDATE_CHART",
6371
- "UPDATE_CAROUSEL_ACTIVE_ITEM",
6372
- "UPDATE_PIVOT",
6373
- ]);
6374
- const coreTypes = new Set([
6375
- /** CELLS */
6376
- "UPDATE_CELL",
6377
- "UPDATE_CELL_POSITION",
6378
- "CLEAR_CELL",
6379
- "CLEAR_CELLS",
6380
- "DELETE_CONTENT",
6381
- /** GRID SHAPE */
6382
- "ADD_COLUMNS_ROWS",
6383
- "REMOVE_COLUMNS_ROWS",
6384
- "RESIZE_COLUMNS_ROWS",
6385
- "HIDE_COLUMNS_ROWS",
6386
- "UNHIDE_COLUMNS_ROWS",
6387
- "SET_GRID_LINES_VISIBILITY",
6388
- "UNFREEZE_COLUMNS",
6389
- "UNFREEZE_ROWS",
6390
- "FREEZE_COLUMNS",
6391
- "FREEZE_ROWS",
6392
- "UNFREEZE_COLUMNS_ROWS",
6393
- /** MERGE */
6394
- "ADD_MERGE",
6395
- "REMOVE_MERGE",
6396
- /** SHEETS MANIPULATION */
6397
- "CREATE_SHEET",
6398
- "DELETE_SHEET",
6399
- "DUPLICATE_SHEET",
6400
- "MOVE_SHEET",
6401
- "RENAME_SHEET",
6402
- "COLOR_SHEET",
6403
- "HIDE_SHEET",
6404
- "SHOW_SHEET",
6405
- /** RANGES MANIPULATION */
6406
- "MOVE_RANGES",
6407
- /** CONDITIONAL FORMAT */
6408
- "ADD_CONDITIONAL_FORMAT",
6409
- "REMOVE_CONDITIONAL_FORMAT",
6410
- "CHANGE_CONDITIONAL_FORMAT_PRIORITY",
6411
- /** FIGURES */
6412
- "CREATE_FIGURE",
6413
- "DELETE_FIGURE",
6414
- "UPDATE_FIGURE",
6415
- "CREATE_CAROUSEL",
6416
- "UPDATE_CAROUSEL",
6417
- /** FORMATTING */
6418
- "SET_FORMATTING",
6419
- "CLEAR_FORMATTING",
6420
- "SET_BORDER",
6421
- "SET_ZONE_BORDERS",
6422
- "SET_BORDERS_ON_TARGET",
6423
- /** CHART */
6424
- "CREATE_CHART",
6425
- "UPDATE_CHART",
6426
- "DELETE_CHART",
6427
- /** FILTERS */
6428
- "CREATE_TABLE",
6429
- "REMOVE_TABLE",
6430
- "UPDATE_TABLE",
6431
- "CREATE_TABLE_STYLE",
6432
- "REMOVE_TABLE_STYLE",
6433
- /** IMAGE */
6434
- "CREATE_IMAGE",
6435
- /** HEADER GROUP */
6436
- "GROUP_HEADERS",
6437
- "UNGROUP_HEADERS",
6438
- "UNFOLD_HEADER_GROUP",
6439
- "FOLD_HEADER_GROUP",
6440
- "FOLD_ALL_HEADER_GROUPS",
6441
- "UNFOLD_ALL_HEADER_GROUPS",
6442
- "UNFOLD_HEADER_GROUPS_IN_ZONE",
6443
- "FOLD_HEADER_GROUPS_IN_ZONE",
6444
- /** DATA VALIDATION */
6445
- "ADD_DATA_VALIDATION_RULE",
6446
- "REMOVE_DATA_VALIDATION_RULE",
6447
- /** MISC */
6448
- "UPDATE_LOCALE",
6449
- /** PIVOT */
6450
- "ADD_PIVOT",
6451
- "UPDATE_PIVOT",
6452
- "INSERT_PIVOT",
6453
- "RENAME_PIVOT",
6454
- "REMOVE_PIVOT",
6455
- "DUPLICATE_PIVOT",
6456
- ]);
6457
- function isCoreCommand(cmd) {
6458
- return coreTypes.has(cmd.type);
6459
- }
6460
- function canExecuteInReadonly(cmd) {
6461
- return readonlyAllowedCommands.has(cmd.type);
6462
- }
6463
- /**
6464
- * Holds the result of a command dispatch.
6465
- * The command may have been successfully dispatched or cancelled
6466
- * for one or more reasons.
6467
- */
6468
- class DispatchResult {
6469
- reasons;
6470
- constructor(results = []) {
6471
- if (!Array.isArray(results)) {
6472
- results = [results];
6473
- }
6474
- results = [...new Set(results)];
6475
- this.reasons = results.filter((result) => result !== "Success" /* CommandResult.Success */);
6476
- }
6477
- /**
6478
- * Static helper which returns a successful DispatchResult
6479
- */
6480
- static get Success() {
6481
- return SUCCESS;
6482
- }
6483
- get isSuccessful() {
6484
- return this.reasons.length === 0;
6485
- }
6486
- /**
6487
- * Check if the dispatch has been cancelled because of
6488
- * the given reason.
6489
- */
6490
- isCancelledBecause(reason) {
6491
- return this.reasons.includes(reason);
6492
- }
6493
- }
6494
- const SUCCESS = new DispatchResult();
6495
- var CommandResult;
6496
- (function (CommandResult) {
6497
- CommandResult["Success"] = "Success";
6498
- CommandResult["CancelledForUnknownReason"] = "CancelledForUnknownReason";
6499
- CommandResult["WillRemoveExistingMerge"] = "WillRemoveExistingMerge";
6500
- CommandResult["CannotMoveTableHeader"] = "CannotMoveTableHeader";
6501
- CommandResult["MergeIsDestructive"] = "MergeIsDestructive";
6502
- CommandResult["CellIsMerged"] = "CellIsMerged";
6503
- CommandResult["InvalidTarget"] = "InvalidTarget";
6504
- CommandResult["EmptyUndoStack"] = "EmptyUndoStack";
6505
- CommandResult["EmptyRedoStack"] = "EmptyRedoStack";
6506
- CommandResult["NotEnoughElements"] = "NotEnoughElements";
6507
- CommandResult["NotEnoughSheets"] = "NotEnoughSheets";
6508
- CommandResult["MissingSheetName"] = "MissingSheetName";
6509
- CommandResult["UnchangedSheetName"] = "UnchangedSheetName";
6510
- CommandResult["DuplicatedSheetName"] = "DuplicatedSheetName";
6511
- CommandResult["DuplicatedSheetId"] = "DuplicatedSheetId";
6512
- CommandResult["ForbiddenCharactersInSheetName"] = "ForbiddenCharactersInSheetName";
6513
- CommandResult["WrongSheetMove"] = "WrongSheetMove";
6514
- CommandResult["WrongSheetPosition"] = "WrongSheetPosition";
6515
- CommandResult["InvalidAnchorZone"] = "InvalidAnchorZone";
6516
- CommandResult["SelectionOutOfBound"] = "SelectionOutOfBound";
6517
- CommandResult["TargetOutOfSheet"] = "TargetOutOfSheet";
6518
- CommandResult["WrongCutSelection"] = "WrongCutSelection";
6519
- CommandResult["WrongPasteSelection"] = "WrongPasteSelection";
6520
- CommandResult["WrongPasteOption"] = "WrongPasteOption";
6521
- CommandResult["WrongFigurePasteOption"] = "WrongFigurePasteOption";
6522
- CommandResult["EmptyClipboard"] = "EmptyClipboard";
6523
- CommandResult["EmptyRange"] = "EmptyRange";
6524
- CommandResult["InvalidRange"] = "InvalidRange";
6525
- CommandResult["InvalidZones"] = "InvalidZones";
6526
- CommandResult["InvalidSheetId"] = "InvalidSheetId";
6527
- CommandResult["InvalidCellId"] = "InvalidCellId";
6528
- CommandResult["InvalidFigureId"] = "InvalidFigureId";
6529
- CommandResult["InputAlreadyFocused"] = "InputAlreadyFocused";
6530
- CommandResult["MaximumRangesReached"] = "MaximumRangesReached";
6531
- CommandResult["MinimumRangesReached"] = "MinimumRangesReached";
6532
- CommandResult["InvalidChartDefinition"] = "InvalidChartDefinition";
6533
- CommandResult["InvalidDataSet"] = "InvalidDataSet";
6534
- CommandResult["InvalidLabelRange"] = "InvalidLabelRange";
6535
- CommandResult["InvalidScorecardKeyValue"] = "InvalidScorecardKeyValue";
6536
- CommandResult["InvalidScorecardBaseline"] = "InvalidScorecardBaseline";
6537
- CommandResult["InvalidGaugeDataRange"] = "InvalidGaugeDataRange";
6538
- CommandResult["EmptyGaugeRangeMin"] = "EmptyGaugeRangeMin";
6539
- CommandResult["GaugeRangeMinNaN"] = "GaugeRangeMinNaN";
6540
- CommandResult["EmptyGaugeRangeMax"] = "EmptyGaugeRangeMax";
6541
- CommandResult["GaugeRangeMaxNaN"] = "GaugeRangeMaxNaN";
6542
- CommandResult["GaugeLowerInflectionPointNaN"] = "GaugeLowerInflectionPointNaN";
6543
- CommandResult["GaugeUpperInflectionPointNaN"] = "GaugeUpperInflectionPointNaN";
6544
- CommandResult["InvalidAutofillSelection"] = "InvalidAutofillSelection";
6545
- CommandResult["MinBiggerThanMax"] = "MinBiggerThanMax";
6546
- CommandResult["LowerBiggerThanUpper"] = "LowerBiggerThanUpper";
6547
- CommandResult["MidBiggerThanMax"] = "MidBiggerThanMax";
6548
- CommandResult["MinBiggerThanMid"] = "MinBiggerThanMid";
6549
- CommandResult["FirstArgMissing"] = "FirstArgMissing";
6550
- CommandResult["SecondArgMissing"] = "SecondArgMissing";
6551
- CommandResult["MinNaN"] = "MinNaN";
6552
- CommandResult["MidNaN"] = "MidNaN";
6553
- CommandResult["MaxNaN"] = "MaxNaN";
6554
- CommandResult["ValueUpperInflectionNaN"] = "ValueUpperInflectionNaN";
6555
- CommandResult["ValueLowerInflectionNaN"] = "ValueLowerInflectionNaN";
6556
- CommandResult["MinInvalidFormula"] = "MinInvalidFormula";
6557
- CommandResult["MidInvalidFormula"] = "MidInvalidFormula";
6558
- CommandResult["MaxInvalidFormula"] = "MaxInvalidFormula";
6559
- CommandResult["ValueUpperInvalidFormula"] = "ValueUpperInvalidFormula";
6560
- CommandResult["ValueLowerInvalidFormula"] = "ValueLowerInvalidFormula";
6561
- CommandResult["InvalidSortAnchor"] = "InvalidSortAnchor";
6562
- CommandResult["InvalidSortZone"] = "InvalidSortZone";
6563
- CommandResult["SortZoneWithArrayFormulas"] = "SortZoneWithArrayFormulas";
6564
- CommandResult["WaitingSessionConfirmation"] = "WaitingSessionConfirmation";
6565
- CommandResult["MergeOverlap"] = "MergeOverlap";
6566
- CommandResult["TooManyHiddenElements"] = "TooManyHiddenElements";
6567
- CommandResult["Readonly"] = "Readonly";
6568
- CommandResult["InvalidViewportSize"] = "InvalidViewportSize";
6569
- CommandResult["InvalidScrollingDirection"] = "InvalidScrollingDirection";
6570
- CommandResult["ViewportScrollLimitsReached"] = "ViewportScrollLimitsReached";
6571
- CommandResult["FigureDoesNotExist"] = "FigureDoesNotExist";
6572
- CommandResult["InvalidConditionalFormatId"] = "InvalidConditionalFormatId";
6573
- CommandResult["InvalidCellPopover"] = "InvalidCellPopover";
6574
- CommandResult["EmptyTarget"] = "EmptyTarget";
6575
- CommandResult["InvalidFreezeQuantity"] = "InvalidFreezeQuantity";
6576
- CommandResult["FrozenPaneOverlap"] = "FrozenPaneOverlap";
6577
- CommandResult["ValuesNotChanged"] = "ValuesNotChanged";
6578
- CommandResult["InvalidFilterZone"] = "InvalidFilterZone";
6579
- CommandResult["TableNotFound"] = "TableNotFound";
6580
- CommandResult["TableOverlap"] = "TableOverlap";
6581
- CommandResult["InvalidTableConfig"] = "InvalidTableConfig";
6582
- CommandResult["InvalidTableStyle"] = "InvalidTableStyle";
6583
- CommandResult["FilterNotFound"] = "FilterNotFound";
6584
- CommandResult["MergeInTable"] = "MergeInTable";
6585
- CommandResult["NonContinuousTargets"] = "NonContinuousTargets";
6586
- CommandResult["DuplicatedFigureId"] = "DuplicatedFigureId";
6587
- CommandResult["InvalidSelectionStep"] = "InvalidSelectionStep";
6588
- CommandResult["DuplicatedChartId"] = "DuplicatedChartId";
6589
- CommandResult["ChartDoesNotExist"] = "ChartDoesNotExist";
6590
- CommandResult["InvalidHeaderIndex"] = "InvalidHeaderIndex";
6591
- CommandResult["InvalidQuantity"] = "InvalidQuantity";
6592
- CommandResult["MoreThanOneColumnSelected"] = "MoreThanOneColumnSelected";
6593
- CommandResult["EmptySplitSeparator"] = "EmptySplitSeparator";
6594
- CommandResult["SplitWillOverwriteContent"] = "SplitWillOverwriteContent";
6595
- CommandResult["NoSplitSeparatorInSelection"] = "NoSplitSeparatorInSelection";
6596
- CommandResult["NoActiveSheet"] = "NoActiveSheet";
6597
- CommandResult["InvalidLocale"] = "InvalidLocale";
6598
- CommandResult["MoreThanOneRangeSelected"] = "MoreThanOneRangeSelected";
6599
- CommandResult["NoColumnsProvided"] = "NoColumnsProvided";
6600
- CommandResult["ColumnsNotIncludedInZone"] = "ColumnsNotIncludedInZone";
6601
- CommandResult["DuplicatesColumnsSelected"] = "DuplicatesColumnsSelected";
6602
- CommandResult["InvalidHeaderGroupStartEnd"] = "InvalidHeaderGroupStartEnd";
6603
- CommandResult["HeaderGroupAlreadyExists"] = "HeaderGroupAlreadyExists";
6604
- CommandResult["UnknownHeaderGroup"] = "UnknownHeaderGroup";
6605
- CommandResult["UnknownDataValidationRule"] = "UnknownDataValidationRule";
6606
- CommandResult["UnknownDataValidationCriterionType"] = "UnknownDataValidationCriterionType";
6607
- CommandResult["InvalidDataValidationCriterionValue"] = "InvalidDataValidationCriterionValue";
6608
- CommandResult["InvalidNumberOfCriterionValues"] = "InvalidNumberOfCriterionValues";
6609
- CommandResult["InvalidCopyPasteSelection"] = "InvalidCopyPasteSelection";
6610
- CommandResult["NoChanges"] = "NoChanges";
6611
- CommandResult["InvalidInputId"] = "InvalidInputId";
6612
- CommandResult["SheetIsHidden"] = "SheetIsHidden";
6613
- CommandResult["InvalidTableResize"] = "InvalidTableResize";
6614
- CommandResult["PivotIdNotFound"] = "PivotIdNotFound";
6615
- CommandResult["PivotIdTaken"] = "PivotIdTaken";
6616
- CommandResult["PivotInError"] = "PivotInError";
6617
- CommandResult["EmptyName"] = "EmptyName";
6618
- CommandResult["ValueCellIsInvalidFormula"] = "ValueCellIsInvalidFormula";
6619
- CommandResult["InvalidDefinition"] = "InvalidDefinition";
6620
- CommandResult["InvalidColor"] = "InvalidColor";
6621
- CommandResult["InvalidPivotDataSet"] = "InvalidPivotDataSet";
6622
- CommandResult["InvalidPivotCustomField"] = "InvalidPivotCustomField";
6623
- CommandResult["MissingFigureArguments"] = "MissingFigureArguments";
6624
- CommandResult["InvalidCarouselItem"] = "InvalidCarouselItem";
6625
- })(CommandResult || (CommandResult = {}));
6626
-
6627
- /**
6628
- * BasePlugin
6629
- *
6630
- * Since the spreadsheet internal state is quite complex, it is split into
6631
- * multiple parts, each managing a specific concern.
6632
- *
6633
- * This file introduces the BasePlugin, which is the common class that defines
6634
- * how each of these model sub parts should interact with each other.
6635
- * There are two kinds of plugins: core plugins handling persistent data
6636
- * and UI plugins handling transient data.
6637
- */
6638
- class BasePlugin {
6639
- static getters = [];
6640
- history;
6641
- constructor(stateObserver) {
6642
- this.history = Object.assign(Object.create(stateObserver), {
6643
- update: stateObserver.addChange.bind(stateObserver, this),
6644
- selectCell: () => { },
6645
- });
6646
- }
6647
- /**
6648
- * Export for excel should be available for all plugins, even for the UI.
6649
- * In some cases, we need to export evaluated value, which is available from
6650
- * UI plugin only.
6651
- */
6652
- exportForExcel(data) { }
6653
- // ---------------------------------------------------------------------------
6654
- // Command handling
6655
- // ---------------------------------------------------------------------------
6656
- /**
6657
- * Before a command is accepted, the model will ask each plugin if the command
6658
- * is allowed. If all of them return true, then we can proceed. Otherwise,
6659
- * the command is cancelled.
6660
- *
6661
- * There should not be any side effects in this method.
6662
- */
6663
- allowDispatch(command) {
6664
- return "Success" /* CommandResult.Success */;
6665
- }
6666
- /**
6667
- * This method is useful when a plugin needs to perform some action before a
6668
- * command is handled in another plugin. This should only be used if it is not
6669
- * possible to do the work in the handle method.
6670
- */
6671
- beforeHandle(command) { }
6672
- /**
6673
- * This is the standard place to handle any command. Most of the plugin
6674
- * command handling work should take place here.
6675
- */
6676
- handle(command) { }
6677
- /**
6678
- * Sometimes, it is useful to perform some work after a command (and all its
6679
- * subcommands) has been completely handled. For example, when we paste
6680
- * multiple cells, we only want to reevaluate the cell values once at the end.
6681
- */
6682
- finalize() { }
6683
- /**
6684
- * Combine multiple validation functions into a single function
6685
- * returning the list of results of every validation.
6686
- */
6687
- batchValidations(...validations) {
6688
- return (toValidate) => validations.map((validation) => validation.call(this, toValidate)).flat();
6689
- }
6690
- /**
6691
- * Combine multiple validation functions. Every validation is executed one after
6692
- * the other. As soon as one validation fails, it stops and the cancelled reason
6693
- * is returned.
6694
- */
6695
- chainValidations(...validations) {
6696
- return (toValidate) => {
6697
- for (const validation of validations) {
6698
- let results = validation.call(this, toValidate);
6699
- if (!Array.isArray(results)) {
6700
- results = [results];
6701
- }
6702
- const cancelledReasons = results.filter((result) => result !== "Success" /* CommandResult.Success */);
6703
- if (cancelledReasons.length) {
6704
- return cancelledReasons;
6705
- }
6706
- }
6707
- return "Success" /* CommandResult.Success */;
6708
- };
6709
- }
6710
- checkValidations(command, ...validations) {
6711
- return this.batchValidations(...validations)(command);
6712
- }
6713
- }
6714
-
6715
- /**
6716
- * UI plugins handle any transient data required to display a spreadsheet.
6717
- * They can draw on the grid canvas.
6718
- */
6719
- class UIPlugin extends BasePlugin {
6720
- static layers = [];
6721
- getters;
6722
- ui;
6723
- selection;
6724
- dispatch;
6725
- canDispatch;
6726
- constructor({ getters, stateObserver, dispatch, canDispatch, uiActions, selection, }) {
6727
- super(stateObserver);
6728
- this.getters = getters;
6729
- this.ui = uiActions;
6730
- this.selection = selection;
6731
- this.dispatch = dispatch;
6732
- this.canDispatch = canDispatch;
6733
- }
6734
- // ---------------------------------------------------------------------------
6735
- // Grid rendering
6736
- // ---------------------------------------------------------------------------
6737
- drawLayer(ctx, layer) { }
6738
- }
6739
-
6740
- class SubtotalEvaluationPlugin extends UIPlugin {
6741
- subtotalCells = new Set();
6742
- handle(cmd) {
6743
- switch (cmd.type) {
6744
- case "START": {
6745
- this.subtotalCells.clear();
6746
- for (const sheetId of this.getters.getSheetIds()) {
6747
- const cells = this.getters.getCells(sheetId);
6748
- for (const cellId in cells) {
6749
- const cell = cells[cellId];
6750
- if (isSubtotalCell(cell)) {
6751
- this.subtotalCells.add(cell.id);
6752
- }
6753
- }
6754
- }
6755
- break;
6756
- }
6757
- case "UPDATE_CELL": {
6758
- if (!("content" in cmd))
6759
- return;
6760
- const cell = this.getters.getCell(cmd);
6761
- if (!cell)
6762
- return;
6763
- if (isSubtotalCell(cell)) {
6764
- this.subtotalCells.add(cell.id);
6765
- }
6766
- else {
6767
- this.subtotalCells.delete(cell.id);
6768
- }
6769
- break;
6770
- }
6771
- }
6772
- if (invalidSubtotalFormulasCommands.has(cmd.type)) {
6773
- this.dispatch("EVALUATE_CELLS", { cellIds: Array.from(this.subtotalCells) });
6774
- }
6775
- }
6776
- }
6777
- function isSubtotalCell(cell) {
6778
- return (cell.isFormula &&
6779
- cell.compiledFormula.tokens.some((t) => t.type === "SYMBOL" && t.value.toUpperCase() === "SUBTOTAL"));
6780
- }
6781
-
6782
6315
  function sum(values, locale) {
6783
6316
  return reduceNumbers(values, (acc, a) => acc + a, 0, locale);
6784
6317
  }
@@ -7856,19 +7389,22 @@
7856
7389
  const ref0 = ref[0][0];
7857
7390
  const sheetName = splitReference(ref0.value).sheetName;
7858
7391
  const sheetId = sheetName ? this.getters.getSheetIdByName(sheetName) : this.__originSheetId;
7859
- if (!sheetId)
7392
+ if (!sheetId) {
7860
7393
  continue;
7394
+ }
7861
7395
  const { top, left } = toZone(ref0.value);
7862
7396
  const right = left + ref.length - 1;
7863
7397
  const bottom = top + ref[0].length - 1;
7864
7398
  for (let row = top; row <= bottom; row++) {
7865
- if (this.getters.isRowFiltered(sheetId, row))
7399
+ if (this.getters.isRowFiltered(sheetId, row)) {
7866
7400
  continue;
7867
- if (!acceptHiddenCells && this.getters.isRowHiddenByUser(sheetId, row))
7401
+ }
7402
+ if (!acceptHiddenCells && this.getters.isRowHiddenByUser(sheetId, row)) {
7868
7403
  continue;
7404
+ }
7869
7405
  for (let col = left; col <= right; col++) {
7870
7406
  const cell = this.getters.getCorrespondingFormulaCell({ sheetId, col, row });
7871
- if (!cell || !isSubtotalCell(cell)) {
7407
+ if (!cell || !doesCellContainFunction(cell, "SUBTOTAL")) {
7872
7408
  evaluatedCellToKeep.push(this.getters.getEvaluatedCell({ sheetId, col, row }));
7873
7409
  }
7874
7410
  }
@@ -9779,7 +9315,7 @@
9779
9315
  * formulas.
9780
9316
  */
9781
9317
  const POSTFIX_UNARY_OPERATORS = ["%"];
9782
- const OPERATORS = "+,-,*,/,:,=,<>,>=,>,<=,<,^,&".split(",").concat(POSTFIX_UNARY_OPERATORS);
9318
+ const OPERATORS = "+,-,*,/,:,=,<>,>=,>,<=,<,^,&,#".split(",").concat(POSTFIX_UNARY_OPERATORS);
9783
9319
  function tokenize(str, locale = DEFAULT_LOCALE) {
9784
9320
  str = replaceNewLines(str);
9785
9321
  const chars = new TokenizingChars(str);
@@ -9794,10 +9330,10 @@
9794
9330
  tokenizeArgsSeparator(chars, locale) ||
9795
9331
  tokenizeBraces(chars) ||
9796
9332
  tokenizeParenthesis(chars) ||
9333
+ tokenizeInvalidRange(chars) ||
9797
9334
  tokenizeOperator(chars) ||
9798
9335
  tokenizeString(chars) ||
9799
9336
  tokenizeDebugger(chars) ||
9800
- tokenizeInvalidRange(chars) ||
9801
9337
  tokenizeNumber(chars, locale) ||
9802
9338
  tokenizeSymbol(chars);
9803
9339
  if (!token) {
@@ -11422,8 +10958,9 @@
11422
10958
  }
11423
10959
  result.push(row.data);
11424
10960
  }
11425
- if (!result.length)
10961
+ if (!result.length) {
11426
10962
  return new EvaluationError(_t("No unique values found"));
10963
+ }
11427
10964
  return _byColumn ? result : transposeMatrix(result);
11428
10965
  },
11429
10966
  isExported: true,
@@ -12355,10 +11892,12 @@
12355
11892
  let negative = false;
12356
11893
  const amounts = [];
12357
11894
  visitNumbers([cashFlowAmounts], ({ value: amount }) => {
12358
- if (amount > 0)
11895
+ if (amount > 0) {
12359
11896
  positive = true;
12360
- if (amount < 0)
11897
+ }
11898
+ if (amount < 0) {
12361
11899
  negative = true;
11900
+ }
12362
11901
  amounts.push(amount);
12363
11902
  }, this.locale);
12364
11903
  if (!positive || !negative) {
@@ -12669,8 +12208,9 @@
12669
12208
  throw new EvaluationError(expectPeriodBetweenOneAndNumberOfPeriods(n));
12670
12209
  }
12671
12210
  const payment = pmt(r, n, pValue, fValue, t);
12672
- if (t === 1 && per === 1)
12211
+ if (t === 1 && per === 1) {
12673
12212
  return payment;
12213
+ }
12674
12214
  const eqPeriod = t === 0 ? per - 1 : per - 2;
12675
12215
  const eqPv = pValue + payment * t;
12676
12216
  const capitalAtPeriod = -fv(r, eqPeriod, payment, eqPv, 0);
@@ -13303,8 +12843,9 @@
13303
12843
  if (_factor <= 0) {
13304
12844
  return new EvaluationError(expectDeprecationFactorStrictlyPositive(_factor));
13305
12845
  }
13306
- if (_cost === 0)
12846
+ if (_cost === 0) {
13307
12847
  return 0;
12848
+ }
13308
12849
  if (_salvage >= _cost) {
13309
12850
  return _startPeriod < 1 ? _cost - _salvage : 0;
13310
12851
  }
@@ -13369,10 +12910,12 @@
13369
12910
  const map = new Map();
13370
12911
  for (const i of range(0, _dates.length)) {
13371
12912
  const date = _dates[i];
13372
- if (map.has(date))
12913
+ if (map.has(date)) {
13373
12914
  map.set(date, map.get(date) + _cashFlows[i]);
13374
- else
12915
+ }
12916
+ else {
13375
12917
  map.set(date, _cashFlows[i]);
12918
+ }
13376
12919
  }
13377
12920
  const dates = Array.from(map.keys());
13378
12921
  const values = dates.map((date) => map.get(date));
@@ -13410,8 +12953,9 @@
13410
12953
  };
13411
12954
  const nanFallback = (previousFallback) => {
13412
12955
  // -0.9 => -0.99 => -0.999 => ...
13413
- if (!previousFallback)
12956
+ if (!previousFallback) {
13414
12957
  return -0.9;
12958
+ }
13415
12959
  return previousFallback / 10 - 0.9;
13416
12960
  };
13417
12961
  return newtonMethod(func, derivFunc, guess, 40, 1e-5, nanFallback);
@@ -13445,16 +12989,19 @@
13445
12989
  if (rate <= 0) {
13446
12990
  return new EvaluationError(expectRateStrictlyPositive(rate));
13447
12991
  }
13448
- if (_cashFlows.length === 1)
12992
+ if (_cashFlows.length === 1) {
13449
12993
  return _cashFlows[0];
12994
+ }
13450
12995
  // aggregate values of the same date
13451
12996
  const map = new Map();
13452
12997
  for (const i of range(0, _dates.length)) {
13453
12998
  const date = _dates[i];
13454
- if (map.has(date))
12999
+ if (map.has(date)) {
13455
13000
  map.set(date, map.get(date) + _cashFlows[i]);
13456
- else
13001
+ }
13002
+ else {
13457
13003
  map.set(date, _cashFlows[i]);
13004
+ }
13458
13005
  }
13459
13006
  const dates = Array.from(map.keys());
13460
13007
  const values = dates.map((date) => map.get(date));
@@ -14739,6 +14286,10 @@
14739
14286
  displayMeasuresRow: true,
14740
14287
  numberOfRows: Number.MAX_VALUE,
14741
14288
  numberOfColumns: Number.MAX_VALUE,
14289
+ tableStyleId: "None",
14290
+ bandedRows: false,
14291
+ bandedColumns: false,
14292
+ hasFilters: false,
14742
14293
  };
14743
14294
  const AGGREGATOR_NAMES = {
14744
14295
  count: _t("Count"),
@@ -15052,7 +14603,17 @@
15052
14603
  const displayMeasuresRow = includeMeasuresRowArg !== undefined
15053
14604
  ? toBoolean(includeMeasuresRowArg)
15054
14605
  : style?.displayMeasuresRow ?? DEFAULT_PIVOT_STYLE.displayMeasuresRow;
15055
- return { numberOfRows, numberOfColumns, displayTotals, displayColumnHeaders, displayMeasuresRow };
14606
+ return {
14607
+ numberOfRows,
14608
+ numberOfColumns,
14609
+ displayTotals,
14610
+ displayColumnHeaders,
14611
+ displayMeasuresRow,
14612
+ tableStyleId: style?.tableStyleId || DEFAULT_PIVOT_STYLE.tableStyleId,
14613
+ bandedRows: style?.bandedRows ?? DEFAULT_PIVOT_STYLE.bandedRows,
14614
+ bandedColumns: style?.bandedColumns ?? DEFAULT_PIVOT_STYLE.bandedColumns,
14615
+ hasFilters: style?.hasFilters ?? DEFAULT_PIVOT_STYLE.hasFilters,
14616
+ };
15056
14617
  }
15057
14618
 
15058
14619
  /**
@@ -15077,9 +14638,10 @@
15077
14638
  throw new EvaluationError(_t("Function PIVOT takes an even number of arguments."));
15078
14639
  }
15079
14640
  }
15080
- function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
14641
+ function addPivotDependencies(evalContext, pivotId, forMeasures) {
15081
14642
  //TODO This function can be very costly when used with PIVOT.VALUE and PIVOT.HEADER
15082
14643
  const dependencies = [];
14644
+ const coreDefinition = evalContext.getters.getPivotCoreDefinition(pivotId);
15083
14645
  if (coreDefinition.type === "SPREADSHEET" && coreDefinition.dataSet) {
15084
14646
  const { sheetId, zone } = coreDefinition.dataSet;
15085
14647
  const xc = zoneToXc(zone);
@@ -15096,8 +14658,7 @@
15096
14658
  }
15097
14659
  for (const measure of forMeasures) {
15098
14660
  if (measure.computedBy) {
15099
- const formula = evalContext.getters.getMeasureCompiledFormula(measure);
15100
- dependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
14661
+ dependencies.push(...evalContext.getters.getMeasureFullDependencies(pivotId, measure));
15101
14662
  }
15102
14663
  }
15103
14664
  const originPosition = evalContext.__originCellPosition;
@@ -15594,7 +15155,7 @@
15594
15155
  assertDomainLength(domainArgs);
15595
15156
  const pivot = this.getters.getPivot(pivotId);
15596
15157
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
15597
- addPivotDependencies(this, coreDefinition, coreDefinition.measures.filter((m) => m.id === _measure));
15158
+ addPivotDependencies(this, pivotId, coreDefinition.measures.filter((m) => m.id === _measure));
15598
15159
  pivot.init({ reload: pivot.needsReevaluation });
15599
15160
  const error = pivot.assertIsValid({ throwOnError: false });
15600
15161
  if (error) {
@@ -15627,8 +15188,7 @@
15627
15188
  const _pivotId = getPivotId(_pivotFormulaId, this.getters);
15628
15189
  assertDomainLength(domainArgs);
15629
15190
  const pivot = this.getters.getPivot(_pivotId);
15630
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
15631
- addPivotDependencies(this, coreDefinition, []);
15191
+ addPivotDependencies(this, _pivotId, []);
15632
15192
  pivot.init({ reload: pivot.needsReevaluation });
15633
15193
  const error = pivot.assertIsValid({ throwOnError: false });
15634
15194
  if (error) {
@@ -15680,7 +15240,7 @@
15680
15240
  if (pivotStyle.numberOfColumns < 0) {
15681
15241
  return new EvaluationError(_t("The number of columns must be positive."));
15682
15242
  }
15683
- addPivotDependencies(this, coreDefinition, coreDefinition.measures);
15243
+ addPivotDependencies(this, pivotId, coreDefinition.measures);
15684
15244
  pivot.init({ reload: pivot.needsReevaluation });
15685
15245
  const error = pivot.assertIsValid({ throwOnError: false });
15686
15246
  if (error) {
@@ -15691,23 +15251,19 @@
15691
15251
  return new EvaluationError(getPivotTooBigErrorMessage(table.numberOfCells, this.locale));
15692
15252
  }
15693
15253
  const cells = table.getPivotCells(pivotStyle);
15694
- let headerRows = 0;
15695
15254
  if (pivotStyle.displayColumnHeaders) {
15696
- headerRows = table.columns.length - 1;
15697
- }
15698
- if (pivotStyle.displayMeasuresRow) {
15699
- headerRows++;
15255
+ table.columns.length - 1;
15700
15256
  }
15257
+ if (pivotStyle.displayMeasuresRow) ;
15701
15258
  const pivotTitle = this.getters.getPivotName(pivotId);
15702
- const tableHeight = Math.min(headerRows + pivotStyle.numberOfRows, cells[0].length);
15703
- if (tableHeight === 0) {
15259
+ const { numberOfCols, numberOfRows } = table.getPivotTableDimensions(pivotStyle);
15260
+ if (numberOfRows === 0) {
15704
15261
  return [[{ value: pivotTitle }]];
15705
15262
  }
15706
- const tableWidth = Math.min(1 + pivotStyle.numberOfColumns, cells.length);
15707
15263
  const result = [];
15708
- for (const col of range(0, tableWidth)) {
15264
+ for (const col of range(0, numberOfCols)) {
15709
15265
  result[col] = [];
15710
- for (const row of range(0, tableHeight)) {
15266
+ for (const row of range(0, numberOfRows)) {
15711
15267
  const pivotCell = cells[col][row];
15712
15268
  switch (pivotCell.type) {
15713
15269
  case "EMPTY":
@@ -16189,6 +15745,58 @@
16189
15745
  },
16190
15746
  };
16191
15747
  // -----------------------------------------------------------------------------
15748
+ // SPILLED_RANGE
15749
+ // -----------------------------------------------------------------------------
15750
+ /**
15751
+ * Internal formula implementing the # operator.
15752
+ * It allows to get the spilled range of an array formula from any reference, including
15753
+ * references returned by other functions.
15754
+ * e.g. =IF(condition, A1, H10)#
15755
+ **/
15756
+ const SPILLED_RANGE = {
15757
+ description: _t("Gets the spilled range of an array formula."),
15758
+ args: [arg("ref (meta , range<meta>)", _t("The reference to get the spilled range from."))],
15759
+ compute: function (ref) {
15760
+ if (ref === undefined) {
15761
+ return new EvaluationError(_t("The range is out of bounds."));
15762
+ }
15763
+ if (ref.length !== 1 || ref[0].length !== 1) {
15764
+ return new EvaluationError(_t("Only single-cell references are allowed to get the spilled range."));
15765
+ }
15766
+ const _ref = ref[0][0];
15767
+ if (isEvaluationError(_ref.value)) {
15768
+ return _ref;
15769
+ }
15770
+ const initialRange = this.getters.getRangeFromSheetXC(this.__originSheetId, _ref.value);
15771
+ const cellPosition = {
15772
+ col: initialRange.zone.left,
15773
+ row: initialRange.zone.top,
15774
+ sheetId: initialRange.sheetId,
15775
+ };
15776
+ const originPosition = this.__originCellPosition;
15777
+ if (originPosition) {
15778
+ // The following line is used to reset the dependencies of the cell, to avoid
15779
+ // keeping dependencies from previous evaluation (i.e. in case the reference
15780
+ // has been changed).
15781
+ this.updateDependencies?.(originPosition);
15782
+ }
15783
+ const spilledZone = this.getters.getSpreadZone(cellPosition);
15784
+ if (spilledZone === undefined) {
15785
+ return new InvalidReferenceError();
15786
+ }
15787
+ const spilledRange = this.getters.getRangeFromZone(initialRange.sheetId, spilledZone);
15788
+ if (originPosition) {
15789
+ this.addDependencies?.(originPosition, [spilledRange]);
15790
+ }
15791
+ return generateMatrix(spilledZone.right - spilledZone.left + 1, spilledZone.bottom - spilledZone.top + 1, (col, row) => this.getters.getEvaluatedCell({
15792
+ sheetId: spilledRange.sheetId,
15793
+ col: spilledZone.left + col,
15794
+ row: spilledZone.top + row,
15795
+ }));
15796
+ },
15797
+ hidden: true,
15798
+ };
15799
+ // -----------------------------------------------------------------------------
16192
15800
  // UMINUS
16193
15801
  // -----------------------------------------------------------------------------
16194
15802
  const UMINUS = {
@@ -16238,6 +15846,7 @@
16238
15846
  MULTIPLY: MULTIPLY,
16239
15847
  NE: NE,
16240
15848
  POW: POW,
15849
+ SPILLED_RANGE: SPILLED_RANGE,
16241
15850
  UMINUS: UMINUS,
16242
15851
  UNARY_PERCENT: UNARY_PERCENT,
16243
15852
  UPLUS: UPLUS
@@ -16496,8 +16105,9 @@
16496
16105
  }
16497
16106
  function getTransformation(key) {
16498
16107
  for (const [prefix, value] of Object.entries(UNIT_PREFIXES)) {
16499
- if (prefix && !key.startsWith(prefix))
16108
+ if (prefix && !key.startsWith(prefix)) {
16500
16109
  continue;
16110
+ }
16501
16111
  const _key = key.slice(prefix.length);
16502
16112
  let conversion = UNITS[_key];
16503
16113
  if (!conversion && UNITS_ALIASES[_key]) {
@@ -17232,8 +16842,9 @@
17232
16842
  compute: function (url, linkLabel) {
17233
16843
  const processedUrl = toString(url).trim();
17234
16844
  const processedLabel = toString(linkLabel) || processedUrl;
17235
- if (processedUrl === "")
16845
+ if (processedUrl === "") {
17236
16846
  return processedLabel;
16847
+ }
17237
16848
  return markdownLink(processedLabel, processedUrl);
17238
16849
  },
17239
16850
  isExported: true,
@@ -17437,7 +17048,7 @@
17437
17048
 
17438
17049
  const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
17439
17050
  const UNARY_OPERATORS_PREFIX = ["-", "+"];
17440
- const UNARY_OPERATORS_POSTFIX = ["%"];
17051
+ const UNARY_OPERATORS_POSTFIX = ["%", "#"];
17441
17052
  class TokenList {
17442
17053
  tokens;
17443
17054
  currentIndex = 0;
@@ -17458,6 +17069,7 @@
17458
17069
  }
17459
17070
  }
17460
17071
  const OP_PRIORITY = {
17072
+ "#": 40,
17461
17073
  "%": 40,
17462
17074
  "^": 30,
17463
17075
  "*": 20,
@@ -17804,6 +17416,7 @@
17804
17416
  "-": "UMINUS",
17805
17417
  "+": "UPLUS",
17806
17418
  "%": "UNARY.PERCENT",
17419
+ "#": "SPILLED.RANGE",
17807
17420
  };
17808
17421
  // this cache contains all compiled function code, grouped by "structure". For
17809
17422
  // example, "=2*sum(A1:A4)" and "=2*sum(B1:B4)" are compiled into the same
@@ -17944,7 +17557,10 @@
17944
17557
  }
17945
17558
  case "UNARY_OPERATION": {
17946
17559
  const fnName = UNARY_OPERATOR_MAP[ast.value];
17947
- const operand = compileAST(ast.operand, false, false).assignResultToVariable();
17560
+ const { isMeta, hasRange } = ast.value === "#"
17561
+ ? { isMeta: true, hasRange: true } // hasRange is true to avoid vectorization of SPILLED.RANGE
17562
+ : { isMeta: false, hasRange: false };
17563
+ const operand = compileAST(ast.operand, isMeta, hasRange).assignResultToVariable();
17948
17564
  code.append(operand);
17949
17565
  return code.return(`ctx['${fnName}'](${operand.returnExpression})`);
17950
17566
  }
@@ -18683,6 +18299,359 @@
18683
18299
  }
18684
18300
  const specificRangeTransformRegistry = new SpecificRangeTransformRegistry();
18685
18301
 
18302
+ function isSheetDependent(cmd) {
18303
+ return "sheetId" in cmd;
18304
+ }
18305
+ function isHeadersDependant(cmd) {
18306
+ return "dimension" in cmd && "sheetId" in cmd && "elements" in cmd;
18307
+ }
18308
+ function isTargetDependent(cmd) {
18309
+ return "target" in cmd && "sheetId" in cmd;
18310
+ }
18311
+ function isRangeDependant(cmd) {
18312
+ return "ranges" in cmd;
18313
+ }
18314
+ function isPositionDependent(cmd) {
18315
+ return "col" in cmd && "row" in cmd && "sheetId" in cmd;
18316
+ }
18317
+ function isZoneDependent(cmd) {
18318
+ return "sheetId" in cmd && "zone" in cmd;
18319
+ }
18320
+ const invalidateEvaluationCommands = new Set([
18321
+ "RENAME_SHEET",
18322
+ "DELETE_SHEET",
18323
+ "CREATE_SHEET",
18324
+ "DUPLICATE_SHEET",
18325
+ "ADD_COLUMNS_ROWS",
18326
+ "REMOVE_COLUMNS_ROWS",
18327
+ "UNDO",
18328
+ "REDO",
18329
+ "ADD_MERGE",
18330
+ "REMOVE_MERGE",
18331
+ "UPDATE_LOCALE",
18332
+ "ADD_PIVOT",
18333
+ "UPDATE_PIVOT",
18334
+ "INSERT_PIVOT",
18335
+ "RENAME_PIVOT",
18336
+ "REMOVE_PIVOT",
18337
+ "DUPLICATE_PIVOT",
18338
+ ]);
18339
+ const invalidateChartEvaluationCommands = new Set([
18340
+ "EVALUATE_CELLS",
18341
+ "EVALUATE_CHARTS",
18342
+ "UPDATE_CELL",
18343
+ "UNHIDE_COLUMNS_ROWS",
18344
+ "HIDE_COLUMNS_ROWS",
18345
+ "GROUP_HEADERS",
18346
+ "SET_FORMATTING",
18347
+ "CLEAR_FORMATTING",
18348
+ "UNGROUP_HEADERS",
18349
+ "FOLD_ALL_HEADER_GROUPS",
18350
+ "FOLD_HEADER_GROUP",
18351
+ "FOLD_HEADER_GROUPS_IN_ZONE",
18352
+ "UNFOLD_ALL_HEADER_GROUPS",
18353
+ "UNFOLD_HEADER_GROUP",
18354
+ "UNFOLD_HEADER_GROUPS_IN_ZONE",
18355
+ "UPDATE_TABLE",
18356
+ "UPDATE_FILTER",
18357
+ "UNDO",
18358
+ "REDO",
18359
+ ]);
18360
+ const invalidateDependenciesCommands = new Set(["MOVE_RANGES"]);
18361
+ const invalidateCFEvaluationCommands = new Set([
18362
+ "EVALUATE_CELLS",
18363
+ "ADD_CONDITIONAL_FORMAT",
18364
+ "REMOVE_CONDITIONAL_FORMAT",
18365
+ "CHANGE_CONDITIONAL_FORMAT_PRIORITY",
18366
+ ]);
18367
+ const invalidateBordersCommands = new Set([
18368
+ "AUTOFILL_CELL",
18369
+ "SET_BORDER",
18370
+ "SET_ZONE_BORDERS",
18371
+ "SET_BORDERS_ON_TARGET",
18372
+ ]);
18373
+ const invalidSubtotalFormulasCommands = new Set([
18374
+ "UNHIDE_COLUMNS_ROWS",
18375
+ "HIDE_COLUMNS_ROWS",
18376
+ "GROUP_HEADERS",
18377
+ "UNGROUP_HEADERS",
18378
+ "FOLD_ALL_HEADER_GROUPS",
18379
+ "FOLD_HEADER_GROUP",
18380
+ "FOLD_HEADER_GROUPS_IN_ZONE",
18381
+ "UNFOLD_ALL_HEADER_GROUPS",
18382
+ "UNFOLD_HEADER_GROUP",
18383
+ "UNFOLD_HEADER_GROUPS_IN_ZONE",
18384
+ "UPDATE_TABLE",
18385
+ "UPDATE_FILTER",
18386
+ ]);
18387
+ const readonlyAllowedCommands = new Set([
18388
+ "START",
18389
+ "ACTIVATE_SHEET",
18390
+ "COPY",
18391
+ "RESIZE_SHEETVIEW",
18392
+ "SET_VIEWPORT_OFFSET",
18393
+ "SET_ZOOM",
18394
+ "EVALUATE_CELLS",
18395
+ "EVALUATE_CHARTS",
18396
+ "SET_FORMULA_VISIBILITY",
18397
+ "UPDATE_FILTER",
18398
+ "UPDATE_CHART",
18399
+ "UPDATE_CAROUSEL_ACTIVE_ITEM",
18400
+ "UPDATE_PIVOT",
18401
+ ]);
18402
+ const coreTypes = new Set([
18403
+ /** CELLS */
18404
+ "UPDATE_CELL",
18405
+ "UPDATE_CELL_POSITION",
18406
+ "CLEAR_CELL",
18407
+ "CLEAR_CELLS",
18408
+ "DELETE_CONTENT",
18409
+ /** GRID SHAPE */
18410
+ "ADD_COLUMNS_ROWS",
18411
+ "REMOVE_COLUMNS_ROWS",
18412
+ "RESIZE_COLUMNS_ROWS",
18413
+ "HIDE_COLUMNS_ROWS",
18414
+ "UNHIDE_COLUMNS_ROWS",
18415
+ "SET_GRID_LINES_VISIBILITY",
18416
+ "UNFREEZE_COLUMNS",
18417
+ "UNFREEZE_ROWS",
18418
+ "FREEZE_COLUMNS",
18419
+ "FREEZE_ROWS",
18420
+ "UNFREEZE_COLUMNS_ROWS",
18421
+ /** MERGE */
18422
+ "ADD_MERGE",
18423
+ "REMOVE_MERGE",
18424
+ /** SHEETS MANIPULATION */
18425
+ "CREATE_SHEET",
18426
+ "DELETE_SHEET",
18427
+ "DUPLICATE_SHEET",
18428
+ "MOVE_SHEET",
18429
+ "RENAME_SHEET",
18430
+ "COLOR_SHEET",
18431
+ "HIDE_SHEET",
18432
+ "SHOW_SHEET",
18433
+ /** RANGES MANIPULATION */
18434
+ "MOVE_RANGES",
18435
+ /** CONDITIONAL FORMAT */
18436
+ "ADD_CONDITIONAL_FORMAT",
18437
+ "REMOVE_CONDITIONAL_FORMAT",
18438
+ "CHANGE_CONDITIONAL_FORMAT_PRIORITY",
18439
+ /** FIGURES */
18440
+ "CREATE_FIGURE",
18441
+ "DELETE_FIGURE",
18442
+ "UPDATE_FIGURE",
18443
+ "CREATE_CAROUSEL",
18444
+ "UPDATE_CAROUSEL",
18445
+ /** FORMATTING */
18446
+ "SET_FORMATTING",
18447
+ "CLEAR_FORMATTING",
18448
+ "SET_BORDER",
18449
+ "SET_ZONE_BORDERS",
18450
+ "SET_BORDERS_ON_TARGET",
18451
+ /** CHART */
18452
+ "CREATE_CHART",
18453
+ "UPDATE_CHART",
18454
+ "DELETE_CHART",
18455
+ /** FILTERS */
18456
+ "CREATE_TABLE",
18457
+ "REMOVE_TABLE",
18458
+ "UPDATE_TABLE",
18459
+ "CREATE_TABLE_STYLE",
18460
+ "REMOVE_TABLE_STYLE",
18461
+ /** IMAGE */
18462
+ "CREATE_IMAGE",
18463
+ /** HEADER GROUP */
18464
+ "GROUP_HEADERS",
18465
+ "UNGROUP_HEADERS",
18466
+ "UNFOLD_HEADER_GROUP",
18467
+ "FOLD_HEADER_GROUP",
18468
+ "FOLD_ALL_HEADER_GROUPS",
18469
+ "UNFOLD_ALL_HEADER_GROUPS",
18470
+ "UNFOLD_HEADER_GROUPS_IN_ZONE",
18471
+ "FOLD_HEADER_GROUPS_IN_ZONE",
18472
+ /** DATA VALIDATION */
18473
+ "ADD_DATA_VALIDATION_RULE",
18474
+ "REMOVE_DATA_VALIDATION_RULE",
18475
+ /** MISC */
18476
+ "UPDATE_LOCALE",
18477
+ /** PIVOT */
18478
+ "ADD_PIVOT",
18479
+ "UPDATE_PIVOT",
18480
+ "INSERT_PIVOT",
18481
+ "RENAME_PIVOT",
18482
+ "REMOVE_PIVOT",
18483
+ "DUPLICATE_PIVOT",
18484
+ ]);
18485
+ function isCoreCommand(cmd) {
18486
+ return coreTypes.has(cmd.type);
18487
+ }
18488
+ function canExecuteInReadonly(cmd) {
18489
+ return readonlyAllowedCommands.has(cmd.type);
18490
+ }
18491
+ /**
18492
+ * Holds the result of a command dispatch.
18493
+ * The command may have been successfully dispatched or cancelled
18494
+ * for one or more reasons.
18495
+ */
18496
+ class DispatchResult {
18497
+ reasons;
18498
+ constructor(results = []) {
18499
+ if (!Array.isArray(results)) {
18500
+ results = [results];
18501
+ }
18502
+ results = [...new Set(results)];
18503
+ this.reasons = results.filter((result) => result !== "Success" /* CommandResult.Success */);
18504
+ }
18505
+ /**
18506
+ * Static helper which returns a successful DispatchResult
18507
+ */
18508
+ static get Success() {
18509
+ return SUCCESS;
18510
+ }
18511
+ get isSuccessful() {
18512
+ return this.reasons.length === 0;
18513
+ }
18514
+ /**
18515
+ * Check if the dispatch has been cancelled because of
18516
+ * the given reason.
18517
+ */
18518
+ isCancelledBecause(reason) {
18519
+ return this.reasons.includes(reason);
18520
+ }
18521
+ }
18522
+ const SUCCESS = new DispatchResult();
18523
+ var CommandResult;
18524
+ (function (CommandResult) {
18525
+ CommandResult["Success"] = "Success";
18526
+ CommandResult["CancelledForUnknownReason"] = "CancelledForUnknownReason";
18527
+ CommandResult["WillRemoveExistingMerge"] = "WillRemoveExistingMerge";
18528
+ CommandResult["CannotMoveTableHeader"] = "CannotMoveTableHeader";
18529
+ CommandResult["MergeIsDestructive"] = "MergeIsDestructive";
18530
+ CommandResult["CellIsMerged"] = "CellIsMerged";
18531
+ CommandResult["InvalidTarget"] = "InvalidTarget";
18532
+ CommandResult["EmptyUndoStack"] = "EmptyUndoStack";
18533
+ CommandResult["EmptyRedoStack"] = "EmptyRedoStack";
18534
+ CommandResult["NotEnoughElements"] = "NotEnoughElements";
18535
+ CommandResult["NotEnoughSheets"] = "NotEnoughSheets";
18536
+ CommandResult["MissingSheetName"] = "MissingSheetName";
18537
+ CommandResult["UnchangedSheetName"] = "UnchangedSheetName";
18538
+ CommandResult["DuplicatedSheetName"] = "DuplicatedSheetName";
18539
+ CommandResult["DuplicatedSheetId"] = "DuplicatedSheetId";
18540
+ CommandResult["ForbiddenCharactersInSheetName"] = "ForbiddenCharactersInSheetName";
18541
+ CommandResult["WrongSheetMove"] = "WrongSheetMove";
18542
+ CommandResult["WrongSheetPosition"] = "WrongSheetPosition";
18543
+ CommandResult["InvalidAnchorZone"] = "InvalidAnchorZone";
18544
+ CommandResult["SelectionOutOfBound"] = "SelectionOutOfBound";
18545
+ CommandResult["TargetOutOfSheet"] = "TargetOutOfSheet";
18546
+ CommandResult["WrongCutSelection"] = "WrongCutSelection";
18547
+ CommandResult["WrongPasteSelection"] = "WrongPasteSelection";
18548
+ CommandResult["WrongPasteOption"] = "WrongPasteOption";
18549
+ CommandResult["WrongFigurePasteOption"] = "WrongFigurePasteOption";
18550
+ CommandResult["EmptyClipboard"] = "EmptyClipboard";
18551
+ CommandResult["EmptyRange"] = "EmptyRange";
18552
+ CommandResult["InvalidRange"] = "InvalidRange";
18553
+ CommandResult["InvalidZones"] = "InvalidZones";
18554
+ CommandResult["InvalidSheetId"] = "InvalidSheetId";
18555
+ CommandResult["InvalidCellId"] = "InvalidCellId";
18556
+ CommandResult["InvalidFigureId"] = "InvalidFigureId";
18557
+ CommandResult["InputAlreadyFocused"] = "InputAlreadyFocused";
18558
+ CommandResult["MaximumRangesReached"] = "MaximumRangesReached";
18559
+ CommandResult["MinimumRangesReached"] = "MinimumRangesReached";
18560
+ CommandResult["InvalidChartDefinition"] = "InvalidChartDefinition";
18561
+ CommandResult["InvalidDataSet"] = "InvalidDataSet";
18562
+ CommandResult["InvalidLabelRange"] = "InvalidLabelRange";
18563
+ CommandResult["InvalidScorecardKeyValue"] = "InvalidScorecardKeyValue";
18564
+ CommandResult["InvalidScorecardBaseline"] = "InvalidScorecardBaseline";
18565
+ CommandResult["InvalidGaugeDataRange"] = "InvalidGaugeDataRange";
18566
+ CommandResult["EmptyGaugeRangeMin"] = "EmptyGaugeRangeMin";
18567
+ CommandResult["GaugeRangeMinNaN"] = "GaugeRangeMinNaN";
18568
+ CommandResult["EmptyGaugeRangeMax"] = "EmptyGaugeRangeMax";
18569
+ CommandResult["GaugeRangeMaxNaN"] = "GaugeRangeMaxNaN";
18570
+ CommandResult["GaugeLowerInflectionPointNaN"] = "GaugeLowerInflectionPointNaN";
18571
+ CommandResult["GaugeUpperInflectionPointNaN"] = "GaugeUpperInflectionPointNaN";
18572
+ CommandResult["InvalidAutofillSelection"] = "InvalidAutofillSelection";
18573
+ CommandResult["MinBiggerThanMax"] = "MinBiggerThanMax";
18574
+ CommandResult["LowerBiggerThanUpper"] = "LowerBiggerThanUpper";
18575
+ CommandResult["MidBiggerThanMax"] = "MidBiggerThanMax";
18576
+ CommandResult["MinBiggerThanMid"] = "MinBiggerThanMid";
18577
+ CommandResult["FirstArgMissing"] = "FirstArgMissing";
18578
+ CommandResult["SecondArgMissing"] = "SecondArgMissing";
18579
+ CommandResult["MinNaN"] = "MinNaN";
18580
+ CommandResult["MidNaN"] = "MidNaN";
18581
+ CommandResult["MaxNaN"] = "MaxNaN";
18582
+ CommandResult["ValueUpperInflectionNaN"] = "ValueUpperInflectionNaN";
18583
+ CommandResult["ValueLowerInflectionNaN"] = "ValueLowerInflectionNaN";
18584
+ CommandResult["MinInvalidFormula"] = "MinInvalidFormula";
18585
+ CommandResult["MidInvalidFormula"] = "MidInvalidFormula";
18586
+ CommandResult["MaxInvalidFormula"] = "MaxInvalidFormula";
18587
+ CommandResult["ValueUpperInvalidFormula"] = "ValueUpperInvalidFormula";
18588
+ CommandResult["ValueLowerInvalidFormula"] = "ValueLowerInvalidFormula";
18589
+ CommandResult["InvalidSortAnchor"] = "InvalidSortAnchor";
18590
+ CommandResult["InvalidSortZone"] = "InvalidSortZone";
18591
+ CommandResult["SortZoneWithArrayFormulas"] = "SortZoneWithArrayFormulas";
18592
+ CommandResult["WaitingSessionConfirmation"] = "WaitingSessionConfirmation";
18593
+ CommandResult["MergeOverlap"] = "MergeOverlap";
18594
+ CommandResult["TooManyHiddenElements"] = "TooManyHiddenElements";
18595
+ CommandResult["Readonly"] = "Readonly";
18596
+ CommandResult["InvalidViewportSize"] = "InvalidViewportSize";
18597
+ CommandResult["InvalidScrollingDirection"] = "InvalidScrollingDirection";
18598
+ CommandResult["ViewportScrollLimitsReached"] = "ViewportScrollLimitsReached";
18599
+ CommandResult["FigureDoesNotExist"] = "FigureDoesNotExist";
18600
+ CommandResult["InvalidConditionalFormatId"] = "InvalidConditionalFormatId";
18601
+ CommandResult["InvalidCellPopover"] = "InvalidCellPopover";
18602
+ CommandResult["EmptyTarget"] = "EmptyTarget";
18603
+ CommandResult["InvalidFreezeQuantity"] = "InvalidFreezeQuantity";
18604
+ CommandResult["FrozenPaneOverlap"] = "FrozenPaneOverlap";
18605
+ CommandResult["ValuesNotChanged"] = "ValuesNotChanged";
18606
+ CommandResult["InvalidFilterZone"] = "InvalidFilterZone";
18607
+ CommandResult["TableNotFound"] = "TableNotFound";
18608
+ CommandResult["TableOverlap"] = "TableOverlap";
18609
+ CommandResult["InvalidTableConfig"] = "InvalidTableConfig";
18610
+ CommandResult["InvalidTableStyle"] = "InvalidTableStyle";
18611
+ CommandResult["FilterNotFound"] = "FilterNotFound";
18612
+ CommandResult["MergeInTable"] = "MergeInTable";
18613
+ CommandResult["NonContinuousTargets"] = "NonContinuousTargets";
18614
+ CommandResult["DuplicatedFigureId"] = "DuplicatedFigureId";
18615
+ CommandResult["InvalidSelectionStep"] = "InvalidSelectionStep";
18616
+ CommandResult["DuplicatedChartId"] = "DuplicatedChartId";
18617
+ CommandResult["ChartDoesNotExist"] = "ChartDoesNotExist";
18618
+ CommandResult["InvalidHeaderIndex"] = "InvalidHeaderIndex";
18619
+ CommandResult["InvalidQuantity"] = "InvalidQuantity";
18620
+ CommandResult["MoreThanOneColumnSelected"] = "MoreThanOneColumnSelected";
18621
+ CommandResult["EmptySplitSeparator"] = "EmptySplitSeparator";
18622
+ CommandResult["SplitWillOverwriteContent"] = "SplitWillOverwriteContent";
18623
+ CommandResult["NoSplitSeparatorInSelection"] = "NoSplitSeparatorInSelection";
18624
+ CommandResult["NoActiveSheet"] = "NoActiveSheet";
18625
+ CommandResult["InvalidLocale"] = "InvalidLocale";
18626
+ CommandResult["MoreThanOneRangeSelected"] = "MoreThanOneRangeSelected";
18627
+ CommandResult["NoColumnsProvided"] = "NoColumnsProvided";
18628
+ CommandResult["ColumnsNotIncludedInZone"] = "ColumnsNotIncludedInZone";
18629
+ CommandResult["DuplicatesColumnsSelected"] = "DuplicatesColumnsSelected";
18630
+ CommandResult["InvalidHeaderGroupStartEnd"] = "InvalidHeaderGroupStartEnd";
18631
+ CommandResult["HeaderGroupAlreadyExists"] = "HeaderGroupAlreadyExists";
18632
+ CommandResult["UnknownHeaderGroup"] = "UnknownHeaderGroup";
18633
+ CommandResult["UnknownDataValidationRule"] = "UnknownDataValidationRule";
18634
+ CommandResult["UnknownDataValidationCriterionType"] = "UnknownDataValidationCriterionType";
18635
+ CommandResult["InvalidDataValidationCriterionValue"] = "InvalidDataValidationCriterionValue";
18636
+ CommandResult["InvalidNumberOfCriterionValues"] = "InvalidNumberOfCriterionValues";
18637
+ CommandResult["InvalidCopyPasteSelection"] = "InvalidCopyPasteSelection";
18638
+ CommandResult["NoChanges"] = "NoChanges";
18639
+ CommandResult["InvalidInputId"] = "InvalidInputId";
18640
+ CommandResult["SheetIsHidden"] = "SheetIsHidden";
18641
+ CommandResult["InvalidTableResize"] = "InvalidTableResize";
18642
+ CommandResult["PivotIdNotFound"] = "PivotIdNotFound";
18643
+ CommandResult["PivotIdTaken"] = "PivotIdTaken";
18644
+ CommandResult["PivotInError"] = "PivotInError";
18645
+ CommandResult["EmptyName"] = "EmptyName";
18646
+ CommandResult["ValueCellIsInvalidFormula"] = "ValueCellIsInvalidFormula";
18647
+ CommandResult["InvalidDefinition"] = "InvalidDefinition";
18648
+ CommandResult["InvalidColor"] = "InvalidColor";
18649
+ CommandResult["InvalidPivotDataSet"] = "InvalidPivotDataSet";
18650
+ CommandResult["InvalidPivotCustomField"] = "InvalidPivotCustomField";
18651
+ CommandResult["MissingFigureArguments"] = "MissingFigureArguments";
18652
+ CommandResult["InvalidCarouselItem"] = "InvalidCarouselItem";
18653
+ })(CommandResult || (CommandResult = {}));
18654
+
18686
18655
  function transformZone(zone, executed) {
18687
18656
  if (executed.type === "REMOVE_COLUMNS_ROWS") {
18688
18657
  return reduceZoneOnDeletion(zone, executed.dimension === "COL" ? "left" : "top", executed.elements);
@@ -18835,16 +18804,21 @@
18835
18804
  let g = rgba.g.toString(16);
18836
18805
  let b = rgba.b.toString(16);
18837
18806
  let a = Math.round(rgba.a * 255).toString(16);
18838
- if (r.length === 1)
18807
+ if (r.length === 1) {
18839
18808
  r = "0" + r;
18840
- if (g.length === 1)
18809
+ }
18810
+ if (g.length === 1) {
18841
18811
  g = "0" + g;
18842
- if (b.length === 1)
18812
+ }
18813
+ if (b.length === 1) {
18843
18814
  b = "0" + b;
18844
- if (a.length === 1)
18815
+ }
18816
+ if (a.length === 1) {
18845
18817
  a = "0" + a;
18846
- if (a === "ff")
18818
+ }
18819
+ if (a === "ff") {
18847
18820
  a = "";
18821
+ }
18848
18822
  return ("#" + r + g + b + a).toUpperCase();
18849
18823
  }
18850
18824
  /**
@@ -18944,21 +18918,26 @@
18944
18918
  let l = 0;
18945
18919
  // Calculate hue
18946
18920
  // No difference
18947
- if (delta === 0)
18921
+ if (delta === 0) {
18948
18922
  h = 0;
18923
+ }
18949
18924
  // Red is max
18950
- else if (cMax === r)
18925
+ else if (cMax === r) {
18951
18926
  h = ((g - b) / delta) % 6;
18927
+ }
18952
18928
  // Green is max
18953
- else if (cMax === g)
18929
+ else if (cMax === g) {
18954
18930
  h = (b - r) / delta + 2;
18931
+ }
18955
18932
  // Blue is max
18956
- else
18933
+ else {
18957
18934
  h = (r - g) / delta + 4;
18935
+ }
18958
18936
  h = Math.round(h * 60);
18959
18937
  // Make negative hues positive behind 360°
18960
- if (h < 0)
18938
+ if (h < 0) {
18961
18939
  h += 360;
18940
+ }
18962
18941
  l = (cMax + cMin) / 2;
18963
18942
  // Calculate saturation
18964
18943
  s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
@@ -19289,12 +19268,6 @@
19289
19268
  return (r << 16) | (g << 8) | b;
19290
19269
  }
19291
19270
 
19292
- ({
19293
- light: _t("Light"),
19294
- medium: _t("Medium"),
19295
- dark: _t("Dark"),
19296
- custom: _t("Custom"),
19297
- });
19298
19271
  const DEFAULT_TABLE_CONFIG = {
19299
19272
  hasFilters: false,
19300
19273
  totalRow: false,
@@ -19306,6 +19279,11 @@
19306
19279
  automaticAutofill: true,
19307
19280
  styleId: "TableStyleMedium2",
19308
19281
  };
19282
+ const TABLE_STYLE_CATEGORIES = {
19283
+ light: _t("Light"),
19284
+ medium: _t("Medium"),
19285
+ dark: _t("Dark"),
19286
+ };
19309
19287
  function generateTableColorSet(name, highlightColor) {
19310
19288
  return {
19311
19289
  coloredText: darkenColor(highlightColor, 0.3),
@@ -19317,7 +19295,7 @@
19317
19295
  name,
19318
19296
  };
19319
19297
  }
19320
- const COLOR_SETS = {
19298
+ const TABLE_COLOR_SETS = {
19321
19299
  black: {
19322
19300
  name: _t("Black"),
19323
19301
  coloredText: "#000000",
@@ -19327,9 +19305,9 @@
19327
19305
  mediumBorder: "#000000",
19328
19306
  highlight: "#000000",
19329
19307
  },
19330
- lightBlue: generateTableColorSet(_t("Light blue"), "#346B90"),
19308
+ lightBlue: generateTableColorSet(_t("Blue"), "#346B90"),
19331
19309
  red: generateTableColorSet(_t("Red"), "#C53628"),
19332
- lightGreen: generateTableColorSet(_t("Light green"), "#748747"),
19310
+ lightGreen: generateTableColorSet(_t("Green"), "#748747"),
19333
19311
  purple: generateTableColorSet(_t("Purple"), "#6C4E65"),
19334
19312
  gray: {
19335
19313
  name: _t("Gray"),
@@ -19342,11 +19320,11 @@
19342
19320
  },
19343
19321
  orange: generateTableColorSet(_t("Orange"), "#C37034"),
19344
19322
  };
19345
- const DARK_COLOR_SETS = {
19346
- black: COLOR_SETS.black,
19347
- orangeBlue: { ...COLOR_SETS.lightBlue, highlight: COLOR_SETS.orange.highlight },
19348
- purpleGreen: { ...COLOR_SETS.lightGreen, highlight: COLOR_SETS.purple.highlight },
19349
- redBlue: { ...COLOR_SETS.lightBlue, highlight: COLOR_SETS.red.highlight },
19323
+ const DARK_TABLE_COLOR_SETS = {
19324
+ black: TABLE_COLOR_SETS.black,
19325
+ orangeBlue: { ...TABLE_COLOR_SETS.lightBlue, highlight: TABLE_COLOR_SETS.orange.highlight },
19326
+ purpleGreen: { ...TABLE_COLOR_SETS.lightGreen, highlight: TABLE_COLOR_SETS.purple.highlight },
19327
+ redBlue: { ...TABLE_COLOR_SETS.lightBlue, highlight: TABLE_COLOR_SETS.red.highlight },
19350
19328
  };
19351
19329
  const lightColoredText = (colorSet) => ({
19352
19330
  category: "light",
@@ -19359,9 +19337,17 @@
19359
19337
  bottom: { color: colorSet.highlight, style: "thin" },
19360
19338
  },
19361
19339
  },
19362
- headerRow: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
19363
- totalRow: { border: { top: { color: colorSet.highlight, style: "thin" } } },
19340
+ headerRow: {
19341
+ border: { bottom: { color: colorSet.highlight, style: "thin" } },
19342
+ style: { bold: true },
19343
+ },
19344
+ totalRow: {
19345
+ border: { top: { color: colorSet.highlight, style: "thin" } },
19346
+ style: { bold: true },
19347
+ },
19364
19348
  firstRowStripe: { style: { fillColor: colorSet.light } },
19349
+ firstColumn: { style: { bold: true } },
19350
+ lastColumn: { style: { bold: true } },
19365
19351
  });
19366
19352
  const lightWithHeader = (colorSet) => ({
19367
19353
  category: "light",
@@ -19376,12 +19362,17 @@
19376
19362
  },
19377
19363
  },
19378
19364
  headerRow: {
19379
- style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
19365
+ style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true },
19380
19366
  border: { bottom: { color: colorSet.highlight, style: "thin" } },
19381
19367
  },
19382
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
19368
+ totalRow: {
19369
+ border: { top: { color: colorSet.highlight, style: "medium" } }, // @compatibility: should be double line
19370
+ style: { bold: true },
19371
+ },
19383
19372
  firstRowStripe: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
19384
19373
  secondRowStripe: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
19374
+ firstColumn: { style: { bold: true } },
19375
+ lastColumn: { style: { bold: true } },
19385
19376
  });
19386
19377
  const lightAllBorders = (colorSet) => ({
19387
19378
  category: "light",
@@ -19397,10 +19388,18 @@
19397
19388
  vertical: { color: colorSet.highlight, style: "thin" },
19398
19389
  },
19399
19390
  },
19400
- headerRow: { border: { bottom: { color: colorSet.highlight, style: "medium" } } },
19401
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
19391
+ headerRow: {
19392
+ border: { bottom: { color: colorSet.highlight, style: "medium" } },
19393
+ style: { bold: true },
19394
+ },
19395
+ totalRow: {
19396
+ border: { top: { color: colorSet.highlight, style: "medium" } }, // @compatibility: should be double line
19397
+ style: { bold: true },
19398
+ },
19402
19399
  firstRowStripe: { style: { fillColor: colorSet.light } },
19403
19400
  firstColumnStripe: { style: { fillColor: colorSet.light } },
19401
+ firstColumn: { style: { bold: true } },
19402
+ lastColumn: { style: { bold: true } },
19404
19403
  });
19405
19404
  const mediumBandedBorders = (colorSet) => ({
19406
19405
  category: "medium",
@@ -19415,12 +19414,15 @@
19415
19414
  horizontal: { color: colorSet.mediumBorder, style: "thin" },
19416
19415
  },
19417
19416
  },
19418
- headerRow: {
19419
- style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
19417
+ headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19418
+ totalRow: {
19419
+ border: { top: { color: colorSet.highlight, style: "medium" } }, // @compatibility: should be double line
19420
+ style: { bold: true },
19420
19421
  },
19421
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
19422
19422
  firstRowStripe: { style: { fillColor: colorSet.light } },
19423
19423
  firstColumnStripe: { style: { fillColor: colorSet.light } },
19424
+ firstColumn: { style: { bold: true } },
19425
+ lastColumn: { style: { bold: true } },
19424
19426
  });
19425
19427
  const mediumWhiteBorders = (colorSet) => ({
19426
19428
  category: "medium",
@@ -19435,14 +19437,14 @@
19435
19437
  },
19436
19438
  headerRow: {
19437
19439
  border: { bottom: { color: "#FFFFFF", style: "thick" } },
19438
- style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
19440
+ style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true },
19439
19441
  },
19440
19442
  totalRow: {
19441
19443
  border: { top: { color: "#FFFFFF", style: "thick" } },
19442
- style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
19444
+ style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true },
19443
19445
  },
19444
- firstColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19445
- lastColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19446
+ firstColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19447
+ lastColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19446
19448
  firstRowStripe: { style: { fillColor: colorSet.medium } },
19447
19449
  firstColumnStripe: { style: { fillColor: colorSet.medium } },
19448
19450
  });
@@ -19456,15 +19458,18 @@
19456
19458
  bottom: { color: "#000000", style: "medium" },
19457
19459
  },
19458
19460
  },
19459
- totalRow: { border: { top: { color: "#000000", style: "medium" } } }, // @compatibility: should be double line
19461
+ totalRow: {
19462
+ border: { top: { color: "#000000", style: "medium" } }, // @compatibility: should be double line
19463
+ style: { bold: true },
19464
+ },
19460
19465
  headerRow: {
19461
- style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
19466
+ style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true },
19462
19467
  border: { bottom: { color: "#000000", style: "medium" } },
19463
19468
  },
19464
- firstColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19465
- lastColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19466
- firstRowStripe: { style: { fillColor: COLOR_SETS.black.light } },
19467
- firstColumnStripe: { style: { fillColor: COLOR_SETS.black.light } },
19469
+ firstColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19470
+ lastColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19471
+ firstRowStripe: { style: { fillColor: TABLE_COLOR_SETS.black.light } },
19472
+ firstColumnStripe: { style: { fillColor: TABLE_COLOR_SETS.black.light } },
19468
19473
  });
19469
19474
  const mediumAllBorders = (colorSet) => ({
19470
19475
  category: "medium",
@@ -19481,9 +19486,15 @@
19481
19486
  },
19482
19487
  style: { fillColor: colorSet.light },
19483
19488
  },
19484
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
19489
+ totalRow: {
19490
+ border: { top: { color: colorSet.highlight, style: "medium" } }, // @compatibility: should be double line
19491
+ style: { bold: true },
19492
+ },
19485
19493
  firstRowStripe: { style: { fillColor: colorSet.medium } },
19486
19494
  firstColumnStripe: { style: { fillColor: colorSet.medium } },
19495
+ firstColumn: { style: { bold: true } },
19496
+ lastColumn: { style: { bold: true } },
19497
+ headerRow: { style: { bold: true } },
19487
19498
  });
19488
19499
  const dark = (colorSet) => ({
19489
19500
  category: "dark",
@@ -19491,19 +19502,19 @@
19491
19502
  primaryColor: colorSet.highlight,
19492
19503
  wholeTable: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19493
19504
  totalRow: {
19494
- style: { fillColor: colorSet.dark, textColor: "#FFFFFF" },
19505
+ style: { fillColor: colorSet.dark, textColor: "#FFFFFF", bold: true },
19495
19506
  border: { top: { color: "#FFFFFF", style: "thick" } },
19496
19507
  },
19497
19508
  headerRow: {
19498
- style: { fillColor: "#000000" },
19509
+ style: { fillColor: "#000000", bold: true },
19499
19510
  border: { bottom: { color: "#FFFFFF", style: "thick" } },
19500
19511
  },
19501
19512
  firstColumn: {
19502
- style: { fillColor: colorSet.dark },
19513
+ style: { fillColor: colorSet.dark, bold: true },
19503
19514
  border: { right: { color: "#FFFFFF", style: "thick" } },
19504
19515
  },
19505
19516
  lastColumn: {
19506
- style: { fillColor: colorSet.dark },
19517
+ style: { fillColor: colorSet.dark, bold: true },
19507
19518
  border: { left: { color: "#FFFFFF", style: "thick" } },
19508
19519
  },
19509
19520
  firstRowStripe: { style: { fillColor: colorSet.dark } },
@@ -19514,14 +19525,19 @@
19514
19525
  templateName: "darkNoBorders",
19515
19526
  primaryColor: colorSet.highlight,
19516
19527
  wholeTable: { style: { fillColor: colorSet.light } },
19517
- totalRow: { border: { top: { color: "#000000", style: "medium" } } }, // @compatibility: should be double line
19518
- headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19528
+ totalRow: {
19529
+ border: { top: { color: "#000000", style: "medium" } }, // @compatibility: should be double line
19530
+ style: { bold: true },
19531
+ },
19532
+ headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19519
19533
  firstRowStripe: { style: { fillColor: colorSet.medium } },
19520
19534
  firstColumnStripe: { style: { fillColor: colorSet.medium } },
19535
+ firstColumn: { style: { bold: true } },
19536
+ lastColumn: { style: { bold: true } },
19521
19537
  });
19522
- const darkTemplateInBlack = dark(COLOR_SETS.black);
19538
+ const darkTemplateInBlack = dark(TABLE_COLOR_SETS.black);
19523
19539
  darkTemplateInBlack.wholeTable.style.fillColor = "#737373";
19524
- const mediumMinimalBordersInBlack = mediumMinimalBorders(COLOR_SETS.black);
19540
+ const mediumMinimalBordersInBlack = mediumMinimalBorders(TABLE_COLOR_SETS.black);
19525
19541
  mediumMinimalBordersInBlack.wholeTable.border = {
19526
19542
  ...mediumMinimalBordersInBlack.wholeTable.border,
19527
19543
  left: { color: "#000000", style: "thin" },
@@ -19533,67 +19549,67 @@
19533
19549
  return { ...template(colorSet), displayName: `${colorSet.name}, ${name}` };
19534
19550
  }
19535
19551
  const TABLE_PRESETS = {
19536
- None: { category: "light", templateName: "none", primaryColor: "", displayName: "none" },
19537
- TableStyleLight1: buildPreset("TableStyleLight1", lightColoredText, COLOR_SETS.black),
19538
- TableStyleLight2: buildPreset("TableStyleLight2", lightColoredText, COLOR_SETS.lightBlue),
19539
- TableStyleLight3: buildPreset("TableStyleLight3", lightColoredText, COLOR_SETS.red),
19540
- TableStyleLight4: buildPreset("TableStyleLight4", lightColoredText, COLOR_SETS.lightGreen),
19541
- TableStyleLight5: buildPreset("TableStyleLight5", lightColoredText, COLOR_SETS.purple),
19542
- TableStyleLight6: buildPreset("TableStyleLight6", lightColoredText, COLOR_SETS.gray),
19543
- TableStyleLight7: buildPreset("TableStyleLight7", lightColoredText, COLOR_SETS.orange),
19544
- TableStyleLight8: buildPreset("TableStyleLight8", lightWithHeader, COLOR_SETS.black),
19545
- TableStyleLight9: buildPreset("TableStyleLight9", lightWithHeader, COLOR_SETS.lightBlue),
19546
- TableStyleLight10: buildPreset("TableStyleLight10", lightWithHeader, COLOR_SETS.red),
19547
- TableStyleLight11: buildPreset("TableStyleLight11", lightWithHeader, COLOR_SETS.lightGreen),
19548
- TableStyleLight12: buildPreset("TableStyleLight12", lightWithHeader, COLOR_SETS.purple),
19549
- TableStyleLight13: buildPreset("TableStyleLight13", lightWithHeader, COLOR_SETS.gray),
19550
- TableStyleLight14: buildPreset("TableStyleLight14", lightWithHeader, COLOR_SETS.orange),
19551
- TableStyleLight15: buildPreset("TableStyleLight15", lightAllBorders, COLOR_SETS.black),
19552
- TableStyleLight16: buildPreset("TableStyleLight16", lightAllBorders, COLOR_SETS.lightBlue),
19553
- TableStyleLight17: buildPreset("TableStyleLight17", lightAllBorders, COLOR_SETS.red),
19554
- TableStyleLight18: buildPreset("TableStyleLight18", lightAllBorders, COLOR_SETS.lightGreen),
19555
- TableStyleLight19: buildPreset("TableStyleLight19", lightAllBorders, COLOR_SETS.purple),
19556
- TableStyleLight20: buildPreset("TableStyleLight20", lightAllBorders, COLOR_SETS.gray),
19557
- TableStyleLight21: buildPreset("TableStyleLight21", lightAllBorders, COLOR_SETS.orange),
19558
- TableStyleMedium1: buildPreset("TableStyleMedium1", mediumBandedBorders, COLOR_SETS.black),
19559
- TableStyleMedium2: buildPreset("TableStyleMedium2", mediumBandedBorders, COLOR_SETS.lightBlue),
19560
- TableStyleMedium3: buildPreset("TableStyleMedium3", mediumBandedBorders, COLOR_SETS.red),
19561
- TableStyleMedium4: buildPreset("TableStyleMedium4", mediumBandedBorders, COLOR_SETS.lightGreen),
19562
- TableStyleMedium5: buildPreset("TableStyleMedium5", mediumBandedBorders, COLOR_SETS.purple),
19563
- TableStyleMedium6: buildPreset("TableStyleMedium6", mediumBandedBorders, COLOR_SETS.gray),
19564
- TableStyleMedium7: buildPreset("TableStyleMedium7", mediumBandedBorders, COLOR_SETS.orange),
19565
- TableStyleMedium8: buildPreset("TableStyleMedium8", mediumWhiteBorders, COLOR_SETS.black),
19566
- TableStyleMedium9: buildPreset("TableStyleMedium9", mediumWhiteBorders, COLOR_SETS.lightBlue),
19567
- TableStyleMedium10: buildPreset("TableStyleMedium10", mediumWhiteBorders, COLOR_SETS.red),
19568
- TableStyleMedium11: buildPreset("TableStyleMedium11", mediumWhiteBorders, COLOR_SETS.lightGreen),
19569
- TableStyleMedium12: buildPreset("TableStyleMedium12", mediumWhiteBorders, COLOR_SETS.purple),
19570
- TableStyleMedium13: buildPreset("TableStyleMedium13", mediumWhiteBorders, COLOR_SETS.gray),
19571
- TableStyleMedium14: buildPreset("TableStyleMedium14", mediumWhiteBorders, COLOR_SETS.orange),
19552
+ None: { category: "light", templateName: "none", primaryColor: "", displayName: _t("None") },
19553
+ TableStyleLight1: buildPreset("TableStyleLight1", lightColoredText, TABLE_COLOR_SETS.black),
19554
+ TableStyleLight2: buildPreset("TableStyleLight2", lightColoredText, TABLE_COLOR_SETS.lightBlue),
19555
+ TableStyleLight3: buildPreset("TableStyleLight3", lightColoredText, TABLE_COLOR_SETS.red),
19556
+ TableStyleLight4: buildPreset("TableStyleLight4", lightColoredText, TABLE_COLOR_SETS.lightGreen),
19557
+ TableStyleLight5: buildPreset("TableStyleLight5", lightColoredText, TABLE_COLOR_SETS.purple),
19558
+ TableStyleLight6: buildPreset("TableStyleLight6", lightColoredText, TABLE_COLOR_SETS.gray),
19559
+ TableStyleLight7: buildPreset("TableStyleLight7", lightColoredText, TABLE_COLOR_SETS.orange),
19560
+ TableStyleLight8: buildPreset("TableStyleLight8", lightWithHeader, TABLE_COLOR_SETS.black),
19561
+ TableStyleLight9: buildPreset("TableStyleLight9", lightWithHeader, TABLE_COLOR_SETS.lightBlue),
19562
+ TableStyleLight10: buildPreset("TableStyleLight10", lightWithHeader, TABLE_COLOR_SETS.red),
19563
+ TableStyleLight11: buildPreset("TableStyleLight11", lightWithHeader, TABLE_COLOR_SETS.lightGreen),
19564
+ TableStyleLight12: buildPreset("TableStyleLight12", lightWithHeader, TABLE_COLOR_SETS.purple),
19565
+ TableStyleLight13: buildPreset("TableStyleLight13", lightWithHeader, TABLE_COLOR_SETS.gray),
19566
+ TableStyleLight14: buildPreset("TableStyleLight14", lightWithHeader, TABLE_COLOR_SETS.orange),
19567
+ TableStyleLight15: buildPreset("TableStyleLight15", lightAllBorders, TABLE_COLOR_SETS.black),
19568
+ TableStyleLight16: buildPreset("TableStyleLight16", lightAllBorders, TABLE_COLOR_SETS.lightBlue),
19569
+ TableStyleLight17: buildPreset("TableStyleLight17", lightAllBorders, TABLE_COLOR_SETS.red),
19570
+ TableStyleLight18: buildPreset("TableStyleLight18", lightAllBorders, TABLE_COLOR_SETS.lightGreen),
19571
+ TableStyleLight19: buildPreset("TableStyleLight19", lightAllBorders, TABLE_COLOR_SETS.purple),
19572
+ TableStyleLight20: buildPreset("TableStyleLight20", lightAllBorders, TABLE_COLOR_SETS.gray),
19573
+ TableStyleLight21: buildPreset("TableStyleLight21", lightAllBorders, TABLE_COLOR_SETS.orange),
19574
+ TableStyleMedium1: buildPreset("TableStyleMedium1", mediumBandedBorders, TABLE_COLOR_SETS.black),
19575
+ TableStyleMedium2: buildPreset("TableStyleMedium2", mediumBandedBorders, TABLE_COLOR_SETS.lightBlue),
19576
+ TableStyleMedium3: buildPreset("TableStyleMedium3", mediumBandedBorders, TABLE_COLOR_SETS.red),
19577
+ TableStyleMedium4: buildPreset("TableStyleMedium4", mediumBandedBorders, TABLE_COLOR_SETS.lightGreen),
19578
+ TableStyleMedium5: buildPreset("TableStyleMedium5", mediumBandedBorders, TABLE_COLOR_SETS.purple),
19579
+ TableStyleMedium6: buildPreset("TableStyleMedium6", mediumBandedBorders, TABLE_COLOR_SETS.gray),
19580
+ TableStyleMedium7: buildPreset("TableStyleMedium7", mediumBandedBorders, TABLE_COLOR_SETS.orange),
19581
+ TableStyleMedium8: buildPreset("TableStyleMedium8", mediumWhiteBorders, TABLE_COLOR_SETS.black),
19582
+ TableStyleMedium9: buildPreset("TableStyleMedium9", mediumWhiteBorders, TABLE_COLOR_SETS.lightBlue),
19583
+ TableStyleMedium10: buildPreset("TableStyleMedium10", mediumWhiteBorders, TABLE_COLOR_SETS.red),
19584
+ TableStyleMedium11: buildPreset("TableStyleMedium11", mediumWhiteBorders, TABLE_COLOR_SETS.lightGreen),
19585
+ TableStyleMedium12: buildPreset("TableStyleMedium12", mediumWhiteBorders, TABLE_COLOR_SETS.purple),
19586
+ TableStyleMedium13: buildPreset("TableStyleMedium13", mediumWhiteBorders, TABLE_COLOR_SETS.gray),
19587
+ TableStyleMedium14: buildPreset("TableStyleMedium14", mediumWhiteBorders, TABLE_COLOR_SETS.orange),
19572
19588
  TableStyleMedium15: { ...mediumMinimalBordersInBlack, displayName: "Black, TableStyleMedium15" },
19573
- TableStyleMedium16: buildPreset("TableStyleMedium16", mediumMinimalBorders, COLOR_SETS.lightBlue),
19574
- TableStyleMedium17: buildPreset("TableStyleMedium17", mediumMinimalBorders, COLOR_SETS.red),
19575
- TableStyleMedium18: buildPreset("TableStyleMedium18", mediumMinimalBorders, COLOR_SETS.lightGreen),
19576
- TableStyleMedium19: buildPreset("TableStyleMedium19", mediumMinimalBorders, COLOR_SETS.purple),
19577
- TableStyleMedium20: buildPreset("TableStyleMedium20", mediumMinimalBorders, COLOR_SETS.gray),
19578
- TableStyleMedium21: buildPreset("TableStyleMedium21", mediumMinimalBorders, COLOR_SETS.orange),
19579
- TableStyleMedium22: buildPreset("TableStyleMedium22", mediumAllBorders, COLOR_SETS.black),
19580
- TableStyleMedium23: buildPreset("TableStyleMedium23", mediumAllBorders, COLOR_SETS.lightBlue),
19581
- TableStyleMedium24: buildPreset("TableStyleMedium24", mediumAllBorders, COLOR_SETS.red),
19582
- TableStyleMedium25: buildPreset("TableStyleMedium25", mediumAllBorders, COLOR_SETS.lightGreen),
19583
- TableStyleMedium26: buildPreset("TableStyleMedium26", mediumAllBorders, COLOR_SETS.purple),
19584
- TableStyleMedium27: buildPreset("TableStyleMedium27", mediumAllBorders, COLOR_SETS.gray),
19585
- TableStyleMedium28: buildPreset("TableStyleMedium28", mediumAllBorders, COLOR_SETS.orange),
19589
+ TableStyleMedium16: buildPreset("TableStyleMedium16", mediumMinimalBorders, TABLE_COLOR_SETS.lightBlue),
19590
+ TableStyleMedium17: buildPreset("TableStyleMedium17", mediumMinimalBorders, TABLE_COLOR_SETS.red),
19591
+ TableStyleMedium18: buildPreset("TableStyleMedium18", mediumMinimalBorders, TABLE_COLOR_SETS.lightGreen),
19592
+ TableStyleMedium19: buildPreset("TableStyleMedium19", mediumMinimalBorders, TABLE_COLOR_SETS.purple),
19593
+ TableStyleMedium20: buildPreset("TableStyleMedium20", mediumMinimalBorders, TABLE_COLOR_SETS.gray),
19594
+ TableStyleMedium21: buildPreset("TableStyleMedium21", mediumMinimalBorders, TABLE_COLOR_SETS.orange),
19595
+ TableStyleMedium22: buildPreset("TableStyleMedium22", mediumAllBorders, TABLE_COLOR_SETS.black),
19596
+ TableStyleMedium23: buildPreset("TableStyleMedium23", mediumAllBorders, TABLE_COLOR_SETS.lightBlue),
19597
+ TableStyleMedium24: buildPreset("TableStyleMedium24", mediumAllBorders, TABLE_COLOR_SETS.red),
19598
+ TableStyleMedium25: buildPreset("TableStyleMedium25", mediumAllBorders, TABLE_COLOR_SETS.lightGreen),
19599
+ TableStyleMedium26: buildPreset("TableStyleMedium26", mediumAllBorders, TABLE_COLOR_SETS.purple),
19600
+ TableStyleMedium27: buildPreset("TableStyleMedium27", mediumAllBorders, TABLE_COLOR_SETS.gray),
19601
+ TableStyleMedium28: buildPreset("TableStyleMedium28", mediumAllBorders, TABLE_COLOR_SETS.orange),
19586
19602
  TableStyleDark1: { ...darkTemplateInBlack, displayName: "Black, TableStyleDark1" },
19587
- TableStyleDark2: buildPreset("TableStyleDark2", dark, COLOR_SETS.lightBlue),
19588
- TableStyleDark3: buildPreset("TableStyleDark3", dark, COLOR_SETS.red),
19589
- TableStyleDark4: buildPreset("TableStyleDark4", dark, COLOR_SETS.lightGreen),
19590
- TableStyleDark5: buildPreset("TableStyleDark5", dark, COLOR_SETS.purple),
19591
- TableStyleDark6: buildPreset("TableStyleDark6", dark, COLOR_SETS.gray),
19592
- TableStyleDark7: buildPreset("TableStyleDark7", dark, COLOR_SETS.orange),
19593
- TableStyleDark8: buildPreset("TableStyleDark8", darkNoBorders, DARK_COLOR_SETS.black),
19594
- TableStyleDark9: buildPreset("TableStyleDark9", darkNoBorders, DARK_COLOR_SETS.redBlue),
19595
- TableStyleDark10: buildPreset("TableStyleDark10", darkNoBorders, DARK_COLOR_SETS.purpleGreen),
19596
- TableStyleDark11: buildPreset("TableStyleDark11", darkNoBorders, DARK_COLOR_SETS.orangeBlue),
19603
+ TableStyleDark2: buildPreset("TableStyleDark2", dark, TABLE_COLOR_SETS.lightBlue),
19604
+ TableStyleDark3: buildPreset("TableStyleDark3", dark, TABLE_COLOR_SETS.red),
19605
+ TableStyleDark4: buildPreset("TableStyleDark4", dark, TABLE_COLOR_SETS.lightGreen),
19606
+ TableStyleDark5: buildPreset("TableStyleDark5", dark, TABLE_COLOR_SETS.purple),
19607
+ TableStyleDark6: buildPreset("TableStyleDark6", dark, TABLE_COLOR_SETS.gray),
19608
+ TableStyleDark7: buildPreset("TableStyleDark7", dark, TABLE_COLOR_SETS.orange),
19609
+ TableStyleDark8: buildPreset("TableStyleDark8", darkNoBorders, DARK_TABLE_COLOR_SETS.black),
19610
+ TableStyleDark9: buildPreset("TableStyleDark9", darkNoBorders, DARK_TABLE_COLOR_SETS.redBlue),
19611
+ TableStyleDark10: buildPreset("TableStyleDark10", darkNoBorders, DARK_TABLE_COLOR_SETS.purpleGreen),
19612
+ TableStyleDark11: buildPreset("TableStyleDark11", darkNoBorders, DARK_TABLE_COLOR_SETS.orangeBlue),
19597
19613
  };
19598
19614
  const TABLE_STYLES_TEMPLATES = {
19599
19615
  none: () => ({ category: "none", templateName: "none", primaryColor: "", name: "none" }),
@@ -20653,8 +20669,9 @@
20653
20669
  * It will be transmitted to all other connected clients.
20654
20670
  */
20655
20671
  save(rootCommand, commands, changes) {
20656
- if (!commands.length || !changes.length || !this.canApplyOptimisticUpdate())
20672
+ if (!commands.length || !changes.length || !this.canApplyOptimisticUpdate()) {
20657
20673
  return;
20674
+ }
20658
20675
  const revision = new Revision(this.uuidGenerator.uuidv4(), this.clientId, commands, rootCommand, changes, Date.now());
20659
20676
  this.revisions.append(revision.id, revision);
20660
20677
  // REQUEST_REDO just repeats the last operation, the
@@ -20812,8 +20829,9 @@
20812
20829
  * session.
20813
20830
  */
20814
20831
  onMessageReceived(message) {
20815
- if (this.isAlreadyProcessed(message))
20832
+ if (this.isAlreadyProcessed(message)) {
20816
20833
  return;
20834
+ }
20817
20835
  if (this.isWrongServerRevisionId(message)) {
20818
20836
  this.trigger("unexpected-revision-id");
20819
20837
  return;
@@ -20915,8 +20933,9 @@
20915
20933
  */
20916
20934
  sendPendingMessage() {
20917
20935
  let message = this.pendingMessages[0];
20918
- if (!message)
20936
+ if (!message) {
20919
20937
  return;
20938
+ }
20920
20939
  if (message.type === "REMOTE_REVISION") {
20921
20940
  let revision = this.revisions.get(message.nextRevisionId);
20922
20941
  if (revision.commands.length === 0) {
@@ -21175,10 +21194,12 @@
21175
21194
  */
21176
21195
  getFirstOperationAmong(op1, op2) {
21177
21196
  for (const operation of this.operations) {
21178
- if (operation.id === op1)
21197
+ if (operation.id === op1) {
21179
21198
  return op1;
21180
- if (operation.id === op2)
21199
+ }
21200
+ if (operation.id === op2) {
21181
21201
  return op2;
21202
+ }
21182
21203
  }
21183
21204
  throw new Error(`Operation ${op1} and ${op2} not found`);
21184
21205
  }
@@ -21500,8 +21521,9 @@
21500
21521
  */
21501
21522
  redo(branch) {
21502
21523
  const removedBranch = this.nextBranch(branch);
21503
- if (!removedBranch)
21524
+ if (!removedBranch) {
21504
21525
  return;
21526
+ }
21505
21527
  const nextBranch = this.nextBranch(removedBranch);
21506
21528
  this.removeBranchFromTree(removedBranch);
21507
21529
  const undoBranchingId = this.branchingOperationIds.get(removedBranch);
@@ -21555,8 +21577,9 @@
21555
21577
  */
21556
21578
  rebaseUp(branch) {
21557
21579
  const { previousBranch, branchingOperation } = this.findPreviousBranchingOperation(branch);
21558
- if (!previousBranch || !branchingOperation)
21580
+ if (!previousBranch || !branchingOperation) {
21559
21581
  return;
21582
+ }
21560
21583
  const rebaseTransformation = this.buildTransformation.without(branchingOperation.data);
21561
21584
  const newBranch = previousBranch.fork(branchingOperation.id);
21562
21585
  this.branchingOperationIds.set(newBranch, this.branchingOperationIds.get(branch));
@@ -21643,8 +21666,9 @@
21643
21666
  */
21644
21667
  insertPrevious(branch, newOperation, insertAfter) {
21645
21668
  const { previousBranch, branchingOperation } = this.findPreviousBranchingOperation(branch);
21646
- if (!previousBranch || !branchingOperation)
21669
+ if (!previousBranch || !branchingOperation) {
21647
21670
  return;
21671
+ }
21648
21672
  const transformation = this.buildTransformation.with(branchingOperation.data);
21649
21673
  const branchTail = branch.fork(insertAfter);
21650
21674
  branchTail.transform(transformation);
@@ -21655,11 +21679,13 @@
21655
21679
  }
21656
21680
  findPreviousBranchingOperation(branch) {
21657
21681
  const previousBranch = this.previousBranch(branch);
21658
- if (!previousBranch)
21682
+ if (!previousBranch) {
21659
21683
  return { previousBranch: undefined, branchingOperation: undefined };
21684
+ }
21660
21685
  const previousBranchingId = this.branchingOperationIds.get(previousBranch);
21661
- if (!previousBranchingId)
21686
+ if (!previousBranchingId) {
21662
21687
  return { previousBranch: undefined, branchingOperation: undefined };
21688
+ }
21663
21689
  return {
21664
21690
  previousBranch,
21665
21691
  branchingOperation: previousBranch.getOperation(previousBranchingId),
@@ -22750,8 +22776,9 @@
22750
22776
  * representation #RRGGBBAA
22751
22777
  */
22752
22778
  function xlsxColorToHEXA(color) {
22753
- if (color.length === 6)
22779
+ if (color.length === 6) {
22754
22780
  return "#" + color + "FF";
22781
+ }
22755
22782
  return "#" + color.slice(2) + color.slice(0, 2);
22756
22783
  }
22757
22784
  /**
@@ -22855,8 +22882,9 @@
22855
22882
  return arrayToObject(borderArray, 1);
22856
22883
  }
22857
22884
  function convertBorderDescr$1(borderDescr, warningManager) {
22858
- if (!borderDescr)
22885
+ if (!borderDescr) {
22859
22886
  return undefined;
22887
+ }
22860
22888
  addBorderDescrWarnings(borderDescr, warningManager);
22861
22889
  const style = BORDER_STYLE_CONVERSION_MAP[borderDescr.style];
22862
22890
  return style ? { style, color: convertColor(borderDescr.color) } : undefined;
@@ -22941,16 +22969,18 @@
22941
22969
  const cfs = [];
22942
22970
  let cfId = 1;
22943
22971
  for (const cf of xlsxCfs) {
22944
- if (cf.cfRules.length === 0)
22972
+ if (cf.cfRules.length === 0) {
22945
22973
  continue;
22974
+ }
22946
22975
  addCfConversionWarnings(cf, dxfs, warningManager);
22947
22976
  const rule = cf.cfRules[0];
22948
22977
  let operator;
22949
22978
  const values = [];
22950
22979
  const cfAdditionalProperties = {};
22951
22980
  if (rule.dxfId === undefined &&
22952
- !(rule.type === "colorScale" || rule.type === "iconSet" || rule.type === "dataBar"))
22981
+ !(rule.type === "colorScale" || rule.type === "iconSet" || rule.type === "dataBar")) {
22953
22982
  continue;
22983
+ }
22954
22984
  switch (rule.type) {
22955
22985
  case "aboveAverage":
22956
22986
  case "containsErrors":
@@ -22982,14 +23012,16 @@
22982
23012
  case "notContainsText":
22983
23013
  case "beginsWith":
22984
23014
  case "endsWith":
22985
- if (!rule.text)
23015
+ if (!rule.text) {
22986
23016
  continue;
23017
+ }
22987
23018
  operator = CF_TYPE_CONVERSION_MAP[rule.type];
22988
23019
  values.push(rule.text);
22989
23020
  break;
22990
23021
  case "expression":
22991
- if (!rule.formula?.length)
23022
+ if (!rule.formula?.length) {
22992
23023
  continue;
23024
+ }
22993
23025
  operator = CF_TYPE_CONVERSION_MAP[rule.type];
22994
23026
  values.push(`=${rule.formula[0]}`);
22995
23027
  break;
@@ -22998,8 +23030,9 @@
22998
23030
  operator = CF_TYPE_CONVERSION_MAP[rule.type];
22999
23031
  break;
23000
23032
  case "cellIs":
23001
- if (!rule.operator || !rule.formula || rule.formula.length === 0)
23033
+ if (!rule.operator || !rule.formula || rule.formula.length === 0) {
23002
23034
  continue;
23035
+ }
23003
23036
  operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.operator];
23004
23037
  values.push(prefixFormulaWithEqual(rule.formula[0]));
23005
23038
  if (rule.formula.length === 2) {
@@ -23007,8 +23040,9 @@
23007
23040
  }
23008
23041
  break;
23009
23042
  case "top10":
23010
- if (rule.rank === undefined)
23043
+ if (rule.rank === undefined) {
23011
23044
  continue;
23045
+ }
23012
23046
  operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.type];
23013
23047
  values.push(rule.rank.toString());
23014
23048
  if (rule.percent) {
@@ -23038,8 +23072,9 @@
23038
23072
  }
23039
23073
  function convertDataBar(id, xlsxCf) {
23040
23074
  const dataBar = xlsxCf.cfRules[0].dataBar;
23041
- if (!dataBar)
23075
+ if (!dataBar) {
23042
23076
  return undefined;
23077
+ }
23043
23078
  const color = hexaToInt(convertColor(dataBar.color) || "#FFFFFF");
23044
23079
  return {
23045
23080
  id: id.toString(),
@@ -23089,8 +23124,9 @@
23089
23124
  */
23090
23125
  function convertIconSet(id, xlsxCf, warningManager) {
23091
23126
  const xlsxIconSet = xlsxCf.cfRules[0].iconSet;
23092
- if (!xlsxIconSet)
23127
+ if (!xlsxIconSet) {
23093
23128
  return undefined;
23129
+ }
23094
23130
  let cfVos = xlsxIconSet.cfvos;
23095
23131
  let cfIcons = xlsxIconSet.cfIcons;
23096
23132
  if (cfVos.length < 3 || (cfIcons && cfIcons.length < 3)) {
@@ -23166,8 +23202,9 @@
23166
23202
  */
23167
23203
  function convertIcons(xlsxIconSet, index) {
23168
23204
  const iconSet = ICON_SET_CONVERSION_MAP[xlsxIconSet];
23169
- if (!iconSet)
23205
+ if (!iconSet) {
23170
23206
  return "";
23207
+ }
23171
23208
  return index === 0
23172
23209
  ? ICON_SETS[iconSet].bad
23173
23210
  : index === 1
@@ -23246,18 +23283,22 @@
23246
23283
  }
23247
23284
  }
23248
23285
  function getCanonicalRepresentation(item) {
23249
- if (item === null)
23286
+ if (item === null) {
23250
23287
  return "null";
23251
- if (item === undefined)
23288
+ }
23289
+ if (item === undefined) {
23252
23290
  return "undefined";
23253
- if (typeof item !== "object")
23291
+ }
23292
+ if (typeof item !== "object") {
23254
23293
  return String(item);
23294
+ }
23255
23295
  if (Array.isArray(item)) {
23256
23296
  const len = item.length;
23257
23297
  let result = "[";
23258
23298
  for (let i = 0; i < len; i++) {
23259
- if (i > 0)
23299
+ if (i > 0) {
23260
23300
  result += ",";
23301
+ }
23261
23302
  result += getCanonicalRepresentation(item[i]);
23262
23303
  }
23263
23304
  return result + "]";
@@ -23348,13 +23389,15 @@
23348
23389
  return Math.round(WIDTH_FACTOR * width * 100) / 100;
23349
23390
  }
23350
23391
  function convertHeightFromExcel(height) {
23351
- if (!height)
23392
+ if (!height) {
23352
23393
  return height;
23394
+ }
23353
23395
  return Math.round((height / HEIGHT_FACTOR) * 100) / 100;
23354
23396
  }
23355
23397
  function convertWidthFromExcel(width) {
23356
- if (!width)
23398
+ if (!width) {
23357
23399
  return width;
23400
+ }
23358
23401
  return Math.round((width / WIDTH_FACTOR) * 100) / 100;
23359
23402
  }
23360
23403
  function extractStyle(data, content, styleId, formatId, borderId) {
@@ -24244,12 +24287,15 @@
24244
24287
  for (let i = 1; i < numberOfCols + 1; i++) {
24245
24288
  const col = sheet.cols.find((col) => col.min <= i && i <= col.max);
24246
24289
  let colSize;
24247
- if (col && col.width)
24290
+ if (col && col.width) {
24248
24291
  colSize = col.width;
24249
- else if (sheet.sheetFormat?.defaultColWidth)
24292
+ }
24293
+ else if (sheet.sheetFormat?.defaultColWidth) {
24250
24294
  colSize = sheet.sheetFormat.defaultColWidth;
24251
- else
24295
+ }
24296
+ else {
24252
24297
  colSize = EXCEL_DEFAULT_COL_WIDTH;
24298
+ }
24253
24299
  // In xlsx there is no difference between hidden columns and columns inside a folded group.
24254
24300
  // But in o-spreadsheet folded columns are not considered hidden.
24255
24301
  const colIndex = i - 1;
@@ -24267,12 +24313,15 @@
24267
24313
  for (let i = 1; i < numberOfRows + 1; i++) {
24268
24314
  const row = sheet.rows.find((row) => row.index === i);
24269
24315
  let rowSize;
24270
- if (row && row.height)
24316
+ if (row && row.height) {
24271
24317
  rowSize = row.height;
24272
- else if (sheet.sheetFormat?.defaultRowHeight)
24318
+ }
24319
+ else if (sheet.sheetFormat?.defaultRowHeight) {
24273
24320
  rowSize = sheet.sheetFormat.defaultRowHeight;
24274
- else
24321
+ }
24322
+ else {
24275
24323
  rowSize = EXCEL_DEFAULT_ROW_HEIGHT;
24324
+ }
24276
24325
  // In xlsx there is no difference between hidden rows and rows inside a folded group.
24277
24326
  // But in o-spreadsheet folded rows are not considered hidden.
24278
24327
  const rowIndex = i - 1;
@@ -24440,10 +24489,12 @@
24440
24489
  function convertTables(convertedData, xlsxData) {
24441
24490
  for (const xlsxSheet of xlsxData.sheets) {
24442
24491
  const sheet = convertedData.sheets.find((sheet) => sheet.name === xlsxSheet.sheetName);
24443
- if (!sheet)
24492
+ if (!sheet) {
24444
24493
  continue;
24445
- if (!sheet.tables)
24494
+ }
24495
+ if (!sheet.tables) {
24446
24496
  sheet.tables = [];
24497
+ }
24447
24498
  for (const table of xlsxSheet.tables) {
24448
24499
  sheet.tables.push({ range: table.ref, config: convertTableConfig(table) });
24449
24500
  }
@@ -24863,10 +24914,12 @@
24863
24914
  return fixXlsxUnicode(String(this.value));
24864
24915
  }
24865
24916
  asBool() {
24866
- if (this.value === "true")
24867
- return true; // for files exported from Libre Office
24868
- if (this.value === "false")
24917
+ if (this.value === "true") {
24918
+ return true;
24919
+ } // for files exported from Libre Office
24920
+ if (this.value === "false") {
24869
24921
  return false;
24922
+ }
24870
24923
  return Boolean(Number(this.value));
24871
24924
  }
24872
24925
  asNum() {
@@ -24978,8 +25031,9 @@
24978
25031
  */
24979
25032
  extractAttr(e, attName, optionalArgs) {
24980
25033
  const attribute = e.attributes[attName];
24981
- if (!attribute)
25034
+ if (!attribute) {
24982
25035
  this.handleMissingValue(e, `attribute "${attName}"`, optionalArgs);
25036
+ }
24983
25037
  const value = attribute?.value ? attribute.value : optionalArgs?.default;
24984
25038
  return (value === undefined ? undefined : new AttributeValue(value));
24985
25039
  }
@@ -25097,26 +25151,30 @@
25097
25151
  * Returns the xml file targeted by a relationship.
25098
25152
  */
25099
25153
  getTargetXmlFile(relationship) {
25100
- if (!relationship)
25154
+ if (!relationship) {
25101
25155
  throw new Error("Undefined target file");
25156
+ }
25102
25157
  const target = this.processRelationshipTargetName(relationship.target);
25103
25158
  // Use "endsWith" because targets are relative paths, and we know the files by their absolute path.
25104
25159
  const f = this.getListOfXMLFiles().find((f) => f.file.fileName.endsWith(target));
25105
- if (!f || !f.file)
25160
+ if (!f || !f.file) {
25106
25161
  throw new Error("Cannot find target file");
25162
+ }
25107
25163
  return f;
25108
25164
  }
25109
25165
  /**
25110
25166
  * Returns the image parameters targeted by a relationship.
25111
25167
  */
25112
25168
  getTargetImageFile(relationship) {
25113
- if (!relationship)
25169
+ if (!relationship) {
25114
25170
  throw new Error("Undefined target file");
25171
+ }
25115
25172
  const target = this.processRelationshipTargetName(relationship.target);
25116
25173
  // Use "endsWith" because targets are relative paths, and we know the files by their absolute path.
25117
25174
  const f = this.xlsxFileStructure.images.find((f) => f.fileName.endsWith(target));
25118
- if (!f)
25175
+ if (!f) {
25119
25176
  throw new Error("Cannot find target file");
25177
+ }
25120
25178
  return f;
25121
25179
  }
25122
25180
  querySelector(element, query) {
@@ -25252,8 +25310,9 @@
25252
25310
  }
25253
25311
  extractCfColorScale(cfRulesElement, theme) {
25254
25312
  const colorScaleElement = this.querySelector(cfRulesElement, "colorScale");
25255
- if (!colorScaleElement)
25313
+ if (!colorScaleElement) {
25256
25314
  return undefined;
25315
+ }
25257
25316
  return {
25258
25317
  colors: this.mapOnElements({ parent: colorScaleElement, query: "color" }, (colorElement) => {
25259
25318
  return this.extractColor(colorElement, theme, "ffffff");
@@ -25263,8 +25322,9 @@
25263
25322
  }
25264
25323
  extractCfDataBar(cfRulesElement, theme) {
25265
25324
  const dataBarElement = this.querySelector(cfRulesElement, "dataBar");
25266
- if (!dataBarElement)
25325
+ if (!dataBarElement) {
25267
25326
  return undefined;
25327
+ }
25268
25328
  return {
25269
25329
  color: this.extractColor(dataBarElement.querySelector("color"), theme, "EFF7FF"),
25270
25330
  // TODO ATM, we only support color for dataBar, not the minimum and maximum fill percentage
@@ -25273,8 +25333,9 @@
25273
25333
  }
25274
25334
  extractCfIconSet(cfRulesElement) {
25275
25335
  const iconSetElement = this.querySelector(cfRulesElement, "iconSet, x14:iconSet");
25276
- if (!iconSetElement)
25336
+ if (!iconSetElement) {
25277
25337
  return undefined;
25338
+ }
25278
25339
  return {
25279
25340
  iconSet: this.extractAttr(iconSetElement, "iconSet", {
25280
25341
  default: "3TrafficLights1",
@@ -25868,8 +25929,9 @@
25868
25929
  }
25869
25930
  extractSheetFormat(worksheet) {
25870
25931
  const formatElement = this.querySelector(worksheet, "sheetFormatPr");
25871
- if (!formatElement)
25932
+ if (!formatElement) {
25872
25933
  return undefined;
25934
+ }
25873
25935
  return {
25874
25936
  defaultColWidth: this.extractAttr(formatElement, "defaultColWidth", {
25875
25937
  default: EXCEL_DEFAULT_COL_WIDTH.toString(),
@@ -25881,8 +25943,9 @@
25881
25943
  }
25882
25944
  extractSheetProperties(worksheet) {
25883
25945
  const propertiesElement = this.querySelector(worksheet, "sheetPr");
25884
- if (!propertiesElement)
25946
+ if (!propertiesElement) {
25885
25947
  return undefined;
25948
+ }
25886
25949
  return {
25887
25950
  outlinePr: this.extractSheetOutlineProperties(propertiesElement),
25888
25951
  tabColor: this.extractColor(this.querySelector(propertiesElement, "tabColor"), this.theme),
@@ -25890,8 +25953,9 @@
25890
25953
  }
25891
25954
  extractSheetOutlineProperties(sheetProperties) {
25892
25955
  const properties = this.querySelector(sheetProperties, "outlinePr");
25893
- if (!properties)
25956
+ if (!properties) {
25894
25957
  return undefined;
25958
+ }
25895
25959
  return {
25896
25960
  summaryBelow: this.extractAttr(properties, "summaryBelow", { default: true }).asBool(),
25897
25961
  summaryRight: this.extractAttr(properties, "summaryRight", { default: true }).asBool(),
@@ -25952,8 +26016,9 @@
25952
26016
  }
25953
26017
  extractCellFormula(cellElement) {
25954
26018
  const formulaElement = this.querySelector(cellElement, "f");
25955
- if (!formulaElement)
26019
+ if (!formulaElement) {
25956
26020
  return undefined;
26021
+ }
25957
26022
  const content = this.extractTextContent(formulaElement);
25958
26023
  const sharedIndex = this.extractAttr(formulaElement, "si")?.asNum();
25959
26024
  const ref = this.extractAttr(formulaElement, "ref")?.asString();
@@ -26087,8 +26152,9 @@
26087
26152
  }
26088
26153
  extractSingleBorder(borderElement, direction, theme) {
26089
26154
  const directionElement = this.querySelector(borderElement, direction);
26090
- if (!directionElement || !directionElement.attributes["style"])
26155
+ if (!directionElement || !directionElement.attributes["style"]) {
26091
26156
  return undefined;
26157
+ }
26092
26158
  return {
26093
26159
  style: this.extractAttr(directionElement, "style", {
26094
26160
  required: true,
@@ -27530,6 +27596,94 @@
27530
27596
  }
27531
27597
  }
27532
27598
 
27599
+ /**
27600
+ * BasePlugin
27601
+ *
27602
+ * Since the spreadsheet internal state is quite complex, it is split into
27603
+ * multiple parts, each managing a specific concern.
27604
+ *
27605
+ * This file introduces the BasePlugin, which is the common class that defines
27606
+ * how each of these model sub parts should interact with each other.
27607
+ * There are two kinds of plugins: core plugins handling persistent data
27608
+ * and UI plugins handling transient data.
27609
+ */
27610
+ class BasePlugin {
27611
+ static getters = [];
27612
+ history;
27613
+ constructor(stateObserver) {
27614
+ this.history = Object.assign(Object.create(stateObserver), {
27615
+ update: stateObserver.addChange.bind(stateObserver, this),
27616
+ selectCell: () => { },
27617
+ });
27618
+ }
27619
+ /**
27620
+ * Export for excel should be available for all plugins, even for the UI.
27621
+ * In some cases, we need to export evaluated value, which is available from
27622
+ * UI plugin only.
27623
+ */
27624
+ exportForExcel(data) { }
27625
+ // ---------------------------------------------------------------------------
27626
+ // Command handling
27627
+ // ---------------------------------------------------------------------------
27628
+ /**
27629
+ * Before a command is accepted, the model will ask each plugin if the command
27630
+ * is allowed. If all of them return true, then we can proceed. Otherwise,
27631
+ * the command is cancelled.
27632
+ *
27633
+ * There should not be any side effects in this method.
27634
+ */
27635
+ allowDispatch(command) {
27636
+ return "Success" /* CommandResult.Success */;
27637
+ }
27638
+ /**
27639
+ * This method is useful when a plugin needs to perform some action before a
27640
+ * command is handled in another plugin. This should only be used if it is not
27641
+ * possible to do the work in the handle method.
27642
+ */
27643
+ beforeHandle(command) { }
27644
+ /**
27645
+ * This is the standard place to handle any command. Most of the plugin
27646
+ * command handling work should take place here.
27647
+ */
27648
+ handle(command) { }
27649
+ /**
27650
+ * Sometimes, it is useful to perform some work after a command (and all its
27651
+ * subcommands) has been completely handled. For example, when we paste
27652
+ * multiple cells, we only want to reevaluate the cell values once at the end.
27653
+ */
27654
+ finalize() { }
27655
+ /**
27656
+ * Combine multiple validation functions into a single function
27657
+ * returning the list of results of every validation.
27658
+ */
27659
+ batchValidations(...validations) {
27660
+ return (toValidate) => validations.map((validation) => validation.call(this, toValidate)).flat();
27661
+ }
27662
+ /**
27663
+ * Combine multiple validation functions. Every validation is executed one after
27664
+ * the other. As soon as one validation fails, it stops and the cancelled reason
27665
+ * is returned.
27666
+ */
27667
+ chainValidations(...validations) {
27668
+ return (toValidate) => {
27669
+ for (const validation of validations) {
27670
+ let results = validation.call(this, toValidate);
27671
+ if (!Array.isArray(results)) {
27672
+ results = [results];
27673
+ }
27674
+ const cancelledReasons = results.filter((result) => result !== "Success" /* CommandResult.Success */);
27675
+ if (cancelledReasons.length) {
27676
+ return cancelledReasons;
27677
+ }
27678
+ }
27679
+ return "Success" /* CommandResult.Success */;
27680
+ };
27681
+ }
27682
+ checkValidations(command, ...validations) {
27683
+ return this.batchValidations(...validations)(command);
27684
+ }
27685
+ }
27686
+
27533
27687
  /**
27534
27688
  * Core plugins handle spreadsheet data.
27535
27689
  * They are responsible to import, export and maintain the spreadsheet
@@ -27601,8 +27755,9 @@
27601
27755
  this.history.update("borders", allBorders);
27602
27756
  break;
27603
27757
  case "SET_BORDER":
27604
- if (cmd.border)
27758
+ if (cmd.border) {
27605
27759
  this.addBorders(cmd.sheetId, [positionToZone(cmd)], cmd.border);
27760
+ }
27606
27761
  break;
27607
27762
  case "SET_BORDERS_ON_TARGET":
27608
27763
  for (const zone of cmd.target) {
@@ -27719,8 +27874,9 @@
27719
27874
  for (const border of this.borders[sheetId] ?? []) {
27720
27875
  const { zone: bzone, style: bstyle } = border;
27721
27876
  const inter = intersection(bzone, zone);
27722
- if (!inter)
27877
+ if (!inter) {
27723
27878
  continue;
27879
+ }
27724
27880
  for (let col = inter.left; col <= inter.right; col++) {
27725
27881
  for (let row = inter.top; row <= inter.bottom; row++) {
27726
27882
  const cell = borders.get({ sheetId, col, row }) ?? {};
@@ -27738,8 +27894,9 @@
27738
27894
  const colors = new Set();
27739
27895
  for (const border of this.borders[sheetId] ?? []) {
27740
27896
  for (const style of Object.values(border.style)) {
27741
- if (style?.color)
27897
+ if (style?.color) {
27742
27898
  colors.add(style.color);
27899
+ }
27743
27900
  }
27744
27901
  }
27745
27902
  return [...colors];
@@ -27781,13 +27938,16 @@
27781
27938
  }
27782
27939
  borderIsClear(border) {
27783
27940
  const style = border.style;
27784
- if (style.left || style.right || style.bottom || style.top)
27941
+ if (style.left || style.right || style.bottom || style.top) {
27785
27942
  return false;
27943
+ }
27786
27944
  const zone = border.zone;
27787
- if ((zone.bottom === undefined || zone.top < zone.bottom) && style.horizontal)
27945
+ if ((zone.bottom === undefined || zone.top < zone.bottom) && style.horizontal) {
27788
27946
  return false;
27789
- if ((zone.right === undefined || zone.left < zone.right) && style.vertical)
27947
+ }
27948
+ if ((zone.right === undefined || zone.left < zone.right) && style.vertical) {
27790
27949
  return false;
27950
+ }
27791
27951
  return true;
27792
27952
  }
27793
27953
  clearBorders(sheetId, zones) {
@@ -27932,8 +28092,9 @@
27932
28092
  return "Success" /* CommandResult.Success */;
27933
28093
  }
27934
28094
  ensureHasBorder(cmd) {
27935
- if (!cmd.border)
28095
+ if (!cmd.border) {
27936
28096
  return "NoChanges" /* CommandResult.NoChanges */;
28097
+ }
27937
28098
  return "Success" /* CommandResult.Success */;
27938
28099
  }
27939
28100
  /**
@@ -28577,16 +28738,18 @@
28577
28738
  checkCellOutOfSheet(cmd) {
28578
28739
  const { sheetId, col, row } = cmd;
28579
28740
  const sheet = this.getters.tryGetSheet(sheetId);
28580
- if (!sheet)
28741
+ if (!sheet) {
28581
28742
  return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
28743
+ }
28582
28744
  const sheetZone = this.getters.getSheetZone(sheetId);
28583
28745
  return isInside(col, row, sheetZone) ? "Success" /* CommandResult.Success */ : "TargetOutOfSheet" /* CommandResult.TargetOutOfSheet */;
28584
28746
  }
28585
28747
  checkUselessClearCell(cmd) {
28586
28748
  const cell = this.getters.getCell(cmd);
28587
28749
  const style = this.getters.getCellStyle(cmd);
28588
- if (!cell)
28750
+ if (!cell) {
28589
28751
  return "NoChanges" /* CommandResult.NoChanges */;
28752
+ }
28590
28753
  if (!cell.content && !style && !cell.format) {
28591
28754
  return "NoChanges" /* CommandResult.NoChanges */;
28592
28755
  }
@@ -29849,11 +30012,13 @@
29849
30012
  this.history.update("cfRules", sheet, currentCF);
29850
30013
  }
29851
30014
  checkValidPriorityChange(cfId, delta, sheetId) {
29852
- if (!this.cfRules[sheetId])
30015
+ if (!this.cfRules[sheetId]) {
29853
30016
  return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
30017
+ }
29854
30018
  const ruleIndex = this.cfRules[sheetId].findIndex((cf) => cf.id === cfId);
29855
- if (ruleIndex === -1)
30019
+ if (ruleIndex === -1) {
29856
30020
  return "InvalidConditionalFormatId" /* CommandResult.InvalidConditionalFormatId */;
30021
+ }
29857
30022
  const cfIndex2 = ruleIndex - delta;
29858
30023
  if (cfIndex2 < 0 || cfIndex2 >= this.cfRules[sheetId].length) {
29859
30024
  return "InvalidConditionalFormatId" /* CommandResult.InvalidConditionalFormatId */;
@@ -29925,8 +30090,9 @@
29925
30090
  return "Success" /* CommandResult.Success */;
29926
30091
  }
29927
30092
  checkFormulaCompilation(threshold, thresholdName) {
29928
- if (threshold.type !== "formula")
30093
+ if (threshold.type !== "formula") {
29929
30094
  return "Success" /* CommandResult.Success */;
30095
+ }
29930
30096
  const compiledFormula = compile(threshold.value || "");
29931
30097
  if (compiledFormula.isBadExpression) {
29932
30098
  switch (thresholdName) {
@@ -29994,8 +30160,9 @@
29994
30160
  }
29995
30161
  checkCFValues(rule) {
29996
30162
  for (const value of rule.values) {
29997
- if (!value.startsWith("="))
30163
+ if (!value.startsWith("=")) {
29998
30164
  continue;
30165
+ }
29999
30166
  const compiledFormula = compile(value || "");
30000
30167
  if (compiledFormula.isBadExpression) {
30001
30168
  return "ValueCellIsInvalidFormula" /* CommandResult.ValueCellIsInvalidFormula */;
@@ -30167,8 +30334,9 @@
30167
30334
  }
30168
30335
  cellHasListDataValidationIcon(cellPosition) {
30169
30336
  const rule = this.getValidationRuleForCell(cellPosition);
30170
- if (!rule)
30337
+ if (!rule) {
30171
30338
  return false;
30339
+ }
30172
30340
  return ((rule.criterion.type === "isValueInList" || rule.criterion.type === "isValueInRange") &&
30173
30341
  (rule.criterion.displayStyle === "arrow" || rule.criterion.displayStyle === "chip"));
30174
30342
  }
@@ -31505,7 +31673,6 @@
31505
31673
  "getMerge",
31506
31674
  "getMergesInZone",
31507
31675
  "isSingleCellOrMerge",
31508
- "getSelectionRangeString",
31509
31676
  "isMainCellPosition",
31510
31677
  ];
31511
31678
  nextId = 1;
@@ -31542,8 +31709,9 @@
31542
31709
  break;
31543
31710
  case "DUPLICATE_SHEET":
31544
31711
  const merges = this.merges[cmd.sheetId];
31545
- if (!merges)
31712
+ if (!merges) {
31546
31713
  break;
31714
+ }
31547
31715
  for (const range of Object.values(merges).filter(isDefined)) {
31548
31716
  this.addMerge(cmd.sheetIdTo, range.zone);
31549
31717
  }
@@ -31578,8 +31746,9 @@
31578
31746
  }
31579
31747
  getMergesInZone(sheetId, zone) {
31580
31748
  const sheetMap = this.mergeCellMap[sheetId];
31581
- if (!sheetMap)
31749
+ if (!sheetMap) {
31582
31750
  return [];
31751
+ }
31583
31752
  const mergeIds = new Set();
31584
31753
  for (let col = zone.left; col <= zone.right; col++) {
31585
31754
  for (let row = zone.top; row <= zone.bottom; row++) {
@@ -31593,26 +31762,6 @@
31593
31762
  .map((mergeId) => this.getMergeById(sheetId, mergeId))
31594
31763
  .filter(isDefined);
31595
31764
  }
31596
- /**
31597
- * Same as `getRangeString` but add all necessary merge to the range to make it a valid selection
31598
- */
31599
- getSelectionRangeString(range, forSheetId) {
31600
- const expandedZone = this.getters.expandZone(range.sheetId, range.zone);
31601
- const expandedRange = createRange({
31602
- ...range,
31603
- zone: {
31604
- ...expandedZone,
31605
- bottom: isFullColRange(range) ? undefined : expandedZone.bottom,
31606
- right: isFullRowRange(range) ? undefined : expandedZone.right,
31607
- },
31608
- }, this.getters.getSheetSize);
31609
- const rangeString = this.getters.getRangeString(expandedRange, forSheetId);
31610
- if (this.isSingleCellOrMerge(range.sheetId, range.zone)) {
31611
- const { sheetName, xc } = splitReference(rangeString);
31612
- return getFullReference(sheetName, xc.split(":")[0]);
31613
- }
31614
- return rangeString;
31615
- }
31616
31765
  /**
31617
31766
  * Return true if the zone intersects an existing merge:
31618
31767
  * if they have at least a common cell
@@ -31744,8 +31893,9 @@
31744
31893
  }
31745
31894
  checkDestructiveMerge({ sheetId, target }) {
31746
31895
  const sheet = this.getters.tryGetSheet(sheetId);
31747
- if (!sheet)
31896
+ if (!sheet) {
31748
31897
  return "Success" /* CommandResult.Success */;
31898
+ }
31749
31899
  const isDestructive = target.some((zone) => this.isMergeDestructive(sheetId, zone));
31750
31900
  return isDestructive ? "MergeIsDestructive" /* CommandResult.MergeIsDestructive */ : "Success" /* CommandResult.Success */;
31751
31901
  }
@@ -31761,8 +31911,9 @@
31761
31911
  }
31762
31912
  checkFrozenPanes({ sheetId, target }) {
31763
31913
  const sheet = this.getters.tryGetSheet(sheetId);
31764
- if (!sheet)
31914
+ if (!sheet) {
31765
31915
  return "Success" /* CommandResult.Success */;
31916
+ }
31766
31917
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
31767
31918
  if (doesAnyZoneCrossFrozenPane(target, xSplit, ySplit)) {
31768
31919
  return "FrozenPaneOverlap" /* CommandResult.FrozenPaneOverlap */;
@@ -32631,6 +32782,24 @@
32631
32782
  }
32632
32783
  return this.rows.filter((row) => row.indent === depth + 1).map((row) => this.getDomain(row));
32633
32784
  }
32785
+ getPivotTableDimensions(pivotStyle) {
32786
+ const cells = this.getPivotCells(pivotStyle);
32787
+ let numberOfHeaderRows = 0;
32788
+ if (pivotStyle.displayColumnHeaders) {
32789
+ numberOfHeaderRows = this.columns.length - 1;
32790
+ }
32791
+ if (pivotStyle.displayMeasuresRow) {
32792
+ numberOfHeaderRows++;
32793
+ }
32794
+ return {
32795
+ numberOfCols: Math.min(1 + pivotStyle.numberOfColumns, cells.length),
32796
+ numberOfRows: Math.min(numberOfHeaderRows + pivotStyle.numberOfRows, cells[0].length),
32797
+ numberOfHeaderRows,
32798
+ };
32799
+ }
32800
+ getNumberOfRowGroupBys() {
32801
+ return Math.max(...this.rows.map((row) => row.fields.length));
32802
+ }
32634
32803
  }
32635
32804
  const EMPTY_PIVOT_CELL = { type: "EMPTY" };
32636
32805
 
@@ -33396,8 +33565,9 @@
33396
33565
  }
33397
33566
  for (const customFieldName in this.definition.customFields || {}) {
33398
33567
  const customField = this.definition.customFields?.[customFieldName];
33399
- if (!customField)
33568
+ if (!customField) {
33400
33569
  continue;
33570
+ }
33401
33571
  const baseValue = entry[customField.parentField];
33402
33572
  const parentField = this.fields[customField.parentField];
33403
33573
  if (!baseValue || !parentField) {
@@ -33499,6 +33669,7 @@
33499
33669
  "getMeasureCompiledFormula",
33500
33670
  "getPivotName",
33501
33671
  "isExistingPivot",
33672
+ "getMeasureFullDependencies",
33502
33673
  ];
33503
33674
  nextFormulaId = 1;
33504
33675
  pivots = {};
@@ -33584,7 +33755,7 @@
33584
33755
  }
33585
33756
  case "UPDATE_PIVOT": {
33586
33757
  this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
33587
- this.compileCalculatedMeasures(cmd.pivot.measures);
33758
+ this.compileCalculatedMeasures(cmd.pivotId, cmd.pivot.measures);
33588
33759
  break;
33589
33760
  }
33590
33761
  }
@@ -33602,9 +33773,14 @@
33602
33773
  this.history.update("pivots", pivotId, "definition", newDefinition);
33603
33774
  }
33604
33775
  }
33605
- for (const sheetId in this.compiledMeasureFormulas) {
33606
- for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
33607
- const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
33776
+ for (const pivotId in this.compiledMeasureFormulas) {
33777
+ for (const measureId in this.compiledMeasureFormulas[pivotId]) {
33778
+ const measure = this.pivots[pivotId]?.definition.measures.find((m) => m.id === measureId);
33779
+ if (!measure || !measure.computedBy) {
33780
+ continue;
33781
+ }
33782
+ const sheetId = measure.computedBy.sheetId;
33783
+ const compiledFormula = this.compiledMeasureFormulas[pivotId][measureId].formula;
33608
33784
  const newDependencies = [];
33609
33785
  for (const range of compiledFormula.dependencies) {
33610
33786
  const change = applyChange(range);
@@ -33616,8 +33792,9 @@
33616
33792
  }
33617
33793
  }
33618
33794
  const newFormulaString = this.getters.getFormulaString(sheetId, compiledFormula.tokens, newDependencies);
33619
- if (newFormulaString !== formulaString) {
33620
- this.replaceMeasureFormula(sheetId, formulaString, newFormulaString);
33795
+ const oldFormulaString = measure.computedBy.formula;
33796
+ if (newFormulaString !== oldFormulaString) {
33797
+ this.replaceMeasureFormula(pivotId, measure, newFormulaString);
33621
33798
  }
33622
33799
  }
33623
33800
  }
@@ -33655,31 +33832,60 @@
33655
33832
  isExistingPivot(pivotId) {
33656
33833
  return pivotId in this.pivots;
33657
33834
  }
33658
- getMeasureCompiledFormula(measure) {
33835
+ getMeasureCompiledFormula(pivotId, measure) {
33836
+ if (!measure.computedBy) {
33837
+ throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
33838
+ }
33839
+ return this.compiledMeasureFormulas[pivotId][measure.id].formula;
33840
+ }
33841
+ getMeasureFullDependencies(pivotId, measure) {
33659
33842
  if (!measure.computedBy) {
33660
33843
  throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
33661
33844
  }
33662
- const sheetId = measure.computedBy.sheetId;
33663
- return this.compiledMeasureFormulas[sheetId][measure.computedBy.formula];
33845
+ return this.compiledMeasureFormulas[pivotId][measure.id].dependencies;
33664
33846
  }
33665
33847
  // -------------------------------------------------------------------------
33666
33848
  // Private
33667
33849
  // -------------------------------------------------------------------------
33668
33850
  addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
33669
33851
  this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
33670
- this.compileCalculatedMeasures(pivot.measures);
33852
+ this.compileCalculatedMeasures(pivotId, pivot.measures);
33671
33853
  this.history.update("formulaIds", formulaId, pivotId);
33672
33854
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
33673
33855
  }
33674
- compileCalculatedMeasures(measures) {
33856
+ compileCalculatedMeasures(pivotId, measures) {
33675
33857
  for (const measure of measures) {
33676
33858
  if (measure.computedBy) {
33677
- const sheetId = measure.computedBy.sheetId;
33678
33859
  const compiledFormula = this.compileMeasureFormula(measure.computedBy.sheetId, measure.computedBy.formula);
33679
- this.history.update("compiledMeasureFormulas", sheetId, measure.computedBy.formula, compiledFormula);
33860
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "formula", compiledFormula);
33861
+ }
33862
+ }
33863
+ for (const measure of measures) {
33864
+ if (measure.computedBy) {
33865
+ const dependencies = this.computeMeasureFullDependencies(pivotId, measure);
33866
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "dependencies", dependencies);
33680
33867
  }
33681
33868
  }
33682
33869
  }
33870
+ computeMeasureFullDependencies(pivotId, measure, exploredMeasures = new Set()) {
33871
+ const rangeDependencies = [];
33872
+ const definition = this.getPivotCoreDefinition(pivotId);
33873
+ const formula = this.getMeasureCompiledFormula(pivotId, measure);
33874
+ exploredMeasures.add(measure.id);
33875
+ for (const token of formula.tokens) {
33876
+ if (token.type !== "SYMBOL") {
33877
+ continue;
33878
+ }
33879
+ const otherMeasure = definition.measures.find((measureCandidate) => getCanonicalSymbolName(measureCandidate.id) === token.value &&
33880
+ measure.id !== measureCandidate.id);
33881
+ if (!otherMeasure || exploredMeasures.has(otherMeasure.id) || !otherMeasure.computedBy) {
33882
+ continue;
33883
+ }
33884
+ rangeDependencies.push(...this.computeMeasureFullDependencies(pivotId, otherMeasure, exploredMeasures));
33885
+ }
33886
+ rangeDependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
33887
+ return rangeDependencies;
33888
+ }
33683
33889
  insertPivot(position, formulaId, table) {
33684
33890
  this.resizeSheet(position.sheetId, position, table);
33685
33891
  const pivotCells = table.getPivotCells();
@@ -33738,21 +33944,17 @@
33738
33944
  dependencies: rangeDependencies,
33739
33945
  };
33740
33946
  }
33741
- replaceMeasureFormula(sheetId, formulaString, newFormulaString) {
33742
- this.history.update("compiledMeasureFormulas", sheetId, formulaString, undefined);
33743
- this.history.update("compiledMeasureFormulas", sheetId, newFormulaString, this.compileMeasureFormula(sheetId, newFormulaString));
33744
- for (const pivotId in this.pivots) {
33745
- const pivot = this.pivots[pivotId];
33746
- if (!pivot) {
33747
- continue;
33748
- }
33749
- for (const measure of pivot.definition.measures) {
33750
- if (measure.computedBy?.formula === formulaString) {
33751
- const measureIndex = pivot.definition.measures.indexOf(measure);
33752
- this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
33753
- }
33754
- }
33947
+ replaceMeasureFormula(pivotId, measure, newFormulaString) {
33948
+ const pivot = this.pivots[pivotId];
33949
+ if (!pivot) {
33950
+ return;
33755
33951
  }
33952
+ const measureIndex = pivot.definition.measures.indexOf(measure);
33953
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", {
33954
+ formula: newFormulaString,
33955
+ sheetId: measure.computedBy.sheetId,
33956
+ });
33957
+ this.compileCalculatedMeasures(pivotId, pivot.definition.measures);
33756
33958
  }
33757
33959
  checkSortedColumnInMeasures(definition) {
33758
33960
  const measures = definition.measures.map((measure) => measure.id);
@@ -33906,6 +34108,7 @@
33906
34108
  "getUnboundedZone",
33907
34109
  "checkElementsIncludeAllNonFrozenHeaders",
33908
34110
  "getDuplicateSheetName",
34111
+ "tryGetCellPosition",
33909
34112
  ];
33910
34113
  sheetIdsMapName = {};
33911
34114
  orderedSheetIds = [];
@@ -33930,10 +34133,12 @@
33930
34133
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
33931
34134
  }
33932
34135
  case "DUPLICATE_SHEET": {
33933
- if (this.sheets[cmd.sheetIdTo])
34136
+ if (this.sheets[cmd.sheetIdTo]) {
33934
34137
  return "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */;
33935
- if (this.orderedSheetIds.map(this.getSheetName.bind(this)).includes(cmd.sheetNameTo))
34138
+ }
34139
+ if (this.orderedSheetIds.map(this.getSheetName.bind(this)).includes(cmd.sheetNameTo)) {
33936
34140
  return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
34141
+ }
33937
34142
  return "Success" /* CommandResult.Success */;
33938
34143
  }
33939
34144
  case "MOVE_SHEET":
@@ -34206,6 +34411,9 @@
34206
34411
  }
34207
34412
  return cell;
34208
34413
  }
34414
+ tryGetCellPosition(cellId) {
34415
+ return this.cellPosition[cellId];
34416
+ }
34209
34417
  getNumberCols(sheetId) {
34210
34418
  return this.getSheet(sheetId).numberOfCols;
34211
34419
  }
@@ -34297,8 +34505,9 @@
34297
34505
  * not outside the sheet.
34298
34506
  */
34299
34507
  checkZonesExistInSheet(sheetId, zones) {
34300
- if (!zones.every(isZoneValid))
34508
+ if (!zones.every(isZoneValid)) {
34301
34509
  return "InvalidRange" /* CommandResult.InvalidRange */;
34510
+ }
34302
34511
  if (zones.length) {
34303
34512
  const sheetZone = this.getSheetZone(sheetId);
34304
34513
  return zones.every((zone) => isZoneInside(zone, sheetZone))
@@ -34732,8 +34941,9 @@
34732
34941
  * not outside the sheet.
34733
34942
  */
34734
34943
  checkZonesAreInSheet(cmd) {
34735
- if (!("sheetId" in cmd))
34944
+ if (!("sheetId" in cmd)) {
34736
34945
  return "Success" /* CommandResult.Success */;
34946
+ }
34737
34947
  if ("ranges" in cmd &&
34738
34948
  cmd.ranges.some((rangeData) => rangeData._sheetId !== "" && !this.getters.tryGetSheet(rangeData._sheetId))) {
34739
34949
  return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
@@ -34813,7 +35023,7 @@
34813
35023
  case "UPDATE_CELL":
34814
35024
  if (cmd.style !== undefined) {
34815
35025
  if (cmd.style !== null) {
34816
- this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style);
35026
+ this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style, { force: true });
34817
35027
  }
34818
35028
  else {
34819
35029
  this.clearStyle(cmd.sheetId, [positionToZone(cmd)]);
@@ -34881,16 +35091,22 @@
34881
35091
  }
34882
35092
  }
34883
35093
  styleIsDefault(style) {
34884
- return deepEquals(this.removeDefaultStyleValues(style), {});
35094
+ for (const key in style) {
35095
+ if (DEFAULT_STYLE_NO_ALIGN[key] !== style[key]) {
35096
+ return false;
35097
+ }
35098
+ }
35099
+ return true;
34885
35100
  }
34886
35101
  removeDefaultStyleValues(style) {
34887
35102
  const cleanedStyle = { ...style };
34888
- for (const property in DEFAULT_STYLE_NO_ALIGN) {
34889
- if (cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
35103
+ for (const property in style) {
35104
+ if (cleanedStyle[property] === undefined ||
35105
+ cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
34890
35106
  delete cleanedStyle[property];
34891
35107
  }
34892
35108
  }
34893
- return cleanedStyle;
35109
+ return Object.keys(cleanedStyle).length > 0 ? cleanedStyle : undefined;
34894
35110
  }
34895
35111
  onMerge(sheetId, zone) {
34896
35112
  this.setStyle(sheetId, zone, this.getCellStyle({ sheetId, col: zone.left, row: zone.top }), {
@@ -34926,13 +35142,13 @@
34926
35142
  }
34927
35143
  editingZone = recomputeZones(editingZone, [inter]);
34928
35144
  }
35145
+ style = this.removeDefaultStyleValues(style);
34929
35146
  if (style) {
34930
- const newStyle = this.removeDefaultStyleValues(style);
34931
35147
  styles.push(...editingZone.map((zone) => {
34932
- return { zone, style: newStyle };
35148
+ return { zone, style };
34933
35149
  }));
34934
35150
  }
34935
- this.history.update("styles", sheetId, styles.filter((zoneStyle) => !this.styleIsDefault(zoneStyle.style)));
35151
+ this.history.update("styles", sheetId, styles);
34936
35152
  }
34937
35153
  clearStyle(sheetId, zones) {
34938
35154
  this.setStyles(sheetId, zones, undefined, { force: true });
@@ -34950,8 +35166,9 @@
34950
35166
  const styles = new PositionMap();
34951
35167
  for (const { zone: z, style } of this.styles[sheetId] ?? []) {
34952
35168
  const inter = intersection(z, zone);
34953
- if (!inter)
35169
+ if (!inter) {
34954
35170
  continue;
35171
+ }
34955
35172
  for (let col = inter.left; col <= inter.right; col++) {
34956
35173
  for (let row = inter.top; row <= inter.bottom; row++) {
34957
35174
  styles.set({ sheetId, col, row }, style);
@@ -34964,8 +35181,9 @@
34964
35181
  const styles = [];
34965
35182
  for (const style of this.styles[sheetId] ?? []) {
34966
35183
  const inter = intersection(style.zone, zone);
34967
- if (inter)
35184
+ if (inter) {
34968
35185
  styles.push({ zone: inter, style: style.style });
35186
+ }
34969
35187
  }
34970
35188
  return styles;
34971
35189
  }
@@ -35038,6 +35256,463 @@
35038
35256
  }
35039
35257
  }
35040
35258
 
35259
+ const pivotLightWithLightBorders = (colorSet) => ({
35260
+ category: "light",
35261
+ templateName: "pivotLightWithLightBorders",
35262
+ primaryColor: colorSet.highlight,
35263
+ wholeTable: {
35264
+ style: { hideGridLines: true },
35265
+ border: { horizontal: { color: colorSet.light, style: "thin" } },
35266
+ },
35267
+ headerRow: {
35268
+ style: { bold: true },
35269
+ border: {
35270
+ top: { color: colorSet.highlight, style: "thin" },
35271
+ bottom: { color: colorSet.highlight, style: "thin" },
35272
+ },
35273
+ },
35274
+ mainSubHeaderRow: { style: { bold: true } },
35275
+ firstAlternatingSubHeaderRow: { style: { bold: true, textColor: colorSet.highlight } },
35276
+ totalRow: {
35277
+ border: {
35278
+ top: { color: colorSet.highlight, style: "thin" },
35279
+ bottom: { color: colorSet.highlight, style: "thin" },
35280
+ },
35281
+ style: { bold: true, fillColor: "#FFFFFF" },
35282
+ },
35283
+ firstRowStripe: {
35284
+ style: { fillColor: colorSet.light },
35285
+ border: {
35286
+ bottom: { color: colorSet.medium, style: "thin" },
35287
+ top: { color: colorSet.medium, style: "thin" },
35288
+ vertical: { color: colorSet.medium, style: "thin" },
35289
+ },
35290
+ },
35291
+ secondColumnStripe: {
35292
+ style: { fillColor: colorSet.light },
35293
+ border: {
35294
+ left: { color: colorSet.medium, style: "thin" },
35295
+ right: { color: colorSet.medium, style: "thin" },
35296
+ horizontal: { color: colorSet.medium, style: "thin" },
35297
+ },
35298
+ },
35299
+ });
35300
+ const pivotLightWithMediumBorders = (colorSet) => ({
35301
+ category: "light",
35302
+ templateName: "pivotLightWithMediumBorders",
35303
+ primaryColor: colorSet.highlight,
35304
+ wholeTable: {
35305
+ style: { textColor: colorSet.coloredText, hideGridLines: true },
35306
+ border: { horizontal: { color: colorSet.light, style: "thin" } },
35307
+ },
35308
+ firstColumn: { border: { right: { color: colorSet.highlight, style: "thin" } } },
35309
+ headerRow: {
35310
+ style: { bold: true, textColor: "#000000" },
35311
+ border: {
35312
+ top: { color: colorSet.highlight, style: "medium" },
35313
+ bottom: { color: colorSet.highlight, style: "medium" },
35314
+ left: { color: colorSet.highlight, style: "medium" },
35315
+ right: { color: colorSet.highlight, style: "medium" },
35316
+ },
35317
+ },
35318
+ measureHeader: { border: { top: { color: colorSet.light, style: "thin" } } },
35319
+ mainSubHeaderRow: {
35320
+ style: { bold: true, textColor: "#000000", fillColor: colorSet.light },
35321
+ },
35322
+ firstAlternatingSubHeaderRow: { style: { bold: true, textColor: "#000000" } },
35323
+ totalRow: {
35324
+ border: {
35325
+ top: { color: colorSet.highlight, style: "medium" },
35326
+ bottom: { color: colorSet.highlight, style: "medium" },
35327
+ left: { color: colorSet.highlight, style: "medium" },
35328
+ right: { color: colorSet.highlight, style: "medium" },
35329
+ },
35330
+ style: { bold: true, textColor: "#000000" },
35331
+ },
35332
+ firstRowStripe: {
35333
+ border: {
35334
+ bottom: { color: colorSet.highlight, style: "thin" },
35335
+ top: { color: colorSet.highlight, style: "thin" },
35336
+ },
35337
+ },
35338
+ secondRowStripe: {
35339
+ border: { bottom: { color: colorSet.highlight, style: "thin" } },
35340
+ },
35341
+ firstColumnStripe: {
35342
+ border: {
35343
+ left: { color: colorSet.highlight, style: "thin" },
35344
+ right: { color: colorSet.highlight, style: "thin" },
35345
+ },
35346
+ },
35347
+ secondColumnStripe: {
35348
+ border: {
35349
+ left: { color: colorSet.highlight, style: "thin" },
35350
+ right: { color: colorSet.highlight, style: "thin" },
35351
+ },
35352
+ },
35353
+ });
35354
+ const pivotLightWithGrayBands = (colorSet) => ({
35355
+ category: "light",
35356
+ templateName: "PivotLightWithGrayBands",
35357
+ primaryColor: colorSet.highlight,
35358
+ wholeTable: { style: { hideGridLines: true } },
35359
+ headerRow: {
35360
+ style: { bold: true, fillColor: colorSet.light },
35361
+ border: {
35362
+ horizontal: { color: colorSet.light, style: "thin" },
35363
+ vertical: { color: colorSet.light, style: "thin" },
35364
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35365
+ },
35366
+ },
35367
+ measureHeader: { border: { top: { color: "#FFFFFF", style: "thin" } } },
35368
+ mainSubHeaderRow: {
35369
+ style: { bold: true },
35370
+ border: { bottom: { color: colorSet.mediumBorder, style: "thin" } },
35371
+ },
35372
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35373
+ totalRow: {
35374
+ border: { top: { color: colorSet.mediumBorder, style: "medium" } },
35375
+ style: { bold: true, fillColor: colorSet.light },
35376
+ },
35377
+ firstRowStripe: { style: { fillColor: TABLE_COLOR_SETS.black.light } },
35378
+ secondColumnStripe: {
35379
+ style: { fillColor: TABLE_COLOR_SETS.black.light },
35380
+ border: {
35381
+ left: { color: TABLE_COLOR_SETS.black.medium, style: "thin" },
35382
+ right: { color: TABLE_COLOR_SETS.black.medium, style: "thin" },
35383
+ },
35384
+ },
35385
+ });
35386
+ const pivotLightWithColoredText = (colorSet) => ({
35387
+ category: "light",
35388
+ templateName: "pivotLightWithColoredText",
35389
+ primaryColor: colorSet.highlight,
35390
+ wholeTable: {
35391
+ style: { hideGridLines: true, textColor: colorSet.coloredText },
35392
+ border: {
35393
+ vertical: { color: colorSet.mediumBorder, style: "thin" },
35394
+ top: { color: colorSet.mediumBorder, style: "thin" },
35395
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35396
+ left: { color: colorSet.mediumBorder, style: "thin" },
35397
+ right: { color: colorSet.mediumBorder, style: "thin" },
35398
+ },
35399
+ },
35400
+ headerRow: {
35401
+ border: {
35402
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35403
+ vertical: { color: colorSet.mediumBorder, style: "thin" },
35404
+ },
35405
+ },
35406
+ totalRow: {
35407
+ border: { top: { color: colorSet.mediumBorder, style: "thin" } },
35408
+ },
35409
+ firstRowStripe: {
35410
+ style: { fillColor: colorSet.light },
35411
+ border: {
35412
+ top: { color: TABLE_COLOR_SETS.black.medium, style: "thin" },
35413
+ bottom: { color: TABLE_COLOR_SETS.black.medium, style: "thin" },
35414
+ },
35415
+ },
35416
+ secondColumnStripe: { style: { fillColor: colorSet.light } },
35417
+ });
35418
+ const pivotMediumHeavyColors = (colorSet) => ({
35419
+ category: "medium",
35420
+ templateName: "pivotMediumHeavyColors",
35421
+ primaryColor: colorSet.highlight,
35422
+ wholeTable: {
35423
+ style: { hideGridLines: true },
35424
+ border: { horizontal: { color: colorSet.light, style: "thin" } },
35425
+ },
35426
+ headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
35427
+ measureHeader: { border: { top: { color: colorSet.light, style: "thin" } } },
35428
+ mainSubHeaderRow: { style: { fillColor: colorSet.mediumBorder, textColor: "#FFFFFF" } },
35429
+ firstAlternatingSubHeaderRow: {
35430
+ style: { fillColor: colorSet.light },
35431
+ border: { bottom: { color: colorSet.highlight, style: "thin" } },
35432
+ },
35433
+ totalRow: {
35434
+ border: { top: { color: colorSet.highlight, style: "medium" } }, // @compatibility: should be double line
35435
+ style: { bold: true },
35436
+ },
35437
+ firstRowStripe: {
35438
+ border: {
35439
+ bottom: { color: colorSet.highlight, style: "thin" },
35440
+ top: { color: colorSet.highlight, style: "thin" },
35441
+ },
35442
+ },
35443
+ firstColumnStripe: {
35444
+ border: {
35445
+ left: { color: colorSet.highlight, style: "thin" },
35446
+ right: { color: colorSet.highlight, style: "thin" },
35447
+ },
35448
+ },
35449
+ });
35450
+ const pivotMediumLightColors = (colorSet) => ({
35451
+ category: "medium",
35452
+ templateName: "pivotMediumLightColors",
35453
+ primaryColor: colorSet.highlight,
35454
+ wholeTable: {
35455
+ style: { hideGridLines: true },
35456
+ border: {
35457
+ top: { color: colorSet.dark, style: "medium" },
35458
+ bottom: { color: colorSet.dark, style: "medium" },
35459
+ },
35460
+ },
35461
+ headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
35462
+ measureHeader: { border: { top: { color: colorSet.mediumBorder, style: "thin" } } },
35463
+ mainSubHeaderRow: { style: { fillColor: colorSet.light, bold: true } },
35464
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35465
+ totalRow: {
35466
+ border: { top: { color: colorSet.dark, style: "thin" } },
35467
+ style: { bold: true },
35468
+ },
35469
+ firstRowStripe: {
35470
+ border: {
35471
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35472
+ top: { color: colorSet.mediumBorder, style: "thin" },
35473
+ },
35474
+ },
35475
+ firstColumnStripe: {
35476
+ border: {
35477
+ left: { color: colorSet.mediumBorder, style: "thin" },
35478
+ right: { color: colorSet.mediumBorder, style: "thin" },
35479
+ },
35480
+ },
35481
+ });
35482
+ const pivotMediumBlackHeaders = (colorSet) => ({
35483
+ category: "medium",
35484
+ templateName: "pivotMediumBlackHeaders",
35485
+ primaryColor: colorSet.highlight,
35486
+ wholeTable: {
35487
+ style: { hideGridLines: true, fillColor: colorSet.light },
35488
+ border: { vertical: { color: colorSet.mediumBorder, style: "thin" } },
35489
+ },
35490
+ headerRow: { style: { fillColor: "#000000", textColor: "#FFFFFF" } },
35491
+ measureHeader: { border: { top: { color: "#FFFFFF", style: "thin" } } },
35492
+ mainSubHeaderRow: { style: { bold: true } },
35493
+ firstAlternatingSubHeaderRow: { style: { bold: true, textColor: "#808080" } },
35494
+ secondAlternatingSubHeaderRow: { style: { bold: true } },
35495
+ totalRow: {
35496
+ style: { fillColor: "#000000", textColor: "#FFFFFF" },
35497
+ border: { vertical: null },
35498
+ },
35499
+ firstRowStripe: {
35500
+ border: {
35501
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35502
+ top: { color: colorSet.mediumBorder, style: "thin" },
35503
+ },
35504
+ },
35505
+ });
35506
+ const pivotMediumColoredTexts = (colorSet) => ({
35507
+ category: "medium",
35508
+ templateName: "pivotMediumBlackHeaders",
35509
+ primaryColor: colorSet.highlight,
35510
+ wholeTable: {
35511
+ style: { hideGridLines: true, fillColor: colorSet.light, textColor: colorSet.coloredText },
35512
+ border: { vertical: { color: "#FFFFFF", style: "thin" } },
35513
+ },
35514
+ headerRow: {
35515
+ style: { bold: true },
35516
+ border: {
35517
+ vertical: { color: "#FFFFFF", style: "thin" },
35518
+ bottom: { color: "#FFFFFF", style: "thin" },
35519
+ },
35520
+ },
35521
+ firstColumn: { style: { fillColor: colorSet.medium } },
35522
+ measureHeader: { border: { top: { color: "#FFFFFF", style: "thin" } } },
35523
+ mainSubHeaderRow: { style: { bold: true, textColor: "#000000" } },
35524
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35525
+ secondAlternatingSubHeaderRow: { style: { bold: true } },
35526
+ totalRow: { style: { bold: true } },
35527
+ firstRowStripe: { style: { fillColor: colorSet.medium } },
35528
+ firstColumnStripe: { style: { fillColor: colorSet.medium } },
35529
+ });
35530
+ const pivotDarkWithDarkHeader = (colorSet) => ({
35531
+ category: "dark",
35532
+ templateName: "pivotDarkWithDarkHeader",
35533
+ primaryColor: colorSet.highlight,
35534
+ wholeTable: {
35535
+ style: { hideGridLines: true, fillColor: colorSet.medium },
35536
+ border: { horizontal: { color: colorSet.light, style: "thin" } },
35537
+ },
35538
+ headerRow: { style: { bold: true, fillColor: colorSet.dark, textColor: "#FFFFFF" } },
35539
+ measureHeader: { border: { top: { color: colorSet.light, style: "thin" } } },
35540
+ mainSubHeaderRow: { style: { bold: true, fillColor: colorSet.light } },
35541
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35542
+ totalRow: { style: { bold: true, fillColor: colorSet.dark, textColor: "#FFFFFF" } },
35543
+ secondRowStripe: { style: { fillColor: colorSet.mediumBorder } },
35544
+ firstColumnStripe: {
35545
+ border: {
35546
+ left: { color: colorSet.light, style: "thin" },
35547
+ right: { color: colorSet.light, style: "thin" },
35548
+ },
35549
+ },
35550
+ });
35551
+ const pivotDarkWithGrayHeader = (colorSet) => ({
35552
+ category: "dark",
35553
+ templateName: "pivotDarkWithGrayHeader",
35554
+ primaryColor: colorSet.highlight,
35555
+ wholeTable: { style: { hideGridLines: true, fillColor: colorSet.light } },
35556
+ headerRow: {
35557
+ style: { bold: true, fillColor: TABLE_COLOR_SETS.black.dark, textColor: "#FFFFFF" },
35558
+ },
35559
+ measureHeader: { border: { top: { color: colorSet.light, style: "medium" } } },
35560
+ mainSubHeaderRow: { style: { bold: true, fillColor: colorSet.medium } },
35561
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35562
+ totalRow: { style: { bold: true, fillColor: TABLE_COLOR_SETS.black.dark, textColor: "#FFFFFF" } },
35563
+ firstRowStripe: {
35564
+ border: {
35565
+ bottom: { color: colorSet.medium, style: "thin" },
35566
+ top: { color: colorSet.medium, style: "thin" },
35567
+ },
35568
+ },
35569
+ firstColumnStripe: {
35570
+ border: {
35571
+ left: { color: colorSet.mediumBorder, style: "thin" },
35572
+ right: { color: colorSet.mediumBorder, style: "thin" },
35573
+ },
35574
+ },
35575
+ });
35576
+ const pivotDarkWithBlackHeader = (colorSet) => ({
35577
+ category: "dark",
35578
+ templateName: "pivotDarkWithBlackHeader",
35579
+ primaryColor: colorSet.highlight,
35580
+ wholeTable: {
35581
+ style: { hideGridLines: true, fillColor: colorSet.highlight, textColor: "#FFFFFF" },
35582
+ },
35583
+ headerRow: { style: { bold: true, fillColor: "#000000" } },
35584
+ measureHeader: { border: { top: { color: colorSet.light, style: "thin" } } },
35585
+ mainSubHeaderRow: { style: { bold: true, fillColor: colorSet.dark } },
35586
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35587
+ totalRow: { style: { bold: true, fillColor: "#000000" } },
35588
+ firstRowStripe: {
35589
+ border: {
35590
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35591
+ top: { color: colorSet.mediumBorder, style: "thin" },
35592
+ },
35593
+ },
35594
+ firstColumnStripe: {
35595
+ border: {
35596
+ left: { color: colorSet.mediumBorder, style: "thin" },
35597
+ right: { color: colorSet.mediumBorder, style: "thin" },
35598
+ },
35599
+ },
35600
+ });
35601
+ const pivotDarkWithFirstColumn = (colorSet) => ({
35602
+ category: "dark",
35603
+ templateName: "pivotDarkWithFirstColumn",
35604
+ primaryColor: colorSet.highlight,
35605
+ wholeTable: {
35606
+ style: { hideGridLines: true, fillColor: colorSet.highlight, textColor: "#FFFFFF" },
35607
+ border: { vertical: { color: "#FFFFFF", style: "thin" } },
35608
+ },
35609
+ headerRow: {
35610
+ style: { fillColor: colorSet.dark },
35611
+ border: { bottom: { color: "#FFFFFF", style: "medium" } },
35612
+ },
35613
+ firstColumn: { style: { fillColor: colorSet.dark } },
35614
+ measureHeader: { border: { top: { color: colorSet.light, style: "thin" } } },
35615
+ mainSubHeaderRow: { style: { bold: true } },
35616
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35617
+ totalRow: {
35618
+ style: { bold: true, fillColor: colorSet.dark },
35619
+ border: { top: { color: "#FFFFFF", style: "medium" } },
35620
+ },
35621
+ secondRowStripe: { style: { fillColor: colorSet.mediumBorder } },
35622
+ firstColumnStripe: { style: { fillColor: colorSet.mediumBorder } },
35623
+ });
35624
+ const PIVOT_TABLE_PRESETS = {
35625
+ None: { category: "light", templateName: "none", primaryColor: "", displayName: _t("None") },
35626
+ };
35627
+ const colorSets = [
35628
+ TABLE_COLOR_SETS.black,
35629
+ TABLE_COLOR_SETS.lightBlue,
35630
+ TABLE_COLOR_SETS.red,
35631
+ TABLE_COLOR_SETS.lightGreen,
35632
+ TABLE_COLOR_SETS.purple,
35633
+ TABLE_COLOR_SETS.gray,
35634
+ TABLE_COLOR_SETS.orange,
35635
+ ];
35636
+ function addTemplatesToPresets(baseName, templates) {
35637
+ let index = 1;
35638
+ for (const template of templates) {
35639
+ for (const colorSet of colorSets) {
35640
+ const name = baseName + index++;
35641
+ const preset = {
35642
+ ...template(colorSet),
35643
+ displayName: getPresetDisplayName(colorSet.name, baseName, index - 1),
35644
+ };
35645
+ PIVOT_TABLE_PRESETS[name] = preset;
35646
+ }
35647
+ }
35648
+ }
35649
+ function getPresetDisplayName(colorName, baseName, index) {
35650
+ let category = "";
35651
+ if (baseName.includes("Light")) {
35652
+ category = TABLE_STYLE_CATEGORIES.light;
35653
+ }
35654
+ else if (baseName.includes("Medium")) {
35655
+ category = TABLE_STYLE_CATEGORIES.medium;
35656
+ }
35657
+ else if (baseName.includes("Dark")) {
35658
+ category = TABLE_STYLE_CATEGORIES.dark;
35659
+ }
35660
+ return `${category} ${colorName} ${index}`;
35661
+ }
35662
+ addTemplatesToPresets("PivotTableStyleLight", [
35663
+ pivotLightWithLightBorders,
35664
+ pivotLightWithMediumBorders,
35665
+ pivotLightWithGrayBands,
35666
+ pivotLightWithColoredText,
35667
+ ]);
35668
+ addTemplatesToPresets("PivotTableStyleMedium", [
35669
+ pivotMediumHeavyColors,
35670
+ pivotMediumLightColors,
35671
+ pivotMediumBlackHeaders,
35672
+ pivotMediumColoredTexts,
35673
+ ]);
35674
+ addTemplatesToPresets("PivotTableStyleDark", [
35675
+ pivotDarkWithDarkHeader,
35676
+ pivotDarkWithGrayHeader,
35677
+ pivotDarkWithBlackHeader,
35678
+ pivotDarkWithFirstColumn,
35679
+ ]);
35680
+ // Tweak some presets with the black color set
35681
+ PIVOT_TABLE_PRESETS["PivotTableStyleDark1"] = {
35682
+ ...PIVOT_TABLE_PRESETS["PivotTableStyleDark1"],
35683
+ ...pivotDarkWithDarkHeader({
35684
+ ...TABLE_COLOR_SETS.black,
35685
+ mediumBorder: darkenColor(TABLE_COLOR_SETS.black.medium, 0.1),
35686
+ }),
35687
+ };
35688
+ PIVOT_TABLE_PRESETS["PivotTableStyleDark15"] = {
35689
+ ...PIVOT_TABLE_PRESETS["PivotTableStyleDark15"],
35690
+ ...pivotDarkWithBlackHeader({
35691
+ ...TABLE_COLOR_SETS.black,
35692
+ highlight: TABLE_COLOR_SETS.gray.dark,
35693
+ mediumBorder: TABLE_COLOR_SETS.black.medium,
35694
+ }),
35695
+ };
35696
+ PIVOT_TABLE_PRESETS["PivotTableStyleDark22"] = {
35697
+ ...PIVOT_TABLE_PRESETS["PivotTableStyleDark22"],
35698
+ ...pivotDarkWithFirstColumn({
35699
+ ...TABLE_COLOR_SETS.black,
35700
+ highlight: TABLE_COLOR_SETS.gray.dark,
35701
+ mediumBorder: TABLE_COLOR_SETS.black.medium,
35702
+ }),
35703
+ };
35704
+ function pivotTableStyleIdToTableStyleId(pivotStyleId) {
35705
+ const template = PIVOT_TABLE_PRESETS[pivotStyleId];
35706
+ if (!template) {
35707
+ return "None";
35708
+ }
35709
+ return (Object.keys(TABLE_PRESETS).find((tableStyleId) => {
35710
+ const tablePreset = TABLE_PRESETS[tableStyleId];
35711
+ return (tablePreset.category === template.category &&
35712
+ tablePreset.primaryColor === template.primaryColor);
35713
+ }) || "None");
35714
+ }
35715
+
35041
35716
  class TableStylePlugin extends CorePlugin {
35042
35717
  static getters = [
35043
35718
  "getNewCustomTableStyleName",
@@ -35093,6 +35768,9 @@
35093
35768
  }
35094
35769
  }
35095
35770
  getTableStyle(styleId) {
35771
+ if (PIVOT_TABLE_PRESETS[styleId]) {
35772
+ return PIVOT_TABLE_PRESETS[styleId];
35773
+ }
35096
35774
  if (!this.styles[styleId]) {
35097
35775
  throw new Error(`Table style ${styleId} does not exist`);
35098
35776
  }
@@ -35142,6 +35820,10 @@
35142
35820
  "firstColumn",
35143
35821
  "lastColumn",
35144
35822
  "headerRow",
35823
+ "measureHeader",
35824
+ "firstAlternatingSubHeaderRow",
35825
+ "secondAlternatingSubHeaderRow",
35826
+ "mainSubHeaderRow",
35145
35827
  "totalRow",
35146
35828
  ];
35147
35829
  /** Return the content zone of the table, ie. the table zone without the headers */
@@ -35164,40 +35846,42 @@
35164
35846
  filteredRange: filteredZone.top > filteredZone.bottom ? undefined : filteredRange,
35165
35847
  };
35166
35848
  }
35167
- function getComputedTableStyle(tableConfig, style, numberOfCols, numberOfRows) {
35849
+ function getComputedTableStyle(tableConfig, style, tableMetaData) {
35168
35850
  return {
35169
- borders: getAllTableBorders(tableConfig, style, numberOfCols, numberOfRows),
35170
- styles: getAllTableStyles(tableConfig, style, numberOfCols, numberOfRows),
35851
+ borders: getAllTableBorders(tableConfig, style, tableMetaData),
35852
+ styles: getAllTableStyles(tableConfig, style, tableMetaData),
35171
35853
  };
35172
35854
  }
35173
- function getAllTableBorders(tableConfig, style, nOfCols, nOfRows) {
35855
+ function getAllTableBorders(tableConfig, style, tableMetaData) {
35856
+ const { numberOfCols: nOfCols, numberOfRows: nOfRows } = tableMetaData;
35174
35857
  const borders = generateMatrix(nOfCols, nOfRows, () => ({}));
35175
35858
  for (const tableElement of TABLE_ELEMENTS_BY_PRIORITY) {
35176
35859
  const styleBorder = style[tableElement]?.border;
35177
- if (!styleBorder)
35860
+ if (!styleBorder) {
35178
35861
  continue;
35179
- const zones = getTableElementZones(tableElement, tableConfig, nOfCols, nOfRows);
35862
+ }
35863
+ const zones = getTableElementZones(tableElement, tableConfig, tableMetaData);
35180
35864
  for (const zone of zones) {
35181
35865
  for (let col = zone.left; col <= zone.right; col++) {
35182
35866
  for (let row = zone.top; row <= zone.bottom; row++) {
35183
35867
  // Special case: we don't want borders inside the headers rows
35184
35868
  const noInsideBorder = tableElement === "wholeTable" && row <= tableConfig.numberOfHeaders - 1;
35185
- if (row === zone.top && styleBorder?.top) {
35869
+ if (row === zone.top && styleBorder?.top !== undefined) {
35186
35870
  setBorderDescr(borders, "top", styleBorder.top, col, row, nOfCols, nOfRows);
35187
35871
  }
35188
- else if (row !== zone.top && !noInsideBorder && styleBorder?.horizontal) {
35872
+ else if (row !== zone.top && !noInsideBorder && styleBorder?.horizontal !== undefined) {
35189
35873
  setBorderDescr(borders, "top", styleBorder.horizontal, col, row, nOfCols, nOfRows);
35190
35874
  }
35191
- if (row === zone.bottom && styleBorder?.bottom) {
35875
+ if (row === zone.bottom && styleBorder?.bottom !== undefined) {
35192
35876
  setBorderDescr(borders, "bottom", styleBorder.bottom, col, row, nOfCols, nOfRows);
35193
35877
  }
35194
- if (col === zone.left && styleBorder?.left) {
35878
+ if (col === zone.left && styleBorder?.left !== undefined) {
35195
35879
  setBorderDescr(borders, "left", styleBorder.left, col, row, nOfCols, nOfRows);
35196
35880
  }
35197
- if (col === zone.right && styleBorder?.right) {
35881
+ if (col === zone.right && styleBorder?.right !== undefined) {
35198
35882
  setBorderDescr(borders, "right", styleBorder.right, col, row, nOfCols, nOfRows);
35199
35883
  }
35200
- else if (col !== zone.right && !noInsideBorder && styleBorder?.vertical) {
35884
+ else if (col !== zone.right && !noInsideBorder && styleBorder?.vertical !== undefined) {
35201
35885
  setBorderDescr(borders, "right", styleBorder.vertical, col, row, nOfCols, nOfRows);
35202
35886
  }
35203
35887
  }
@@ -35214,40 +35898,40 @@
35214
35898
  function setBorderDescr(computedBorders, dir, borderDescr, col, row, numberOfCols, numberOfRows) {
35215
35899
  switch (dir) {
35216
35900
  case "top":
35217
- computedBorders[col][row].top = borderDescr;
35901
+ computedBorders[col][row].top = borderDescr ?? undefined;
35218
35902
  if (row !== 0) {
35219
- computedBorders[col][row - 1].bottom = borderDescr;
35903
+ computedBorders[col][row - 1].bottom = borderDescr ?? undefined;
35220
35904
  }
35221
35905
  return;
35222
35906
  case "bottom":
35223
- computedBorders[col][row].bottom = borderDescr;
35907
+ computedBorders[col][row].bottom = borderDescr ?? undefined;
35224
35908
  if (row !== numberOfRows - 1) {
35225
- computedBorders[col][row + 1].top = borderDescr;
35909
+ computedBorders[col][row + 1].top = borderDescr ?? undefined;
35226
35910
  }
35227
35911
  return;
35228
35912
  case "left":
35229
- computedBorders[col][row].left = borderDescr;
35913
+ computedBorders[col][row].left = borderDescr ?? undefined;
35230
35914
  if (col !== 0) {
35231
- computedBorders[col - 1][row].right = borderDescr;
35915
+ computedBorders[col - 1][row].right = borderDescr ?? undefined;
35232
35916
  }
35233
35917
  return;
35234
35918
  case "right":
35235
- computedBorders[col][row].right = borderDescr;
35919
+ computedBorders[col][row].right = borderDescr ?? undefined;
35236
35920
  if (col !== numberOfCols - 1) {
35237
- computedBorders[col + 1][row].left = borderDescr;
35921
+ computedBorders[col + 1][row].left = borderDescr ?? undefined;
35238
35922
  }
35239
35923
  return;
35240
35924
  }
35241
35925
  }
35242
- function getAllTableStyles(tableConfig, style, numberOfCols, numberOfRows) {
35926
+ function getAllTableStyles(tableConfig, style, tableMetaData) {
35927
+ const { numberOfCols, numberOfRows } = tableMetaData;
35243
35928
  const styles = generateMatrix(numberOfCols, numberOfRows, () => ({}));
35244
35929
  for (const tableElement of TABLE_ELEMENTS_BY_PRIORITY) {
35245
35930
  const tableElStyle = style[tableElement];
35246
- const bold = isTableElementInBold(tableElement);
35247
- if (!tableElStyle && !bold) {
35931
+ if (!tableElStyle) {
35248
35932
  continue;
35249
35933
  }
35250
- const zones = getTableElementZones(tableElement, tableConfig, numberOfCols, numberOfRows);
35934
+ const zones = getTableElementZones(tableElement, tableConfig, tableMetaData);
35251
35935
  for (const zone of zones) {
35252
35936
  for (let col = zone.left; col <= zone.right; col++) {
35253
35937
  for (let row = zone.top; row <= zone.bottom; row++) {
@@ -35258,22 +35942,14 @@
35258
35942
  ...styles[col][row],
35259
35943
  ...tableElStyle?.style,
35260
35944
  };
35261
- if (bold) {
35262
- styles[col][row].bold = true;
35263
- }
35264
35945
  }
35265
35946
  }
35266
35947
  }
35267
35948
  }
35268
35949
  return styles;
35269
35950
  }
35270
- function isTableElementInBold(tableElement) {
35271
- return (tableElement === "firstColumn" ||
35272
- tableElement === "lastColumn" ||
35273
- tableElement === "headerRow" ||
35274
- tableElement === "totalRow");
35275
- }
35276
- function getTableElementZones(el, tableConfig, numberOfCols, numberOfRows) {
35951
+ function getTableElementZones(el, tableConfig, tableMetaData) {
35952
+ const { numberOfCols, numberOfRows } = tableMetaData;
35277
35953
  const zones = [];
35278
35954
  const headerRows = Math.min(tableConfig.numberOfHeaders, numberOfRows);
35279
35955
  const totalRows = tableConfig.totalRow ? 1 : 0;
@@ -35284,51 +35960,84 @@
35284
35960
  zones.push({ top: 0, left: 0, bottom: lastRow, right: lastCol });
35285
35961
  break;
35286
35962
  case "firstColumn":
35287
- if (!tableConfig.firstColumn)
35963
+ if (!tableConfig.firstColumn) {
35288
35964
  break;
35965
+ }
35289
35966
  zones.push({ top: 0, left: 0, bottom: lastRow, right: 0 });
35290
35967
  break;
35291
35968
  case "lastColumn":
35292
- if (!tableConfig.lastColumn)
35969
+ if (!tableConfig.lastColumn) {
35293
35970
  break;
35971
+ }
35294
35972
  zones.push({ top: 0, left: lastCol, bottom: lastRow, right: lastCol });
35295
35973
  break;
35296
35974
  case "headerRow":
35297
- if (!tableConfig.numberOfHeaders)
35975
+ if (!tableConfig.numberOfHeaders) {
35298
35976
  break;
35977
+ }
35299
35978
  zones.push({ top: 0, left: 0, bottom: headerRows - 1, right: lastCol });
35300
35979
  break;
35301
35980
  case "totalRow":
35302
- if (!tableConfig.totalRow)
35981
+ if (!tableConfig.totalRow) {
35303
35982
  break;
35983
+ }
35304
35984
  zones.push({ top: lastRow, left: 0, bottom: lastRow, right: lastCol });
35305
35985
  break;
35306
35986
  case "firstRowStripe":
35307
- if (!tableConfig.bandedRows)
35987
+ if (!tableConfig.bandedRows) {
35308
35988
  break;
35989
+ }
35309
35990
  for (let i = headerRows; i < numberOfRows - totalRows; i += 2) {
35310
35991
  zones.push({ top: i, left: 0, bottom: i, right: lastCol });
35311
35992
  }
35312
35993
  break;
35313
35994
  case "secondRowStripe":
35314
- if (!tableConfig.bandedRows)
35995
+ if (!tableConfig.bandedRows) {
35315
35996
  break;
35997
+ }
35316
35998
  for (let i = headerRows + 1; i < numberOfRows - totalRows; i += 2) {
35317
35999
  zones.push({ top: i, left: 0, bottom: i, right: lastCol });
35318
36000
  }
35319
36001
  break;
35320
- case "firstColumnStripe":
35321
- if (!tableConfig.bandedColumns)
36002
+ case "firstColumnStripe": {
36003
+ if (!tableConfig.bandedColumns) {
35322
36004
  break;
36005
+ }
36006
+ const bottom = tableMetaData.mode === "pivot" ? lastRow : lastRow - totalRows;
35323
36007
  for (let i = 0; i < numberOfCols; i += 2) {
35324
- zones.push({ top: headerRows, left: i, bottom: lastRow - totalRows, right: i });
36008
+ zones.push({ top: headerRows, left: i, bottom, right: i });
35325
36009
  }
35326
36010
  break;
35327
- case "secondColumnStripe":
35328
- if (!tableConfig.bandedColumns)
36011
+ }
36012
+ case "secondColumnStripe": {
36013
+ if (!tableConfig.bandedColumns) {
35329
36014
  break;
36015
+ }
36016
+ const bottom = tableMetaData.mode === "pivot" ? lastRow : lastRow - totalRows;
35330
36017
  for (let i = 1; i < numberOfCols; i += 2) {
35331
- zones.push({ top: headerRows, left: i, bottom: lastRow - totalRows, right: i });
36018
+ zones.push({ top: headerRows, left: i, bottom, right: i });
36019
+ }
36020
+ break;
36021
+ }
36022
+ case "mainSubHeaderRow":
36023
+ for (const row of tableMetaData.mainSubHeaderRows || []) {
36024
+ zones.push({ top: row, bottom: row, left: 0, right: tableMetaData.numberOfCols - 1 });
36025
+ }
36026
+ break;
36027
+ case "firstAlternatingSubHeaderRow":
36028
+ for (const row of tableMetaData.firstAlternatingSubHeaderRows || []) {
36029
+ zones.push({ top: row, bottom: row, left: 0, right: tableMetaData.numberOfCols - 1 });
36030
+ }
36031
+ break;
36032
+ case "secondAlternatingSubHeaderRow":
36033
+ for (const row of tableMetaData.secondAlternatingSubHeaderRows || []) {
36034
+ zones.push({ top: row, bottom: row, left: 0, right: tableMetaData.numberOfCols - 1 });
36035
+ }
36036
+ break;
36037
+ case "measureHeader":
36038
+ if (tableMetaData.measureRow !== undefined && tableMetaData.numberOfCols > 1) {
36039
+ const row = tableMetaData.measureRow;
36040
+ zones.push({ top: row, bottom: row, left: 1, right: tableMetaData.numberOfCols - 1 });
35332
36041
  }
35333
36042
  break;
35334
36043
  }
@@ -37887,8 +38596,9 @@
37887
38596
  */
37888
38597
  getRangeFormattedValues(range) {
37889
38598
  const sheet = this.getters.tryGetSheet(range.sheetId);
37890
- if (sheet === undefined)
38599
+ if (sheet === undefined) {
37891
38600
  return [];
38601
+ }
37892
38602
  return this.mapVisiblePositions(range, (p) => this.getters.getEvaluatedCell(p).formattedValue);
37893
38603
  }
37894
38604
  /**
@@ -37896,8 +38606,9 @@
37896
38606
  */
37897
38607
  getRangeValues(range) {
37898
38608
  const sheet = this.getters.tryGetSheet(range.sheetId);
37899
- if (sheet === undefined)
38609
+ if (sheet === undefined) {
37900
38610
  return [];
38611
+ }
37901
38612
  return this.mapVisiblePositions(range, (p) => this.getters.getEvaluatedCell(p).value);
37902
38613
  }
37903
38614
  /**
@@ -37905,8 +38616,9 @@
37905
38616
  */
37906
38617
  getRangeFormats(range) {
37907
38618
  const sheet = this.getters.tryGetSheet(range.sheetId);
37908
- if (sheet === undefined)
38619
+ if (sheet === undefined) {
37909
38620
  return [];
38621
+ }
37910
38622
  return this.getters.getEvaluatedCellsInZone(sheet.id, range.zone).map((cell) => cell.format);
37911
38623
  }
37912
38624
  getEvaluatedCell(position) {
@@ -38069,8 +38781,9 @@
38069
38781
  return `${italicStr} ${weight} ${fontSize}px ${DEFAULT_FONT}`;
38070
38782
  }
38071
38783
  function computeMultilineTextSize(context, textLines, style = {}, fontUnit = "pt") {
38072
- if (!textLines.length)
38784
+ if (!textLines.length) {
38073
38785
  return { width: 0, height: 0 };
38786
+ }
38074
38787
  const font = computeTextFont(style, fontUnit);
38075
38788
  const sizes = textLines.map((line) => computeCachedTextDimension(context, line, font));
38076
38789
  const height = computeTextLinesHeight(sizes[0].height, textLines.length);
@@ -38162,10 +38875,12 @@
38162
38875
  * line if it contains NEWLINE characters, or if it's longer than the given width.
38163
38876
  */
38164
38877
  function splitTextToWidth(ctx, text, style, width) {
38165
- if (!style)
38878
+ if (!style) {
38166
38879
  style = {};
38167
- if (isMarkdownLink(text))
38880
+ }
38881
+ if (isMarkdownLink(text)) {
38168
38882
  text = parseMarkdownLink(text).label;
38883
+ }
38169
38884
  const brokenText = [];
38170
38885
  // Checking if text contains NEWLINE before split makes it very slightly slower if text contains it,
38171
38886
  // but 5-10x faster if it doesn't
@@ -38228,10 +38943,12 @@
38228
38943
  */
38229
38944
  function getFontSizeMatchingWidth(lineWidth, maxFontSize, getTextWidth, precision = 0.25) {
38230
38945
  let minFontSize = 1;
38231
- if (getTextWidth(minFontSize) > lineWidth)
38946
+ if (getTextWidth(minFontSize) > lineWidth) {
38232
38947
  return minFontSize;
38233
- if (getTextWidth(maxFontSize) < lineWidth)
38948
+ }
38949
+ if (getTextWidth(maxFontSize) < lineWidth) {
38234
38950
  return maxFontSize;
38951
+ }
38235
38952
  // Dichotomic search
38236
38953
  let fontSize = (minFontSize + maxFontSize) / 2;
38237
38954
  let currentTextWidth = getTextWidth(fontSize);
@@ -38766,16 +39483,10 @@
38766
39483
  const tables = [];
38767
39484
  const coreTables = this.getters.getCoreTables(sheetId);
38768
39485
  // First we create the static tables, so we can use them to compute collision with dynamic tables
38769
- for (const table of coreTables) {
38770
- if (table.type === "dynamic")
38771
- continue;
38772
- tables.push(table);
38773
- }
38774
- const staticTables = [...tables];
39486
+ const staticTables = [...coreTables].filter((table) => table.type !== "dynamic");
39487
+ tables.push(...staticTables);
38775
39488
  // Then we create the dynamic tables
38776
- for (const coreTable of coreTables) {
38777
- if (coreTable.type !== "dynamic")
38778
- continue;
39489
+ for (const coreTable of this.getDynamicTables(sheetId)) {
38779
39490
  const table = this.coreTableToTable(sheetId, coreTable);
38780
39491
  let tableZone = table.range.zone;
38781
39492
  // Reduce the zone to avoid collision with static tables. Per design, dynamic tables can't overlap with other
@@ -38789,6 +39500,50 @@
38789
39500
  }
38790
39501
  return tables;
38791
39502
  }
39503
+ getDynamicTables(sheetId) {
39504
+ const dynamicTablesFromCore = this.getters
39505
+ .getCoreTables(sheetId)
39506
+ .filter((table) => table.type === "dynamic");
39507
+ const pivotTables = this.getTablesFromPivots(sheetId);
39508
+ const pivotRanges = new Set(pivotTables.map((t) => this.getters.getRangeString(t.range, sheetId)));
39509
+ const nonPivotDynamicTables = dynamicTablesFromCore.filter((t) => !pivotRanges.has(this.getters.getRangeString(t.range, sheetId)));
39510
+ return [...pivotTables, ...nonPivotDynamicTables];
39511
+ }
39512
+ getTablesFromPivots(sheetId) {
39513
+ const tables = [];
39514
+ for (const { position, pivotStyle, pivotId } of this.getters.getAllPivotArrayFormulas()) {
39515
+ const spreadZone = this.getters.getSpreadZone(position);
39516
+ const cell = this.getters.getCell(position);
39517
+ if (position.sheetId !== sheetId ||
39518
+ !spreadZone ||
39519
+ !cell ||
39520
+ pivotStyle.tableStyleId === "None") {
39521
+ continue;
39522
+ }
39523
+ tables.push({
39524
+ type: "dynamic",
39525
+ id: "pivot_table_" + pivotId + "_" + cell.id,
39526
+ range: this.getters.getRangeFromZone(sheetId, positionToZone(position)),
39527
+ config: this.getTableConfigFromPivotStyle(pivotId, pivotStyle),
39528
+ isPivotTable: true,
39529
+ });
39530
+ }
39531
+ return tables;
39532
+ }
39533
+ getTableConfigFromPivotStyle(pivotId, pivotStyle) {
39534
+ const pivot = this.getters.getPivot(pivotId);
39535
+ const pivotTable = pivot.getCollapsedTableStructure();
39536
+ return {
39537
+ hasFilters: pivotStyle.hasFilters,
39538
+ totalRow: pivotStyle.displayTotals,
39539
+ firstColumn: true,
39540
+ lastColumn: true,
39541
+ numberOfHeaders: pivotTable.getPivotTableDimensions(pivotStyle).numberOfHeaderRows,
39542
+ bandedRows: pivotStyle.bandedRows,
39543
+ bandedColumns: pivotStyle.bandedColumns,
39544
+ styleId: pivotStyle.tableStyleId,
39545
+ };
39546
+ }
38792
39547
  getFilters(sheetId) {
38793
39548
  return this.getTables(sheetId)
38794
39549
  .filter((table) => table.config.hasFilters)
@@ -38868,7 +39623,7 @@
38868
39623
  const zone = this.getters.getSpreadZone(tablePosition) ?? table.range.zone;
38869
39624
  const range = this.getters.getRangeFromZone(sheetId, zone);
38870
39625
  const filters = this.getDynamicTableFilters(sheetId, table, zone);
38871
- return { id: table.id, range, filters, config: table.config };
39626
+ return { id: table.id, range, filters, config: table.config, isPivotTable: table.isPivotTable };
38872
39627
  }
38873
39628
  getDynamicTableFilters(sheetId, table, tableZone) {
38874
39629
  const filters = [];
@@ -39656,8 +40411,9 @@
39656
40411
  }
39657
40412
  // TODO: make a registry of chart types to their rendering functions
39658
40413
  else {
39659
- if (!globalThis.OffscreenCanvas)
40414
+ if (!globalThis.OffscreenCanvas) {
39660
40415
  throw new Error(`converting a ${type} chart to an image using OffscreenCanvas is not supported in this environment`);
40416
+ }
39661
40417
  if (type === "scorecard") {
39662
40418
  const design = getScorecardConfiguration(figure, runtime);
39663
40419
  drawScoreChart(design, canvas);
@@ -39751,8 +40507,9 @@
39751
40507
  * Get the background and textColor of a chart based on the color of the first cell of the main range of the chart.
39752
40508
  */
39753
40509
  getStyleOfSingleCellChart(chartBackground, mainRange) {
39754
- if (chartBackground)
40510
+ if (chartBackground) {
39755
40511
  return { background: chartBackground, fontColor: chartFontColor(chartBackground) };
40512
+ }
39756
40513
  if (!mainRange) {
39757
40514
  return {
39758
40515
  background: BACKGROUND_CHART_COLOR,
@@ -39907,8 +40664,9 @@
39907
40664
  return value;
39908
40665
  });
39909
40666
  if (this.getRuleResultForTarget(target, { ...cf.rule, values }, preComputedCriterion)) {
39910
- if (!computedStyle[col])
40667
+ if (!computedStyle[col]) {
39911
40668
  computedStyle[col] = [];
40669
+ }
39912
40670
  // we must combine all the properties of all the CF rules applied to the given cell
39913
40671
  computedStyle[col][row] = Object.assign(computedStyle[col]?.[row] || {}, cf.rule.style);
39914
40672
  }
@@ -39923,8 +40681,9 @@
39923
40681
  getComputedIcons(sheetId) {
39924
40682
  const computedIcons = {};
39925
40683
  for (const cf of this.getters.getConditionalFormats(sheetId).reverse()) {
39926
- if (cf.rule.type !== "IconSetRule")
40684
+ if (cf.rule.type !== "IconSetRule") {
39927
40685
  continue;
40686
+ }
39928
40687
  for (const range of cf.ranges) {
39929
40688
  this.applyIcon(sheetId, range, cf.rule, computedIcons);
39930
40689
  }
@@ -39934,8 +40693,9 @@
39934
40693
  getComputedDataBars(sheetId) {
39935
40694
  const computedDataBars = {};
39936
40695
  for (const cf of this.getters.getConditionalFormats(sheetId).reverse()) {
39937
- if (cf.rule.type !== "DataBarRule")
40696
+ if (cf.rule.type !== "DataBarRule") {
39938
40697
  continue;
40698
+ }
39939
40699
  for (const range of cf.ranges) {
39940
40700
  this.applyDataBar(sheetId, range, cf.rule, computedDataBars);
39941
40701
  }
@@ -40027,8 +40787,9 @@
40027
40787
  // values negatives or 0 are ignored
40028
40788
  continue;
40029
40789
  }
40030
- if (!computedDataBars[col])
40790
+ if (!computedDataBars[col]) {
40031
40791
  computedDataBars[col] = [];
40792
+ }
40032
40793
  computedDataBars[col][row] = {
40033
40794
  color: colorNumberToHex(color),
40034
40795
  percentage: (cell.value * 100) / max,
@@ -40061,8 +40822,9 @@
40061
40822
  const cell = this.getters.getEvaluatedCell({ sheetId, col, row });
40062
40823
  if (cell.type === CellValueType.number) {
40063
40824
  const value = clip(cell.value, minValue, maxValue);
40064
- if (!computedStyle[col])
40825
+ if (!computedStyle[col]) {
40065
40826
  computedStyle[col] = [];
40827
+ }
40066
40828
  computedStyle[col][row] = computedStyle[col]?.[row] || {};
40067
40829
  computedStyle[col][row].fillColor = colorScale(value);
40068
40830
  }
@@ -40300,6 +41062,56 @@
40300
41062
  }
40301
41063
  }
40302
41064
 
41065
+ const trackedFormulas = ["SUBTOTAL", "PIVOT"];
41066
+ class FormulaTrackerPlugin extends CoreViewPlugin {
41067
+ static getters = ["getCellsWithTrackedFormula"];
41068
+ trackedCells = {};
41069
+ handle(cmd) {
41070
+ switch (cmd.type) {
41071
+ case "START": {
41072
+ for (const formula of trackedFormulas) {
41073
+ this.trackedCells[formula] = {};
41074
+ }
41075
+ for (const sheetId of this.getters.getSheetIds()) {
41076
+ const cells = this.getters.getCells(sheetId);
41077
+ for (const cellId in cells) {
41078
+ const cell = cells[cellId];
41079
+ for (const formula of trackedFormulas) {
41080
+ if (doesCellContainFunction(cell, formula)) {
41081
+ this.history.update("trackedCells", formula, cell.id, true);
41082
+ }
41083
+ }
41084
+ }
41085
+ }
41086
+ break;
41087
+ }
41088
+ case "UPDATE_CELL": {
41089
+ if (!("content" in cmd)) {
41090
+ return;
41091
+ }
41092
+ const cell = this.getters.getCell(cmd);
41093
+ // We don't update `this.trackedCells` and rely on `getCellsWithTrackedFormula` filtering out non-existing cells.
41094
+ // We cannot store the id in the beforeHandle, because the cell is already deleted in the beforeHandle of the sheet plugin
41095
+ if (!cell) {
41096
+ return;
41097
+ }
41098
+ for (const formula of trackedFormulas) {
41099
+ if (doesCellContainFunction(cell, formula)) {
41100
+ this.history.update("trackedCells", formula, cell.id, true);
41101
+ }
41102
+ else if (this.trackedCells[formula][cell.id]) {
41103
+ this.history.update("trackedCells", formula, cell.id, undefined);
41104
+ }
41105
+ }
41106
+ break;
41107
+ }
41108
+ }
41109
+ }
41110
+ getCellsWithTrackedFormula(formula) {
41111
+ return Object.keys(this.trackedCells[formula] || {}).filter((cellId) => this.trackedCells[formula][cellId] && this.getters.tryGetCellPosition(cellId));
41112
+ }
41113
+ }
41114
+
40303
41115
  class HeaderSizeUIPlugin extends CoreViewPlugin {
40304
41116
  static getters = ["getRowSize", "getHeaderSize", "getMaxAnchorOffset"];
40305
41117
  tallestCellInRow = {};
@@ -40590,14 +41402,16 @@
40590
41402
  function withPivotPresentationLayer (PivotClass) {
40591
41403
  class PivotPresentationLayer extends PivotClass {
40592
41404
  getters;
41405
+ pivotId;
40593
41406
  cache = {};
40594
41407
  rankAsc = {};
40595
41408
  rankDesc = {};
40596
41409
  runningTotal = {};
40597
41410
  runningTotalInPercent = {};
40598
- constructor(custom, params) {
41411
+ constructor(pivotId, custom, params) {
40599
41412
  super(custom, params);
40600
41413
  this.getters = params.getters;
41414
+ this.pivotId = pivotId;
40601
41415
  }
40602
41416
  markAsDirtyForEvaluation() {
40603
41417
  this.cache = {};
@@ -40647,7 +41461,7 @@
40647
41461
  return handleError(error, measure.aggregator.toUpperCase());
40648
41462
  }
40649
41463
  }
40650
- const formula = this.getters.getMeasureCompiledFormula(measure);
41464
+ const formula = this.getters.getMeasureCompiledFormula(this.pivotId, measure);
40651
41465
  const getSymbolValue = (symbolName) => {
40652
41466
  const { columns, rows } = this.definition;
40653
41467
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
@@ -41158,6 +41972,8 @@
41158
41972
  "generateNewCalculatedMeasureName",
41159
41973
  "isPivotUnused",
41160
41974
  "isSpillPivotFormula",
41975
+ "getAllPivotArrayFormulas",
41976
+ "getPivotStyleAtPosition",
41161
41977
  ];
41162
41978
  pivots = {};
41163
41979
  unusedPivotsInFormulas;
@@ -41305,8 +42121,7 @@
41305
42121
  if (!pivot.isValid()) {
41306
42122
  return EMPTY_PIVOT_CELL;
41307
42123
  }
41308
- if (functionName === "PIVOT" &&
41309
- !cell.content.replaceAll(" ", "").toUpperCase().startsWith("=PIVOT")) {
42124
+ if (functionName === "PIVOT" && !this.isMainFunctionPivotSpreadFunction(cell)) {
41310
42125
  return EMPTY_PIVOT_CELL;
41311
42126
  }
41312
42127
  if (functionName === "PIVOT") {
@@ -41394,7 +42209,7 @@
41394
42209
  const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
41395
42210
  if (!(pivotId in this.pivots)) {
41396
42211
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
41397
- this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
42212
+ this.pivots[pivotId] = new Pivot(pivotId, this.custom, { definition, getters: this.getters });
41398
42213
  }
41399
42214
  else if (recreate) {
41400
42215
  this.pivots[pivotId].onDefinitionChange(definition);
@@ -41421,6 +42236,42 @@
41421
42236
  this.unusedPivotsInFormulas = [...unusedPivots];
41422
42237
  return this.unusedPivotsInFormulas;
41423
42238
  }
42239
+ getAllPivotArrayFormulas() {
42240
+ const result = [];
42241
+ for (const cellId of this.getters.getCellsWithTrackedFormula("PIVOT")) {
42242
+ const position = this.getters.getCellPosition(cellId);
42243
+ const pivotInfo = this.getPivotStyleAtPosition(position);
42244
+ if (pivotInfo) {
42245
+ result.push({ position, ...pivotInfo });
42246
+ }
42247
+ }
42248
+ return result;
42249
+ }
42250
+ getPivotStyleAtPosition(position) {
42251
+ const cell = this.getters.getCell(position);
42252
+ if (!cell || !cell.isFormula || !this.isMainFunctionPivotSpreadFunction(cell)) {
42253
+ return undefined;
42254
+ }
42255
+ const pivotFunction = this.getFirstPivotFunction(position.sheetId, cell.compiledFormula.tokens);
42256
+ if (!pivotFunction || pivotFunction.functionName !== "PIVOT") {
42257
+ return undefined;
42258
+ }
42259
+ const pivotIdArg = pivotFunction.args[0];
42260
+ if (!pivotIdArg) {
42261
+ return undefined;
42262
+ }
42263
+ const pivotId = this.getters.getPivotId(pivotIdArg.toString());
42264
+ if (!pivotId) {
42265
+ return undefined;
42266
+ }
42267
+ const pivotStyle = getPivotStyleFromFnArgs(this.getters.getPivotCoreDefinition(pivotId), toScalar(pivotFunction.args[1]), toScalar(pivotFunction.args[2]), toScalar(pivotFunction.args[3]), toScalar(pivotFunction.args[4]), toScalar(pivotFunction.args[5]), this.getters.getLocale());
42268
+ return { pivotStyle, pivotId };
42269
+ }
42270
+ isMainFunctionPivotSpreadFunction(cell) {
42271
+ const tokens = cell.compiledFormula.tokens;
42272
+ const firstNonSpaceToken = tokens.find((token, i) => i > 0 && token.type !== "SPACE");
42273
+ return (firstNonSpaceToken?.type === "SYMBOL" && firstNonSpaceToken.value.toUpperCase() === "PIVOT");
42274
+ }
41424
42275
  }
41425
42276
 
41426
42277
  /**
@@ -41809,6 +42660,31 @@
41809
42660
  return res.slice(1);
41810
42661
  }
41811
42662
 
42663
+ /**
42664
+ * UI plugins handle any transient data required to display a spreadsheet.
42665
+ * They can draw on the grid canvas.
42666
+ */
42667
+ class UIPlugin extends BasePlugin {
42668
+ static layers = [];
42669
+ getters;
42670
+ ui;
42671
+ selection;
42672
+ dispatch;
42673
+ canDispatch;
42674
+ constructor({ getters, stateObserver, dispatch, canDispatch, uiActions, selection, }) {
42675
+ super(stateObserver);
42676
+ this.getters = getters;
42677
+ this.ui = uiActions;
42678
+ this.selection = selection;
42679
+ this.dispatch = dispatch;
42680
+ this.canDispatch = canDispatch;
42681
+ }
42682
+ // ---------------------------------------------------------------------------
42683
+ // Grid rendering
42684
+ // ---------------------------------------------------------------------------
42685
+ drawLayer(ctx, layer) { }
42686
+ }
42687
+
41812
42688
  /**
41813
42689
  * This plugin manage the autofill.
41814
42690
  *
@@ -42659,17 +43535,17 @@
42659
43535
  }
42660
43536
  computeTableStyle(sheetId, table) {
42661
43537
  return lazy(() => {
42662
- const { config, numberOfCols, numberOfRows } = this.getTableRuntimeConfig(sheetId, table);
42663
43538
  const style = this.getters.getTableStyle(table.config.styleId);
42664
- const relativeTableStyle = getComputedTableStyle(config, style, numberOfCols, numberOfRows);
43539
+ const { tableMetaData, config } = this.getTableMetaData(sheetId, table);
43540
+ const relativeTableStyle = getComputedTableStyle(config, style, tableMetaData);
42665
43541
  // Return the style with sheet coordinates instead of tables coordinates
42666
43542
  const mapping = this.getTableMapping(sheetId, table);
42667
43543
  const absoluteTableStyle = { borders: {}, styles: {} };
42668
- for (let col = 0; col < numberOfCols; col++) {
43544
+ for (let col = 0; col < tableMetaData.numberOfCols; col++) {
42669
43545
  const colInSheet = mapping.colMapping[col];
42670
43546
  absoluteTableStyle.borders[colInSheet] = {};
42671
43547
  absoluteTableStyle.styles[colInSheet] = {};
42672
- for (let row = 0; row < numberOfRows; row++) {
43548
+ for (let row = 0; row < tableMetaData.numberOfRows; row++) {
42673
43549
  const rowInSheet = mapping.rowMapping[row];
42674
43550
  absoluteTableStyle.borders[colInSheet][rowInSheet] = relativeTableStyle.borders[col][row];
42675
43551
  absoluteTableStyle.styles[colInSheet][rowInSheet] = relativeTableStyle.styles[col][row];
@@ -42678,6 +43554,58 @@
42678
43554
  return absoluteTableStyle;
42679
43555
  });
42680
43556
  }
43557
+ getTableMetaData(sheetId, table) {
43558
+ const { config, numberOfCols, numberOfRows } = this.getTableRuntimeConfig(sheetId, table);
43559
+ if (!table.isPivotTable) {
43560
+ return { tableMetaData: { numberOfCols, numberOfRows, mode: "table" }, config };
43561
+ }
43562
+ const mainPosition = { sheetId, col: table.range.zone.left, row: table.range.zone.top };
43563
+ const pivotInfo = this.getters.getPivotStyleAtPosition(mainPosition);
43564
+ if (!pivotInfo) {
43565
+ throw new Error("No dynamic pivot info found at pivot table position");
43566
+ }
43567
+ const pivot = this.getters.getPivot(pivotInfo.pivotId);
43568
+ const pivotStyle = pivotInfo.pivotStyle;
43569
+ const maxRowDepth = pivot.getExpandedTableStructure().getNumberOfRowGroupBys();
43570
+ const pivotCells = pivot.getCollapsedTableStructure().getPivotCells(pivotStyle);
43571
+ const mainSubHeaderRows = new Set();
43572
+ const firstAlternatingSubHeaderRows = new Set();
43573
+ const secondAlternatingSubHeaderRows = new Set();
43574
+ let hiddenRowsOffset = 0;
43575
+ for (let row = 0; row < pivotCells[0].length; row++) {
43576
+ const isRowHidden = this.getters.isRowHidden(sheetId, row + table.range.zone.top);
43577
+ if (isRowHidden) {
43578
+ hiddenRowsOffset++;
43579
+ continue;
43580
+ }
43581
+ const cell = pivotCells[0][row];
43582
+ if (cell.type !== "HEADER" || cell.domain.length === 0) {
43583
+ continue;
43584
+ }
43585
+ if (cell.domain.length === 1 && maxRowDepth > 1) {
43586
+ mainSubHeaderRows.add(row - hiddenRowsOffset);
43587
+ }
43588
+ else if (cell.domain.length % 2 === 0 && maxRowDepth > cell.domain.length) {
43589
+ firstAlternatingSubHeaderRows.add(row - hiddenRowsOffset);
43590
+ }
43591
+ else if (cell.domain.length % 2 === 1 && maxRowDepth > cell.domain.length) {
43592
+ secondAlternatingSubHeaderRows.add(row - hiddenRowsOffset);
43593
+ }
43594
+ }
43595
+ const hasMeasureRow = config.numberOfHeaders &&
43596
+ pivotStyle.displayMeasuresRow &&
43597
+ !this.getters.isRowHidden(sheetId, config.numberOfHeaders - 1 + table.range.zone.top);
43598
+ const tableMetaData = {
43599
+ mode: "pivot",
43600
+ numberOfCols,
43601
+ numberOfRows,
43602
+ mainSubHeaderRows,
43603
+ firstAlternatingSubHeaderRows,
43604
+ secondAlternatingSubHeaderRows,
43605
+ measureRow: hasMeasureRow ? config.numberOfHeaders - 1 : undefined,
43606
+ };
43607
+ return { tableMetaData, config };
43608
+ }
42681
43609
  /**
42682
43610
  * Get the actual table config that will be used to compute the table style. It is different from
42683
43611
  * the config of the table because of hidden rows and columns in the sheet. For example remove the
@@ -42822,8 +43750,9 @@
42822
43750
  for (let col = zone.left; col <= zone.right; col++) {
42823
43751
  for (let row = zone.top; row <= zone.bottom; row++) {
42824
43752
  const position = { sheetId, col, row };
42825
- if (this.borders.get(position) !== undefined)
43753
+ if (this.borders.get(position) !== undefined) {
42826
43754
  continue;
43755
+ }
42827
43756
  const cellBorder = borders.get(position);
42828
43757
  const cellTableBorder = tableBorders.get(position);
42829
43758
  const border = {
@@ -42854,8 +43783,9 @@
42854
43783
  for (let col = zone.left; col <= zone.right; col++) {
42855
43784
  for (let row = zone.top; row <= zone.bottom; row++) {
42856
43785
  const position = { sheetId, col, row };
42857
- if (this.styles.get(position) !== undefined)
43786
+ if (this.styles.get(position) !== undefined) {
42858
43787
  continue;
43788
+ }
42859
43789
  const computedStyle = {
42860
43790
  ...removeFalsyAttributes(tableStyles.get(position)),
42861
43791
  ...removeFalsyAttributes(this.getters.getDataValidationCellStyle(position)),
@@ -43359,6 +44289,7 @@
43359
44289
  measures: [],
43360
44290
  name: _t("New pivot"),
43361
44291
  type: "SPREADSHEET",
44292
+ style: { tableStyleId: PIVOT_INSERT_TABLE_STYLE_ID },
43362
44293
  },
43363
44294
  });
43364
44295
  const position = this.getters.getSheetIds().findIndex((sheetId) => sheetId === currentSheetId) + 1;
@@ -43409,21 +44340,13 @@
43409
44340
  const pivotTable = new SpreadsheetPivotTable(cols, rows, measures, fieldsType || {});
43410
44341
  const numberOfHeaders = pivotTable.columns.length - 1;
43411
44342
  this.resizeSheet(sheetId, col, row, pivotTable);
43412
- const pivotFormulaId = this.getters.getPivotFormulaId(pivotId);
43413
- let zone;
43414
44343
  if (mode === "dynamic") {
43415
44344
  this.dispatch("UPDATE_CELL", {
43416
44345
  sheetId,
43417
44346
  col,
43418
44347
  row,
43419
- content: `=PIVOT(${pivotFormulaId})`,
44348
+ content: `=PIVOT(${this.getters.getPivotFormulaId(pivotId)})`,
43420
44349
  });
43421
- zone = {
43422
- left: col,
43423
- right: col,
43424
- top: row,
43425
- bottom: row,
43426
- };
43427
44350
  }
43428
44351
  else {
43429
44352
  this.dispatch("INSERT_PIVOT", {
@@ -43433,19 +44356,19 @@
43433
44356
  pivotId,
43434
44357
  table: pivotTable.export(),
43435
44358
  });
43436
- zone = {
44359
+ const zone = {
43437
44360
  left: col,
43438
44361
  right: col + pivotTable.getNumberOfDataColumns(),
43439
44362
  top: row,
43440
44363
  bottom: row + numberOfHeaders + pivotTable.rows.length,
43441
44364
  };
44365
+ this.dispatch("CREATE_TABLE", {
44366
+ tableType: "static",
44367
+ sheetId,
44368
+ ranges: [this.getters.getRangeDataFromZone(sheetId, zone)],
44369
+ config: { ...PIVOT_STATIC_TABLE_CONFIG, numberOfHeaders },
44370
+ });
43442
44371
  }
43443
- this.dispatch("CREATE_TABLE", {
43444
- tableType: mode,
43445
- sheetId,
43446
- ranges: [this.getters.getRangeDataFromZone(sheetId, zone)],
43447
- config: { ...PIVOT_TABLE_CONFIG, numberOfHeaders },
43448
- });
43449
44372
  }
43450
44373
  resizeSheet(sheetId, col, row, table) {
43451
44374
  const colLimit = table.getNumberOfDataColumns() + 1; // +1 for the Top-Left
@@ -43476,7 +44399,9 @@
43476
44399
  }
43477
44400
  }
43478
44401
  splitPivotFormula(sheetId, col, row, pivotId) {
43479
- const spreadZone = this.getters.getSpreadZone({ sheetId, col, row });
44402
+ const position = { sheetId, col, row };
44403
+ const spreadZone = this.getters.getSpreadZone(position);
44404
+ const table = this.getters.getTable(position);
43480
44405
  if (!spreadZone) {
43481
44406
  return;
43482
44407
  }
@@ -43494,15 +44419,16 @@
43494
44419
  content: createPivotFormula(formulaId, pivotCell),
43495
44420
  });
43496
44421
  }
43497
- const table = this.getters.getCoreTable({ sheetId, col, row });
43498
- if (table?.type === "dynamic") {
43499
- const zone = positionToZone({ col, row });
44422
+ if (this.getters.getCoreTable(position)) {
44423
+ this.dispatch("REMOVE_TABLE", { sheetId, target: [positionToZone(position)] });
44424
+ }
44425
+ if (table?.isPivotTable) {
43500
44426
  const rangeData = this.getters.getRangeDataFromZone(sheetId, spreadZone);
43501
- this.dispatch("UPDATE_TABLE", {
43502
- sheetId,
43503
- zone,
43504
- newTableRange: rangeData,
44427
+ this.dispatch("CREATE_TABLE", {
43505
44428
  tableType: "static",
44429
+ sheetId,
44430
+ ranges: [rangeData],
44431
+ config: { ...table.config, styleId: pivotTableStyleIdToTableStyleId(table.config.styleId) },
43506
44432
  });
43507
44433
  }
43508
44434
  }
@@ -43643,8 +44569,9 @@
43643
44569
  return this.undoStack.length > 0;
43644
44570
  }
43645
44571
  canRedo() {
43646
- if (this.redoStack.length > 0)
44572
+ if (this.redoStack.length > 0) {
43647
44573
  return true;
44574
+ }
43648
44575
  const lastNonRedoRevision = this.getPossibleRevisionToRepeat();
43649
44576
  return canRepeatRevision(lastNonRedoRevision);
43650
44577
  }
@@ -43780,8 +44707,9 @@
43780
44707
  *
43781
44708
  */
43782
44709
  hasHeader(sheetId, items) {
43783
- if (items[0].length === 1)
44710
+ if (items[0].length === 1) {
43784
44711
  return false;
44712
+ }
43785
44713
  let cells = items.map((col) => col.map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }).type));
43786
44714
  // ignore left-most column when topLeft cell is empty
43787
44715
  const topLeft = cells[0][0];
@@ -44066,6 +44994,16 @@
44066
44994
  }
44067
44995
  }
44068
44996
 
44997
+ class SubtotalEvaluationPlugin extends UIPlugin {
44998
+ handle(cmd) {
44999
+ if (invalidSubtotalFormulasCommands.has(cmd.type)) {
45000
+ this.dispatch("EVALUATE_CELLS", {
45001
+ cellIds: this.getters.getCellsWithTrackedFormula("SUBTOTAL"),
45002
+ });
45003
+ }
45004
+ }
45005
+ }
45006
+
44069
45007
  class TableAutofillPlugin extends UIPlugin {
44070
45008
  handle(cmd) {
44071
45009
  switch (cmd.type) {
@@ -44137,12 +45075,14 @@
44137
45075
  case "RESIZE_TABLE": {
44138
45076
  const table = this.getters.getCoreTableMatchingTopLeft(cmd.sheetId, cmd.zone);
44139
45077
  this.dispatch("UPDATE_TABLE", { ...cmd });
44140
- if (!table)
45078
+ if (!table) {
44141
45079
  return;
45080
+ }
44142
45081
  const newTableZone = this.getters.getRangeFromRangeData(cmd.newTableRange).zone;
44143
45082
  this.selection.selectCell(newTableZone.right, newTableZone.bottom);
44144
- if (!table.config.automaticAutofill)
45083
+ if (!table.config.automaticAutofill) {
44145
45084
  return;
45085
+ }
44146
45086
  const oldTableZone = table.range.zone;
44147
45087
  if (newTableZone.bottom >= oldTableZone.bottom) {
44148
45088
  for (let col = newTableZone.left; col <= newTableZone.right; col++) {
@@ -44404,8 +45344,9 @@
44404
45344
  let evaluatedRowSize = 0;
44405
45345
  let tallestCell = undefined;
44406
45346
  for (const [position, evaluatedCell] of this.getters.getEvaluatedCellsPositionInZone(sheetId, this.getters.getRowsZone(sheetId, row, row))) {
44407
- if (evaluatedCell.value === undefined)
45347
+ if (evaluatedCell.value === undefined) {
44408
45348
  continue;
45349
+ }
44409
45350
  const colSize = this.getters.getColSize(sheetId, position.col);
44410
45351
  const style = this.getters.getCellStyle(position);
44411
45352
  const content = evaluatedCell.formattedValue;
@@ -44693,8 +45634,9 @@
44693
45634
  */
44694
45635
  function cellStyleToCss(style) {
44695
45636
  const attributes = cellTextStyleToCss(style);
44696
- if (!style)
45637
+ if (!style) {
44697
45638
  return attributes;
45639
+ }
44698
45640
  if (style.fillColor) {
44699
45641
  attributes["background"] = style.fillColor;
44700
45642
  }
@@ -44705,8 +45647,9 @@
44705
45647
  */
44706
45648
  function cellTextStyleToCss(style) {
44707
45649
  const attributes = {};
44708
- if (!style)
45650
+ if (!style) {
44709
45651
  return attributes;
45652
+ }
44710
45653
  if (style.bold) {
44711
45654
  attributes["font-weight"] = "bold";
44712
45655
  }
@@ -44899,14 +45842,33 @@
44899
45842
  if (zones.length > 1 || (zones[0].top === 0 && zones[0].bottom === 0)) {
44900
45843
  return "InvalidCopyPasteSelection" /* CommandResult.InvalidCopyPasteSelection */;
44901
45844
  }
44902
- break;
45845
+ const zone = this.getters.getSelectedZone();
45846
+ const copiedData = this.getCopiedDataAbove(zone);
45847
+ return this.isPasteAllowed(zones, copiedData, {
45848
+ isCutOperation: false,
45849
+ });
44903
45850
  }
44904
45851
  case "COPY_PASTE_CELLS_ON_LEFT": {
44905
45852
  const zones = this.getters.getSelectedZones();
44906
45853
  if (zones.length > 1 || (zones[0].left === 0 && zones[0].right === 0)) {
44907
45854
  return "InvalidCopyPasteSelection" /* CommandResult.InvalidCopyPasteSelection */;
44908
45855
  }
44909
- break;
45856
+ const zone = this.getters.getSelectedZone();
45857
+ const copiedData = this.getCopiedDataOnLeft(zone);
45858
+ return this.isPasteAllowed(zones, copiedData, {
45859
+ isCutOperation: false,
45860
+ });
45861
+ }
45862
+ case "COPY_PASTE_CELLS_ON_ZONE": {
45863
+ const zones = this.getters.getSelectedZones();
45864
+ if (zones.length > 1) {
45865
+ return "InvalidCopyPasteSelection" /* CommandResult.InvalidCopyPasteSelection */;
45866
+ }
45867
+ const zone = this.getters.getSelectedZone();
45868
+ const copiedData = this.getCopiedDataOnLeft(zone);
45869
+ return this.isPasteAllowed(zones, copiedData, {
45870
+ isCutOperation: false,
45871
+ });
44910
45872
  }
44911
45873
  case "INSERT_CELL": {
44912
45874
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
@@ -44983,14 +45945,8 @@
44983
45945
  case "COPY_PASTE_CELLS_ABOVE":
44984
45946
  {
44985
45947
  const zone = this.getters.getSelectedZone();
44986
- const multipleRowsInSelection = zone.top !== zone.bottom;
44987
- const copyTarget = {
44988
- ...zone,
44989
- bottom: multipleRowsInSelection ? zone.top : zone.top - 1,
44990
- top: multipleRowsInSelection ? zone.top : zone.top - 1,
44991
- };
44992
45948
  this.originSheetId = this.getters.getActiveSheetId();
44993
- const copiedData = this.copy([copyTarget]);
45949
+ const copiedData = this.getCopiedDataAbove(zone);
44994
45950
  this.paste([zone], copiedData, {
44995
45951
  isCutOperation: false,
44996
45952
  selectTarget: true,
@@ -45000,14 +45956,19 @@
45000
45956
  case "COPY_PASTE_CELLS_ON_LEFT":
45001
45957
  {
45002
45958
  const zone = this.getters.getSelectedZone();
45003
- const multipleColsInSelection = zone.left !== zone.right;
45004
- const copyTarget = {
45005
- ...zone,
45006
- right: multipleColsInSelection ? zone.left : zone.left - 1,
45007
- left: multipleColsInSelection ? zone.left : zone.left - 1,
45008
- };
45009
45959
  this.originSheetId = this.getters.getActiveSheetId();
45010
- const copiedData = this.copy([copyTarget]);
45960
+ const copiedData = this.getCopiedDataOnLeft(zone);
45961
+ this.paste([zone], copiedData, {
45962
+ isCutOperation: false,
45963
+ selectTarget: true,
45964
+ });
45965
+ }
45966
+ break;
45967
+ case "COPY_PASTE_CELLS_ON_ZONE":
45968
+ {
45969
+ const zone = this.getters.getSelectedZone();
45970
+ this.originSheetId = this.getters.getActiveSheetId();
45971
+ const copiedData = this.getCopiedDataAboveOnLeft(zone);
45011
45972
  this.paste([zone], copiedData, {
45012
45973
  isCutOperation: false,
45013
45974
  selectTarget: true,
@@ -45087,6 +46048,32 @@
45087
46048
  }
45088
46049
  }
45089
46050
  }
46051
+ getCopiedDataAbove(zone) {
46052
+ const multipleRowsInSelection = zone.top !== zone.bottom;
46053
+ const copyTarget = {
46054
+ ...zone,
46055
+ bottom: multipleRowsInSelection ? zone.top : zone.top - 1,
46056
+ top: multipleRowsInSelection ? zone.top : zone.top - 1,
46057
+ };
46058
+ return this.copy([copyTarget]);
46059
+ }
46060
+ getCopiedDataOnLeft(zone) {
46061
+ const multipleColsInSelection = zone.left !== zone.right;
46062
+ const copyTarget = {
46063
+ ...zone,
46064
+ right: multipleColsInSelection ? zone.left : zone.left - 1,
46065
+ left: multipleColsInSelection ? zone.left : zone.left - 1,
46066
+ };
46067
+ return this.copy([copyTarget]);
46068
+ }
46069
+ getCopiedDataAboveOnLeft(zone) {
46070
+ const copyTarget = {
46071
+ ...zone,
46072
+ right: zone.left,
46073
+ bottom: zone.top,
46074
+ };
46075
+ return this.copy([copyTarget]);
46076
+ }
45090
46077
  convertTextToClipboardData(clipboardData) {
45091
46078
  const handlers = this.selectClipboardHandlers({ figureId: true }).concat(this.selectClipboardHandlers({}));
45092
46079
  const copiedData = {};
@@ -45537,27 +46524,31 @@
45537
46524
  getFilterHiddenValues(position) {
45538
46525
  const id = this.getters.getFilterId(position);
45539
46526
  const sheetId = position.sheetId;
45540
- if (!id || !this.filterValues[sheetId])
46527
+ if (!id || !this.filterValues[sheetId]) {
45541
46528
  return [];
46529
+ }
45542
46530
  const value = this.filterValues[sheetId][id] || [];
45543
46531
  return value.filterType === "values" ? value.hiddenValues : [];
45544
46532
  }
45545
46533
  getFilterCriterionValue(position) {
45546
46534
  const id = this.getters.getFilterId(position);
45547
46535
  const sheetId = position.sheetId;
45548
- if (!id || !this.filterValues[sheetId])
46536
+ if (!id || !this.filterValues[sheetId]) {
45549
46537
  return EMPTY_CRITERION;
46538
+ }
45550
46539
  const value = this.filterValues[sheetId][id];
45551
46540
  return value && value.filterType === "criterion" ? value : EMPTY_CRITERION;
45552
46541
  }
45553
46542
  isFilterActive(position) {
45554
46543
  const id = this.getters.getFilterId(position);
45555
- if (!id)
46544
+ if (!id) {
45556
46545
  return false;
46546
+ }
45557
46547
  const sheetId = position.sheetId;
45558
46548
  const value = this.filterValues[sheetId]?.[id];
45559
- if (!value)
46549
+ if (!value) {
45560
46550
  return false;
46551
+ }
45561
46552
  return value.filterType === "values" ? value.hiddenValues.length > 0 : value.type !== "none";
45562
46553
  }
45563
46554
  getFirstTableInSelection() {
@@ -45567,10 +46558,12 @@
45567
46558
  }
45568
46559
  updateFilter({ col, row, value, sheetId }) {
45569
46560
  const id = this.getters.getFilterId({ sheetId, col, row });
45570
- if (!id)
46561
+ if (!id) {
45571
46562
  return;
45572
- if (!this.filterValues[sheetId])
46563
+ }
46564
+ if (!this.filterValues[sheetId]) {
45573
46565
  this.filterValues[sheetId] = {};
46566
+ }
45574
46567
  this.filterValues[sheetId][id] = value;
45575
46568
  }
45576
46569
  updateHiddenRows(sheetId) {
@@ -45590,8 +46583,9 @@
45590
46583
  }
45591
46584
  if (filterValue.filterType === "values") {
45592
46585
  const filteredValues = filterValue.hiddenValues?.map(toLowerCase);
45593
- if (!filteredValues)
46586
+ if (!filteredValues) {
45594
46587
  continue;
46588
+ }
45595
46589
  const filteredValuesSet = new Set(filteredValues);
45596
46590
  for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
45597
46591
  const value = this.getCellValueAsString(sheetId, filter.col, row);
@@ -45601,8 +46595,9 @@
45601
46595
  }
45602
46596
  }
45603
46597
  else {
45604
- if (filterValue.type === "none")
46598
+ if (filterValue.type === "none") {
45605
46599
  continue;
46600
+ }
45606
46601
  const evaluator = criterionEvaluatorRegistry.get(filterValue.type);
45607
46602
  const preComputedCriterion = evaluator.preComputeCriterion?.(filterValue, [filter.filteredRange], this.getters);
45608
46603
  const evaluatedCriterionValues = filterValue.values.map((value) => {
@@ -45833,6 +46828,7 @@
45833
46828
  "tryGetActiveSheetId",
45834
46829
  "isGridSelectionActive",
45835
46830
  "getSelectecUnboundedZone",
46831
+ "getSelectionRangeString",
45836
46832
  ];
45837
46833
  gridSelection = {
45838
46834
  anchor: {
@@ -46161,6 +47157,38 @@
46161
47157
  }
46162
47158
  return [...new Set(elements)].sort();
46163
47159
  }
47160
+ /**
47161
+ * Same as `getRangeString` but add:
47162
+ * - all necessary merge to the range to make it a valid selection
47163
+ * - the "#" suffix if the range is a spilled reference
47164
+ */
47165
+ getSelectionRangeString(range, forSheetId) {
47166
+ const expandedZone = this.getters.expandZone(range.sheetId, range.zone);
47167
+ const expandedRange = createRange({
47168
+ ...range,
47169
+ zone: {
47170
+ ...expandedZone,
47171
+ bottom: isFullColRange(range) ? undefined : expandedZone.bottom,
47172
+ right: isFullRowRange(range) ? undefined : expandedZone.right,
47173
+ },
47174
+ }, this.getters.getSheetSize);
47175
+ const rangeString = this.getters.getRangeString(expandedRange, forSheetId);
47176
+ if (this.getters.isSingleCellOrMerge(range.sheetId, range.zone)) {
47177
+ const { sheetName, xc } = splitReference(rangeString);
47178
+ return getFullReference(sheetName, xc.split(":")[0]);
47179
+ }
47180
+ const spreaderPosition = this.getters.getArrayFormulaSpreadingOn({
47181
+ sheetId: expandedRange.sheetId,
47182
+ col: expandedRange.zone.left,
47183
+ row: expandedRange.zone.top,
47184
+ });
47185
+ const spreadZone = spreaderPosition && this.getters.getSpreadZone(spreaderPosition, { ignoreSpillError: true });
47186
+ if (spreadZone && isEqual(spreadZone, expandedRange.zone)) {
47187
+ const { sheetName, xc } = splitReference(rangeString);
47188
+ return getFullReference(sheetName, xc.split(":")[0]) + "#";
47189
+ }
47190
+ return rangeString;
47191
+ }
46164
47192
  // ---------------------------------------------------------------------------
46165
47193
  // Other
46166
47194
  // ---------------------------------------------------------------------------
@@ -47525,8 +48553,9 @@
47525
48553
  * It returns -1 if no col is found.
47526
48554
  */
47527
48555
  getColIndexLeftOfMainViewport(x) {
47528
- if (x >= 0)
48556
+ if (x >= 0) {
47529
48557
  return -1;
48558
+ }
47530
48559
  const sheetId = this.getters.getActiveSheetId();
47531
48560
  let col = this.getActiveMainViewport().left;
47532
48561
  let colStart = -this.getActiveSheetScrollInfo().scrollX - this.getters.getColRowOffset("COL", col, 0);
@@ -47541,8 +48570,9 @@
47541
48570
  * It returns -1 if no row is found.
47542
48571
  */
47543
48572
  getRowIndexTopOfMainViewport(y) {
47544
- if (y >= 0)
48573
+ if (y >= 0) {
47545
48574
  return -1;
48575
+ }
47546
48576
  const sheetId = this.getters.getActiveSheetId();
47547
48577
  let row = this.getActiveMainViewport().top;
47548
48578
  let rowStart = -this.getActiveSheetScrollInfo().scrollY - this.getters.getColRowOffset("ROW", row, 0);
@@ -47701,7 +48731,8 @@
47701
48731
  .add("dynamic_tables", DynamicTablesPlugin)
47702
48732
  .add("custom_colors", CustomColorsPlugin)
47703
48733
  .add("pivot_ui", PivotUIPlugin)
47704
- .add("cell_icon", CellIconPlugin);
48734
+ .add("cell_icon", CellIconPlugin)
48735
+ .add("formula_tracker", FormulaTrackerPlugin);
47705
48736
 
47706
48737
  class RangeAdapter {
47707
48738
  getters;
@@ -48831,8 +49862,9 @@
48831
49862
  `;
48832
49863
  }
48833
49864
  function extractTrendline(trend, dataSetColor) {
48834
- if (!trend)
49865
+ if (!trend) {
48835
49866
  return escapeXml /*xml*/ ``;
49867
+ }
48836
49868
  const { type, order, window } = trend;
48837
49869
  const trendLineNodes = [];
48838
49870
  switch (type) {
@@ -50719,8 +51751,9 @@
50719
51751
  </mergeCells>
50720
51752
  `;
50721
51753
  }
50722
- else
51754
+ else {
50723
51755
  return escapeXml ``;
51756
+ }
50724
51757
  }
50725
51758
  function addSheetViews(sheet) {
50726
51759
  const panes = sheet.panes;
@@ -50848,12 +51881,14 @@
50848
51881
  }
50849
51882
  for (const image of sheet.images) {
50850
51883
  const mimeType = image.data.mimetype;
50851
- if (mimeType === undefined)
51884
+ if (mimeType === undefined) {
50852
51885
  continue;
51886
+ }
50853
51887
  const extension = IMAGE_MIMETYPE_TO_EXTENSION_MAPPING[mimeType];
50854
51888
  // only support exporting images with mimetypes specified in the mapping
50855
- if (extension === undefined)
51889
+ if (extension === undefined) {
50856
51890
  continue;
51891
+ }
50857
51892
  const xlsxImageId = convertImageId(image.id);
50858
51893
  const imageFileName = `image${xlsxImageId}.${extension}`;
50859
51894
  const imageRelId = addRelsToFile(construct.relsFiles, `xl/drawings/_rels/drawing${sheetIndex}.xml.rels`, {
@@ -50937,8 +51972,9 @@
50937
51972
  */
50938
51973
  function createTablesForSheet(sheetData, sheetId, startingTableId, construct, files) {
50939
51974
  let currentTableId = startingTableId;
50940
- if (!sheetData.tables.length)
51975
+ if (!sheetData.tables.length) {
50941
51976
  return new XMLString("");
51977
+ }
50942
51978
  const sheetRelFile = `xl/worksheets/_rels/sheet${sheetId}.xml.rels`;
50943
51979
  const tableParts = [];
50944
51980
  for (const table of sheetData.tables) {
@@ -51718,6 +52754,7 @@
51718
52754
  exports.deepCopy = deepCopy;
51719
52755
  exports.deepEquals = deepEquals;
51720
52756
  exports.deepEqualsArray = deepEqualsArray;
52757
+ exports.doesCellContainFunction = doesCellContainFunction;
51721
52758
  exports.errorTypes = errorTypes;
51722
52759
  exports.escapeRegExp = escapeRegExp;
51723
52760
  exports.findNextDefinedValue = findNextDefinedValue;
@@ -51786,8 +52823,8 @@
51786
52823
 
51787
52824
 
51788
52825
  __info__.version = "19.1.0-alpha.3";
51789
- __info__.date = "2026-01-07T16:20:57.293Z";
51790
- __info__.hash = "ac2fa3e";
52826
+ __info__.date = "2026-01-14T10:01:30.535Z";
52827
+ __info__.hash = "e5cbf18";
51791
52828
 
51792
52829
 
51793
52830
  })(this.o_spreadsheet_engine = this.o_spreadsheet_engine || {});