@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
  class FunctionCodeBuilder {
@@ -641,6 +641,7 @@ const DEFAULT_STYLE = {
641
641
  fillColor: "",
642
642
  textColor: "",
643
643
  rotation: 0,
644
+ hideGridLines: false,
644
645
  };
645
646
  const DEFAULT_VERTICAL_ALIGN = DEFAULT_STYLE.verticalAlign;
646
647
  // Fonts
@@ -673,7 +674,7 @@ function getDefaultSheetViewSize() {
673
674
  }
674
675
  const NEWLINE = "\n";
675
676
  // Pivot
676
- const PIVOT_TABLE_CONFIG = {
677
+ const PIVOT_STATIC_TABLE_CONFIG = {
677
678
  hasFilters: false,
678
679
  totalRow: false,
679
680
  firstColumn: true,
@@ -684,6 +685,7 @@ const PIVOT_TABLE_CONFIG = {
684
685
  styleId: "TableStyleMedium5",
685
686
  automaticAutofill: false,
686
687
  };
688
+ const PIVOT_INSERT_TABLE_STYLE_ID = "PivotTableStyleMedium12";
687
689
  const PIVOT_INDENT = 15;
688
690
  const PIVOT_COLLAPSE_ICON_SIZE = 12;
689
691
  const PIVOT_MAX_NUMBER_OF_CELLS = 5e5;
@@ -910,8 +912,9 @@ function isNotNull(argument) {
910
912
  * Check if all the values of an object, and all the values of the objects inside of it, are undefined.
911
913
  */
912
914
  function isObjectEmptyRecursive(argument) {
913
- if (argument === undefined)
915
+ if (argument === undefined) {
914
916
  return true;
917
+ }
915
918
  return Object.values(argument).every((value) => typeof value === "object" ? isObjectEmptyRecursive(value) : !value);
916
919
  }
917
920
  /**
@@ -1028,23 +1031,29 @@ function getAddHeaderStartIndex(position, base) {
1028
1031
  * Compares n objects.
1029
1032
  */
1030
1033
  function deepEquals(...o) {
1031
- if (o.length <= 1)
1034
+ if (o.length <= 1) {
1032
1035
  return true;
1036
+ }
1033
1037
  for (let index = 1; index < o.length; index++) {
1034
- if (!_deepEquals(o[0], o[index]))
1038
+ if (!_deepEquals(o[0], o[index])) {
1035
1039
  return false;
1040
+ }
1036
1041
  }
1037
1042
  return true;
1038
1043
  }
1039
1044
  function _deepEquals(o1, o2) {
1040
- if (o1 === o2)
1045
+ if (o1 === o2) {
1041
1046
  return true;
1042
- if ((o1 && !o2) || (o2 && !o1))
1047
+ }
1048
+ if ((o1 && !o2) || (o2 && !o1)) {
1043
1049
  return false;
1044
- if (typeof o1 !== typeof o2)
1050
+ }
1051
+ if (typeof o1 !== typeof o2) {
1045
1052
  return false;
1046
- if (typeof o1 !== "object")
1053
+ }
1054
+ if (typeof o1 !== "object") {
1047
1055
  return false;
1056
+ }
1048
1057
  // Objects can have different keys if the values are undefined
1049
1058
  for (const key in o2) {
1050
1059
  if (!(key in o1) && o2[key] !== undefined) {
@@ -1052,15 +1061,18 @@ function _deepEquals(o1, o2) {
1052
1061
  }
1053
1062
  }
1054
1063
  for (const key in o1) {
1055
- if (typeof o1[key] !== typeof o2[key])
1064
+ if (typeof o1[key] !== typeof o2[key]) {
1056
1065
  return false;
1066
+ }
1057
1067
  if (typeof o1[key] === "object") {
1058
- if (!_deepEquals(o1[key], o2[key]))
1068
+ if (!_deepEquals(o1[key], o2[key])) {
1059
1069
  return false;
1070
+ }
1060
1071
  }
1061
1072
  else {
1062
- if (o1[key] !== o2[key])
1073
+ if (o1[key] !== o2[key]) {
1063
1074
  return false;
1075
+ }
1064
1076
  }
1065
1077
  }
1066
1078
  return true;
@@ -1096,8 +1108,9 @@ function includesAll(arr, values) {
1096
1108
  * Return an object with all the keys in the object that have a falsy value removed.
1097
1109
  */
1098
1110
  function removeFalsyAttributes(obj) {
1099
- if (!obj)
1111
+ if (!obj) {
1100
1112
  return obj;
1113
+ }
1101
1114
  const cleanObject = { ...obj };
1102
1115
  Object.keys(cleanObject).forEach((key) => !cleanObject[key] && delete cleanObject[key]);
1103
1116
  return cleanObject;
@@ -1129,8 +1142,9 @@ const whiteSpaceCharacters = specialWhiteSpaceSpecialCharacters.concat([" "]);
1129
1142
  * Replace all different newlines characters by \n.
1130
1143
  */
1131
1144
  function replaceNewLines(text) {
1132
- if (!text)
1145
+ if (!text) {
1133
1146
  return "";
1147
+ }
1134
1148
  return text.replace(newLineRegexp, NEWLINE);
1135
1149
  }
1136
1150
  /**
@@ -1209,8 +1223,9 @@ function getSearchRegex(searchStr, searchOptions) {
1209
1223
  */
1210
1224
  function largeMax(array) {
1211
1225
  let len = array.length;
1212
- if (len < 100_000)
1226
+ if (len < 100_000) {
1213
1227
  return Math.max(...array);
1228
+ }
1214
1229
  let max = -Infinity;
1215
1230
  while (len--) {
1216
1231
  max = array[len] > max ? array[len] : max;
@@ -1223,8 +1238,9 @@ function largeMax(array) {
1223
1238
  */
1224
1239
  function largeMin(array) {
1225
1240
  let len = array.length;
1226
- if (len < 100_000)
1241
+ if (len < 100_000) {
1227
1242
  return Math.min(...array);
1243
+ }
1228
1244
  let min = +Infinity;
1229
1245
  while (len--) {
1230
1246
  min = array[len] < min ? array[len] : min;
@@ -1325,6 +1341,10 @@ function chartStyleToCellStyle(style) {
1325
1341
  align: style.align,
1326
1342
  };
1327
1343
  }
1344
+ function doesCellContainFunction(cell, formula) {
1345
+ return (cell.isFormula &&
1346
+ cell.compiledFormula.tokens.some((t) => t.type === "SYMBOL" && t.value.toUpperCase() === formula));
1347
+ }
1328
1348
 
1329
1349
  // -----------------------------------------------------------------------------
1330
1350
  // Date Type
@@ -1741,10 +1761,12 @@ function getYearFrac(startDate, endDate, _dayCountConvention) {
1741
1761
  switch (_dayCountConvention) {
1742
1762
  // 30/360 US convention --------------------------------------------------
1743
1763
  case 0:
1744
- if (dayStart === 31)
1764
+ if (dayStart === 31) {
1745
1765
  dayStart = 30;
1746
- if (dayStart === 30 && dayEnd === 31)
1766
+ }
1767
+ if (dayStart === 30 && dayEnd === 31) {
1747
1768
  dayEnd = 30;
1769
+ }
1748
1770
  // If jsStartDate is the last day of February
1749
1771
  if (monthStart === 1 && dayStart === (isLeapYear(yearStart) ? 29 : 28)) {
1750
1772
  dayStart = 30;
@@ -1818,10 +1840,12 @@ function getYearFrac(startDate, endDate, _dayCountConvention) {
1818
1840
  break;
1819
1841
  // 30/360 European convention --------------------------------------------
1820
1842
  case 4:
1821
- if (dayStart === 31)
1843
+ if (dayStart === 31) {
1822
1844
  dayStart = 30;
1823
- if (dayEnd === 31)
1845
+ }
1846
+ if (dayEnd === 31) {
1824
1847
  dayEnd = 30;
1848
+ }
1825
1849
  yearsStart = yearStart + (monthStart * 30 + dayStart) / 360;
1826
1850
  yearsEnd = yearEnd + (monthEnd * 30 + dayEnd) / 360;
1827
1851
  break;
@@ -1929,8 +1953,9 @@ const getNumberRegex = memoize(function getNumberRegex(locale) {
1929
1953
  * Note that "" (empty string) does not count as a number string
1930
1954
  */
1931
1955
  function isNumber(value, locale) {
1932
- if (!value)
1956
+ if (!value) {
1933
1957
  return false;
1958
+ }
1934
1959
  // TO DO: add regexp for DATE string format (ex match: "28 02 2020")
1935
1960
  return getNumberRegex(locale).test(value.trim());
1936
1961
  }
@@ -2409,15 +2434,17 @@ function conditionalVisitArgs(args, cellCb, dataCb) {
2409
2434
  const lenCol = arg[0].length;
2410
2435
  for (let y = 0; y < lenCol; y++) {
2411
2436
  for (let x = 0; x < lenRow; x++) {
2412
- if (!cellCb(arg[x][y] ?? undefined))
2437
+ if (!cellCb(arg[x][y] ?? undefined)) {
2413
2438
  return;
2439
+ }
2414
2440
  }
2415
2441
  }
2416
2442
  }
2417
2443
  else {
2418
2444
  // arg is set directly in the formula function
2419
- if (!dataCb(arg))
2445
+ if (!dataCb(arg)) {
2420
2446
  return;
2447
+ }
2421
2448
  }
2422
2449
  }
2423
2450
  }
@@ -3551,8 +3578,9 @@ function applyIntegerFormat(integerDigits, internalFormat, thousandsSeparator) {
3551
3578
  if (digitType === "0") {
3552
3579
  digit = digit || "0";
3553
3580
  }
3554
- if (!digit)
3581
+ if (!digit) {
3555
3582
  return;
3583
+ }
3556
3584
  const digitIndex = integerDigits.length - 1 - indexInIntegerString;
3557
3585
  if (thousandsSeparator && digitIndex > 0 && digitIndex % 3 === 0) {
3558
3586
  formattedInteger = digit + thousandsSeparator + formattedInteger;
@@ -3630,8 +3658,9 @@ const numberRepresentation = [];
3630
3658
  **/
3631
3659
  function splitNumber(value, maxDecimals = MAX_DECIMAL_PLACES) {
3632
3660
  const asString = value.toString();
3633
- if (asString.includes("e"))
3661
+ if (asString.includes("e")) {
3634
3662
  return splitNumberIntl(value, maxDecimals);
3663
+ }
3635
3664
  if (Number.isInteger(value)) {
3636
3665
  return { integerDigits: asString, decimalDigits: undefined };
3637
3666
  }
@@ -3819,8 +3848,9 @@ const getDecimalNumberRegex = memoize(function getDecimalNumberRegex(locale) {
3819
3848
  */
3820
3849
  function createDefaultFormat(value) {
3821
3850
  let { integerDigits, decimalDigits } = splitNumber(value);
3822
- if (!decimalDigits)
3851
+ if (!decimalDigits) {
3823
3852
  return "0";
3853
+ }
3824
3854
  const digitsInIntegerPart = integerDigits.replace("-", "").length;
3825
3855
  // If there's no space for at least the decimal separator + a decimal digit, don't display decimals
3826
3856
  if (digitsInIntegerPart + 2 > DEFAULT_FORMAT_NUMBER_OF_DIGITS) {
@@ -4004,8 +4034,9 @@ function isExcelCompatible(format) {
4004
4034
  return true;
4005
4035
  }
4006
4036
  function isTextFormat(format) {
4007
- if (!format)
4037
+ if (!format) {
4008
4038
  return false;
4039
+ }
4009
4040
  try {
4010
4041
  const internalFormat = parseFormat(format);
4011
4042
  return internalFormat.positive.type === "text";
@@ -4905,8 +4936,9 @@ function getFullReference(sheetName, xc) {
4905
4936
  * A1:$B$1 => $A$1:B$1 => A$1:$B1 => $A1:B1 => A1:$B$1
4906
4937
  */
4907
4938
  function loopThroughReferenceType(token) {
4908
- if (token.type !== "REFERENCE")
4939
+ if (token.type !== "REFERENCE") {
4909
4940
  return token;
4941
+ }
4910
4942
  const { xc, sheetName } = splitReference(token.value);
4911
4943
  const [left, right] = xc.split(":");
4912
4944
  const updatedLeft = getTokenNextReferenceType(left);
@@ -4958,16 +4990,19 @@ function _setXcToFixedReferenceType(xc, referenceType) {
4958
4990
  const hasRow = indexOfNumber >= 0;
4959
4991
  switch (referenceType) {
4960
4992
  case "col":
4961
- if (!hasCol)
4993
+ if (!hasCol) {
4962
4994
  return xc;
4995
+ }
4963
4996
  return "$" + xc;
4964
4997
  case "row":
4965
- if (!hasRow)
4998
+ if (!hasRow) {
4966
4999
  return xc;
5000
+ }
4967
5001
  return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
4968
5002
  case "colrow":
4969
- if (!hasRow || !hasCol)
5003
+ if (!hasRow || !hasCol) {
4970
5004
  return "$" + xc;
5005
+ }
4971
5006
  return "$" + xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
4972
5007
  case "none":
4973
5008
  return xc;
@@ -5136,8 +5171,9 @@ function consumeSpaces(chars) {
5136
5171
  }
5137
5172
  }
5138
5173
  function consumeLetters(chars) {
5139
- if (chars.current === "$")
5174
+ if (chars.current === "$") {
5140
5175
  chars.advanceBy(1);
5176
+ }
5141
5177
  if (!chars.current || !isCharALetter(chars.current)) {
5142
5178
  return -1;
5143
5179
  }
@@ -5148,8 +5184,9 @@ function consumeLetters(chars) {
5148
5184
  return colCoordinate;
5149
5185
  }
5150
5186
  function consumeDigits(chars) {
5151
- if (chars.current === "$")
5187
+ if (chars.current === "$") {
5152
5188
  chars.advanceBy(1);
5189
+ }
5153
5190
  if (!chars.current || !isCharADigit(chars.current)) {
5154
5191
  return -1;
5155
5192
  }
@@ -5807,8 +5844,9 @@ function reduceZoneOnDeletion(zone, start, elements) {
5807
5844
  for (const removedElement of elements.sort((a, b) => b - a)) {
5808
5845
  if (zone[start] > removedElement) {
5809
5846
  newStart--;
5810
- if (newEnd !== undefined)
5847
+ if (newEnd !== undefined) {
5811
5848
  newEnd--;
5849
+ }
5812
5850
  }
5813
5851
  if (zoneEnd !== undefined &&
5814
5852
  newEnd !== undefined &&
@@ -5878,8 +5916,9 @@ function isEqual(z1, z2) {
5878
5916
  * Returns the adjacent size of z1 as well as the indexes of the header by which they are adjacent.
5879
5917
  */
5880
5918
  function adjacent(z1, z2) {
5881
- if (intersection(z1, z2))
5919
+ if (intersection(z1, z2)) {
5882
5920
  return undefined;
5921
+ }
5883
5922
  let adjacentEdge = undefined;
5884
5923
  if (z1.left === z2.right + 1) {
5885
5924
  adjacentEdge = {
@@ -6164,14 +6203,16 @@ function boundUnboundedZone(unboundedZone, sheetSize) {
6164
6203
  * including cells outside the zones
6165
6204
  * */
6166
6205
  function areZonesContinuous(zones) {
6167
- if (zones.length < 2)
6206
+ if (zones.length < 2) {
6168
6207
  return true;
6208
+ }
6169
6209
  return recomputeZones(zones).length === 1;
6170
6210
  }
6171
6211
  function splitIfAdjacent(zone, zoneToRemove) {
6172
6212
  const adjacentEdge = adjacent(zone, zoneToRemove);
6173
- if (!adjacentEdge)
6213
+ if (!adjacentEdge) {
6174
6214
  return [zone];
6215
+ }
6175
6216
  const newZones = [];
6176
6217
  switch (adjacentEdge.position) {
6177
6218
  case "bottom":
@@ -6268,514 +6309,6 @@ function splitZone(z1, z2) {
6268
6309
  return zones;
6269
6310
  }
6270
6311
 
6271
- function isSheetDependent(cmd) {
6272
- return "sheetId" in cmd;
6273
- }
6274
- function isHeadersDependant(cmd) {
6275
- return "dimension" in cmd && "sheetId" in cmd && "elements" in cmd;
6276
- }
6277
- function isTargetDependent(cmd) {
6278
- return "target" in cmd && "sheetId" in cmd;
6279
- }
6280
- function isRangeDependant(cmd) {
6281
- return "ranges" in cmd;
6282
- }
6283
- function isPositionDependent(cmd) {
6284
- return "col" in cmd && "row" in cmd && "sheetId" in cmd;
6285
- }
6286
- function isZoneDependent(cmd) {
6287
- return "sheetId" in cmd && "zone" in cmd;
6288
- }
6289
- const invalidateEvaluationCommands = new Set([
6290
- "RENAME_SHEET",
6291
- "DELETE_SHEET",
6292
- "CREATE_SHEET",
6293
- "DUPLICATE_SHEET",
6294
- "ADD_COLUMNS_ROWS",
6295
- "REMOVE_COLUMNS_ROWS",
6296
- "UNDO",
6297
- "REDO",
6298
- "ADD_MERGE",
6299
- "REMOVE_MERGE",
6300
- "UPDATE_LOCALE",
6301
- "ADD_PIVOT",
6302
- "UPDATE_PIVOT",
6303
- "INSERT_PIVOT",
6304
- "RENAME_PIVOT",
6305
- "REMOVE_PIVOT",
6306
- "DUPLICATE_PIVOT",
6307
- ]);
6308
- const invalidateChartEvaluationCommands = new Set([
6309
- "EVALUATE_CELLS",
6310
- "EVALUATE_CHARTS",
6311
- "UPDATE_CELL",
6312
- "UNHIDE_COLUMNS_ROWS",
6313
- "HIDE_COLUMNS_ROWS",
6314
- "GROUP_HEADERS",
6315
- "SET_FORMATTING",
6316
- "CLEAR_FORMATTING",
6317
- "UNGROUP_HEADERS",
6318
- "FOLD_ALL_HEADER_GROUPS",
6319
- "FOLD_HEADER_GROUP",
6320
- "FOLD_HEADER_GROUPS_IN_ZONE",
6321
- "UNFOLD_ALL_HEADER_GROUPS",
6322
- "UNFOLD_HEADER_GROUP",
6323
- "UNFOLD_HEADER_GROUPS_IN_ZONE",
6324
- "UPDATE_TABLE",
6325
- "UPDATE_FILTER",
6326
- "UNDO",
6327
- "REDO",
6328
- ]);
6329
- const invalidateDependenciesCommands = new Set(["MOVE_RANGES"]);
6330
- const invalidateCFEvaluationCommands = new Set([
6331
- "EVALUATE_CELLS",
6332
- "ADD_CONDITIONAL_FORMAT",
6333
- "REMOVE_CONDITIONAL_FORMAT",
6334
- "CHANGE_CONDITIONAL_FORMAT_PRIORITY",
6335
- ]);
6336
- const invalidateBordersCommands = new Set([
6337
- "AUTOFILL_CELL",
6338
- "SET_BORDER",
6339
- "SET_ZONE_BORDERS",
6340
- "SET_BORDERS_ON_TARGET",
6341
- ]);
6342
- const invalidSubtotalFormulasCommands = new Set([
6343
- "UNHIDE_COLUMNS_ROWS",
6344
- "HIDE_COLUMNS_ROWS",
6345
- "GROUP_HEADERS",
6346
- "UNGROUP_HEADERS",
6347
- "FOLD_ALL_HEADER_GROUPS",
6348
- "FOLD_HEADER_GROUP",
6349
- "FOLD_HEADER_GROUPS_IN_ZONE",
6350
- "UNFOLD_ALL_HEADER_GROUPS",
6351
- "UNFOLD_HEADER_GROUP",
6352
- "UNFOLD_HEADER_GROUPS_IN_ZONE",
6353
- "UPDATE_TABLE",
6354
- "UPDATE_FILTER",
6355
- ]);
6356
- const readonlyAllowedCommands = new Set([
6357
- "START",
6358
- "ACTIVATE_SHEET",
6359
- "COPY",
6360
- "RESIZE_SHEETVIEW",
6361
- "SET_VIEWPORT_OFFSET",
6362
- "SET_ZOOM",
6363
- "EVALUATE_CELLS",
6364
- "EVALUATE_CHARTS",
6365
- "SET_FORMULA_VISIBILITY",
6366
- "UPDATE_FILTER",
6367
- "UPDATE_CHART",
6368
- "UPDATE_CAROUSEL_ACTIVE_ITEM",
6369
- "UPDATE_PIVOT",
6370
- ]);
6371
- const coreTypes = new Set([
6372
- /** CELLS */
6373
- "UPDATE_CELL",
6374
- "UPDATE_CELL_POSITION",
6375
- "CLEAR_CELL",
6376
- "CLEAR_CELLS",
6377
- "DELETE_CONTENT",
6378
- /** GRID SHAPE */
6379
- "ADD_COLUMNS_ROWS",
6380
- "REMOVE_COLUMNS_ROWS",
6381
- "RESIZE_COLUMNS_ROWS",
6382
- "HIDE_COLUMNS_ROWS",
6383
- "UNHIDE_COLUMNS_ROWS",
6384
- "SET_GRID_LINES_VISIBILITY",
6385
- "UNFREEZE_COLUMNS",
6386
- "UNFREEZE_ROWS",
6387
- "FREEZE_COLUMNS",
6388
- "FREEZE_ROWS",
6389
- "UNFREEZE_COLUMNS_ROWS",
6390
- /** MERGE */
6391
- "ADD_MERGE",
6392
- "REMOVE_MERGE",
6393
- /** SHEETS MANIPULATION */
6394
- "CREATE_SHEET",
6395
- "DELETE_SHEET",
6396
- "DUPLICATE_SHEET",
6397
- "MOVE_SHEET",
6398
- "RENAME_SHEET",
6399
- "COLOR_SHEET",
6400
- "HIDE_SHEET",
6401
- "SHOW_SHEET",
6402
- /** RANGES MANIPULATION */
6403
- "MOVE_RANGES",
6404
- /** CONDITIONAL FORMAT */
6405
- "ADD_CONDITIONAL_FORMAT",
6406
- "REMOVE_CONDITIONAL_FORMAT",
6407
- "CHANGE_CONDITIONAL_FORMAT_PRIORITY",
6408
- /** FIGURES */
6409
- "CREATE_FIGURE",
6410
- "DELETE_FIGURE",
6411
- "UPDATE_FIGURE",
6412
- "CREATE_CAROUSEL",
6413
- "UPDATE_CAROUSEL",
6414
- /** FORMATTING */
6415
- "SET_FORMATTING",
6416
- "CLEAR_FORMATTING",
6417
- "SET_BORDER",
6418
- "SET_ZONE_BORDERS",
6419
- "SET_BORDERS_ON_TARGET",
6420
- /** CHART */
6421
- "CREATE_CHART",
6422
- "UPDATE_CHART",
6423
- "DELETE_CHART",
6424
- /** FILTERS */
6425
- "CREATE_TABLE",
6426
- "REMOVE_TABLE",
6427
- "UPDATE_TABLE",
6428
- "CREATE_TABLE_STYLE",
6429
- "REMOVE_TABLE_STYLE",
6430
- /** IMAGE */
6431
- "CREATE_IMAGE",
6432
- /** HEADER GROUP */
6433
- "GROUP_HEADERS",
6434
- "UNGROUP_HEADERS",
6435
- "UNFOLD_HEADER_GROUP",
6436
- "FOLD_HEADER_GROUP",
6437
- "FOLD_ALL_HEADER_GROUPS",
6438
- "UNFOLD_ALL_HEADER_GROUPS",
6439
- "UNFOLD_HEADER_GROUPS_IN_ZONE",
6440
- "FOLD_HEADER_GROUPS_IN_ZONE",
6441
- /** DATA VALIDATION */
6442
- "ADD_DATA_VALIDATION_RULE",
6443
- "REMOVE_DATA_VALIDATION_RULE",
6444
- /** MISC */
6445
- "UPDATE_LOCALE",
6446
- /** PIVOT */
6447
- "ADD_PIVOT",
6448
- "UPDATE_PIVOT",
6449
- "INSERT_PIVOT",
6450
- "RENAME_PIVOT",
6451
- "REMOVE_PIVOT",
6452
- "DUPLICATE_PIVOT",
6453
- ]);
6454
- function isCoreCommand(cmd) {
6455
- return coreTypes.has(cmd.type);
6456
- }
6457
- function canExecuteInReadonly(cmd) {
6458
- return readonlyAllowedCommands.has(cmd.type);
6459
- }
6460
- /**
6461
- * Holds the result of a command dispatch.
6462
- * The command may have been successfully dispatched or cancelled
6463
- * for one or more reasons.
6464
- */
6465
- class DispatchResult {
6466
- reasons;
6467
- constructor(results = []) {
6468
- if (!Array.isArray(results)) {
6469
- results = [results];
6470
- }
6471
- results = [...new Set(results)];
6472
- this.reasons = results.filter((result) => result !== "Success" /* CommandResult.Success */);
6473
- }
6474
- /**
6475
- * Static helper which returns a successful DispatchResult
6476
- */
6477
- static get Success() {
6478
- return SUCCESS;
6479
- }
6480
- get isSuccessful() {
6481
- return this.reasons.length === 0;
6482
- }
6483
- /**
6484
- * Check if the dispatch has been cancelled because of
6485
- * the given reason.
6486
- */
6487
- isCancelledBecause(reason) {
6488
- return this.reasons.includes(reason);
6489
- }
6490
- }
6491
- const SUCCESS = new DispatchResult();
6492
- var CommandResult;
6493
- (function (CommandResult) {
6494
- CommandResult["Success"] = "Success";
6495
- CommandResult["CancelledForUnknownReason"] = "CancelledForUnknownReason";
6496
- CommandResult["WillRemoveExistingMerge"] = "WillRemoveExistingMerge";
6497
- CommandResult["CannotMoveTableHeader"] = "CannotMoveTableHeader";
6498
- CommandResult["MergeIsDestructive"] = "MergeIsDestructive";
6499
- CommandResult["CellIsMerged"] = "CellIsMerged";
6500
- CommandResult["InvalidTarget"] = "InvalidTarget";
6501
- CommandResult["EmptyUndoStack"] = "EmptyUndoStack";
6502
- CommandResult["EmptyRedoStack"] = "EmptyRedoStack";
6503
- CommandResult["NotEnoughElements"] = "NotEnoughElements";
6504
- CommandResult["NotEnoughSheets"] = "NotEnoughSheets";
6505
- CommandResult["MissingSheetName"] = "MissingSheetName";
6506
- CommandResult["UnchangedSheetName"] = "UnchangedSheetName";
6507
- CommandResult["DuplicatedSheetName"] = "DuplicatedSheetName";
6508
- CommandResult["DuplicatedSheetId"] = "DuplicatedSheetId";
6509
- CommandResult["ForbiddenCharactersInSheetName"] = "ForbiddenCharactersInSheetName";
6510
- CommandResult["WrongSheetMove"] = "WrongSheetMove";
6511
- CommandResult["WrongSheetPosition"] = "WrongSheetPosition";
6512
- CommandResult["InvalidAnchorZone"] = "InvalidAnchorZone";
6513
- CommandResult["SelectionOutOfBound"] = "SelectionOutOfBound";
6514
- CommandResult["TargetOutOfSheet"] = "TargetOutOfSheet";
6515
- CommandResult["WrongCutSelection"] = "WrongCutSelection";
6516
- CommandResult["WrongPasteSelection"] = "WrongPasteSelection";
6517
- CommandResult["WrongPasteOption"] = "WrongPasteOption";
6518
- CommandResult["WrongFigurePasteOption"] = "WrongFigurePasteOption";
6519
- CommandResult["EmptyClipboard"] = "EmptyClipboard";
6520
- CommandResult["EmptyRange"] = "EmptyRange";
6521
- CommandResult["InvalidRange"] = "InvalidRange";
6522
- CommandResult["InvalidZones"] = "InvalidZones";
6523
- CommandResult["InvalidSheetId"] = "InvalidSheetId";
6524
- CommandResult["InvalidCellId"] = "InvalidCellId";
6525
- CommandResult["InvalidFigureId"] = "InvalidFigureId";
6526
- CommandResult["InputAlreadyFocused"] = "InputAlreadyFocused";
6527
- CommandResult["MaximumRangesReached"] = "MaximumRangesReached";
6528
- CommandResult["MinimumRangesReached"] = "MinimumRangesReached";
6529
- CommandResult["InvalidChartDefinition"] = "InvalidChartDefinition";
6530
- CommandResult["InvalidDataSet"] = "InvalidDataSet";
6531
- CommandResult["InvalidLabelRange"] = "InvalidLabelRange";
6532
- CommandResult["InvalidScorecardKeyValue"] = "InvalidScorecardKeyValue";
6533
- CommandResult["InvalidScorecardBaseline"] = "InvalidScorecardBaseline";
6534
- CommandResult["InvalidGaugeDataRange"] = "InvalidGaugeDataRange";
6535
- CommandResult["EmptyGaugeRangeMin"] = "EmptyGaugeRangeMin";
6536
- CommandResult["GaugeRangeMinNaN"] = "GaugeRangeMinNaN";
6537
- CommandResult["EmptyGaugeRangeMax"] = "EmptyGaugeRangeMax";
6538
- CommandResult["GaugeRangeMaxNaN"] = "GaugeRangeMaxNaN";
6539
- CommandResult["GaugeLowerInflectionPointNaN"] = "GaugeLowerInflectionPointNaN";
6540
- CommandResult["GaugeUpperInflectionPointNaN"] = "GaugeUpperInflectionPointNaN";
6541
- CommandResult["InvalidAutofillSelection"] = "InvalidAutofillSelection";
6542
- CommandResult["MinBiggerThanMax"] = "MinBiggerThanMax";
6543
- CommandResult["LowerBiggerThanUpper"] = "LowerBiggerThanUpper";
6544
- CommandResult["MidBiggerThanMax"] = "MidBiggerThanMax";
6545
- CommandResult["MinBiggerThanMid"] = "MinBiggerThanMid";
6546
- CommandResult["FirstArgMissing"] = "FirstArgMissing";
6547
- CommandResult["SecondArgMissing"] = "SecondArgMissing";
6548
- CommandResult["MinNaN"] = "MinNaN";
6549
- CommandResult["MidNaN"] = "MidNaN";
6550
- CommandResult["MaxNaN"] = "MaxNaN";
6551
- CommandResult["ValueUpperInflectionNaN"] = "ValueUpperInflectionNaN";
6552
- CommandResult["ValueLowerInflectionNaN"] = "ValueLowerInflectionNaN";
6553
- CommandResult["MinInvalidFormula"] = "MinInvalidFormula";
6554
- CommandResult["MidInvalidFormula"] = "MidInvalidFormula";
6555
- CommandResult["MaxInvalidFormula"] = "MaxInvalidFormula";
6556
- CommandResult["ValueUpperInvalidFormula"] = "ValueUpperInvalidFormula";
6557
- CommandResult["ValueLowerInvalidFormula"] = "ValueLowerInvalidFormula";
6558
- CommandResult["InvalidSortAnchor"] = "InvalidSortAnchor";
6559
- CommandResult["InvalidSortZone"] = "InvalidSortZone";
6560
- CommandResult["SortZoneWithArrayFormulas"] = "SortZoneWithArrayFormulas";
6561
- CommandResult["WaitingSessionConfirmation"] = "WaitingSessionConfirmation";
6562
- CommandResult["MergeOverlap"] = "MergeOverlap";
6563
- CommandResult["TooManyHiddenElements"] = "TooManyHiddenElements";
6564
- CommandResult["Readonly"] = "Readonly";
6565
- CommandResult["InvalidViewportSize"] = "InvalidViewportSize";
6566
- CommandResult["InvalidScrollingDirection"] = "InvalidScrollingDirection";
6567
- CommandResult["ViewportScrollLimitsReached"] = "ViewportScrollLimitsReached";
6568
- CommandResult["FigureDoesNotExist"] = "FigureDoesNotExist";
6569
- CommandResult["InvalidConditionalFormatId"] = "InvalidConditionalFormatId";
6570
- CommandResult["InvalidCellPopover"] = "InvalidCellPopover";
6571
- CommandResult["EmptyTarget"] = "EmptyTarget";
6572
- CommandResult["InvalidFreezeQuantity"] = "InvalidFreezeQuantity";
6573
- CommandResult["FrozenPaneOverlap"] = "FrozenPaneOverlap";
6574
- CommandResult["ValuesNotChanged"] = "ValuesNotChanged";
6575
- CommandResult["InvalidFilterZone"] = "InvalidFilterZone";
6576
- CommandResult["TableNotFound"] = "TableNotFound";
6577
- CommandResult["TableOverlap"] = "TableOverlap";
6578
- CommandResult["InvalidTableConfig"] = "InvalidTableConfig";
6579
- CommandResult["InvalidTableStyle"] = "InvalidTableStyle";
6580
- CommandResult["FilterNotFound"] = "FilterNotFound";
6581
- CommandResult["MergeInTable"] = "MergeInTable";
6582
- CommandResult["NonContinuousTargets"] = "NonContinuousTargets";
6583
- CommandResult["DuplicatedFigureId"] = "DuplicatedFigureId";
6584
- CommandResult["InvalidSelectionStep"] = "InvalidSelectionStep";
6585
- CommandResult["DuplicatedChartId"] = "DuplicatedChartId";
6586
- CommandResult["ChartDoesNotExist"] = "ChartDoesNotExist";
6587
- CommandResult["InvalidHeaderIndex"] = "InvalidHeaderIndex";
6588
- CommandResult["InvalidQuantity"] = "InvalidQuantity";
6589
- CommandResult["MoreThanOneColumnSelected"] = "MoreThanOneColumnSelected";
6590
- CommandResult["EmptySplitSeparator"] = "EmptySplitSeparator";
6591
- CommandResult["SplitWillOverwriteContent"] = "SplitWillOverwriteContent";
6592
- CommandResult["NoSplitSeparatorInSelection"] = "NoSplitSeparatorInSelection";
6593
- CommandResult["NoActiveSheet"] = "NoActiveSheet";
6594
- CommandResult["InvalidLocale"] = "InvalidLocale";
6595
- CommandResult["MoreThanOneRangeSelected"] = "MoreThanOneRangeSelected";
6596
- CommandResult["NoColumnsProvided"] = "NoColumnsProvided";
6597
- CommandResult["ColumnsNotIncludedInZone"] = "ColumnsNotIncludedInZone";
6598
- CommandResult["DuplicatesColumnsSelected"] = "DuplicatesColumnsSelected";
6599
- CommandResult["InvalidHeaderGroupStartEnd"] = "InvalidHeaderGroupStartEnd";
6600
- CommandResult["HeaderGroupAlreadyExists"] = "HeaderGroupAlreadyExists";
6601
- CommandResult["UnknownHeaderGroup"] = "UnknownHeaderGroup";
6602
- CommandResult["UnknownDataValidationRule"] = "UnknownDataValidationRule";
6603
- CommandResult["UnknownDataValidationCriterionType"] = "UnknownDataValidationCriterionType";
6604
- CommandResult["InvalidDataValidationCriterionValue"] = "InvalidDataValidationCriterionValue";
6605
- CommandResult["InvalidNumberOfCriterionValues"] = "InvalidNumberOfCriterionValues";
6606
- CommandResult["InvalidCopyPasteSelection"] = "InvalidCopyPasteSelection";
6607
- CommandResult["NoChanges"] = "NoChanges";
6608
- CommandResult["InvalidInputId"] = "InvalidInputId";
6609
- CommandResult["SheetIsHidden"] = "SheetIsHidden";
6610
- CommandResult["InvalidTableResize"] = "InvalidTableResize";
6611
- CommandResult["PivotIdNotFound"] = "PivotIdNotFound";
6612
- CommandResult["PivotIdTaken"] = "PivotIdTaken";
6613
- CommandResult["PivotInError"] = "PivotInError";
6614
- CommandResult["EmptyName"] = "EmptyName";
6615
- CommandResult["ValueCellIsInvalidFormula"] = "ValueCellIsInvalidFormula";
6616
- CommandResult["InvalidDefinition"] = "InvalidDefinition";
6617
- CommandResult["InvalidColor"] = "InvalidColor";
6618
- CommandResult["InvalidPivotDataSet"] = "InvalidPivotDataSet";
6619
- CommandResult["InvalidPivotCustomField"] = "InvalidPivotCustomField";
6620
- CommandResult["MissingFigureArguments"] = "MissingFigureArguments";
6621
- CommandResult["InvalidCarouselItem"] = "InvalidCarouselItem";
6622
- })(CommandResult || (CommandResult = {}));
6623
-
6624
- /**
6625
- * BasePlugin
6626
- *
6627
- * Since the spreadsheet internal state is quite complex, it is split into
6628
- * multiple parts, each managing a specific concern.
6629
- *
6630
- * This file introduces the BasePlugin, which is the common class that defines
6631
- * how each of these model sub parts should interact with each other.
6632
- * There are two kinds of plugins: core plugins handling persistent data
6633
- * and UI plugins handling transient data.
6634
- */
6635
- class BasePlugin {
6636
- static getters = [];
6637
- history;
6638
- constructor(stateObserver) {
6639
- this.history = Object.assign(Object.create(stateObserver), {
6640
- update: stateObserver.addChange.bind(stateObserver, this),
6641
- selectCell: () => { },
6642
- });
6643
- }
6644
- /**
6645
- * Export for excel should be available for all plugins, even for the UI.
6646
- * In some cases, we need to export evaluated value, which is available from
6647
- * UI plugin only.
6648
- */
6649
- exportForExcel(data) { }
6650
- // ---------------------------------------------------------------------------
6651
- // Command handling
6652
- // ---------------------------------------------------------------------------
6653
- /**
6654
- * Before a command is accepted, the model will ask each plugin if the command
6655
- * is allowed. If all of them return true, then we can proceed. Otherwise,
6656
- * the command is cancelled.
6657
- *
6658
- * There should not be any side effects in this method.
6659
- */
6660
- allowDispatch(command) {
6661
- return "Success" /* CommandResult.Success */;
6662
- }
6663
- /**
6664
- * This method is useful when a plugin needs to perform some action before a
6665
- * command is handled in another plugin. This should only be used if it is not
6666
- * possible to do the work in the handle method.
6667
- */
6668
- beforeHandle(command) { }
6669
- /**
6670
- * This is the standard place to handle any command. Most of the plugin
6671
- * command handling work should take place here.
6672
- */
6673
- handle(command) { }
6674
- /**
6675
- * Sometimes, it is useful to perform some work after a command (and all its
6676
- * subcommands) has been completely handled. For example, when we paste
6677
- * multiple cells, we only want to reevaluate the cell values once at the end.
6678
- */
6679
- finalize() { }
6680
- /**
6681
- * Combine multiple validation functions into a single function
6682
- * returning the list of results of every validation.
6683
- */
6684
- batchValidations(...validations) {
6685
- return (toValidate) => validations.map((validation) => validation.call(this, toValidate)).flat();
6686
- }
6687
- /**
6688
- * Combine multiple validation functions. Every validation is executed one after
6689
- * the other. As soon as one validation fails, it stops and the cancelled reason
6690
- * is returned.
6691
- */
6692
- chainValidations(...validations) {
6693
- return (toValidate) => {
6694
- for (const validation of validations) {
6695
- let results = validation.call(this, toValidate);
6696
- if (!Array.isArray(results)) {
6697
- results = [results];
6698
- }
6699
- const cancelledReasons = results.filter((result) => result !== "Success" /* CommandResult.Success */);
6700
- if (cancelledReasons.length) {
6701
- return cancelledReasons;
6702
- }
6703
- }
6704
- return "Success" /* CommandResult.Success */;
6705
- };
6706
- }
6707
- checkValidations(command, ...validations) {
6708
- return this.batchValidations(...validations)(command);
6709
- }
6710
- }
6711
-
6712
- /**
6713
- * UI plugins handle any transient data required to display a spreadsheet.
6714
- * They can draw on the grid canvas.
6715
- */
6716
- class UIPlugin extends BasePlugin {
6717
- static layers = [];
6718
- getters;
6719
- ui;
6720
- selection;
6721
- dispatch;
6722
- canDispatch;
6723
- constructor({ getters, stateObserver, dispatch, canDispatch, uiActions, selection, }) {
6724
- super(stateObserver);
6725
- this.getters = getters;
6726
- this.ui = uiActions;
6727
- this.selection = selection;
6728
- this.dispatch = dispatch;
6729
- this.canDispatch = canDispatch;
6730
- }
6731
- // ---------------------------------------------------------------------------
6732
- // Grid rendering
6733
- // ---------------------------------------------------------------------------
6734
- drawLayer(ctx, layer) { }
6735
- }
6736
-
6737
- class SubtotalEvaluationPlugin extends UIPlugin {
6738
- subtotalCells = new Set();
6739
- handle(cmd) {
6740
- switch (cmd.type) {
6741
- case "START": {
6742
- this.subtotalCells.clear();
6743
- for (const sheetId of this.getters.getSheetIds()) {
6744
- const cells = this.getters.getCells(sheetId);
6745
- for (const cellId in cells) {
6746
- const cell = cells[cellId];
6747
- if (isSubtotalCell(cell)) {
6748
- this.subtotalCells.add(cell.id);
6749
- }
6750
- }
6751
- }
6752
- break;
6753
- }
6754
- case "UPDATE_CELL": {
6755
- if (!("content" in cmd))
6756
- return;
6757
- const cell = this.getters.getCell(cmd);
6758
- if (!cell)
6759
- return;
6760
- if (isSubtotalCell(cell)) {
6761
- this.subtotalCells.add(cell.id);
6762
- }
6763
- else {
6764
- this.subtotalCells.delete(cell.id);
6765
- }
6766
- break;
6767
- }
6768
- }
6769
- if (invalidSubtotalFormulasCommands.has(cmd.type)) {
6770
- this.dispatch("EVALUATE_CELLS", { cellIds: Array.from(this.subtotalCells) });
6771
- }
6772
- }
6773
- }
6774
- function isSubtotalCell(cell) {
6775
- return (cell.isFormula &&
6776
- cell.compiledFormula.tokens.some((t) => t.type === "SYMBOL" && t.value.toUpperCase() === "SUBTOTAL"));
6777
- }
6778
-
6779
6312
  function sum(values, locale) {
6780
6313
  return reduceNumbers(values, (acc, a) => acc + a, 0, locale);
6781
6314
  }
@@ -7853,19 +7386,22 @@ const SUBTOTAL = {
7853
7386
  const ref0 = ref[0][0];
7854
7387
  const sheetName = splitReference(ref0.value).sheetName;
7855
7388
  const sheetId = sheetName ? this.getters.getSheetIdByName(sheetName) : this.__originSheetId;
7856
- if (!sheetId)
7389
+ if (!sheetId) {
7857
7390
  continue;
7391
+ }
7858
7392
  const { top, left } = toZone(ref0.value);
7859
7393
  const right = left + ref.length - 1;
7860
7394
  const bottom = top + ref[0].length - 1;
7861
7395
  for (let row = top; row <= bottom; row++) {
7862
- if (this.getters.isRowFiltered(sheetId, row))
7396
+ if (this.getters.isRowFiltered(sheetId, row)) {
7863
7397
  continue;
7864
- if (!acceptHiddenCells && this.getters.isRowHiddenByUser(sheetId, row))
7398
+ }
7399
+ if (!acceptHiddenCells && this.getters.isRowHiddenByUser(sheetId, row)) {
7865
7400
  continue;
7401
+ }
7866
7402
  for (let col = left; col <= right; col++) {
7867
7403
  const cell = this.getters.getCorrespondingFormulaCell({ sheetId, col, row });
7868
- if (!cell || !isSubtotalCell(cell)) {
7404
+ if (!cell || !doesCellContainFunction(cell, "SUBTOTAL")) {
7869
7405
  evaluatedCellToKeep.push(this.getters.getEvaluatedCell({ sheetId, col, row }));
7870
7406
  }
7871
7407
  }
@@ -9776,7 +9312,7 @@ var database = /*#__PURE__*/Object.freeze({
9776
9312
  * formulas.
9777
9313
  */
9778
9314
  const POSTFIX_UNARY_OPERATORS = ["%"];
9779
- const OPERATORS = "+,-,*,/,:,=,<>,>=,>,<=,<,^,&".split(",").concat(POSTFIX_UNARY_OPERATORS);
9315
+ const OPERATORS = "+,-,*,/,:,=,<>,>=,>,<=,<,^,&,#".split(",").concat(POSTFIX_UNARY_OPERATORS);
9780
9316
  function tokenize(str, locale = DEFAULT_LOCALE) {
9781
9317
  str = replaceNewLines(str);
9782
9318
  const chars = new TokenizingChars(str);
@@ -9791,10 +9327,10 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
9791
9327
  tokenizeArgsSeparator(chars, locale) ||
9792
9328
  tokenizeBraces(chars) ||
9793
9329
  tokenizeParenthesis(chars) ||
9330
+ tokenizeInvalidRange(chars) ||
9794
9331
  tokenizeOperator(chars) ||
9795
9332
  tokenizeString(chars) ||
9796
9333
  tokenizeDebugger(chars) ||
9797
- tokenizeInvalidRange(chars) ||
9798
9334
  tokenizeNumber(chars, locale) ||
9799
9335
  tokenizeSymbol(chars);
9800
9336
  if (!token) {
@@ -11419,8 +10955,9 @@ const UNIQUE = {
11419
10955
  }
11420
10956
  result.push(row.data);
11421
10957
  }
11422
- if (!result.length)
10958
+ if (!result.length) {
11423
10959
  return new EvaluationError(_t("No unique values found"));
10960
+ }
11424
10961
  return _byColumn ? result : transposeMatrix(result);
11425
10962
  },
11426
10963
  isExported: true,
@@ -12352,10 +11889,12 @@ const IRR = {
12352
11889
  let negative = false;
12353
11890
  const amounts = [];
12354
11891
  visitNumbers([cashFlowAmounts], ({ value: amount }) => {
12355
- if (amount > 0)
11892
+ if (amount > 0) {
12356
11893
  positive = true;
12357
- if (amount < 0)
11894
+ }
11895
+ if (amount < 0) {
12358
11896
  negative = true;
11897
+ }
12359
11898
  amounts.push(amount);
12360
11899
  }, this.locale);
12361
11900
  if (!positive || !negative) {
@@ -12666,8 +12205,9 @@ function ppmt(r, per, n, pValue, fValue, t) {
12666
12205
  throw new EvaluationError(expectPeriodBetweenOneAndNumberOfPeriods(n));
12667
12206
  }
12668
12207
  const payment = pmt(r, n, pValue, fValue, t);
12669
- if (t === 1 && per === 1)
12208
+ if (t === 1 && per === 1) {
12670
12209
  return payment;
12210
+ }
12671
12211
  const eqPeriod = t === 0 ? per - 1 : per - 2;
12672
12212
  const eqPv = pValue + payment * t;
12673
12213
  const capitalAtPeriod = -fv(r, eqPeriod, payment, eqPv, 0);
@@ -13300,8 +12840,9 @@ const VDB = {
13300
12840
  if (_factor <= 0) {
13301
12841
  return new EvaluationError(expectDeprecationFactorStrictlyPositive(_factor));
13302
12842
  }
13303
- if (_cost === 0)
12843
+ if (_cost === 0) {
13304
12844
  return 0;
12845
+ }
13305
12846
  if (_salvage >= _cost) {
13306
12847
  return _startPeriod < 1 ? _cost - _salvage : 0;
13307
12848
  }
@@ -13366,10 +12907,12 @@ const XIRR = {
13366
12907
  const map = new Map();
13367
12908
  for (const i of range(0, _dates.length)) {
13368
12909
  const date = _dates[i];
13369
- if (map.has(date))
12910
+ if (map.has(date)) {
13370
12911
  map.set(date, map.get(date) + _cashFlows[i]);
13371
- else
12912
+ }
12913
+ else {
13372
12914
  map.set(date, _cashFlows[i]);
12915
+ }
13373
12916
  }
13374
12917
  const dates = Array.from(map.keys());
13375
12918
  const values = dates.map((date) => map.get(date));
@@ -13407,8 +12950,9 @@ const XIRR = {
13407
12950
  };
13408
12951
  const nanFallback = (previousFallback) => {
13409
12952
  // -0.9 => -0.99 => -0.999 => ...
13410
- if (!previousFallback)
12953
+ if (!previousFallback) {
13411
12954
  return -0.9;
12955
+ }
13412
12956
  return previousFallback / 10 - 0.9;
13413
12957
  };
13414
12958
  return newtonMethod(func, derivFunc, guess, 40, 1e-5, nanFallback);
@@ -13442,16 +12986,19 @@ const XNPV = {
13442
12986
  if (rate <= 0) {
13443
12987
  return new EvaluationError(expectRateStrictlyPositive(rate));
13444
12988
  }
13445
- if (_cashFlows.length === 1)
12989
+ if (_cashFlows.length === 1) {
13446
12990
  return _cashFlows[0];
12991
+ }
13447
12992
  // aggregate values of the same date
13448
12993
  const map = new Map();
13449
12994
  for (const i of range(0, _dates.length)) {
13450
12995
  const date = _dates[i];
13451
- if (map.has(date))
12996
+ if (map.has(date)) {
13452
12997
  map.set(date, map.get(date) + _cashFlows[i]);
13453
- else
12998
+ }
12999
+ else {
13454
13000
  map.set(date, _cashFlows[i]);
13001
+ }
13455
13002
  }
13456
13003
  const dates = Array.from(map.keys());
13457
13004
  const values = dates.map((date) => map.get(date));
@@ -14736,6 +14283,10 @@ const DEFAULT_PIVOT_STYLE = {
14736
14283
  displayMeasuresRow: true,
14737
14284
  numberOfRows: Number.MAX_VALUE,
14738
14285
  numberOfColumns: Number.MAX_VALUE,
14286
+ tableStyleId: "None",
14287
+ bandedRows: false,
14288
+ bandedColumns: false,
14289
+ hasFilters: false,
14739
14290
  };
14740
14291
  const AGGREGATOR_NAMES = {
14741
14292
  count: _t("Count"),
@@ -15049,7 +14600,17 @@ function getPivotStyleFromFnArgs(definition, rowCountArg, includeTotalArg, inclu
15049
14600
  const displayMeasuresRow = includeMeasuresRowArg !== undefined
15050
14601
  ? toBoolean(includeMeasuresRowArg)
15051
14602
  : style?.displayMeasuresRow ?? DEFAULT_PIVOT_STYLE.displayMeasuresRow;
15052
- return { numberOfRows, numberOfColumns, displayTotals, displayColumnHeaders, displayMeasuresRow };
14603
+ return {
14604
+ numberOfRows,
14605
+ numberOfColumns,
14606
+ displayTotals,
14607
+ displayColumnHeaders,
14608
+ displayMeasuresRow,
14609
+ tableStyleId: style?.tableStyleId || DEFAULT_PIVOT_STYLE.tableStyleId,
14610
+ bandedRows: style?.bandedRows ?? DEFAULT_PIVOT_STYLE.bandedRows,
14611
+ bandedColumns: style?.bandedColumns ?? DEFAULT_PIVOT_STYLE.bandedColumns,
14612
+ hasFilters: style?.hasFilters ?? DEFAULT_PIVOT_STYLE.hasFilters,
14613
+ };
15053
14614
  }
15054
14615
 
15055
14616
  /**
@@ -15074,9 +14635,10 @@ function assertDomainLength(domain) {
15074
14635
  throw new EvaluationError(_t("Function PIVOT takes an even number of arguments."));
15075
14636
  }
15076
14637
  }
15077
- function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
14638
+ function addPivotDependencies(evalContext, pivotId, forMeasures) {
15078
14639
  //TODO This function can be very costly when used with PIVOT.VALUE and PIVOT.HEADER
15079
14640
  const dependencies = [];
14641
+ const coreDefinition = evalContext.getters.getPivotCoreDefinition(pivotId);
15080
14642
  if (coreDefinition.type === "SPREADSHEET" && coreDefinition.dataSet) {
15081
14643
  const { sheetId, zone } = coreDefinition.dataSet;
15082
14644
  const xc = zoneToXc(zone);
@@ -15093,8 +14655,7 @@ function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
15093
14655
  }
15094
14656
  for (const measure of forMeasures) {
15095
14657
  if (measure.computedBy) {
15096
- const formula = evalContext.getters.getMeasureCompiledFormula(measure);
15097
- dependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
14658
+ dependencies.push(...evalContext.getters.getMeasureFullDependencies(pivotId, measure));
15098
14659
  }
15099
14660
  }
15100
14661
  const originPosition = evalContext.__originCellPosition;
@@ -15591,7 +15152,7 @@ const PIVOT_VALUE = {
15591
15152
  assertDomainLength(domainArgs);
15592
15153
  const pivot = this.getters.getPivot(pivotId);
15593
15154
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
15594
- addPivotDependencies(this, coreDefinition, coreDefinition.measures.filter((m) => m.id === _measure));
15155
+ addPivotDependencies(this, pivotId, coreDefinition.measures.filter((m) => m.id === _measure));
15595
15156
  pivot.init({ reload: pivot.needsReevaluation });
15596
15157
  const error = pivot.assertIsValid({ throwOnError: false });
15597
15158
  if (error) {
@@ -15624,8 +15185,7 @@ const PIVOT_HEADER = {
15624
15185
  const _pivotId = getPivotId(_pivotFormulaId, this.getters);
15625
15186
  assertDomainLength(domainArgs);
15626
15187
  const pivot = this.getters.getPivot(_pivotId);
15627
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
15628
- addPivotDependencies(this, coreDefinition, []);
15188
+ addPivotDependencies(this, _pivotId, []);
15629
15189
  pivot.init({ reload: pivot.needsReevaluation });
15630
15190
  const error = pivot.assertIsValid({ throwOnError: false });
15631
15191
  if (error) {
@@ -15677,7 +15237,7 @@ const PIVOT = {
15677
15237
  if (pivotStyle.numberOfColumns < 0) {
15678
15238
  return new EvaluationError(_t("The number of columns must be positive."));
15679
15239
  }
15680
- addPivotDependencies(this, coreDefinition, coreDefinition.measures);
15240
+ addPivotDependencies(this, pivotId, coreDefinition.measures);
15681
15241
  pivot.init({ reload: pivot.needsReevaluation });
15682
15242
  const error = pivot.assertIsValid({ throwOnError: false });
15683
15243
  if (error) {
@@ -15688,23 +15248,19 @@ const PIVOT = {
15688
15248
  return new EvaluationError(getPivotTooBigErrorMessage(table.numberOfCells, this.locale));
15689
15249
  }
15690
15250
  const cells = table.getPivotCells(pivotStyle);
15691
- let headerRows = 0;
15692
15251
  if (pivotStyle.displayColumnHeaders) {
15693
- headerRows = table.columns.length - 1;
15694
- }
15695
- if (pivotStyle.displayMeasuresRow) {
15696
- headerRows++;
15252
+ table.columns.length - 1;
15697
15253
  }
15254
+ if (pivotStyle.displayMeasuresRow) ;
15698
15255
  const pivotTitle = this.getters.getPivotName(pivotId);
15699
- const tableHeight = Math.min(headerRows + pivotStyle.numberOfRows, cells[0].length);
15700
- if (tableHeight === 0) {
15256
+ const { numberOfCols, numberOfRows } = table.getPivotTableDimensions(pivotStyle);
15257
+ if (numberOfRows === 0) {
15701
15258
  return [[{ value: pivotTitle }]];
15702
15259
  }
15703
- const tableWidth = Math.min(1 + pivotStyle.numberOfColumns, cells.length);
15704
15260
  const result = [];
15705
- for (const col of range(0, tableWidth)) {
15261
+ for (const col of range(0, numberOfCols)) {
15706
15262
  result[col] = [];
15707
- for (const row of range(0, tableHeight)) {
15263
+ for (const row of range(0, numberOfRows)) {
15708
15264
  const pivotCell = cells[col][row];
15709
15265
  switch (pivotCell.type) {
15710
15266
  case "EMPTY":
@@ -16186,6 +15742,58 @@ const POW = {
16186
15742
  },
16187
15743
  };
16188
15744
  // -----------------------------------------------------------------------------
15745
+ // SPILLED_RANGE
15746
+ // -----------------------------------------------------------------------------
15747
+ /**
15748
+ * Internal formula implementing the # operator.
15749
+ * It allows to get the spilled range of an array formula from any reference, including
15750
+ * references returned by other functions.
15751
+ * e.g. =IF(condition, A1, H10)#
15752
+ **/
15753
+ const SPILLED_RANGE = {
15754
+ description: _t("Gets the spilled range of an array formula."),
15755
+ args: [arg("ref (meta , range<meta>)", _t("The reference to get the spilled range from."))],
15756
+ compute: function (ref) {
15757
+ if (ref === undefined) {
15758
+ return new EvaluationError(_t("The range is out of bounds."));
15759
+ }
15760
+ if (ref.length !== 1 || ref[0].length !== 1) {
15761
+ return new EvaluationError(_t("Only single-cell references are allowed to get the spilled range."));
15762
+ }
15763
+ const _ref = ref[0][0];
15764
+ if (isEvaluationError(_ref.value)) {
15765
+ return _ref;
15766
+ }
15767
+ const initialRange = this.getters.getRangeFromSheetXC(this.__originSheetId, _ref.value);
15768
+ const cellPosition = {
15769
+ col: initialRange.zone.left,
15770
+ row: initialRange.zone.top,
15771
+ sheetId: initialRange.sheetId,
15772
+ };
15773
+ const originPosition = this.__originCellPosition;
15774
+ if (originPosition) {
15775
+ // The following line is used to reset the dependencies of the cell, to avoid
15776
+ // keeping dependencies from previous evaluation (i.e. in case the reference
15777
+ // has been changed).
15778
+ this.updateDependencies?.(originPosition);
15779
+ }
15780
+ const spilledZone = this.getters.getSpreadZone(cellPosition);
15781
+ if (spilledZone === undefined) {
15782
+ return new InvalidReferenceError();
15783
+ }
15784
+ const spilledRange = this.getters.getRangeFromZone(initialRange.sheetId, spilledZone);
15785
+ if (originPosition) {
15786
+ this.addDependencies?.(originPosition, [spilledRange]);
15787
+ }
15788
+ return generateMatrix(spilledZone.right - spilledZone.left + 1, spilledZone.bottom - spilledZone.top + 1, (col, row) => this.getters.getEvaluatedCell({
15789
+ sheetId: spilledRange.sheetId,
15790
+ col: spilledZone.left + col,
15791
+ row: spilledZone.top + row,
15792
+ }));
15793
+ },
15794
+ hidden: true,
15795
+ };
15796
+ // -----------------------------------------------------------------------------
16189
15797
  // UMINUS
16190
15798
  // -----------------------------------------------------------------------------
16191
15799
  const UMINUS = {
@@ -16235,6 +15843,7 @@ var operators = /*#__PURE__*/Object.freeze({
16235
15843
  MULTIPLY: MULTIPLY,
16236
15844
  NE: NE,
16237
15845
  POW: POW,
15846
+ SPILLED_RANGE: SPILLED_RANGE,
16238
15847
  UMINUS: UMINUS,
16239
15848
  UNARY_PERCENT: UNARY_PERCENT,
16240
15849
  UPLUS: UPLUS
@@ -16493,8 +16102,9 @@ function getTranslatedCategory(key) {
16493
16102
  }
16494
16103
  function getTransformation(key) {
16495
16104
  for (const [prefix, value] of Object.entries(UNIT_PREFIXES)) {
16496
- if (prefix && !key.startsWith(prefix))
16105
+ if (prefix && !key.startsWith(prefix)) {
16497
16106
  continue;
16107
+ }
16498
16108
  const _key = key.slice(prefix.length);
16499
16109
  let conversion = UNITS[_key];
16500
16110
  if (!conversion && UNITS_ALIASES[_key]) {
@@ -17229,8 +16839,9 @@ const HYPERLINK = {
17229
16839
  compute: function (url, linkLabel) {
17230
16840
  const processedUrl = toString(url).trim();
17231
16841
  const processedLabel = toString(linkLabel) || processedUrl;
17232
- if (processedUrl === "")
16842
+ if (processedUrl === "") {
17233
16843
  return processedLabel;
16844
+ }
17234
16845
  return markdownLink(processedLabel, processedUrl);
17235
16846
  },
17236
16847
  isExported: true,
@@ -17434,7 +17045,7 @@ function rangeTokenize(formula, locale = DEFAULT_LOCALE) {
17434
17045
 
17435
17046
  const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
17436
17047
  const UNARY_OPERATORS_PREFIX = ["-", "+"];
17437
- const UNARY_OPERATORS_POSTFIX = ["%"];
17048
+ const UNARY_OPERATORS_POSTFIX = ["%", "#"];
17438
17049
  class TokenList {
17439
17050
  tokens;
17440
17051
  currentIndex = 0;
@@ -17455,6 +17066,7 @@ class TokenList {
17455
17066
  }
17456
17067
  }
17457
17068
  const OP_PRIORITY = {
17069
+ "#": 40,
17458
17070
  "%": 40,
17459
17071
  "^": 30,
17460
17072
  "*": 20,
@@ -17801,6 +17413,7 @@ const UNARY_OPERATOR_MAP = {
17801
17413
  "-": "UMINUS",
17802
17414
  "+": "UPLUS",
17803
17415
  "%": "UNARY.PERCENT",
17416
+ "#": "SPILLED.RANGE",
17804
17417
  };
17805
17418
  // this cache contains all compiled function code, grouped by "structure". For
17806
17419
  // example, "=2*sum(A1:A4)" and "=2*sum(B1:B4)" are compiled into the same
@@ -17941,7 +17554,10 @@ function compileTokensOrThrow(tokens) {
17941
17554
  }
17942
17555
  case "UNARY_OPERATION": {
17943
17556
  const fnName = UNARY_OPERATOR_MAP[ast.value];
17944
- const operand = compileAST(ast.operand, false, false).assignResultToVariable();
17557
+ const { isMeta, hasRange } = ast.value === "#"
17558
+ ? { isMeta: true, hasRange: true } // hasRange is true to avoid vectorization of SPILLED.RANGE
17559
+ : { isMeta: false, hasRange: false };
17560
+ const operand = compileAST(ast.operand, isMeta, hasRange).assignResultToVariable();
17945
17561
  code.append(operand);
17946
17562
  return code.return(`ctx['${fnName}'](${operand.returnExpression})`);
17947
17563
  }
@@ -18680,6 +18296,359 @@ class SpecificRangeTransformRegistry extends Registry {
18680
18296
  }
18681
18297
  const specificRangeTransformRegistry = new SpecificRangeTransformRegistry();
18682
18298
 
18299
+ function isSheetDependent(cmd) {
18300
+ return "sheetId" in cmd;
18301
+ }
18302
+ function isHeadersDependant(cmd) {
18303
+ return "dimension" in cmd && "sheetId" in cmd && "elements" in cmd;
18304
+ }
18305
+ function isTargetDependent(cmd) {
18306
+ return "target" in cmd && "sheetId" in cmd;
18307
+ }
18308
+ function isRangeDependant(cmd) {
18309
+ return "ranges" in cmd;
18310
+ }
18311
+ function isPositionDependent(cmd) {
18312
+ return "col" in cmd && "row" in cmd && "sheetId" in cmd;
18313
+ }
18314
+ function isZoneDependent(cmd) {
18315
+ return "sheetId" in cmd && "zone" in cmd;
18316
+ }
18317
+ const invalidateEvaluationCommands = new Set([
18318
+ "RENAME_SHEET",
18319
+ "DELETE_SHEET",
18320
+ "CREATE_SHEET",
18321
+ "DUPLICATE_SHEET",
18322
+ "ADD_COLUMNS_ROWS",
18323
+ "REMOVE_COLUMNS_ROWS",
18324
+ "UNDO",
18325
+ "REDO",
18326
+ "ADD_MERGE",
18327
+ "REMOVE_MERGE",
18328
+ "UPDATE_LOCALE",
18329
+ "ADD_PIVOT",
18330
+ "UPDATE_PIVOT",
18331
+ "INSERT_PIVOT",
18332
+ "RENAME_PIVOT",
18333
+ "REMOVE_PIVOT",
18334
+ "DUPLICATE_PIVOT",
18335
+ ]);
18336
+ const invalidateChartEvaluationCommands = new Set([
18337
+ "EVALUATE_CELLS",
18338
+ "EVALUATE_CHARTS",
18339
+ "UPDATE_CELL",
18340
+ "UNHIDE_COLUMNS_ROWS",
18341
+ "HIDE_COLUMNS_ROWS",
18342
+ "GROUP_HEADERS",
18343
+ "SET_FORMATTING",
18344
+ "CLEAR_FORMATTING",
18345
+ "UNGROUP_HEADERS",
18346
+ "FOLD_ALL_HEADER_GROUPS",
18347
+ "FOLD_HEADER_GROUP",
18348
+ "FOLD_HEADER_GROUPS_IN_ZONE",
18349
+ "UNFOLD_ALL_HEADER_GROUPS",
18350
+ "UNFOLD_HEADER_GROUP",
18351
+ "UNFOLD_HEADER_GROUPS_IN_ZONE",
18352
+ "UPDATE_TABLE",
18353
+ "UPDATE_FILTER",
18354
+ "UNDO",
18355
+ "REDO",
18356
+ ]);
18357
+ const invalidateDependenciesCommands = new Set(["MOVE_RANGES"]);
18358
+ const invalidateCFEvaluationCommands = new Set([
18359
+ "EVALUATE_CELLS",
18360
+ "ADD_CONDITIONAL_FORMAT",
18361
+ "REMOVE_CONDITIONAL_FORMAT",
18362
+ "CHANGE_CONDITIONAL_FORMAT_PRIORITY",
18363
+ ]);
18364
+ const invalidateBordersCommands = new Set([
18365
+ "AUTOFILL_CELL",
18366
+ "SET_BORDER",
18367
+ "SET_ZONE_BORDERS",
18368
+ "SET_BORDERS_ON_TARGET",
18369
+ ]);
18370
+ const invalidSubtotalFormulasCommands = new Set([
18371
+ "UNHIDE_COLUMNS_ROWS",
18372
+ "HIDE_COLUMNS_ROWS",
18373
+ "GROUP_HEADERS",
18374
+ "UNGROUP_HEADERS",
18375
+ "FOLD_ALL_HEADER_GROUPS",
18376
+ "FOLD_HEADER_GROUP",
18377
+ "FOLD_HEADER_GROUPS_IN_ZONE",
18378
+ "UNFOLD_ALL_HEADER_GROUPS",
18379
+ "UNFOLD_HEADER_GROUP",
18380
+ "UNFOLD_HEADER_GROUPS_IN_ZONE",
18381
+ "UPDATE_TABLE",
18382
+ "UPDATE_FILTER",
18383
+ ]);
18384
+ const readonlyAllowedCommands = new Set([
18385
+ "START",
18386
+ "ACTIVATE_SHEET",
18387
+ "COPY",
18388
+ "RESIZE_SHEETVIEW",
18389
+ "SET_VIEWPORT_OFFSET",
18390
+ "SET_ZOOM",
18391
+ "EVALUATE_CELLS",
18392
+ "EVALUATE_CHARTS",
18393
+ "SET_FORMULA_VISIBILITY",
18394
+ "UPDATE_FILTER",
18395
+ "UPDATE_CHART",
18396
+ "UPDATE_CAROUSEL_ACTIVE_ITEM",
18397
+ "UPDATE_PIVOT",
18398
+ ]);
18399
+ const coreTypes = new Set([
18400
+ /** CELLS */
18401
+ "UPDATE_CELL",
18402
+ "UPDATE_CELL_POSITION",
18403
+ "CLEAR_CELL",
18404
+ "CLEAR_CELLS",
18405
+ "DELETE_CONTENT",
18406
+ /** GRID SHAPE */
18407
+ "ADD_COLUMNS_ROWS",
18408
+ "REMOVE_COLUMNS_ROWS",
18409
+ "RESIZE_COLUMNS_ROWS",
18410
+ "HIDE_COLUMNS_ROWS",
18411
+ "UNHIDE_COLUMNS_ROWS",
18412
+ "SET_GRID_LINES_VISIBILITY",
18413
+ "UNFREEZE_COLUMNS",
18414
+ "UNFREEZE_ROWS",
18415
+ "FREEZE_COLUMNS",
18416
+ "FREEZE_ROWS",
18417
+ "UNFREEZE_COLUMNS_ROWS",
18418
+ /** MERGE */
18419
+ "ADD_MERGE",
18420
+ "REMOVE_MERGE",
18421
+ /** SHEETS MANIPULATION */
18422
+ "CREATE_SHEET",
18423
+ "DELETE_SHEET",
18424
+ "DUPLICATE_SHEET",
18425
+ "MOVE_SHEET",
18426
+ "RENAME_SHEET",
18427
+ "COLOR_SHEET",
18428
+ "HIDE_SHEET",
18429
+ "SHOW_SHEET",
18430
+ /** RANGES MANIPULATION */
18431
+ "MOVE_RANGES",
18432
+ /** CONDITIONAL FORMAT */
18433
+ "ADD_CONDITIONAL_FORMAT",
18434
+ "REMOVE_CONDITIONAL_FORMAT",
18435
+ "CHANGE_CONDITIONAL_FORMAT_PRIORITY",
18436
+ /** FIGURES */
18437
+ "CREATE_FIGURE",
18438
+ "DELETE_FIGURE",
18439
+ "UPDATE_FIGURE",
18440
+ "CREATE_CAROUSEL",
18441
+ "UPDATE_CAROUSEL",
18442
+ /** FORMATTING */
18443
+ "SET_FORMATTING",
18444
+ "CLEAR_FORMATTING",
18445
+ "SET_BORDER",
18446
+ "SET_ZONE_BORDERS",
18447
+ "SET_BORDERS_ON_TARGET",
18448
+ /** CHART */
18449
+ "CREATE_CHART",
18450
+ "UPDATE_CHART",
18451
+ "DELETE_CHART",
18452
+ /** FILTERS */
18453
+ "CREATE_TABLE",
18454
+ "REMOVE_TABLE",
18455
+ "UPDATE_TABLE",
18456
+ "CREATE_TABLE_STYLE",
18457
+ "REMOVE_TABLE_STYLE",
18458
+ /** IMAGE */
18459
+ "CREATE_IMAGE",
18460
+ /** HEADER GROUP */
18461
+ "GROUP_HEADERS",
18462
+ "UNGROUP_HEADERS",
18463
+ "UNFOLD_HEADER_GROUP",
18464
+ "FOLD_HEADER_GROUP",
18465
+ "FOLD_ALL_HEADER_GROUPS",
18466
+ "UNFOLD_ALL_HEADER_GROUPS",
18467
+ "UNFOLD_HEADER_GROUPS_IN_ZONE",
18468
+ "FOLD_HEADER_GROUPS_IN_ZONE",
18469
+ /** DATA VALIDATION */
18470
+ "ADD_DATA_VALIDATION_RULE",
18471
+ "REMOVE_DATA_VALIDATION_RULE",
18472
+ /** MISC */
18473
+ "UPDATE_LOCALE",
18474
+ /** PIVOT */
18475
+ "ADD_PIVOT",
18476
+ "UPDATE_PIVOT",
18477
+ "INSERT_PIVOT",
18478
+ "RENAME_PIVOT",
18479
+ "REMOVE_PIVOT",
18480
+ "DUPLICATE_PIVOT",
18481
+ ]);
18482
+ function isCoreCommand(cmd) {
18483
+ return coreTypes.has(cmd.type);
18484
+ }
18485
+ function canExecuteInReadonly(cmd) {
18486
+ return readonlyAllowedCommands.has(cmd.type);
18487
+ }
18488
+ /**
18489
+ * Holds the result of a command dispatch.
18490
+ * The command may have been successfully dispatched or cancelled
18491
+ * for one or more reasons.
18492
+ */
18493
+ class DispatchResult {
18494
+ reasons;
18495
+ constructor(results = []) {
18496
+ if (!Array.isArray(results)) {
18497
+ results = [results];
18498
+ }
18499
+ results = [...new Set(results)];
18500
+ this.reasons = results.filter((result) => result !== "Success" /* CommandResult.Success */);
18501
+ }
18502
+ /**
18503
+ * Static helper which returns a successful DispatchResult
18504
+ */
18505
+ static get Success() {
18506
+ return SUCCESS;
18507
+ }
18508
+ get isSuccessful() {
18509
+ return this.reasons.length === 0;
18510
+ }
18511
+ /**
18512
+ * Check if the dispatch has been cancelled because of
18513
+ * the given reason.
18514
+ */
18515
+ isCancelledBecause(reason) {
18516
+ return this.reasons.includes(reason);
18517
+ }
18518
+ }
18519
+ const SUCCESS = new DispatchResult();
18520
+ var CommandResult;
18521
+ (function (CommandResult) {
18522
+ CommandResult["Success"] = "Success";
18523
+ CommandResult["CancelledForUnknownReason"] = "CancelledForUnknownReason";
18524
+ CommandResult["WillRemoveExistingMerge"] = "WillRemoveExistingMerge";
18525
+ CommandResult["CannotMoveTableHeader"] = "CannotMoveTableHeader";
18526
+ CommandResult["MergeIsDestructive"] = "MergeIsDestructive";
18527
+ CommandResult["CellIsMerged"] = "CellIsMerged";
18528
+ CommandResult["InvalidTarget"] = "InvalidTarget";
18529
+ CommandResult["EmptyUndoStack"] = "EmptyUndoStack";
18530
+ CommandResult["EmptyRedoStack"] = "EmptyRedoStack";
18531
+ CommandResult["NotEnoughElements"] = "NotEnoughElements";
18532
+ CommandResult["NotEnoughSheets"] = "NotEnoughSheets";
18533
+ CommandResult["MissingSheetName"] = "MissingSheetName";
18534
+ CommandResult["UnchangedSheetName"] = "UnchangedSheetName";
18535
+ CommandResult["DuplicatedSheetName"] = "DuplicatedSheetName";
18536
+ CommandResult["DuplicatedSheetId"] = "DuplicatedSheetId";
18537
+ CommandResult["ForbiddenCharactersInSheetName"] = "ForbiddenCharactersInSheetName";
18538
+ CommandResult["WrongSheetMove"] = "WrongSheetMove";
18539
+ CommandResult["WrongSheetPosition"] = "WrongSheetPosition";
18540
+ CommandResult["InvalidAnchorZone"] = "InvalidAnchorZone";
18541
+ CommandResult["SelectionOutOfBound"] = "SelectionOutOfBound";
18542
+ CommandResult["TargetOutOfSheet"] = "TargetOutOfSheet";
18543
+ CommandResult["WrongCutSelection"] = "WrongCutSelection";
18544
+ CommandResult["WrongPasteSelection"] = "WrongPasteSelection";
18545
+ CommandResult["WrongPasteOption"] = "WrongPasteOption";
18546
+ CommandResult["WrongFigurePasteOption"] = "WrongFigurePasteOption";
18547
+ CommandResult["EmptyClipboard"] = "EmptyClipboard";
18548
+ CommandResult["EmptyRange"] = "EmptyRange";
18549
+ CommandResult["InvalidRange"] = "InvalidRange";
18550
+ CommandResult["InvalidZones"] = "InvalidZones";
18551
+ CommandResult["InvalidSheetId"] = "InvalidSheetId";
18552
+ CommandResult["InvalidCellId"] = "InvalidCellId";
18553
+ CommandResult["InvalidFigureId"] = "InvalidFigureId";
18554
+ CommandResult["InputAlreadyFocused"] = "InputAlreadyFocused";
18555
+ CommandResult["MaximumRangesReached"] = "MaximumRangesReached";
18556
+ CommandResult["MinimumRangesReached"] = "MinimumRangesReached";
18557
+ CommandResult["InvalidChartDefinition"] = "InvalidChartDefinition";
18558
+ CommandResult["InvalidDataSet"] = "InvalidDataSet";
18559
+ CommandResult["InvalidLabelRange"] = "InvalidLabelRange";
18560
+ CommandResult["InvalidScorecardKeyValue"] = "InvalidScorecardKeyValue";
18561
+ CommandResult["InvalidScorecardBaseline"] = "InvalidScorecardBaseline";
18562
+ CommandResult["InvalidGaugeDataRange"] = "InvalidGaugeDataRange";
18563
+ CommandResult["EmptyGaugeRangeMin"] = "EmptyGaugeRangeMin";
18564
+ CommandResult["GaugeRangeMinNaN"] = "GaugeRangeMinNaN";
18565
+ CommandResult["EmptyGaugeRangeMax"] = "EmptyGaugeRangeMax";
18566
+ CommandResult["GaugeRangeMaxNaN"] = "GaugeRangeMaxNaN";
18567
+ CommandResult["GaugeLowerInflectionPointNaN"] = "GaugeLowerInflectionPointNaN";
18568
+ CommandResult["GaugeUpperInflectionPointNaN"] = "GaugeUpperInflectionPointNaN";
18569
+ CommandResult["InvalidAutofillSelection"] = "InvalidAutofillSelection";
18570
+ CommandResult["MinBiggerThanMax"] = "MinBiggerThanMax";
18571
+ CommandResult["LowerBiggerThanUpper"] = "LowerBiggerThanUpper";
18572
+ CommandResult["MidBiggerThanMax"] = "MidBiggerThanMax";
18573
+ CommandResult["MinBiggerThanMid"] = "MinBiggerThanMid";
18574
+ CommandResult["FirstArgMissing"] = "FirstArgMissing";
18575
+ CommandResult["SecondArgMissing"] = "SecondArgMissing";
18576
+ CommandResult["MinNaN"] = "MinNaN";
18577
+ CommandResult["MidNaN"] = "MidNaN";
18578
+ CommandResult["MaxNaN"] = "MaxNaN";
18579
+ CommandResult["ValueUpperInflectionNaN"] = "ValueUpperInflectionNaN";
18580
+ CommandResult["ValueLowerInflectionNaN"] = "ValueLowerInflectionNaN";
18581
+ CommandResult["MinInvalidFormula"] = "MinInvalidFormula";
18582
+ CommandResult["MidInvalidFormula"] = "MidInvalidFormula";
18583
+ CommandResult["MaxInvalidFormula"] = "MaxInvalidFormula";
18584
+ CommandResult["ValueUpperInvalidFormula"] = "ValueUpperInvalidFormula";
18585
+ CommandResult["ValueLowerInvalidFormula"] = "ValueLowerInvalidFormula";
18586
+ CommandResult["InvalidSortAnchor"] = "InvalidSortAnchor";
18587
+ CommandResult["InvalidSortZone"] = "InvalidSortZone";
18588
+ CommandResult["SortZoneWithArrayFormulas"] = "SortZoneWithArrayFormulas";
18589
+ CommandResult["WaitingSessionConfirmation"] = "WaitingSessionConfirmation";
18590
+ CommandResult["MergeOverlap"] = "MergeOverlap";
18591
+ CommandResult["TooManyHiddenElements"] = "TooManyHiddenElements";
18592
+ CommandResult["Readonly"] = "Readonly";
18593
+ CommandResult["InvalidViewportSize"] = "InvalidViewportSize";
18594
+ CommandResult["InvalidScrollingDirection"] = "InvalidScrollingDirection";
18595
+ CommandResult["ViewportScrollLimitsReached"] = "ViewportScrollLimitsReached";
18596
+ CommandResult["FigureDoesNotExist"] = "FigureDoesNotExist";
18597
+ CommandResult["InvalidConditionalFormatId"] = "InvalidConditionalFormatId";
18598
+ CommandResult["InvalidCellPopover"] = "InvalidCellPopover";
18599
+ CommandResult["EmptyTarget"] = "EmptyTarget";
18600
+ CommandResult["InvalidFreezeQuantity"] = "InvalidFreezeQuantity";
18601
+ CommandResult["FrozenPaneOverlap"] = "FrozenPaneOverlap";
18602
+ CommandResult["ValuesNotChanged"] = "ValuesNotChanged";
18603
+ CommandResult["InvalidFilterZone"] = "InvalidFilterZone";
18604
+ CommandResult["TableNotFound"] = "TableNotFound";
18605
+ CommandResult["TableOverlap"] = "TableOverlap";
18606
+ CommandResult["InvalidTableConfig"] = "InvalidTableConfig";
18607
+ CommandResult["InvalidTableStyle"] = "InvalidTableStyle";
18608
+ CommandResult["FilterNotFound"] = "FilterNotFound";
18609
+ CommandResult["MergeInTable"] = "MergeInTable";
18610
+ CommandResult["NonContinuousTargets"] = "NonContinuousTargets";
18611
+ CommandResult["DuplicatedFigureId"] = "DuplicatedFigureId";
18612
+ CommandResult["InvalidSelectionStep"] = "InvalidSelectionStep";
18613
+ CommandResult["DuplicatedChartId"] = "DuplicatedChartId";
18614
+ CommandResult["ChartDoesNotExist"] = "ChartDoesNotExist";
18615
+ CommandResult["InvalidHeaderIndex"] = "InvalidHeaderIndex";
18616
+ CommandResult["InvalidQuantity"] = "InvalidQuantity";
18617
+ CommandResult["MoreThanOneColumnSelected"] = "MoreThanOneColumnSelected";
18618
+ CommandResult["EmptySplitSeparator"] = "EmptySplitSeparator";
18619
+ CommandResult["SplitWillOverwriteContent"] = "SplitWillOverwriteContent";
18620
+ CommandResult["NoSplitSeparatorInSelection"] = "NoSplitSeparatorInSelection";
18621
+ CommandResult["NoActiveSheet"] = "NoActiveSheet";
18622
+ CommandResult["InvalidLocale"] = "InvalidLocale";
18623
+ CommandResult["MoreThanOneRangeSelected"] = "MoreThanOneRangeSelected";
18624
+ CommandResult["NoColumnsProvided"] = "NoColumnsProvided";
18625
+ CommandResult["ColumnsNotIncludedInZone"] = "ColumnsNotIncludedInZone";
18626
+ CommandResult["DuplicatesColumnsSelected"] = "DuplicatesColumnsSelected";
18627
+ CommandResult["InvalidHeaderGroupStartEnd"] = "InvalidHeaderGroupStartEnd";
18628
+ CommandResult["HeaderGroupAlreadyExists"] = "HeaderGroupAlreadyExists";
18629
+ CommandResult["UnknownHeaderGroup"] = "UnknownHeaderGroup";
18630
+ CommandResult["UnknownDataValidationRule"] = "UnknownDataValidationRule";
18631
+ CommandResult["UnknownDataValidationCriterionType"] = "UnknownDataValidationCriterionType";
18632
+ CommandResult["InvalidDataValidationCriterionValue"] = "InvalidDataValidationCriterionValue";
18633
+ CommandResult["InvalidNumberOfCriterionValues"] = "InvalidNumberOfCriterionValues";
18634
+ CommandResult["InvalidCopyPasteSelection"] = "InvalidCopyPasteSelection";
18635
+ CommandResult["NoChanges"] = "NoChanges";
18636
+ CommandResult["InvalidInputId"] = "InvalidInputId";
18637
+ CommandResult["SheetIsHidden"] = "SheetIsHidden";
18638
+ CommandResult["InvalidTableResize"] = "InvalidTableResize";
18639
+ CommandResult["PivotIdNotFound"] = "PivotIdNotFound";
18640
+ CommandResult["PivotIdTaken"] = "PivotIdTaken";
18641
+ CommandResult["PivotInError"] = "PivotInError";
18642
+ CommandResult["EmptyName"] = "EmptyName";
18643
+ CommandResult["ValueCellIsInvalidFormula"] = "ValueCellIsInvalidFormula";
18644
+ CommandResult["InvalidDefinition"] = "InvalidDefinition";
18645
+ CommandResult["InvalidColor"] = "InvalidColor";
18646
+ CommandResult["InvalidPivotDataSet"] = "InvalidPivotDataSet";
18647
+ CommandResult["InvalidPivotCustomField"] = "InvalidPivotCustomField";
18648
+ CommandResult["MissingFigureArguments"] = "MissingFigureArguments";
18649
+ CommandResult["InvalidCarouselItem"] = "InvalidCarouselItem";
18650
+ })(CommandResult || (CommandResult = {}));
18651
+
18683
18652
  function transformZone(zone, executed) {
18684
18653
  if (executed.type === "REMOVE_COLUMNS_ROWS") {
18685
18654
  return reduceZoneOnDeletion(zone, executed.dimension === "COL" ? "left" : "top", executed.elements);
@@ -18832,16 +18801,21 @@ function rgbaToHex(rgba) {
18832
18801
  let g = rgba.g.toString(16);
18833
18802
  let b = rgba.b.toString(16);
18834
18803
  let a = Math.round(rgba.a * 255).toString(16);
18835
- if (r.length === 1)
18804
+ if (r.length === 1) {
18836
18805
  r = "0" + r;
18837
- if (g.length === 1)
18806
+ }
18807
+ if (g.length === 1) {
18838
18808
  g = "0" + g;
18839
- if (b.length === 1)
18809
+ }
18810
+ if (b.length === 1) {
18840
18811
  b = "0" + b;
18841
- if (a.length === 1)
18812
+ }
18813
+ if (a.length === 1) {
18842
18814
  a = "0" + a;
18843
- if (a === "ff")
18815
+ }
18816
+ if (a === "ff") {
18844
18817
  a = "";
18818
+ }
18845
18819
  return ("#" + r + g + b + a).toUpperCase();
18846
18820
  }
18847
18821
  /**
@@ -18941,21 +18915,26 @@ function rgbaToHSLA(rgba) {
18941
18915
  let l = 0;
18942
18916
  // Calculate hue
18943
18917
  // No difference
18944
- if (delta === 0)
18918
+ if (delta === 0) {
18945
18919
  h = 0;
18920
+ }
18946
18921
  // Red is max
18947
- else if (cMax === r)
18922
+ else if (cMax === r) {
18948
18923
  h = ((g - b) / delta) % 6;
18924
+ }
18949
18925
  // Green is max
18950
- else if (cMax === g)
18926
+ else if (cMax === g) {
18951
18927
  h = (b - r) / delta + 2;
18928
+ }
18952
18929
  // Blue is max
18953
- else
18930
+ else {
18954
18931
  h = (r - g) / delta + 4;
18932
+ }
18955
18933
  h = Math.round(h * 60);
18956
18934
  // Make negative hues positive behind 360°
18957
- if (h < 0)
18935
+ if (h < 0) {
18958
18936
  h += 360;
18937
+ }
18959
18938
  l = (cMax + cMin) / 2;
18960
18939
  // Calculate saturation
18961
18940
  s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
@@ -19286,12 +19265,6 @@ function colorCell(value, minValue, minColor, colorDiffUnit) {
19286
19265
  return (r << 16) | (g << 8) | b;
19287
19266
  }
19288
19267
 
19289
- ({
19290
- light: _t("Light"),
19291
- medium: _t("Medium"),
19292
- dark: _t("Dark"),
19293
- custom: _t("Custom"),
19294
- });
19295
19268
  const DEFAULT_TABLE_CONFIG = {
19296
19269
  hasFilters: false,
19297
19270
  totalRow: false,
@@ -19303,6 +19276,11 @@ const DEFAULT_TABLE_CONFIG = {
19303
19276
  automaticAutofill: true,
19304
19277
  styleId: "TableStyleMedium2",
19305
19278
  };
19279
+ const TABLE_STYLE_CATEGORIES = {
19280
+ light: _t("Light"),
19281
+ medium: _t("Medium"),
19282
+ dark: _t("Dark"),
19283
+ };
19306
19284
  function generateTableColorSet(name, highlightColor) {
19307
19285
  return {
19308
19286
  coloredText: darkenColor(highlightColor, 0.3),
@@ -19314,7 +19292,7 @@ function generateTableColorSet(name, highlightColor) {
19314
19292
  name,
19315
19293
  };
19316
19294
  }
19317
- const COLOR_SETS = {
19295
+ const TABLE_COLOR_SETS = {
19318
19296
  black: {
19319
19297
  name: _t("Black"),
19320
19298
  coloredText: "#000000",
@@ -19324,9 +19302,9 @@ const COLOR_SETS = {
19324
19302
  mediumBorder: "#000000",
19325
19303
  highlight: "#000000",
19326
19304
  },
19327
- lightBlue: generateTableColorSet(_t("Light blue"), "#346B90"),
19305
+ lightBlue: generateTableColorSet(_t("Blue"), "#346B90"),
19328
19306
  red: generateTableColorSet(_t("Red"), "#C53628"),
19329
- lightGreen: generateTableColorSet(_t("Light green"), "#748747"),
19307
+ lightGreen: generateTableColorSet(_t("Green"), "#748747"),
19330
19308
  purple: generateTableColorSet(_t("Purple"), "#6C4E65"),
19331
19309
  gray: {
19332
19310
  name: _t("Gray"),
@@ -19339,11 +19317,11 @@ const COLOR_SETS = {
19339
19317
  },
19340
19318
  orange: generateTableColorSet(_t("Orange"), "#C37034"),
19341
19319
  };
19342
- const DARK_COLOR_SETS = {
19343
- black: COLOR_SETS.black,
19344
- orangeBlue: { ...COLOR_SETS.lightBlue, highlight: COLOR_SETS.orange.highlight },
19345
- purpleGreen: { ...COLOR_SETS.lightGreen, highlight: COLOR_SETS.purple.highlight },
19346
- redBlue: { ...COLOR_SETS.lightBlue, highlight: COLOR_SETS.red.highlight },
19320
+ const DARK_TABLE_COLOR_SETS = {
19321
+ black: TABLE_COLOR_SETS.black,
19322
+ orangeBlue: { ...TABLE_COLOR_SETS.lightBlue, highlight: TABLE_COLOR_SETS.orange.highlight },
19323
+ purpleGreen: { ...TABLE_COLOR_SETS.lightGreen, highlight: TABLE_COLOR_SETS.purple.highlight },
19324
+ redBlue: { ...TABLE_COLOR_SETS.lightBlue, highlight: TABLE_COLOR_SETS.red.highlight },
19347
19325
  };
19348
19326
  const lightColoredText = (colorSet) => ({
19349
19327
  category: "light",
@@ -19356,9 +19334,17 @@ const lightColoredText = (colorSet) => ({
19356
19334
  bottom: { color: colorSet.highlight, style: "thin" },
19357
19335
  },
19358
19336
  },
19359
- headerRow: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
19360
- totalRow: { border: { top: { color: colorSet.highlight, style: "thin" } } },
19337
+ headerRow: {
19338
+ border: { bottom: { color: colorSet.highlight, style: "thin" } },
19339
+ style: { bold: true },
19340
+ },
19341
+ totalRow: {
19342
+ border: { top: { color: colorSet.highlight, style: "thin" } },
19343
+ style: { bold: true },
19344
+ },
19361
19345
  firstRowStripe: { style: { fillColor: colorSet.light } },
19346
+ firstColumn: { style: { bold: true } },
19347
+ lastColumn: { style: { bold: true } },
19362
19348
  });
19363
19349
  const lightWithHeader = (colorSet) => ({
19364
19350
  category: "light",
@@ -19373,12 +19359,17 @@ const lightWithHeader = (colorSet) => ({
19373
19359
  },
19374
19360
  },
19375
19361
  headerRow: {
19376
- style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
19362
+ style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true },
19377
19363
  border: { bottom: { color: colorSet.highlight, style: "thin" } },
19378
19364
  },
19379
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
19365
+ totalRow: {
19366
+ border: { top: { color: colorSet.highlight, style: "medium" } }, // @compatibility: should be double line
19367
+ style: { bold: true },
19368
+ },
19380
19369
  firstRowStripe: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
19381
19370
  secondRowStripe: { border: { bottom: { color: colorSet.highlight, style: "thin" } } },
19371
+ firstColumn: { style: { bold: true } },
19372
+ lastColumn: { style: { bold: true } },
19382
19373
  });
19383
19374
  const lightAllBorders = (colorSet) => ({
19384
19375
  category: "light",
@@ -19394,10 +19385,18 @@ const lightAllBorders = (colorSet) => ({
19394
19385
  vertical: { color: colorSet.highlight, style: "thin" },
19395
19386
  },
19396
19387
  },
19397
- headerRow: { border: { bottom: { color: colorSet.highlight, style: "medium" } } },
19398
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
19388
+ headerRow: {
19389
+ border: { bottom: { color: colorSet.highlight, style: "medium" } },
19390
+ style: { bold: true },
19391
+ },
19392
+ totalRow: {
19393
+ border: { top: { color: colorSet.highlight, style: "medium" } }, // @compatibility: should be double line
19394
+ style: { bold: true },
19395
+ },
19399
19396
  firstRowStripe: { style: { fillColor: colorSet.light } },
19400
19397
  firstColumnStripe: { style: { fillColor: colorSet.light } },
19398
+ firstColumn: { style: { bold: true } },
19399
+ lastColumn: { style: { bold: true } },
19401
19400
  });
19402
19401
  const mediumBandedBorders = (colorSet) => ({
19403
19402
  category: "medium",
@@ -19412,12 +19411,15 @@ const mediumBandedBorders = (colorSet) => ({
19412
19411
  horizontal: { color: colorSet.mediumBorder, style: "thin" },
19413
19412
  },
19414
19413
  },
19415
- headerRow: {
19416
- style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
19414
+ headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19415
+ totalRow: {
19416
+ border: { top: { color: colorSet.highlight, style: "medium" } }, // @compatibility: should be double line
19417
+ style: { bold: true },
19417
19418
  },
19418
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
19419
19419
  firstRowStripe: { style: { fillColor: colorSet.light } },
19420
19420
  firstColumnStripe: { style: { fillColor: colorSet.light } },
19421
+ firstColumn: { style: { bold: true } },
19422
+ lastColumn: { style: { bold: true } },
19421
19423
  });
19422
19424
  const mediumWhiteBorders = (colorSet) => ({
19423
19425
  category: "medium",
@@ -19432,14 +19434,14 @@ const mediumWhiteBorders = (colorSet) => ({
19432
19434
  },
19433
19435
  headerRow: {
19434
19436
  border: { bottom: { color: "#FFFFFF", style: "thick" } },
19435
- style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
19437
+ style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true },
19436
19438
  },
19437
19439
  totalRow: {
19438
19440
  border: { top: { color: "#FFFFFF", style: "thick" } },
19439
- style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
19441
+ style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true },
19440
19442
  },
19441
- firstColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19442
- lastColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19443
+ firstColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19444
+ lastColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19443
19445
  firstRowStripe: { style: { fillColor: colorSet.medium } },
19444
19446
  firstColumnStripe: { style: { fillColor: colorSet.medium } },
19445
19447
  });
@@ -19453,15 +19455,18 @@ const mediumMinimalBorders = (colorSet) => ({
19453
19455
  bottom: { color: "#000000", style: "medium" },
19454
19456
  },
19455
19457
  },
19456
- totalRow: { border: { top: { color: "#000000", style: "medium" } } }, // @compatibility: should be double line
19458
+ totalRow: {
19459
+ border: { top: { color: "#000000", style: "medium" } }, // @compatibility: should be double line
19460
+ style: { bold: true },
19461
+ },
19457
19462
  headerRow: {
19458
- style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" },
19463
+ style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true },
19459
19464
  border: { bottom: { color: "#000000", style: "medium" } },
19460
19465
  },
19461
- firstColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19462
- lastColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19463
- firstRowStripe: { style: { fillColor: COLOR_SETS.black.light } },
19464
- firstColumnStripe: { style: { fillColor: COLOR_SETS.black.light } },
19466
+ firstColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19467
+ lastColumn: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19468
+ firstRowStripe: { style: { fillColor: TABLE_COLOR_SETS.black.light } },
19469
+ firstColumnStripe: { style: { fillColor: TABLE_COLOR_SETS.black.light } },
19465
19470
  });
19466
19471
  const mediumAllBorders = (colorSet) => ({
19467
19472
  category: "medium",
@@ -19478,9 +19483,15 @@ const mediumAllBorders = (colorSet) => ({
19478
19483
  },
19479
19484
  style: { fillColor: colorSet.light },
19480
19485
  },
19481
- totalRow: { border: { top: { color: colorSet.highlight, style: "medium" } } }, // @compatibility: should be double line
19486
+ totalRow: {
19487
+ border: { top: { color: colorSet.highlight, style: "medium" } }, // @compatibility: should be double line
19488
+ style: { bold: true },
19489
+ },
19482
19490
  firstRowStripe: { style: { fillColor: colorSet.medium } },
19483
19491
  firstColumnStripe: { style: { fillColor: colorSet.medium } },
19492
+ firstColumn: { style: { bold: true } },
19493
+ lastColumn: { style: { bold: true } },
19494
+ headerRow: { style: { bold: true } },
19484
19495
  });
19485
19496
  const dark = (colorSet) => ({
19486
19497
  category: "dark",
@@ -19488,19 +19499,19 @@ const dark = (colorSet) => ({
19488
19499
  primaryColor: colorSet.highlight,
19489
19500
  wholeTable: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19490
19501
  totalRow: {
19491
- style: { fillColor: colorSet.dark, textColor: "#FFFFFF" },
19502
+ style: { fillColor: colorSet.dark, textColor: "#FFFFFF", bold: true },
19492
19503
  border: { top: { color: "#FFFFFF", style: "thick" } },
19493
19504
  },
19494
19505
  headerRow: {
19495
- style: { fillColor: "#000000" },
19506
+ style: { fillColor: "#000000", bold: true },
19496
19507
  border: { bottom: { color: "#FFFFFF", style: "thick" } },
19497
19508
  },
19498
19509
  firstColumn: {
19499
- style: { fillColor: colorSet.dark },
19510
+ style: { fillColor: colorSet.dark, bold: true },
19500
19511
  border: { right: { color: "#FFFFFF", style: "thick" } },
19501
19512
  },
19502
19513
  lastColumn: {
19503
- style: { fillColor: colorSet.dark },
19514
+ style: { fillColor: colorSet.dark, bold: true },
19504
19515
  border: { left: { color: "#FFFFFF", style: "thick" } },
19505
19516
  },
19506
19517
  firstRowStripe: { style: { fillColor: colorSet.dark } },
@@ -19511,14 +19522,19 @@ const darkNoBorders = (colorSet) => ({
19511
19522
  templateName: "darkNoBorders",
19512
19523
  primaryColor: colorSet.highlight,
19513
19524
  wholeTable: { style: { fillColor: colorSet.light } },
19514
- totalRow: { border: { top: { color: "#000000", style: "medium" } } }, // @compatibility: should be double line
19515
- headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
19525
+ totalRow: {
19526
+ border: { top: { color: "#000000", style: "medium" } }, // @compatibility: should be double line
19527
+ style: { bold: true },
19528
+ },
19529
+ headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
19516
19530
  firstRowStripe: { style: { fillColor: colorSet.medium } },
19517
19531
  firstColumnStripe: { style: { fillColor: colorSet.medium } },
19532
+ firstColumn: { style: { bold: true } },
19533
+ lastColumn: { style: { bold: true } },
19518
19534
  });
19519
- const darkTemplateInBlack = dark(COLOR_SETS.black);
19535
+ const darkTemplateInBlack = dark(TABLE_COLOR_SETS.black);
19520
19536
  darkTemplateInBlack.wholeTable.style.fillColor = "#737373";
19521
- const mediumMinimalBordersInBlack = mediumMinimalBorders(COLOR_SETS.black);
19537
+ const mediumMinimalBordersInBlack = mediumMinimalBorders(TABLE_COLOR_SETS.black);
19522
19538
  mediumMinimalBordersInBlack.wholeTable.border = {
19523
19539
  ...mediumMinimalBordersInBlack.wholeTable.border,
19524
19540
  left: { color: "#000000", style: "thin" },
@@ -19530,67 +19546,67 @@ function buildPreset(name, template, colorSet) {
19530
19546
  return { ...template(colorSet), displayName: `${colorSet.name}, ${name}` };
19531
19547
  }
19532
19548
  const TABLE_PRESETS = {
19533
- None: { category: "light", templateName: "none", primaryColor: "", displayName: "none" },
19534
- TableStyleLight1: buildPreset("TableStyleLight1", lightColoredText, COLOR_SETS.black),
19535
- TableStyleLight2: buildPreset("TableStyleLight2", lightColoredText, COLOR_SETS.lightBlue),
19536
- TableStyleLight3: buildPreset("TableStyleLight3", lightColoredText, COLOR_SETS.red),
19537
- TableStyleLight4: buildPreset("TableStyleLight4", lightColoredText, COLOR_SETS.lightGreen),
19538
- TableStyleLight5: buildPreset("TableStyleLight5", lightColoredText, COLOR_SETS.purple),
19539
- TableStyleLight6: buildPreset("TableStyleLight6", lightColoredText, COLOR_SETS.gray),
19540
- TableStyleLight7: buildPreset("TableStyleLight7", lightColoredText, COLOR_SETS.orange),
19541
- TableStyleLight8: buildPreset("TableStyleLight8", lightWithHeader, COLOR_SETS.black),
19542
- TableStyleLight9: buildPreset("TableStyleLight9", lightWithHeader, COLOR_SETS.lightBlue),
19543
- TableStyleLight10: buildPreset("TableStyleLight10", lightWithHeader, COLOR_SETS.red),
19544
- TableStyleLight11: buildPreset("TableStyleLight11", lightWithHeader, COLOR_SETS.lightGreen),
19545
- TableStyleLight12: buildPreset("TableStyleLight12", lightWithHeader, COLOR_SETS.purple),
19546
- TableStyleLight13: buildPreset("TableStyleLight13", lightWithHeader, COLOR_SETS.gray),
19547
- TableStyleLight14: buildPreset("TableStyleLight14", lightWithHeader, COLOR_SETS.orange),
19548
- TableStyleLight15: buildPreset("TableStyleLight15", lightAllBorders, COLOR_SETS.black),
19549
- TableStyleLight16: buildPreset("TableStyleLight16", lightAllBorders, COLOR_SETS.lightBlue),
19550
- TableStyleLight17: buildPreset("TableStyleLight17", lightAllBorders, COLOR_SETS.red),
19551
- TableStyleLight18: buildPreset("TableStyleLight18", lightAllBorders, COLOR_SETS.lightGreen),
19552
- TableStyleLight19: buildPreset("TableStyleLight19", lightAllBorders, COLOR_SETS.purple),
19553
- TableStyleLight20: buildPreset("TableStyleLight20", lightAllBorders, COLOR_SETS.gray),
19554
- TableStyleLight21: buildPreset("TableStyleLight21", lightAllBorders, COLOR_SETS.orange),
19555
- TableStyleMedium1: buildPreset("TableStyleMedium1", mediumBandedBorders, COLOR_SETS.black),
19556
- TableStyleMedium2: buildPreset("TableStyleMedium2", mediumBandedBorders, COLOR_SETS.lightBlue),
19557
- TableStyleMedium3: buildPreset("TableStyleMedium3", mediumBandedBorders, COLOR_SETS.red),
19558
- TableStyleMedium4: buildPreset("TableStyleMedium4", mediumBandedBorders, COLOR_SETS.lightGreen),
19559
- TableStyleMedium5: buildPreset("TableStyleMedium5", mediumBandedBorders, COLOR_SETS.purple),
19560
- TableStyleMedium6: buildPreset("TableStyleMedium6", mediumBandedBorders, COLOR_SETS.gray),
19561
- TableStyleMedium7: buildPreset("TableStyleMedium7", mediumBandedBorders, COLOR_SETS.orange),
19562
- TableStyleMedium8: buildPreset("TableStyleMedium8", mediumWhiteBorders, COLOR_SETS.black),
19563
- TableStyleMedium9: buildPreset("TableStyleMedium9", mediumWhiteBorders, COLOR_SETS.lightBlue),
19564
- TableStyleMedium10: buildPreset("TableStyleMedium10", mediumWhiteBorders, COLOR_SETS.red),
19565
- TableStyleMedium11: buildPreset("TableStyleMedium11", mediumWhiteBorders, COLOR_SETS.lightGreen),
19566
- TableStyleMedium12: buildPreset("TableStyleMedium12", mediumWhiteBorders, COLOR_SETS.purple),
19567
- TableStyleMedium13: buildPreset("TableStyleMedium13", mediumWhiteBorders, COLOR_SETS.gray),
19568
- TableStyleMedium14: buildPreset("TableStyleMedium14", mediumWhiteBorders, COLOR_SETS.orange),
19549
+ None: { category: "light", templateName: "none", primaryColor: "", displayName: _t("None") },
19550
+ TableStyleLight1: buildPreset("TableStyleLight1", lightColoredText, TABLE_COLOR_SETS.black),
19551
+ TableStyleLight2: buildPreset("TableStyleLight2", lightColoredText, TABLE_COLOR_SETS.lightBlue),
19552
+ TableStyleLight3: buildPreset("TableStyleLight3", lightColoredText, TABLE_COLOR_SETS.red),
19553
+ TableStyleLight4: buildPreset("TableStyleLight4", lightColoredText, TABLE_COLOR_SETS.lightGreen),
19554
+ TableStyleLight5: buildPreset("TableStyleLight5", lightColoredText, TABLE_COLOR_SETS.purple),
19555
+ TableStyleLight6: buildPreset("TableStyleLight6", lightColoredText, TABLE_COLOR_SETS.gray),
19556
+ TableStyleLight7: buildPreset("TableStyleLight7", lightColoredText, TABLE_COLOR_SETS.orange),
19557
+ TableStyleLight8: buildPreset("TableStyleLight8", lightWithHeader, TABLE_COLOR_SETS.black),
19558
+ TableStyleLight9: buildPreset("TableStyleLight9", lightWithHeader, TABLE_COLOR_SETS.lightBlue),
19559
+ TableStyleLight10: buildPreset("TableStyleLight10", lightWithHeader, TABLE_COLOR_SETS.red),
19560
+ TableStyleLight11: buildPreset("TableStyleLight11", lightWithHeader, TABLE_COLOR_SETS.lightGreen),
19561
+ TableStyleLight12: buildPreset("TableStyleLight12", lightWithHeader, TABLE_COLOR_SETS.purple),
19562
+ TableStyleLight13: buildPreset("TableStyleLight13", lightWithHeader, TABLE_COLOR_SETS.gray),
19563
+ TableStyleLight14: buildPreset("TableStyleLight14", lightWithHeader, TABLE_COLOR_SETS.orange),
19564
+ TableStyleLight15: buildPreset("TableStyleLight15", lightAllBorders, TABLE_COLOR_SETS.black),
19565
+ TableStyleLight16: buildPreset("TableStyleLight16", lightAllBorders, TABLE_COLOR_SETS.lightBlue),
19566
+ TableStyleLight17: buildPreset("TableStyleLight17", lightAllBorders, TABLE_COLOR_SETS.red),
19567
+ TableStyleLight18: buildPreset("TableStyleLight18", lightAllBorders, TABLE_COLOR_SETS.lightGreen),
19568
+ TableStyleLight19: buildPreset("TableStyleLight19", lightAllBorders, TABLE_COLOR_SETS.purple),
19569
+ TableStyleLight20: buildPreset("TableStyleLight20", lightAllBorders, TABLE_COLOR_SETS.gray),
19570
+ TableStyleLight21: buildPreset("TableStyleLight21", lightAllBorders, TABLE_COLOR_SETS.orange),
19571
+ TableStyleMedium1: buildPreset("TableStyleMedium1", mediumBandedBorders, TABLE_COLOR_SETS.black),
19572
+ TableStyleMedium2: buildPreset("TableStyleMedium2", mediumBandedBorders, TABLE_COLOR_SETS.lightBlue),
19573
+ TableStyleMedium3: buildPreset("TableStyleMedium3", mediumBandedBorders, TABLE_COLOR_SETS.red),
19574
+ TableStyleMedium4: buildPreset("TableStyleMedium4", mediumBandedBorders, TABLE_COLOR_SETS.lightGreen),
19575
+ TableStyleMedium5: buildPreset("TableStyleMedium5", mediumBandedBorders, TABLE_COLOR_SETS.purple),
19576
+ TableStyleMedium6: buildPreset("TableStyleMedium6", mediumBandedBorders, TABLE_COLOR_SETS.gray),
19577
+ TableStyleMedium7: buildPreset("TableStyleMedium7", mediumBandedBorders, TABLE_COLOR_SETS.orange),
19578
+ TableStyleMedium8: buildPreset("TableStyleMedium8", mediumWhiteBorders, TABLE_COLOR_SETS.black),
19579
+ TableStyleMedium9: buildPreset("TableStyleMedium9", mediumWhiteBorders, TABLE_COLOR_SETS.lightBlue),
19580
+ TableStyleMedium10: buildPreset("TableStyleMedium10", mediumWhiteBorders, TABLE_COLOR_SETS.red),
19581
+ TableStyleMedium11: buildPreset("TableStyleMedium11", mediumWhiteBorders, TABLE_COLOR_SETS.lightGreen),
19582
+ TableStyleMedium12: buildPreset("TableStyleMedium12", mediumWhiteBorders, TABLE_COLOR_SETS.purple),
19583
+ TableStyleMedium13: buildPreset("TableStyleMedium13", mediumWhiteBorders, TABLE_COLOR_SETS.gray),
19584
+ TableStyleMedium14: buildPreset("TableStyleMedium14", mediumWhiteBorders, TABLE_COLOR_SETS.orange),
19569
19585
  TableStyleMedium15: { ...mediumMinimalBordersInBlack, displayName: "Black, TableStyleMedium15" },
19570
- TableStyleMedium16: buildPreset("TableStyleMedium16", mediumMinimalBorders, COLOR_SETS.lightBlue),
19571
- TableStyleMedium17: buildPreset("TableStyleMedium17", mediumMinimalBorders, COLOR_SETS.red),
19572
- TableStyleMedium18: buildPreset("TableStyleMedium18", mediumMinimalBorders, COLOR_SETS.lightGreen),
19573
- TableStyleMedium19: buildPreset("TableStyleMedium19", mediumMinimalBorders, COLOR_SETS.purple),
19574
- TableStyleMedium20: buildPreset("TableStyleMedium20", mediumMinimalBorders, COLOR_SETS.gray),
19575
- TableStyleMedium21: buildPreset("TableStyleMedium21", mediumMinimalBorders, COLOR_SETS.orange),
19576
- TableStyleMedium22: buildPreset("TableStyleMedium22", mediumAllBorders, COLOR_SETS.black),
19577
- TableStyleMedium23: buildPreset("TableStyleMedium23", mediumAllBorders, COLOR_SETS.lightBlue),
19578
- TableStyleMedium24: buildPreset("TableStyleMedium24", mediumAllBorders, COLOR_SETS.red),
19579
- TableStyleMedium25: buildPreset("TableStyleMedium25", mediumAllBorders, COLOR_SETS.lightGreen),
19580
- TableStyleMedium26: buildPreset("TableStyleMedium26", mediumAllBorders, COLOR_SETS.purple),
19581
- TableStyleMedium27: buildPreset("TableStyleMedium27", mediumAllBorders, COLOR_SETS.gray),
19582
- TableStyleMedium28: buildPreset("TableStyleMedium28", mediumAllBorders, COLOR_SETS.orange),
19586
+ TableStyleMedium16: buildPreset("TableStyleMedium16", mediumMinimalBorders, TABLE_COLOR_SETS.lightBlue),
19587
+ TableStyleMedium17: buildPreset("TableStyleMedium17", mediumMinimalBorders, TABLE_COLOR_SETS.red),
19588
+ TableStyleMedium18: buildPreset("TableStyleMedium18", mediumMinimalBorders, TABLE_COLOR_SETS.lightGreen),
19589
+ TableStyleMedium19: buildPreset("TableStyleMedium19", mediumMinimalBorders, TABLE_COLOR_SETS.purple),
19590
+ TableStyleMedium20: buildPreset("TableStyleMedium20", mediumMinimalBorders, TABLE_COLOR_SETS.gray),
19591
+ TableStyleMedium21: buildPreset("TableStyleMedium21", mediumMinimalBorders, TABLE_COLOR_SETS.orange),
19592
+ TableStyleMedium22: buildPreset("TableStyleMedium22", mediumAllBorders, TABLE_COLOR_SETS.black),
19593
+ TableStyleMedium23: buildPreset("TableStyleMedium23", mediumAllBorders, TABLE_COLOR_SETS.lightBlue),
19594
+ TableStyleMedium24: buildPreset("TableStyleMedium24", mediumAllBorders, TABLE_COLOR_SETS.red),
19595
+ TableStyleMedium25: buildPreset("TableStyleMedium25", mediumAllBorders, TABLE_COLOR_SETS.lightGreen),
19596
+ TableStyleMedium26: buildPreset("TableStyleMedium26", mediumAllBorders, TABLE_COLOR_SETS.purple),
19597
+ TableStyleMedium27: buildPreset("TableStyleMedium27", mediumAllBorders, TABLE_COLOR_SETS.gray),
19598
+ TableStyleMedium28: buildPreset("TableStyleMedium28", mediumAllBorders, TABLE_COLOR_SETS.orange),
19583
19599
  TableStyleDark1: { ...darkTemplateInBlack, displayName: "Black, TableStyleDark1" },
19584
- TableStyleDark2: buildPreset("TableStyleDark2", dark, COLOR_SETS.lightBlue),
19585
- TableStyleDark3: buildPreset("TableStyleDark3", dark, COLOR_SETS.red),
19586
- TableStyleDark4: buildPreset("TableStyleDark4", dark, COLOR_SETS.lightGreen),
19587
- TableStyleDark5: buildPreset("TableStyleDark5", dark, COLOR_SETS.purple),
19588
- TableStyleDark6: buildPreset("TableStyleDark6", dark, COLOR_SETS.gray),
19589
- TableStyleDark7: buildPreset("TableStyleDark7", dark, COLOR_SETS.orange),
19590
- TableStyleDark8: buildPreset("TableStyleDark8", darkNoBorders, DARK_COLOR_SETS.black),
19591
- TableStyleDark9: buildPreset("TableStyleDark9", darkNoBorders, DARK_COLOR_SETS.redBlue),
19592
- TableStyleDark10: buildPreset("TableStyleDark10", darkNoBorders, DARK_COLOR_SETS.purpleGreen),
19593
- TableStyleDark11: buildPreset("TableStyleDark11", darkNoBorders, DARK_COLOR_SETS.orangeBlue),
19600
+ TableStyleDark2: buildPreset("TableStyleDark2", dark, TABLE_COLOR_SETS.lightBlue),
19601
+ TableStyleDark3: buildPreset("TableStyleDark3", dark, TABLE_COLOR_SETS.red),
19602
+ TableStyleDark4: buildPreset("TableStyleDark4", dark, TABLE_COLOR_SETS.lightGreen),
19603
+ TableStyleDark5: buildPreset("TableStyleDark5", dark, TABLE_COLOR_SETS.purple),
19604
+ TableStyleDark6: buildPreset("TableStyleDark6", dark, TABLE_COLOR_SETS.gray),
19605
+ TableStyleDark7: buildPreset("TableStyleDark7", dark, TABLE_COLOR_SETS.orange),
19606
+ TableStyleDark8: buildPreset("TableStyleDark8", darkNoBorders, DARK_TABLE_COLOR_SETS.black),
19607
+ TableStyleDark9: buildPreset("TableStyleDark9", darkNoBorders, DARK_TABLE_COLOR_SETS.redBlue),
19608
+ TableStyleDark10: buildPreset("TableStyleDark10", darkNoBorders, DARK_TABLE_COLOR_SETS.purpleGreen),
19609
+ TableStyleDark11: buildPreset("TableStyleDark11", darkNoBorders, DARK_TABLE_COLOR_SETS.orangeBlue),
19594
19610
  };
19595
19611
  const TABLE_STYLES_TEMPLATES = {
19596
19612
  none: () => ({ category: "none", templateName: "none", primaryColor: "", name: "none" }),
@@ -20650,8 +20666,9 @@ class Session extends EventBus {
20650
20666
  * It will be transmitted to all other connected clients.
20651
20667
  */
20652
20668
  save(rootCommand, commands, changes) {
20653
- if (!commands.length || !changes.length || !this.canApplyOptimisticUpdate())
20669
+ if (!commands.length || !changes.length || !this.canApplyOptimisticUpdate()) {
20654
20670
  return;
20671
+ }
20655
20672
  const revision = new Revision(this.uuidGenerator.uuidv4(), this.clientId, commands, rootCommand, changes, Date.now());
20656
20673
  this.revisions.append(revision.id, revision);
20657
20674
  // REQUEST_REDO just repeats the last operation, the
@@ -20809,8 +20826,9 @@ class Session extends EventBus {
20809
20826
  * session.
20810
20827
  */
20811
20828
  onMessageReceived(message) {
20812
- if (this.isAlreadyProcessed(message))
20829
+ if (this.isAlreadyProcessed(message)) {
20813
20830
  return;
20831
+ }
20814
20832
  if (this.isWrongServerRevisionId(message)) {
20815
20833
  this.trigger("unexpected-revision-id");
20816
20834
  return;
@@ -20912,8 +20930,9 @@ class Session extends EventBus {
20912
20930
  */
20913
20931
  sendPendingMessage() {
20914
20932
  let message = this.pendingMessages[0];
20915
- if (!message)
20933
+ if (!message) {
20916
20934
  return;
20935
+ }
20917
20936
  if (message.type === "REMOTE_REVISION") {
20918
20937
  let revision = this.revisions.get(message.nextRevisionId);
20919
20938
  if (revision.commands.length === 0) {
@@ -21172,10 +21191,12 @@ class Branch {
21172
21191
  */
21173
21192
  getFirstOperationAmong(op1, op2) {
21174
21193
  for (const operation of this.operations) {
21175
- if (operation.id === op1)
21194
+ if (operation.id === op1) {
21176
21195
  return op1;
21177
- if (operation.id === op2)
21196
+ }
21197
+ if (operation.id === op2) {
21178
21198
  return op2;
21199
+ }
21179
21200
  }
21180
21201
  throw new Error(`Operation ${op1} and ${op2} not found`);
21181
21202
  }
@@ -21497,8 +21518,9 @@ class Tree {
21497
21518
  */
21498
21519
  redo(branch) {
21499
21520
  const removedBranch = this.nextBranch(branch);
21500
- if (!removedBranch)
21521
+ if (!removedBranch) {
21501
21522
  return;
21523
+ }
21502
21524
  const nextBranch = this.nextBranch(removedBranch);
21503
21525
  this.removeBranchFromTree(removedBranch);
21504
21526
  const undoBranchingId = this.branchingOperationIds.get(removedBranch);
@@ -21552,8 +21574,9 @@ class Tree {
21552
21574
  */
21553
21575
  rebaseUp(branch) {
21554
21576
  const { previousBranch, branchingOperation } = this.findPreviousBranchingOperation(branch);
21555
- if (!previousBranch || !branchingOperation)
21577
+ if (!previousBranch || !branchingOperation) {
21556
21578
  return;
21579
+ }
21557
21580
  const rebaseTransformation = this.buildTransformation.without(branchingOperation.data);
21558
21581
  const newBranch = previousBranch.fork(branchingOperation.id);
21559
21582
  this.branchingOperationIds.set(newBranch, this.branchingOperationIds.get(branch));
@@ -21640,8 +21663,9 @@ class Tree {
21640
21663
  */
21641
21664
  insertPrevious(branch, newOperation, insertAfter) {
21642
21665
  const { previousBranch, branchingOperation } = this.findPreviousBranchingOperation(branch);
21643
- if (!previousBranch || !branchingOperation)
21666
+ if (!previousBranch || !branchingOperation) {
21644
21667
  return;
21668
+ }
21645
21669
  const transformation = this.buildTransformation.with(branchingOperation.data);
21646
21670
  const branchTail = branch.fork(insertAfter);
21647
21671
  branchTail.transform(transformation);
@@ -21652,11 +21676,13 @@ class Tree {
21652
21676
  }
21653
21677
  findPreviousBranchingOperation(branch) {
21654
21678
  const previousBranch = this.previousBranch(branch);
21655
- if (!previousBranch)
21679
+ if (!previousBranch) {
21656
21680
  return { previousBranch: undefined, branchingOperation: undefined };
21681
+ }
21657
21682
  const previousBranchingId = this.branchingOperationIds.get(previousBranch);
21658
- if (!previousBranchingId)
21683
+ if (!previousBranchingId) {
21659
21684
  return { previousBranch: undefined, branchingOperation: undefined };
21685
+ }
21660
21686
  return {
21661
21687
  previousBranch,
21662
21688
  branchingOperation: previousBranch.getOperation(previousBranchingId),
@@ -22747,8 +22773,9 @@ function convertColor(xlsxColor) {
22747
22773
  * representation #RRGGBBAA
22748
22774
  */
22749
22775
  function xlsxColorToHEXA(color) {
22750
- if (color.length === 6)
22776
+ if (color.length === 6) {
22751
22777
  return "#" + color + "FF";
22778
+ }
22752
22779
  return "#" + color.slice(2) + color.slice(0, 2);
22753
22780
  }
22754
22781
  /**
@@ -22852,8 +22879,9 @@ function convertBorders(data, warningManager) {
22852
22879
  return arrayToObject(borderArray, 1);
22853
22880
  }
22854
22881
  function convertBorderDescr$1(borderDescr, warningManager) {
22855
- if (!borderDescr)
22882
+ if (!borderDescr) {
22856
22883
  return undefined;
22884
+ }
22857
22885
  addBorderDescrWarnings(borderDescr, warningManager);
22858
22886
  const style = BORDER_STYLE_CONVERSION_MAP[borderDescr.style];
22859
22887
  return style ? { style, color: convertColor(borderDescr.color) } : undefined;
@@ -22938,16 +22966,18 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
22938
22966
  const cfs = [];
22939
22967
  let cfId = 1;
22940
22968
  for (const cf of xlsxCfs) {
22941
- if (cf.cfRules.length === 0)
22969
+ if (cf.cfRules.length === 0) {
22942
22970
  continue;
22971
+ }
22943
22972
  addCfConversionWarnings(cf, dxfs, warningManager);
22944
22973
  const rule = cf.cfRules[0];
22945
22974
  let operator;
22946
22975
  const values = [];
22947
22976
  const cfAdditionalProperties = {};
22948
22977
  if (rule.dxfId === undefined &&
22949
- !(rule.type === "colorScale" || rule.type === "iconSet" || rule.type === "dataBar"))
22978
+ !(rule.type === "colorScale" || rule.type === "iconSet" || rule.type === "dataBar")) {
22950
22979
  continue;
22980
+ }
22951
22981
  switch (rule.type) {
22952
22982
  case "aboveAverage":
22953
22983
  case "containsErrors":
@@ -22979,14 +23009,16 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
22979
23009
  case "notContainsText":
22980
23010
  case "beginsWith":
22981
23011
  case "endsWith":
22982
- if (!rule.text)
23012
+ if (!rule.text) {
22983
23013
  continue;
23014
+ }
22984
23015
  operator = CF_TYPE_CONVERSION_MAP[rule.type];
22985
23016
  values.push(rule.text);
22986
23017
  break;
22987
23018
  case "expression":
22988
- if (!rule.formula?.length)
23019
+ if (!rule.formula?.length) {
22989
23020
  continue;
23021
+ }
22990
23022
  operator = CF_TYPE_CONVERSION_MAP[rule.type];
22991
23023
  values.push(`=${rule.formula[0]}`);
22992
23024
  break;
@@ -22995,8 +23027,9 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
22995
23027
  operator = CF_TYPE_CONVERSION_MAP[rule.type];
22996
23028
  break;
22997
23029
  case "cellIs":
22998
- if (!rule.operator || !rule.formula || rule.formula.length === 0)
23030
+ if (!rule.operator || !rule.formula || rule.formula.length === 0) {
22999
23031
  continue;
23032
+ }
23000
23033
  operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.operator];
23001
23034
  values.push(prefixFormulaWithEqual(rule.formula[0]));
23002
23035
  if (rule.formula.length === 2) {
@@ -23004,8 +23037,9 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
23004
23037
  }
23005
23038
  break;
23006
23039
  case "top10":
23007
- if (rule.rank === undefined)
23040
+ if (rule.rank === undefined) {
23008
23041
  continue;
23042
+ }
23009
23043
  operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.type];
23010
23044
  values.push(rule.rank.toString());
23011
23045
  if (rule.percent) {
@@ -23035,8 +23069,9 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
23035
23069
  }
23036
23070
  function convertDataBar(id, xlsxCf) {
23037
23071
  const dataBar = xlsxCf.cfRules[0].dataBar;
23038
- if (!dataBar)
23072
+ if (!dataBar) {
23039
23073
  return undefined;
23074
+ }
23040
23075
  const color = hexaToInt(convertColor(dataBar.color) || "#FFFFFF");
23041
23076
  return {
23042
23077
  id: id.toString(),
@@ -23086,8 +23121,9 @@ function convertColorScale(id, xlsxCf) {
23086
23121
  */
23087
23122
  function convertIconSet(id, xlsxCf, warningManager) {
23088
23123
  const xlsxIconSet = xlsxCf.cfRules[0].iconSet;
23089
- if (!xlsxIconSet)
23124
+ if (!xlsxIconSet) {
23090
23125
  return undefined;
23126
+ }
23091
23127
  let cfVos = xlsxIconSet.cfvos;
23092
23128
  let cfIcons = xlsxIconSet.cfIcons;
23093
23129
  if (cfVos.length < 3 || (cfIcons && cfIcons.length < 3)) {
@@ -23163,8 +23199,9 @@ function convertIconSet(id, xlsxCf, warningManager) {
23163
23199
  */
23164
23200
  function convertIcons(xlsxIconSet, index) {
23165
23201
  const iconSet = ICON_SET_CONVERSION_MAP[xlsxIconSet];
23166
- if (!iconSet)
23202
+ if (!iconSet) {
23167
23203
  return "";
23204
+ }
23168
23205
  return index === 0
23169
23206
  ? ICON_SETS[iconSet].bad
23170
23207
  : index === 1
@@ -23243,18 +23280,22 @@ function* iterateItemIdsPositions(sheetId, itemIdsByZones) {
23243
23280
  }
23244
23281
  }
23245
23282
  function getCanonicalRepresentation(item) {
23246
- if (item === null)
23283
+ if (item === null) {
23247
23284
  return "null";
23248
- if (item === undefined)
23285
+ }
23286
+ if (item === undefined) {
23249
23287
  return "undefined";
23250
- if (typeof item !== "object")
23288
+ }
23289
+ if (typeof item !== "object") {
23251
23290
  return String(item);
23291
+ }
23252
23292
  if (Array.isArray(item)) {
23253
23293
  const len = item.length;
23254
23294
  let result = "[";
23255
23295
  for (let i = 0; i < len; i++) {
23256
- if (i > 0)
23296
+ if (i > 0) {
23257
23297
  result += ",";
23298
+ }
23258
23299
  result += getCanonicalRepresentation(item[i]);
23259
23300
  }
23260
23301
  return result + "]";
@@ -23345,13 +23386,15 @@ function convertWidthToExcel(width) {
23345
23386
  return Math.round(WIDTH_FACTOR * width * 100) / 100;
23346
23387
  }
23347
23388
  function convertHeightFromExcel(height) {
23348
- if (!height)
23389
+ if (!height) {
23349
23390
  return height;
23391
+ }
23350
23392
  return Math.round((height / HEIGHT_FACTOR) * 100) / 100;
23351
23393
  }
23352
23394
  function convertWidthFromExcel(width) {
23353
- if (!width)
23395
+ if (!width) {
23354
23396
  return width;
23397
+ }
23355
23398
  return Math.round((width / WIDTH_FACTOR) * 100) / 100;
23356
23399
  }
23357
23400
  function extractStyle(data, content, styleId, formatId, borderId) {
@@ -24241,12 +24284,15 @@ function convertCols(sheet, numberOfCols, headerGroups) {
24241
24284
  for (let i = 1; i < numberOfCols + 1; i++) {
24242
24285
  const col = sheet.cols.find((col) => col.min <= i && i <= col.max);
24243
24286
  let colSize;
24244
- if (col && col.width)
24287
+ if (col && col.width) {
24245
24288
  colSize = col.width;
24246
- else if (sheet.sheetFormat?.defaultColWidth)
24289
+ }
24290
+ else if (sheet.sheetFormat?.defaultColWidth) {
24247
24291
  colSize = sheet.sheetFormat.defaultColWidth;
24248
- else
24292
+ }
24293
+ else {
24249
24294
  colSize = EXCEL_DEFAULT_COL_WIDTH;
24295
+ }
24250
24296
  // In xlsx there is no difference between hidden columns and columns inside a folded group.
24251
24297
  // But in o-spreadsheet folded columns are not considered hidden.
24252
24298
  const colIndex = i - 1;
@@ -24264,12 +24310,15 @@ function convertRows(sheet, numberOfRows, headerGroups) {
24264
24310
  for (let i = 1; i < numberOfRows + 1; i++) {
24265
24311
  const row = sheet.rows.find((row) => row.index === i);
24266
24312
  let rowSize;
24267
- if (row && row.height)
24313
+ if (row && row.height) {
24268
24314
  rowSize = row.height;
24269
- else if (sheet.sheetFormat?.defaultRowHeight)
24315
+ }
24316
+ else if (sheet.sheetFormat?.defaultRowHeight) {
24270
24317
  rowSize = sheet.sheetFormat.defaultRowHeight;
24271
- else
24318
+ }
24319
+ else {
24272
24320
  rowSize = EXCEL_DEFAULT_ROW_HEIGHT;
24321
+ }
24273
24322
  // In xlsx there is no difference between hidden rows and rows inside a folded group.
24274
24323
  // But in o-spreadsheet folded rows are not considered hidden.
24275
24324
  const rowIndex = i - 1;
@@ -24437,10 +24486,12 @@ function getHeader(sheet, dim, index) {
24437
24486
  function convertTables(convertedData, xlsxData) {
24438
24487
  for (const xlsxSheet of xlsxData.sheets) {
24439
24488
  const sheet = convertedData.sheets.find((sheet) => sheet.name === xlsxSheet.sheetName);
24440
- if (!sheet)
24489
+ if (!sheet) {
24441
24490
  continue;
24442
- if (!sheet.tables)
24491
+ }
24492
+ if (!sheet.tables) {
24443
24493
  sheet.tables = [];
24494
+ }
24444
24495
  for (const table of xlsxSheet.tables) {
24445
24496
  sheet.tables.push({ range: table.ref, config: convertTableConfig(table) });
24446
24497
  }
@@ -24860,10 +24911,12 @@ class AttributeValue {
24860
24911
  return fixXlsxUnicode(String(this.value));
24861
24912
  }
24862
24913
  asBool() {
24863
- if (this.value === "true")
24864
- return true; // for files exported from Libre Office
24865
- if (this.value === "false")
24914
+ if (this.value === "true") {
24915
+ return true;
24916
+ } // for files exported from Libre Office
24917
+ if (this.value === "false") {
24866
24918
  return false;
24919
+ }
24867
24920
  return Boolean(Number(this.value));
24868
24921
  }
24869
24922
  asNum() {
@@ -24975,8 +25028,9 @@ class XlsxBaseExtractor {
24975
25028
  */
24976
25029
  extractAttr(e, attName, optionalArgs) {
24977
25030
  const attribute = e.attributes[attName];
24978
- if (!attribute)
25031
+ if (!attribute) {
24979
25032
  this.handleMissingValue(e, `attribute "${attName}"`, optionalArgs);
25033
+ }
24980
25034
  const value = attribute?.value ? attribute.value : optionalArgs?.default;
24981
25035
  return (value === undefined ? undefined : new AttributeValue(value));
24982
25036
  }
@@ -25094,26 +25148,30 @@ class XlsxBaseExtractor {
25094
25148
  * Returns the xml file targeted by a relationship.
25095
25149
  */
25096
25150
  getTargetXmlFile(relationship) {
25097
- if (!relationship)
25151
+ if (!relationship) {
25098
25152
  throw new Error("Undefined target file");
25153
+ }
25099
25154
  const target = this.processRelationshipTargetName(relationship.target);
25100
25155
  // Use "endsWith" because targets are relative paths, and we know the files by their absolute path.
25101
25156
  const f = this.getListOfXMLFiles().find((f) => f.file.fileName.endsWith(target));
25102
- if (!f || !f.file)
25157
+ if (!f || !f.file) {
25103
25158
  throw new Error("Cannot find target file");
25159
+ }
25104
25160
  return f;
25105
25161
  }
25106
25162
  /**
25107
25163
  * Returns the image parameters targeted by a relationship.
25108
25164
  */
25109
25165
  getTargetImageFile(relationship) {
25110
- if (!relationship)
25166
+ if (!relationship) {
25111
25167
  throw new Error("Undefined target file");
25168
+ }
25112
25169
  const target = this.processRelationshipTargetName(relationship.target);
25113
25170
  // Use "endsWith" because targets are relative paths, and we know the files by their absolute path.
25114
25171
  const f = this.xlsxFileStructure.images.find((f) => f.fileName.endsWith(target));
25115
- if (!f)
25172
+ if (!f) {
25116
25173
  throw new Error("Cannot find target file");
25174
+ }
25117
25175
  return f;
25118
25176
  }
25119
25177
  querySelector(element, query) {
@@ -25249,8 +25307,9 @@ class XlsxCfExtractor extends XlsxBaseExtractor {
25249
25307
  }
25250
25308
  extractCfColorScale(cfRulesElement, theme) {
25251
25309
  const colorScaleElement = this.querySelector(cfRulesElement, "colorScale");
25252
- if (!colorScaleElement)
25310
+ if (!colorScaleElement) {
25253
25311
  return undefined;
25312
+ }
25254
25313
  return {
25255
25314
  colors: this.mapOnElements({ parent: colorScaleElement, query: "color" }, (colorElement) => {
25256
25315
  return this.extractColor(colorElement, theme, "ffffff");
@@ -25260,8 +25319,9 @@ class XlsxCfExtractor extends XlsxBaseExtractor {
25260
25319
  }
25261
25320
  extractCfDataBar(cfRulesElement, theme) {
25262
25321
  const dataBarElement = this.querySelector(cfRulesElement, "dataBar");
25263
- if (!dataBarElement)
25322
+ if (!dataBarElement) {
25264
25323
  return undefined;
25324
+ }
25265
25325
  return {
25266
25326
  color: this.extractColor(dataBarElement.querySelector("color"), theme, "EFF7FF"),
25267
25327
  // TODO ATM, we only support color for dataBar, not the minimum and maximum fill percentage
@@ -25270,8 +25330,9 @@ class XlsxCfExtractor extends XlsxBaseExtractor {
25270
25330
  }
25271
25331
  extractCfIconSet(cfRulesElement) {
25272
25332
  const iconSetElement = this.querySelector(cfRulesElement, "iconSet, x14:iconSet");
25273
- if (!iconSetElement)
25333
+ if (!iconSetElement) {
25274
25334
  return undefined;
25335
+ }
25275
25336
  return {
25276
25337
  iconSet: this.extractAttr(iconSetElement, "iconSet", {
25277
25338
  default: "3TrafficLights1",
@@ -25865,8 +25926,9 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
25865
25926
  }
25866
25927
  extractSheetFormat(worksheet) {
25867
25928
  const formatElement = this.querySelector(worksheet, "sheetFormatPr");
25868
- if (!formatElement)
25929
+ if (!formatElement) {
25869
25930
  return undefined;
25931
+ }
25870
25932
  return {
25871
25933
  defaultColWidth: this.extractAttr(formatElement, "defaultColWidth", {
25872
25934
  default: EXCEL_DEFAULT_COL_WIDTH.toString(),
@@ -25878,8 +25940,9 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
25878
25940
  }
25879
25941
  extractSheetProperties(worksheet) {
25880
25942
  const propertiesElement = this.querySelector(worksheet, "sheetPr");
25881
- if (!propertiesElement)
25943
+ if (!propertiesElement) {
25882
25944
  return undefined;
25945
+ }
25883
25946
  return {
25884
25947
  outlinePr: this.extractSheetOutlineProperties(propertiesElement),
25885
25948
  tabColor: this.extractColor(this.querySelector(propertiesElement, "tabColor"), this.theme),
@@ -25887,8 +25950,9 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
25887
25950
  }
25888
25951
  extractSheetOutlineProperties(sheetProperties) {
25889
25952
  const properties = this.querySelector(sheetProperties, "outlinePr");
25890
- if (!properties)
25953
+ if (!properties) {
25891
25954
  return undefined;
25955
+ }
25892
25956
  return {
25893
25957
  summaryBelow: this.extractAttr(properties, "summaryBelow", { default: true }).asBool(),
25894
25958
  summaryRight: this.extractAttr(properties, "summaryRight", { default: true }).asBool(),
@@ -25949,8 +26013,9 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
25949
26013
  }
25950
26014
  extractCellFormula(cellElement) {
25951
26015
  const formulaElement = this.querySelector(cellElement, "f");
25952
- if (!formulaElement)
26016
+ if (!formulaElement) {
25953
26017
  return undefined;
26018
+ }
25954
26019
  const content = this.extractTextContent(formulaElement);
25955
26020
  const sharedIndex = this.extractAttr(formulaElement, "si")?.asNum();
25956
26021
  const ref = this.extractAttr(formulaElement, "ref")?.asString();
@@ -26084,8 +26149,9 @@ class XlsxStyleExtractor extends XlsxBaseExtractor {
26084
26149
  }
26085
26150
  extractSingleBorder(borderElement, direction, theme) {
26086
26151
  const directionElement = this.querySelector(borderElement, direction);
26087
- if (!directionElement || !directionElement.attributes["style"])
26152
+ if (!directionElement || !directionElement.attributes["style"]) {
26088
26153
  return undefined;
26154
+ }
26089
26155
  return {
26090
26156
  style: this.extractAttr(directionElement, "style", {
26091
26157
  required: true,
@@ -27527,6 +27593,94 @@ class PositionMap {
27527
27593
  }
27528
27594
  }
27529
27595
 
27596
+ /**
27597
+ * BasePlugin
27598
+ *
27599
+ * Since the spreadsheet internal state is quite complex, it is split into
27600
+ * multiple parts, each managing a specific concern.
27601
+ *
27602
+ * This file introduces the BasePlugin, which is the common class that defines
27603
+ * how each of these model sub parts should interact with each other.
27604
+ * There are two kinds of plugins: core plugins handling persistent data
27605
+ * and UI plugins handling transient data.
27606
+ */
27607
+ class BasePlugin {
27608
+ static getters = [];
27609
+ history;
27610
+ constructor(stateObserver) {
27611
+ this.history = Object.assign(Object.create(stateObserver), {
27612
+ update: stateObserver.addChange.bind(stateObserver, this),
27613
+ selectCell: () => { },
27614
+ });
27615
+ }
27616
+ /**
27617
+ * Export for excel should be available for all plugins, even for the UI.
27618
+ * In some cases, we need to export evaluated value, which is available from
27619
+ * UI plugin only.
27620
+ */
27621
+ exportForExcel(data) { }
27622
+ // ---------------------------------------------------------------------------
27623
+ // Command handling
27624
+ // ---------------------------------------------------------------------------
27625
+ /**
27626
+ * Before a command is accepted, the model will ask each plugin if the command
27627
+ * is allowed. If all of them return true, then we can proceed. Otherwise,
27628
+ * the command is cancelled.
27629
+ *
27630
+ * There should not be any side effects in this method.
27631
+ */
27632
+ allowDispatch(command) {
27633
+ return "Success" /* CommandResult.Success */;
27634
+ }
27635
+ /**
27636
+ * This method is useful when a plugin needs to perform some action before a
27637
+ * command is handled in another plugin. This should only be used if it is not
27638
+ * possible to do the work in the handle method.
27639
+ */
27640
+ beforeHandle(command) { }
27641
+ /**
27642
+ * This is the standard place to handle any command. Most of the plugin
27643
+ * command handling work should take place here.
27644
+ */
27645
+ handle(command) { }
27646
+ /**
27647
+ * Sometimes, it is useful to perform some work after a command (and all its
27648
+ * subcommands) has been completely handled. For example, when we paste
27649
+ * multiple cells, we only want to reevaluate the cell values once at the end.
27650
+ */
27651
+ finalize() { }
27652
+ /**
27653
+ * Combine multiple validation functions into a single function
27654
+ * returning the list of results of every validation.
27655
+ */
27656
+ batchValidations(...validations) {
27657
+ return (toValidate) => validations.map((validation) => validation.call(this, toValidate)).flat();
27658
+ }
27659
+ /**
27660
+ * Combine multiple validation functions. Every validation is executed one after
27661
+ * the other. As soon as one validation fails, it stops and the cancelled reason
27662
+ * is returned.
27663
+ */
27664
+ chainValidations(...validations) {
27665
+ return (toValidate) => {
27666
+ for (const validation of validations) {
27667
+ let results = validation.call(this, toValidate);
27668
+ if (!Array.isArray(results)) {
27669
+ results = [results];
27670
+ }
27671
+ const cancelledReasons = results.filter((result) => result !== "Success" /* CommandResult.Success */);
27672
+ if (cancelledReasons.length) {
27673
+ return cancelledReasons;
27674
+ }
27675
+ }
27676
+ return "Success" /* CommandResult.Success */;
27677
+ };
27678
+ }
27679
+ checkValidations(command, ...validations) {
27680
+ return this.batchValidations(...validations)(command);
27681
+ }
27682
+ }
27683
+
27530
27684
  /**
27531
27685
  * Core plugins handle spreadsheet data.
27532
27686
  * They are responsible to import, export and maintain the spreadsheet
@@ -27598,8 +27752,9 @@ class BordersPlugin extends CorePlugin {
27598
27752
  this.history.update("borders", allBorders);
27599
27753
  break;
27600
27754
  case "SET_BORDER":
27601
- if (cmd.border)
27755
+ if (cmd.border) {
27602
27756
  this.addBorders(cmd.sheetId, [positionToZone(cmd)], cmd.border);
27757
+ }
27603
27758
  break;
27604
27759
  case "SET_BORDERS_ON_TARGET":
27605
27760
  for (const zone of cmd.target) {
@@ -27716,8 +27871,9 @@ class BordersPlugin extends CorePlugin {
27716
27871
  for (const border of this.borders[sheetId] ?? []) {
27717
27872
  const { zone: bzone, style: bstyle } = border;
27718
27873
  const inter = intersection(bzone, zone);
27719
- if (!inter)
27874
+ if (!inter) {
27720
27875
  continue;
27876
+ }
27721
27877
  for (let col = inter.left; col <= inter.right; col++) {
27722
27878
  for (let row = inter.top; row <= inter.bottom; row++) {
27723
27879
  const cell = borders.get({ sheetId, col, row }) ?? {};
@@ -27735,8 +27891,9 @@ class BordersPlugin extends CorePlugin {
27735
27891
  const colors = new Set();
27736
27892
  for (const border of this.borders[sheetId] ?? []) {
27737
27893
  for (const style of Object.values(border.style)) {
27738
- if (style?.color)
27894
+ if (style?.color) {
27739
27895
  colors.add(style.color);
27896
+ }
27740
27897
  }
27741
27898
  }
27742
27899
  return [...colors];
@@ -27778,13 +27935,16 @@ class BordersPlugin extends CorePlugin {
27778
27935
  }
27779
27936
  borderIsClear(border) {
27780
27937
  const style = border.style;
27781
- if (style.left || style.right || style.bottom || style.top)
27938
+ if (style.left || style.right || style.bottom || style.top) {
27782
27939
  return false;
27940
+ }
27783
27941
  const zone = border.zone;
27784
- if ((zone.bottom === undefined || zone.top < zone.bottom) && style.horizontal)
27942
+ if ((zone.bottom === undefined || zone.top < zone.bottom) && style.horizontal) {
27785
27943
  return false;
27786
- if ((zone.right === undefined || zone.left < zone.right) && style.vertical)
27944
+ }
27945
+ if ((zone.right === undefined || zone.left < zone.right) && style.vertical) {
27787
27946
  return false;
27947
+ }
27788
27948
  return true;
27789
27949
  }
27790
27950
  clearBorders(sheetId, zones) {
@@ -27929,8 +28089,9 @@ class BordersPlugin extends CorePlugin {
27929
28089
  return "Success" /* CommandResult.Success */;
27930
28090
  }
27931
28091
  ensureHasBorder(cmd) {
27932
- if (!cmd.border)
28092
+ if (!cmd.border) {
27933
28093
  return "NoChanges" /* CommandResult.NoChanges */;
28094
+ }
27934
28095
  return "Success" /* CommandResult.Success */;
27935
28096
  }
27936
28097
  /**
@@ -28574,16 +28735,18 @@ class CellPlugin extends CorePlugin {
28574
28735
  checkCellOutOfSheet(cmd) {
28575
28736
  const { sheetId, col, row } = cmd;
28576
28737
  const sheet = this.getters.tryGetSheet(sheetId);
28577
- if (!sheet)
28738
+ if (!sheet) {
28578
28739
  return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
28740
+ }
28579
28741
  const sheetZone = this.getters.getSheetZone(sheetId);
28580
28742
  return isInside(col, row, sheetZone) ? "Success" /* CommandResult.Success */ : "TargetOutOfSheet" /* CommandResult.TargetOutOfSheet */;
28581
28743
  }
28582
28744
  checkUselessClearCell(cmd) {
28583
28745
  const cell = this.getters.getCell(cmd);
28584
28746
  const style = this.getters.getCellStyle(cmd);
28585
- if (!cell)
28747
+ if (!cell) {
28586
28748
  return "NoChanges" /* CommandResult.NoChanges */;
28749
+ }
28587
28750
  if (!cell.content && !style && !cell.format) {
28588
28751
  return "NoChanges" /* CommandResult.NoChanges */;
28589
28752
  }
@@ -29846,11 +30009,13 @@ class ConditionalFormatPlugin extends CorePlugin {
29846
30009
  this.history.update("cfRules", sheet, currentCF);
29847
30010
  }
29848
30011
  checkValidPriorityChange(cfId, delta, sheetId) {
29849
- if (!this.cfRules[sheetId])
30012
+ if (!this.cfRules[sheetId]) {
29850
30013
  return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
30014
+ }
29851
30015
  const ruleIndex = this.cfRules[sheetId].findIndex((cf) => cf.id === cfId);
29852
- if (ruleIndex === -1)
30016
+ if (ruleIndex === -1) {
29853
30017
  return "InvalidConditionalFormatId" /* CommandResult.InvalidConditionalFormatId */;
30018
+ }
29854
30019
  const cfIndex2 = ruleIndex - delta;
29855
30020
  if (cfIndex2 < 0 || cfIndex2 >= this.cfRules[sheetId].length) {
29856
30021
  return "InvalidConditionalFormatId" /* CommandResult.InvalidConditionalFormatId */;
@@ -29922,8 +30087,9 @@ class ConditionalFormatPlugin extends CorePlugin {
29922
30087
  return "Success" /* CommandResult.Success */;
29923
30088
  }
29924
30089
  checkFormulaCompilation(threshold, thresholdName) {
29925
- if (threshold.type !== "formula")
30090
+ if (threshold.type !== "formula") {
29926
30091
  return "Success" /* CommandResult.Success */;
30092
+ }
29927
30093
  const compiledFormula = compile(threshold.value || "");
29928
30094
  if (compiledFormula.isBadExpression) {
29929
30095
  switch (thresholdName) {
@@ -29991,8 +30157,9 @@ class ConditionalFormatPlugin extends CorePlugin {
29991
30157
  }
29992
30158
  checkCFValues(rule) {
29993
30159
  for (const value of rule.values) {
29994
- if (!value.startsWith("="))
30160
+ if (!value.startsWith("=")) {
29995
30161
  continue;
30162
+ }
29996
30163
  const compiledFormula = compile(value || "");
29997
30164
  if (compiledFormula.isBadExpression) {
29998
30165
  return "ValueCellIsInvalidFormula" /* CommandResult.ValueCellIsInvalidFormula */;
@@ -30164,8 +30331,9 @@ class DataValidationPlugin extends CorePlugin {
30164
30331
  }
30165
30332
  cellHasListDataValidationIcon(cellPosition) {
30166
30333
  const rule = this.getValidationRuleForCell(cellPosition);
30167
- if (!rule)
30334
+ if (!rule) {
30168
30335
  return false;
30336
+ }
30169
30337
  return ((rule.criterion.type === "isValueInList" || rule.criterion.type === "isValueInRange") &&
30170
30338
  (rule.criterion.displayStyle === "arrow" || rule.criterion.displayStyle === "chip"));
30171
30339
  }
@@ -31502,7 +31670,6 @@ class MergePlugin extends CorePlugin {
31502
31670
  "getMerge",
31503
31671
  "getMergesInZone",
31504
31672
  "isSingleCellOrMerge",
31505
- "getSelectionRangeString",
31506
31673
  "isMainCellPosition",
31507
31674
  ];
31508
31675
  nextId = 1;
@@ -31539,8 +31706,9 @@ class MergePlugin extends CorePlugin {
31539
31706
  break;
31540
31707
  case "DUPLICATE_SHEET":
31541
31708
  const merges = this.merges[cmd.sheetId];
31542
- if (!merges)
31709
+ if (!merges) {
31543
31710
  break;
31711
+ }
31544
31712
  for (const range of Object.values(merges).filter(isDefined)) {
31545
31713
  this.addMerge(cmd.sheetIdTo, range.zone);
31546
31714
  }
@@ -31575,8 +31743,9 @@ class MergePlugin extends CorePlugin {
31575
31743
  }
31576
31744
  getMergesInZone(sheetId, zone) {
31577
31745
  const sheetMap = this.mergeCellMap[sheetId];
31578
- if (!sheetMap)
31746
+ if (!sheetMap) {
31579
31747
  return [];
31748
+ }
31580
31749
  const mergeIds = new Set();
31581
31750
  for (let col = zone.left; col <= zone.right; col++) {
31582
31751
  for (let row = zone.top; row <= zone.bottom; row++) {
@@ -31590,26 +31759,6 @@ class MergePlugin extends CorePlugin {
31590
31759
  .map((mergeId) => this.getMergeById(sheetId, mergeId))
31591
31760
  .filter(isDefined);
31592
31761
  }
31593
- /**
31594
- * Same as `getRangeString` but add all necessary merge to the range to make it a valid selection
31595
- */
31596
- getSelectionRangeString(range, forSheetId) {
31597
- const expandedZone = this.getters.expandZone(range.sheetId, range.zone);
31598
- const expandedRange = createRange({
31599
- ...range,
31600
- zone: {
31601
- ...expandedZone,
31602
- bottom: isFullColRange(range) ? undefined : expandedZone.bottom,
31603
- right: isFullRowRange(range) ? undefined : expandedZone.right,
31604
- },
31605
- }, this.getters.getSheetSize);
31606
- const rangeString = this.getters.getRangeString(expandedRange, forSheetId);
31607
- if (this.isSingleCellOrMerge(range.sheetId, range.zone)) {
31608
- const { sheetName, xc } = splitReference(rangeString);
31609
- return getFullReference(sheetName, xc.split(":")[0]);
31610
- }
31611
- return rangeString;
31612
- }
31613
31762
  /**
31614
31763
  * Return true if the zone intersects an existing merge:
31615
31764
  * if they have at least a common cell
@@ -31741,8 +31890,9 @@ class MergePlugin extends CorePlugin {
31741
31890
  }
31742
31891
  checkDestructiveMerge({ sheetId, target }) {
31743
31892
  const sheet = this.getters.tryGetSheet(sheetId);
31744
- if (!sheet)
31893
+ if (!sheet) {
31745
31894
  return "Success" /* CommandResult.Success */;
31895
+ }
31746
31896
  const isDestructive = target.some((zone) => this.isMergeDestructive(sheetId, zone));
31747
31897
  return isDestructive ? "MergeIsDestructive" /* CommandResult.MergeIsDestructive */ : "Success" /* CommandResult.Success */;
31748
31898
  }
@@ -31758,8 +31908,9 @@ class MergePlugin extends CorePlugin {
31758
31908
  }
31759
31909
  checkFrozenPanes({ sheetId, target }) {
31760
31910
  const sheet = this.getters.tryGetSheet(sheetId);
31761
- if (!sheet)
31911
+ if (!sheet) {
31762
31912
  return "Success" /* CommandResult.Success */;
31913
+ }
31763
31914
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
31764
31915
  if (doesAnyZoneCrossFrozenPane(target, xSplit, ySplit)) {
31765
31916
  return "FrozenPaneOverlap" /* CommandResult.FrozenPaneOverlap */;
@@ -32628,6 +32779,24 @@ class SpreadsheetPivotTable {
32628
32779
  }
32629
32780
  return this.rows.filter((row) => row.indent === depth + 1).map((row) => this.getDomain(row));
32630
32781
  }
32782
+ getPivotTableDimensions(pivotStyle) {
32783
+ const cells = this.getPivotCells(pivotStyle);
32784
+ let numberOfHeaderRows = 0;
32785
+ if (pivotStyle.displayColumnHeaders) {
32786
+ numberOfHeaderRows = this.columns.length - 1;
32787
+ }
32788
+ if (pivotStyle.displayMeasuresRow) {
32789
+ numberOfHeaderRows++;
32790
+ }
32791
+ return {
32792
+ numberOfCols: Math.min(1 + pivotStyle.numberOfColumns, cells.length),
32793
+ numberOfRows: Math.min(numberOfHeaderRows + pivotStyle.numberOfRows, cells[0].length),
32794
+ numberOfHeaderRows,
32795
+ };
32796
+ }
32797
+ getNumberOfRowGroupBys() {
32798
+ return Math.max(...this.rows.map((row) => row.fields.length));
32799
+ }
32631
32800
  }
32632
32801
  const EMPTY_PIVOT_CELL = { type: "EMPTY" };
32633
32802
 
@@ -33393,8 +33562,9 @@ class SpreadsheetPivot {
33393
33562
  }
33394
33563
  for (const customFieldName in this.definition.customFields || {}) {
33395
33564
  const customField = this.definition.customFields?.[customFieldName];
33396
- if (!customField)
33565
+ if (!customField) {
33397
33566
  continue;
33567
+ }
33398
33568
  const baseValue = entry[customField.parentField];
33399
33569
  const parentField = this.fields[customField.parentField];
33400
33570
  if (!baseValue || !parentField) {
@@ -33496,6 +33666,7 @@ class PivotCorePlugin extends CorePlugin {
33496
33666
  "getMeasureCompiledFormula",
33497
33667
  "getPivotName",
33498
33668
  "isExistingPivot",
33669
+ "getMeasureFullDependencies",
33499
33670
  ];
33500
33671
  nextFormulaId = 1;
33501
33672
  pivots = {};
@@ -33581,7 +33752,7 @@ class PivotCorePlugin extends CorePlugin {
33581
33752
  }
33582
33753
  case "UPDATE_PIVOT": {
33583
33754
  this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
33584
- this.compileCalculatedMeasures(cmd.pivot.measures);
33755
+ this.compileCalculatedMeasures(cmd.pivotId, cmd.pivot.measures);
33585
33756
  break;
33586
33757
  }
33587
33758
  }
@@ -33599,9 +33770,14 @@ class PivotCorePlugin extends CorePlugin {
33599
33770
  this.history.update("pivots", pivotId, "definition", newDefinition);
33600
33771
  }
33601
33772
  }
33602
- for (const sheetId in this.compiledMeasureFormulas) {
33603
- for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
33604
- const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
33773
+ for (const pivotId in this.compiledMeasureFormulas) {
33774
+ for (const measureId in this.compiledMeasureFormulas[pivotId]) {
33775
+ const measure = this.pivots[pivotId]?.definition.measures.find((m) => m.id === measureId);
33776
+ if (!measure || !measure.computedBy) {
33777
+ continue;
33778
+ }
33779
+ const sheetId = measure.computedBy.sheetId;
33780
+ const compiledFormula = this.compiledMeasureFormulas[pivotId][measureId].formula;
33605
33781
  const newDependencies = [];
33606
33782
  for (const range of compiledFormula.dependencies) {
33607
33783
  const change = applyChange(range);
@@ -33613,8 +33789,9 @@ class PivotCorePlugin extends CorePlugin {
33613
33789
  }
33614
33790
  }
33615
33791
  const newFormulaString = this.getters.getFormulaString(sheetId, compiledFormula.tokens, newDependencies);
33616
- if (newFormulaString !== formulaString) {
33617
- this.replaceMeasureFormula(sheetId, formulaString, newFormulaString);
33792
+ const oldFormulaString = measure.computedBy.formula;
33793
+ if (newFormulaString !== oldFormulaString) {
33794
+ this.replaceMeasureFormula(pivotId, measure, newFormulaString);
33618
33795
  }
33619
33796
  }
33620
33797
  }
@@ -33652,31 +33829,60 @@ class PivotCorePlugin extends CorePlugin {
33652
33829
  isExistingPivot(pivotId) {
33653
33830
  return pivotId in this.pivots;
33654
33831
  }
33655
- getMeasureCompiledFormula(measure) {
33832
+ getMeasureCompiledFormula(pivotId, measure) {
33833
+ if (!measure.computedBy) {
33834
+ throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
33835
+ }
33836
+ return this.compiledMeasureFormulas[pivotId][measure.id].formula;
33837
+ }
33838
+ getMeasureFullDependencies(pivotId, measure) {
33656
33839
  if (!measure.computedBy) {
33657
33840
  throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
33658
33841
  }
33659
- const sheetId = measure.computedBy.sheetId;
33660
- return this.compiledMeasureFormulas[sheetId][measure.computedBy.formula];
33842
+ return this.compiledMeasureFormulas[pivotId][measure.id].dependencies;
33661
33843
  }
33662
33844
  // -------------------------------------------------------------------------
33663
33845
  // Private
33664
33846
  // -------------------------------------------------------------------------
33665
33847
  addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
33666
33848
  this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
33667
- this.compileCalculatedMeasures(pivot.measures);
33849
+ this.compileCalculatedMeasures(pivotId, pivot.measures);
33668
33850
  this.history.update("formulaIds", formulaId, pivotId);
33669
33851
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
33670
33852
  }
33671
- compileCalculatedMeasures(measures) {
33853
+ compileCalculatedMeasures(pivotId, measures) {
33672
33854
  for (const measure of measures) {
33673
33855
  if (measure.computedBy) {
33674
- const sheetId = measure.computedBy.sheetId;
33675
33856
  const compiledFormula = this.compileMeasureFormula(measure.computedBy.sheetId, measure.computedBy.formula);
33676
- this.history.update("compiledMeasureFormulas", sheetId, measure.computedBy.formula, compiledFormula);
33857
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "formula", compiledFormula);
33858
+ }
33859
+ }
33860
+ for (const measure of measures) {
33861
+ if (measure.computedBy) {
33862
+ const dependencies = this.computeMeasureFullDependencies(pivotId, measure);
33863
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "dependencies", dependencies);
33677
33864
  }
33678
33865
  }
33679
33866
  }
33867
+ computeMeasureFullDependencies(pivotId, measure, exploredMeasures = new Set()) {
33868
+ const rangeDependencies = [];
33869
+ const definition = this.getPivotCoreDefinition(pivotId);
33870
+ const formula = this.getMeasureCompiledFormula(pivotId, measure);
33871
+ exploredMeasures.add(measure.id);
33872
+ for (const token of formula.tokens) {
33873
+ if (token.type !== "SYMBOL") {
33874
+ continue;
33875
+ }
33876
+ const otherMeasure = definition.measures.find((measureCandidate) => getCanonicalSymbolName(measureCandidate.id) === token.value &&
33877
+ measure.id !== measureCandidate.id);
33878
+ if (!otherMeasure || exploredMeasures.has(otherMeasure.id) || !otherMeasure.computedBy) {
33879
+ continue;
33880
+ }
33881
+ rangeDependencies.push(...this.computeMeasureFullDependencies(pivotId, otherMeasure, exploredMeasures));
33882
+ }
33883
+ rangeDependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
33884
+ return rangeDependencies;
33885
+ }
33680
33886
  insertPivot(position, formulaId, table) {
33681
33887
  this.resizeSheet(position.sheetId, position, table);
33682
33888
  const pivotCells = table.getPivotCells();
@@ -33735,21 +33941,17 @@ class PivotCorePlugin extends CorePlugin {
33735
33941
  dependencies: rangeDependencies,
33736
33942
  };
33737
33943
  }
33738
- replaceMeasureFormula(sheetId, formulaString, newFormulaString) {
33739
- this.history.update("compiledMeasureFormulas", sheetId, formulaString, undefined);
33740
- this.history.update("compiledMeasureFormulas", sheetId, newFormulaString, this.compileMeasureFormula(sheetId, newFormulaString));
33741
- for (const pivotId in this.pivots) {
33742
- const pivot = this.pivots[pivotId];
33743
- if (!pivot) {
33744
- continue;
33745
- }
33746
- for (const measure of pivot.definition.measures) {
33747
- if (measure.computedBy?.formula === formulaString) {
33748
- const measureIndex = pivot.definition.measures.indexOf(measure);
33749
- this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
33750
- }
33751
- }
33944
+ replaceMeasureFormula(pivotId, measure, newFormulaString) {
33945
+ const pivot = this.pivots[pivotId];
33946
+ if (!pivot) {
33947
+ return;
33752
33948
  }
33949
+ const measureIndex = pivot.definition.measures.indexOf(measure);
33950
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", {
33951
+ formula: newFormulaString,
33952
+ sheetId: measure.computedBy.sheetId,
33953
+ });
33954
+ this.compileCalculatedMeasures(pivotId, pivot.definition.measures);
33753
33955
  }
33754
33956
  checkSortedColumnInMeasures(definition) {
33755
33957
  const measures = definition.measures.map((measure) => measure.id);
@@ -33903,6 +34105,7 @@ class SheetPlugin extends CorePlugin {
33903
34105
  "getUnboundedZone",
33904
34106
  "checkElementsIncludeAllNonFrozenHeaders",
33905
34107
  "getDuplicateSheetName",
34108
+ "tryGetCellPosition",
33906
34109
  ];
33907
34110
  sheetIdsMapName = {};
33908
34111
  orderedSheetIds = [];
@@ -33927,10 +34130,12 @@ class SheetPlugin extends CorePlugin {
33927
34130
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
33928
34131
  }
33929
34132
  case "DUPLICATE_SHEET": {
33930
- if (this.sheets[cmd.sheetIdTo])
34133
+ if (this.sheets[cmd.sheetIdTo]) {
33931
34134
  return "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */;
33932
- if (this.orderedSheetIds.map(this.getSheetName.bind(this)).includes(cmd.sheetNameTo))
34135
+ }
34136
+ if (this.orderedSheetIds.map(this.getSheetName.bind(this)).includes(cmd.sheetNameTo)) {
33933
34137
  return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
34138
+ }
33934
34139
  return "Success" /* CommandResult.Success */;
33935
34140
  }
33936
34141
  case "MOVE_SHEET":
@@ -34203,6 +34408,9 @@ class SheetPlugin extends CorePlugin {
34203
34408
  }
34204
34409
  return cell;
34205
34410
  }
34411
+ tryGetCellPosition(cellId) {
34412
+ return this.cellPosition[cellId];
34413
+ }
34206
34414
  getNumberCols(sheetId) {
34207
34415
  return this.getSheet(sheetId).numberOfCols;
34208
34416
  }
@@ -34294,8 +34502,9 @@ class SheetPlugin extends CorePlugin {
34294
34502
  * not outside the sheet.
34295
34503
  */
34296
34504
  checkZonesExistInSheet(sheetId, zones) {
34297
- if (!zones.every(isZoneValid))
34505
+ if (!zones.every(isZoneValid)) {
34298
34506
  return "InvalidRange" /* CommandResult.InvalidRange */;
34507
+ }
34299
34508
  if (zones.length) {
34300
34509
  const sheetZone = this.getSheetZone(sheetId);
34301
34510
  return zones.every((zone) => isZoneInside(zone, sheetZone))
@@ -34729,8 +34938,9 @@ class SheetPlugin extends CorePlugin {
34729
34938
  * not outside the sheet.
34730
34939
  */
34731
34940
  checkZonesAreInSheet(cmd) {
34732
- if (!("sheetId" in cmd))
34941
+ if (!("sheetId" in cmd)) {
34733
34942
  return "Success" /* CommandResult.Success */;
34943
+ }
34734
34944
  if ("ranges" in cmd &&
34735
34945
  cmd.ranges.some((rangeData) => rangeData._sheetId !== "" && !this.getters.tryGetSheet(rangeData._sheetId))) {
34736
34946
  return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
@@ -34810,7 +35020,7 @@ class StylePlugin extends CorePlugin {
34810
35020
  case "UPDATE_CELL":
34811
35021
  if (cmd.style !== undefined) {
34812
35022
  if (cmd.style !== null) {
34813
- this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style);
35023
+ this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style, { force: true });
34814
35024
  }
34815
35025
  else {
34816
35026
  this.clearStyle(cmd.sheetId, [positionToZone(cmd)]);
@@ -34878,16 +35088,22 @@ class StylePlugin extends CorePlugin {
34878
35088
  }
34879
35089
  }
34880
35090
  styleIsDefault(style) {
34881
- return deepEquals(this.removeDefaultStyleValues(style), {});
35091
+ for (const key in style) {
35092
+ if (DEFAULT_STYLE_NO_ALIGN[key] !== style[key]) {
35093
+ return false;
35094
+ }
35095
+ }
35096
+ return true;
34882
35097
  }
34883
35098
  removeDefaultStyleValues(style) {
34884
35099
  const cleanedStyle = { ...style };
34885
- for (const property in DEFAULT_STYLE_NO_ALIGN) {
34886
- if (cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
35100
+ for (const property in style) {
35101
+ if (cleanedStyle[property] === undefined ||
35102
+ cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
34887
35103
  delete cleanedStyle[property];
34888
35104
  }
34889
35105
  }
34890
- return cleanedStyle;
35106
+ return Object.keys(cleanedStyle).length > 0 ? cleanedStyle : undefined;
34891
35107
  }
34892
35108
  onMerge(sheetId, zone) {
34893
35109
  this.setStyle(sheetId, zone, this.getCellStyle({ sheetId, col: zone.left, row: zone.top }), {
@@ -34923,13 +35139,13 @@ class StylePlugin extends CorePlugin {
34923
35139
  }
34924
35140
  editingZone = recomputeZones(editingZone, [inter]);
34925
35141
  }
35142
+ style = this.removeDefaultStyleValues(style);
34926
35143
  if (style) {
34927
- const newStyle = this.removeDefaultStyleValues(style);
34928
35144
  styles.push(...editingZone.map((zone) => {
34929
- return { zone, style: newStyle };
35145
+ return { zone, style };
34930
35146
  }));
34931
35147
  }
34932
- this.history.update("styles", sheetId, styles.filter((zoneStyle) => !this.styleIsDefault(zoneStyle.style)));
35148
+ this.history.update("styles", sheetId, styles);
34933
35149
  }
34934
35150
  clearStyle(sheetId, zones) {
34935
35151
  this.setStyles(sheetId, zones, undefined, { force: true });
@@ -34947,8 +35163,9 @@ class StylePlugin extends CorePlugin {
34947
35163
  const styles = new PositionMap();
34948
35164
  for (const { zone: z, style } of this.styles[sheetId] ?? []) {
34949
35165
  const inter = intersection(z, zone);
34950
- if (!inter)
35166
+ if (!inter) {
34951
35167
  continue;
35168
+ }
34952
35169
  for (let col = inter.left; col <= inter.right; col++) {
34953
35170
  for (let row = inter.top; row <= inter.bottom; row++) {
34954
35171
  styles.set({ sheetId, col, row }, style);
@@ -34961,8 +35178,9 @@ class StylePlugin extends CorePlugin {
34961
35178
  const styles = [];
34962
35179
  for (const style of this.styles[sheetId] ?? []) {
34963
35180
  const inter = intersection(style.zone, zone);
34964
- if (inter)
35181
+ if (inter) {
34965
35182
  styles.push({ zone: inter, style: style.style });
35183
+ }
34966
35184
  }
34967
35185
  return styles;
34968
35186
  }
@@ -35035,6 +35253,463 @@ class StylePlugin extends CorePlugin {
35035
35253
  }
35036
35254
  }
35037
35255
 
35256
+ const pivotLightWithLightBorders = (colorSet) => ({
35257
+ category: "light",
35258
+ templateName: "pivotLightWithLightBorders",
35259
+ primaryColor: colorSet.highlight,
35260
+ wholeTable: {
35261
+ style: { hideGridLines: true },
35262
+ border: { horizontal: { color: colorSet.light, style: "thin" } },
35263
+ },
35264
+ headerRow: {
35265
+ style: { bold: true },
35266
+ border: {
35267
+ top: { color: colorSet.highlight, style: "thin" },
35268
+ bottom: { color: colorSet.highlight, style: "thin" },
35269
+ },
35270
+ },
35271
+ mainSubHeaderRow: { style: { bold: true } },
35272
+ firstAlternatingSubHeaderRow: { style: { bold: true, textColor: colorSet.highlight } },
35273
+ totalRow: {
35274
+ border: {
35275
+ top: { color: colorSet.highlight, style: "thin" },
35276
+ bottom: { color: colorSet.highlight, style: "thin" },
35277
+ },
35278
+ style: { bold: true, fillColor: "#FFFFFF" },
35279
+ },
35280
+ firstRowStripe: {
35281
+ style: { fillColor: colorSet.light },
35282
+ border: {
35283
+ bottom: { color: colorSet.medium, style: "thin" },
35284
+ top: { color: colorSet.medium, style: "thin" },
35285
+ vertical: { color: colorSet.medium, style: "thin" },
35286
+ },
35287
+ },
35288
+ secondColumnStripe: {
35289
+ style: { fillColor: colorSet.light },
35290
+ border: {
35291
+ left: { color: colorSet.medium, style: "thin" },
35292
+ right: { color: colorSet.medium, style: "thin" },
35293
+ horizontal: { color: colorSet.medium, style: "thin" },
35294
+ },
35295
+ },
35296
+ });
35297
+ const pivotLightWithMediumBorders = (colorSet) => ({
35298
+ category: "light",
35299
+ templateName: "pivotLightWithMediumBorders",
35300
+ primaryColor: colorSet.highlight,
35301
+ wholeTable: {
35302
+ style: { textColor: colorSet.coloredText, hideGridLines: true },
35303
+ border: { horizontal: { color: colorSet.light, style: "thin" } },
35304
+ },
35305
+ firstColumn: { border: { right: { color: colorSet.highlight, style: "thin" } } },
35306
+ headerRow: {
35307
+ style: { bold: true, textColor: "#000000" },
35308
+ border: {
35309
+ top: { color: colorSet.highlight, style: "medium" },
35310
+ bottom: { color: colorSet.highlight, style: "medium" },
35311
+ left: { color: colorSet.highlight, style: "medium" },
35312
+ right: { color: colorSet.highlight, style: "medium" },
35313
+ },
35314
+ },
35315
+ measureHeader: { border: { top: { color: colorSet.light, style: "thin" } } },
35316
+ mainSubHeaderRow: {
35317
+ style: { bold: true, textColor: "#000000", fillColor: colorSet.light },
35318
+ },
35319
+ firstAlternatingSubHeaderRow: { style: { bold: true, textColor: "#000000" } },
35320
+ totalRow: {
35321
+ border: {
35322
+ top: { color: colorSet.highlight, style: "medium" },
35323
+ bottom: { color: colorSet.highlight, style: "medium" },
35324
+ left: { color: colorSet.highlight, style: "medium" },
35325
+ right: { color: colorSet.highlight, style: "medium" },
35326
+ },
35327
+ style: { bold: true, textColor: "#000000" },
35328
+ },
35329
+ firstRowStripe: {
35330
+ border: {
35331
+ bottom: { color: colorSet.highlight, style: "thin" },
35332
+ top: { color: colorSet.highlight, style: "thin" },
35333
+ },
35334
+ },
35335
+ secondRowStripe: {
35336
+ border: { bottom: { color: colorSet.highlight, style: "thin" } },
35337
+ },
35338
+ firstColumnStripe: {
35339
+ border: {
35340
+ left: { color: colorSet.highlight, style: "thin" },
35341
+ right: { color: colorSet.highlight, style: "thin" },
35342
+ },
35343
+ },
35344
+ secondColumnStripe: {
35345
+ border: {
35346
+ left: { color: colorSet.highlight, style: "thin" },
35347
+ right: { color: colorSet.highlight, style: "thin" },
35348
+ },
35349
+ },
35350
+ });
35351
+ const pivotLightWithGrayBands = (colorSet) => ({
35352
+ category: "light",
35353
+ templateName: "PivotLightWithGrayBands",
35354
+ primaryColor: colorSet.highlight,
35355
+ wholeTable: { style: { hideGridLines: true } },
35356
+ headerRow: {
35357
+ style: { bold: true, fillColor: colorSet.light },
35358
+ border: {
35359
+ horizontal: { color: colorSet.light, style: "thin" },
35360
+ vertical: { color: colorSet.light, style: "thin" },
35361
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35362
+ },
35363
+ },
35364
+ measureHeader: { border: { top: { color: "#FFFFFF", style: "thin" } } },
35365
+ mainSubHeaderRow: {
35366
+ style: { bold: true },
35367
+ border: { bottom: { color: colorSet.mediumBorder, style: "thin" } },
35368
+ },
35369
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35370
+ totalRow: {
35371
+ border: { top: { color: colorSet.mediumBorder, style: "medium" } },
35372
+ style: { bold: true, fillColor: colorSet.light },
35373
+ },
35374
+ firstRowStripe: { style: { fillColor: TABLE_COLOR_SETS.black.light } },
35375
+ secondColumnStripe: {
35376
+ style: { fillColor: TABLE_COLOR_SETS.black.light },
35377
+ border: {
35378
+ left: { color: TABLE_COLOR_SETS.black.medium, style: "thin" },
35379
+ right: { color: TABLE_COLOR_SETS.black.medium, style: "thin" },
35380
+ },
35381
+ },
35382
+ });
35383
+ const pivotLightWithColoredText = (colorSet) => ({
35384
+ category: "light",
35385
+ templateName: "pivotLightWithColoredText",
35386
+ primaryColor: colorSet.highlight,
35387
+ wholeTable: {
35388
+ style: { hideGridLines: true, textColor: colorSet.coloredText },
35389
+ border: {
35390
+ vertical: { color: colorSet.mediumBorder, style: "thin" },
35391
+ top: { color: colorSet.mediumBorder, style: "thin" },
35392
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35393
+ left: { color: colorSet.mediumBorder, style: "thin" },
35394
+ right: { color: colorSet.mediumBorder, style: "thin" },
35395
+ },
35396
+ },
35397
+ headerRow: {
35398
+ border: {
35399
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35400
+ vertical: { color: colorSet.mediumBorder, style: "thin" },
35401
+ },
35402
+ },
35403
+ totalRow: {
35404
+ border: { top: { color: colorSet.mediumBorder, style: "thin" } },
35405
+ },
35406
+ firstRowStripe: {
35407
+ style: { fillColor: colorSet.light },
35408
+ border: {
35409
+ top: { color: TABLE_COLOR_SETS.black.medium, style: "thin" },
35410
+ bottom: { color: TABLE_COLOR_SETS.black.medium, style: "thin" },
35411
+ },
35412
+ },
35413
+ secondColumnStripe: { style: { fillColor: colorSet.light } },
35414
+ });
35415
+ const pivotMediumHeavyColors = (colorSet) => ({
35416
+ category: "medium",
35417
+ templateName: "pivotMediumHeavyColors",
35418
+ primaryColor: colorSet.highlight,
35419
+ wholeTable: {
35420
+ style: { hideGridLines: true },
35421
+ border: { horizontal: { color: colorSet.light, style: "thin" } },
35422
+ },
35423
+ headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF" } },
35424
+ measureHeader: { border: { top: { color: colorSet.light, style: "thin" } } },
35425
+ mainSubHeaderRow: { style: { fillColor: colorSet.mediumBorder, textColor: "#FFFFFF" } },
35426
+ firstAlternatingSubHeaderRow: {
35427
+ style: { fillColor: colorSet.light },
35428
+ border: { bottom: { color: colorSet.highlight, style: "thin" } },
35429
+ },
35430
+ totalRow: {
35431
+ border: { top: { color: colorSet.highlight, style: "medium" } }, // @compatibility: should be double line
35432
+ style: { bold: true },
35433
+ },
35434
+ firstRowStripe: {
35435
+ border: {
35436
+ bottom: { color: colorSet.highlight, style: "thin" },
35437
+ top: { color: colorSet.highlight, style: "thin" },
35438
+ },
35439
+ },
35440
+ firstColumnStripe: {
35441
+ border: {
35442
+ left: { color: colorSet.highlight, style: "thin" },
35443
+ right: { color: colorSet.highlight, style: "thin" },
35444
+ },
35445
+ },
35446
+ });
35447
+ const pivotMediumLightColors = (colorSet) => ({
35448
+ category: "medium",
35449
+ templateName: "pivotMediumLightColors",
35450
+ primaryColor: colorSet.highlight,
35451
+ wholeTable: {
35452
+ style: { hideGridLines: true },
35453
+ border: {
35454
+ top: { color: colorSet.dark, style: "medium" },
35455
+ bottom: { color: colorSet.dark, style: "medium" },
35456
+ },
35457
+ },
35458
+ headerRow: { style: { fillColor: colorSet.highlight, textColor: "#FFFFFF", bold: true } },
35459
+ measureHeader: { border: { top: { color: colorSet.mediumBorder, style: "thin" } } },
35460
+ mainSubHeaderRow: { style: { fillColor: colorSet.light, bold: true } },
35461
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35462
+ totalRow: {
35463
+ border: { top: { color: colorSet.dark, style: "thin" } },
35464
+ style: { bold: true },
35465
+ },
35466
+ firstRowStripe: {
35467
+ border: {
35468
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35469
+ top: { color: colorSet.mediumBorder, style: "thin" },
35470
+ },
35471
+ },
35472
+ firstColumnStripe: {
35473
+ border: {
35474
+ left: { color: colorSet.mediumBorder, style: "thin" },
35475
+ right: { color: colorSet.mediumBorder, style: "thin" },
35476
+ },
35477
+ },
35478
+ });
35479
+ const pivotMediumBlackHeaders = (colorSet) => ({
35480
+ category: "medium",
35481
+ templateName: "pivotMediumBlackHeaders",
35482
+ primaryColor: colorSet.highlight,
35483
+ wholeTable: {
35484
+ style: { hideGridLines: true, fillColor: colorSet.light },
35485
+ border: { vertical: { color: colorSet.mediumBorder, style: "thin" } },
35486
+ },
35487
+ headerRow: { style: { fillColor: "#000000", textColor: "#FFFFFF" } },
35488
+ measureHeader: { border: { top: { color: "#FFFFFF", style: "thin" } } },
35489
+ mainSubHeaderRow: { style: { bold: true } },
35490
+ firstAlternatingSubHeaderRow: { style: { bold: true, textColor: "#808080" } },
35491
+ secondAlternatingSubHeaderRow: { style: { bold: true } },
35492
+ totalRow: {
35493
+ style: { fillColor: "#000000", textColor: "#FFFFFF" },
35494
+ border: { vertical: null },
35495
+ },
35496
+ firstRowStripe: {
35497
+ border: {
35498
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35499
+ top: { color: colorSet.mediumBorder, style: "thin" },
35500
+ },
35501
+ },
35502
+ });
35503
+ const pivotMediumColoredTexts = (colorSet) => ({
35504
+ category: "medium",
35505
+ templateName: "pivotMediumBlackHeaders",
35506
+ primaryColor: colorSet.highlight,
35507
+ wholeTable: {
35508
+ style: { hideGridLines: true, fillColor: colorSet.light, textColor: colorSet.coloredText },
35509
+ border: { vertical: { color: "#FFFFFF", style: "thin" } },
35510
+ },
35511
+ headerRow: {
35512
+ style: { bold: true },
35513
+ border: {
35514
+ vertical: { color: "#FFFFFF", style: "thin" },
35515
+ bottom: { color: "#FFFFFF", style: "thin" },
35516
+ },
35517
+ },
35518
+ firstColumn: { style: { fillColor: colorSet.medium } },
35519
+ measureHeader: { border: { top: { color: "#FFFFFF", style: "thin" } } },
35520
+ mainSubHeaderRow: { style: { bold: true, textColor: "#000000" } },
35521
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35522
+ secondAlternatingSubHeaderRow: { style: { bold: true } },
35523
+ totalRow: { style: { bold: true } },
35524
+ firstRowStripe: { style: { fillColor: colorSet.medium } },
35525
+ firstColumnStripe: { style: { fillColor: colorSet.medium } },
35526
+ });
35527
+ const pivotDarkWithDarkHeader = (colorSet) => ({
35528
+ category: "dark",
35529
+ templateName: "pivotDarkWithDarkHeader",
35530
+ primaryColor: colorSet.highlight,
35531
+ wholeTable: {
35532
+ style: { hideGridLines: true, fillColor: colorSet.medium },
35533
+ border: { horizontal: { color: colorSet.light, style: "thin" } },
35534
+ },
35535
+ headerRow: { style: { bold: true, fillColor: colorSet.dark, textColor: "#FFFFFF" } },
35536
+ measureHeader: { border: { top: { color: colorSet.light, style: "thin" } } },
35537
+ mainSubHeaderRow: { style: { bold: true, fillColor: colorSet.light } },
35538
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35539
+ totalRow: { style: { bold: true, fillColor: colorSet.dark, textColor: "#FFFFFF" } },
35540
+ secondRowStripe: { style: { fillColor: colorSet.mediumBorder } },
35541
+ firstColumnStripe: {
35542
+ border: {
35543
+ left: { color: colorSet.light, style: "thin" },
35544
+ right: { color: colorSet.light, style: "thin" },
35545
+ },
35546
+ },
35547
+ });
35548
+ const pivotDarkWithGrayHeader = (colorSet) => ({
35549
+ category: "dark",
35550
+ templateName: "pivotDarkWithGrayHeader",
35551
+ primaryColor: colorSet.highlight,
35552
+ wholeTable: { style: { hideGridLines: true, fillColor: colorSet.light } },
35553
+ headerRow: {
35554
+ style: { bold: true, fillColor: TABLE_COLOR_SETS.black.dark, textColor: "#FFFFFF" },
35555
+ },
35556
+ measureHeader: { border: { top: { color: colorSet.light, style: "medium" } } },
35557
+ mainSubHeaderRow: { style: { bold: true, fillColor: colorSet.medium } },
35558
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35559
+ totalRow: { style: { bold: true, fillColor: TABLE_COLOR_SETS.black.dark, textColor: "#FFFFFF" } },
35560
+ firstRowStripe: {
35561
+ border: {
35562
+ bottom: { color: colorSet.medium, style: "thin" },
35563
+ top: { color: colorSet.medium, style: "thin" },
35564
+ },
35565
+ },
35566
+ firstColumnStripe: {
35567
+ border: {
35568
+ left: { color: colorSet.mediumBorder, style: "thin" },
35569
+ right: { color: colorSet.mediumBorder, style: "thin" },
35570
+ },
35571
+ },
35572
+ });
35573
+ const pivotDarkWithBlackHeader = (colorSet) => ({
35574
+ category: "dark",
35575
+ templateName: "pivotDarkWithBlackHeader",
35576
+ primaryColor: colorSet.highlight,
35577
+ wholeTable: {
35578
+ style: { hideGridLines: true, fillColor: colorSet.highlight, textColor: "#FFFFFF" },
35579
+ },
35580
+ headerRow: { style: { bold: true, fillColor: "#000000" } },
35581
+ measureHeader: { border: { top: { color: colorSet.light, style: "thin" } } },
35582
+ mainSubHeaderRow: { style: { bold: true, fillColor: colorSet.dark } },
35583
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35584
+ totalRow: { style: { bold: true, fillColor: "#000000" } },
35585
+ firstRowStripe: {
35586
+ border: {
35587
+ bottom: { color: colorSet.mediumBorder, style: "thin" },
35588
+ top: { color: colorSet.mediumBorder, style: "thin" },
35589
+ },
35590
+ },
35591
+ firstColumnStripe: {
35592
+ border: {
35593
+ left: { color: colorSet.mediumBorder, style: "thin" },
35594
+ right: { color: colorSet.mediumBorder, style: "thin" },
35595
+ },
35596
+ },
35597
+ });
35598
+ const pivotDarkWithFirstColumn = (colorSet) => ({
35599
+ category: "dark",
35600
+ templateName: "pivotDarkWithFirstColumn",
35601
+ primaryColor: colorSet.highlight,
35602
+ wholeTable: {
35603
+ style: { hideGridLines: true, fillColor: colorSet.highlight, textColor: "#FFFFFF" },
35604
+ border: { vertical: { color: "#FFFFFF", style: "thin" } },
35605
+ },
35606
+ headerRow: {
35607
+ style: { fillColor: colorSet.dark },
35608
+ border: { bottom: { color: "#FFFFFF", style: "medium" } },
35609
+ },
35610
+ firstColumn: { style: { fillColor: colorSet.dark } },
35611
+ measureHeader: { border: { top: { color: colorSet.light, style: "thin" } } },
35612
+ mainSubHeaderRow: { style: { bold: true } },
35613
+ firstAlternatingSubHeaderRow: { style: { bold: true } },
35614
+ totalRow: {
35615
+ style: { bold: true, fillColor: colorSet.dark },
35616
+ border: { top: { color: "#FFFFFF", style: "medium" } },
35617
+ },
35618
+ secondRowStripe: { style: { fillColor: colorSet.mediumBorder } },
35619
+ firstColumnStripe: { style: { fillColor: colorSet.mediumBorder } },
35620
+ });
35621
+ const PIVOT_TABLE_PRESETS = {
35622
+ None: { category: "light", templateName: "none", primaryColor: "", displayName: _t("None") },
35623
+ };
35624
+ const colorSets = [
35625
+ TABLE_COLOR_SETS.black,
35626
+ TABLE_COLOR_SETS.lightBlue,
35627
+ TABLE_COLOR_SETS.red,
35628
+ TABLE_COLOR_SETS.lightGreen,
35629
+ TABLE_COLOR_SETS.purple,
35630
+ TABLE_COLOR_SETS.gray,
35631
+ TABLE_COLOR_SETS.orange,
35632
+ ];
35633
+ function addTemplatesToPresets(baseName, templates) {
35634
+ let index = 1;
35635
+ for (const template of templates) {
35636
+ for (const colorSet of colorSets) {
35637
+ const name = baseName + index++;
35638
+ const preset = {
35639
+ ...template(colorSet),
35640
+ displayName: getPresetDisplayName(colorSet.name, baseName, index - 1),
35641
+ };
35642
+ PIVOT_TABLE_PRESETS[name] = preset;
35643
+ }
35644
+ }
35645
+ }
35646
+ function getPresetDisplayName(colorName, baseName, index) {
35647
+ let category = "";
35648
+ if (baseName.includes("Light")) {
35649
+ category = TABLE_STYLE_CATEGORIES.light;
35650
+ }
35651
+ else if (baseName.includes("Medium")) {
35652
+ category = TABLE_STYLE_CATEGORIES.medium;
35653
+ }
35654
+ else if (baseName.includes("Dark")) {
35655
+ category = TABLE_STYLE_CATEGORIES.dark;
35656
+ }
35657
+ return `${category} ${colorName} ${index}`;
35658
+ }
35659
+ addTemplatesToPresets("PivotTableStyleLight", [
35660
+ pivotLightWithLightBorders,
35661
+ pivotLightWithMediumBorders,
35662
+ pivotLightWithGrayBands,
35663
+ pivotLightWithColoredText,
35664
+ ]);
35665
+ addTemplatesToPresets("PivotTableStyleMedium", [
35666
+ pivotMediumHeavyColors,
35667
+ pivotMediumLightColors,
35668
+ pivotMediumBlackHeaders,
35669
+ pivotMediumColoredTexts,
35670
+ ]);
35671
+ addTemplatesToPresets("PivotTableStyleDark", [
35672
+ pivotDarkWithDarkHeader,
35673
+ pivotDarkWithGrayHeader,
35674
+ pivotDarkWithBlackHeader,
35675
+ pivotDarkWithFirstColumn,
35676
+ ]);
35677
+ // Tweak some presets with the black color set
35678
+ PIVOT_TABLE_PRESETS["PivotTableStyleDark1"] = {
35679
+ ...PIVOT_TABLE_PRESETS["PivotTableStyleDark1"],
35680
+ ...pivotDarkWithDarkHeader({
35681
+ ...TABLE_COLOR_SETS.black,
35682
+ mediumBorder: darkenColor(TABLE_COLOR_SETS.black.medium, 0.1),
35683
+ }),
35684
+ };
35685
+ PIVOT_TABLE_PRESETS["PivotTableStyleDark15"] = {
35686
+ ...PIVOT_TABLE_PRESETS["PivotTableStyleDark15"],
35687
+ ...pivotDarkWithBlackHeader({
35688
+ ...TABLE_COLOR_SETS.black,
35689
+ highlight: TABLE_COLOR_SETS.gray.dark,
35690
+ mediumBorder: TABLE_COLOR_SETS.black.medium,
35691
+ }),
35692
+ };
35693
+ PIVOT_TABLE_PRESETS["PivotTableStyleDark22"] = {
35694
+ ...PIVOT_TABLE_PRESETS["PivotTableStyleDark22"],
35695
+ ...pivotDarkWithFirstColumn({
35696
+ ...TABLE_COLOR_SETS.black,
35697
+ highlight: TABLE_COLOR_SETS.gray.dark,
35698
+ mediumBorder: TABLE_COLOR_SETS.black.medium,
35699
+ }),
35700
+ };
35701
+ function pivotTableStyleIdToTableStyleId(pivotStyleId) {
35702
+ const template = PIVOT_TABLE_PRESETS[pivotStyleId];
35703
+ if (!template) {
35704
+ return "None";
35705
+ }
35706
+ return (Object.keys(TABLE_PRESETS).find((tableStyleId) => {
35707
+ const tablePreset = TABLE_PRESETS[tableStyleId];
35708
+ return (tablePreset.category === template.category &&
35709
+ tablePreset.primaryColor === template.primaryColor);
35710
+ }) || "None");
35711
+ }
35712
+
35038
35713
  class TableStylePlugin extends CorePlugin {
35039
35714
  static getters = [
35040
35715
  "getNewCustomTableStyleName",
@@ -35090,6 +35765,9 @@ class TableStylePlugin extends CorePlugin {
35090
35765
  }
35091
35766
  }
35092
35767
  getTableStyle(styleId) {
35768
+ if (PIVOT_TABLE_PRESETS[styleId]) {
35769
+ return PIVOT_TABLE_PRESETS[styleId];
35770
+ }
35093
35771
  if (!this.styles[styleId]) {
35094
35772
  throw new Error(`Table style ${styleId} does not exist`);
35095
35773
  }
@@ -35139,6 +35817,10 @@ const TABLE_ELEMENTS_BY_PRIORITY = [
35139
35817
  "firstColumn",
35140
35818
  "lastColumn",
35141
35819
  "headerRow",
35820
+ "measureHeader",
35821
+ "firstAlternatingSubHeaderRow",
35822
+ "secondAlternatingSubHeaderRow",
35823
+ "mainSubHeaderRow",
35142
35824
  "totalRow",
35143
35825
  ];
35144
35826
  /** Return the content zone of the table, ie. the table zone without the headers */
@@ -35161,40 +35843,42 @@ function createFilter(id, range, config, createRange) {
35161
35843
  filteredRange: filteredZone.top > filteredZone.bottom ? undefined : filteredRange,
35162
35844
  };
35163
35845
  }
35164
- function getComputedTableStyle(tableConfig, style, numberOfCols, numberOfRows) {
35846
+ function getComputedTableStyle(tableConfig, style, tableMetaData) {
35165
35847
  return {
35166
- borders: getAllTableBorders(tableConfig, style, numberOfCols, numberOfRows),
35167
- styles: getAllTableStyles(tableConfig, style, numberOfCols, numberOfRows),
35848
+ borders: getAllTableBorders(tableConfig, style, tableMetaData),
35849
+ styles: getAllTableStyles(tableConfig, style, tableMetaData),
35168
35850
  };
35169
35851
  }
35170
- function getAllTableBorders(tableConfig, style, nOfCols, nOfRows) {
35852
+ function getAllTableBorders(tableConfig, style, tableMetaData) {
35853
+ const { numberOfCols: nOfCols, numberOfRows: nOfRows } = tableMetaData;
35171
35854
  const borders = generateMatrix(nOfCols, nOfRows, () => ({}));
35172
35855
  for (const tableElement of TABLE_ELEMENTS_BY_PRIORITY) {
35173
35856
  const styleBorder = style[tableElement]?.border;
35174
- if (!styleBorder)
35857
+ if (!styleBorder) {
35175
35858
  continue;
35176
- const zones = getTableElementZones(tableElement, tableConfig, nOfCols, nOfRows);
35859
+ }
35860
+ const zones = getTableElementZones(tableElement, tableConfig, tableMetaData);
35177
35861
  for (const zone of zones) {
35178
35862
  for (let col = zone.left; col <= zone.right; col++) {
35179
35863
  for (let row = zone.top; row <= zone.bottom; row++) {
35180
35864
  // Special case: we don't want borders inside the headers rows
35181
35865
  const noInsideBorder = tableElement === "wholeTable" && row <= tableConfig.numberOfHeaders - 1;
35182
- if (row === zone.top && styleBorder?.top) {
35866
+ if (row === zone.top && styleBorder?.top !== undefined) {
35183
35867
  setBorderDescr(borders, "top", styleBorder.top, col, row, nOfCols, nOfRows);
35184
35868
  }
35185
- else if (row !== zone.top && !noInsideBorder && styleBorder?.horizontal) {
35869
+ else if (row !== zone.top && !noInsideBorder && styleBorder?.horizontal !== undefined) {
35186
35870
  setBorderDescr(borders, "top", styleBorder.horizontal, col, row, nOfCols, nOfRows);
35187
35871
  }
35188
- if (row === zone.bottom && styleBorder?.bottom) {
35872
+ if (row === zone.bottom && styleBorder?.bottom !== undefined) {
35189
35873
  setBorderDescr(borders, "bottom", styleBorder.bottom, col, row, nOfCols, nOfRows);
35190
35874
  }
35191
- if (col === zone.left && styleBorder?.left) {
35875
+ if (col === zone.left && styleBorder?.left !== undefined) {
35192
35876
  setBorderDescr(borders, "left", styleBorder.left, col, row, nOfCols, nOfRows);
35193
35877
  }
35194
- if (col === zone.right && styleBorder?.right) {
35878
+ if (col === zone.right && styleBorder?.right !== undefined) {
35195
35879
  setBorderDescr(borders, "right", styleBorder.right, col, row, nOfCols, nOfRows);
35196
35880
  }
35197
- else if (col !== zone.right && !noInsideBorder && styleBorder?.vertical) {
35881
+ else if (col !== zone.right && !noInsideBorder && styleBorder?.vertical !== undefined) {
35198
35882
  setBorderDescr(borders, "right", styleBorder.vertical, col, row, nOfCols, nOfRows);
35199
35883
  }
35200
35884
  }
@@ -35211,40 +35895,40 @@ function getAllTableBorders(tableConfig, style, nOfCols, nOfRows) {
35211
35895
  function setBorderDescr(computedBorders, dir, borderDescr, col, row, numberOfCols, numberOfRows) {
35212
35896
  switch (dir) {
35213
35897
  case "top":
35214
- computedBorders[col][row].top = borderDescr;
35898
+ computedBorders[col][row].top = borderDescr ?? undefined;
35215
35899
  if (row !== 0) {
35216
- computedBorders[col][row - 1].bottom = borderDescr;
35900
+ computedBorders[col][row - 1].bottom = borderDescr ?? undefined;
35217
35901
  }
35218
35902
  return;
35219
35903
  case "bottom":
35220
- computedBorders[col][row].bottom = borderDescr;
35904
+ computedBorders[col][row].bottom = borderDescr ?? undefined;
35221
35905
  if (row !== numberOfRows - 1) {
35222
- computedBorders[col][row + 1].top = borderDescr;
35906
+ computedBorders[col][row + 1].top = borderDescr ?? undefined;
35223
35907
  }
35224
35908
  return;
35225
35909
  case "left":
35226
- computedBorders[col][row].left = borderDescr;
35910
+ computedBorders[col][row].left = borderDescr ?? undefined;
35227
35911
  if (col !== 0) {
35228
- computedBorders[col - 1][row].right = borderDescr;
35912
+ computedBorders[col - 1][row].right = borderDescr ?? undefined;
35229
35913
  }
35230
35914
  return;
35231
35915
  case "right":
35232
- computedBorders[col][row].right = borderDescr;
35916
+ computedBorders[col][row].right = borderDescr ?? undefined;
35233
35917
  if (col !== numberOfCols - 1) {
35234
- computedBorders[col + 1][row].left = borderDescr;
35918
+ computedBorders[col + 1][row].left = borderDescr ?? undefined;
35235
35919
  }
35236
35920
  return;
35237
35921
  }
35238
35922
  }
35239
- function getAllTableStyles(tableConfig, style, numberOfCols, numberOfRows) {
35923
+ function getAllTableStyles(tableConfig, style, tableMetaData) {
35924
+ const { numberOfCols, numberOfRows } = tableMetaData;
35240
35925
  const styles = generateMatrix(numberOfCols, numberOfRows, () => ({}));
35241
35926
  for (const tableElement of TABLE_ELEMENTS_BY_PRIORITY) {
35242
35927
  const tableElStyle = style[tableElement];
35243
- const bold = isTableElementInBold(tableElement);
35244
- if (!tableElStyle && !bold) {
35928
+ if (!tableElStyle) {
35245
35929
  continue;
35246
35930
  }
35247
- const zones = getTableElementZones(tableElement, tableConfig, numberOfCols, numberOfRows);
35931
+ const zones = getTableElementZones(tableElement, tableConfig, tableMetaData);
35248
35932
  for (const zone of zones) {
35249
35933
  for (let col = zone.left; col <= zone.right; col++) {
35250
35934
  for (let row = zone.top; row <= zone.bottom; row++) {
@@ -35255,22 +35939,14 @@ function getAllTableStyles(tableConfig, style, numberOfCols, numberOfRows) {
35255
35939
  ...styles[col][row],
35256
35940
  ...tableElStyle?.style,
35257
35941
  };
35258
- if (bold) {
35259
- styles[col][row].bold = true;
35260
- }
35261
35942
  }
35262
35943
  }
35263
35944
  }
35264
35945
  }
35265
35946
  return styles;
35266
35947
  }
35267
- function isTableElementInBold(tableElement) {
35268
- return (tableElement === "firstColumn" ||
35269
- tableElement === "lastColumn" ||
35270
- tableElement === "headerRow" ||
35271
- tableElement === "totalRow");
35272
- }
35273
- function getTableElementZones(el, tableConfig, numberOfCols, numberOfRows) {
35948
+ function getTableElementZones(el, tableConfig, tableMetaData) {
35949
+ const { numberOfCols, numberOfRows } = tableMetaData;
35274
35950
  const zones = [];
35275
35951
  const headerRows = Math.min(tableConfig.numberOfHeaders, numberOfRows);
35276
35952
  const totalRows = tableConfig.totalRow ? 1 : 0;
@@ -35281,51 +35957,84 @@ function getTableElementZones(el, tableConfig, numberOfCols, numberOfRows) {
35281
35957
  zones.push({ top: 0, left: 0, bottom: lastRow, right: lastCol });
35282
35958
  break;
35283
35959
  case "firstColumn":
35284
- if (!tableConfig.firstColumn)
35960
+ if (!tableConfig.firstColumn) {
35285
35961
  break;
35962
+ }
35286
35963
  zones.push({ top: 0, left: 0, bottom: lastRow, right: 0 });
35287
35964
  break;
35288
35965
  case "lastColumn":
35289
- if (!tableConfig.lastColumn)
35966
+ if (!tableConfig.lastColumn) {
35290
35967
  break;
35968
+ }
35291
35969
  zones.push({ top: 0, left: lastCol, bottom: lastRow, right: lastCol });
35292
35970
  break;
35293
35971
  case "headerRow":
35294
- if (!tableConfig.numberOfHeaders)
35972
+ if (!tableConfig.numberOfHeaders) {
35295
35973
  break;
35974
+ }
35296
35975
  zones.push({ top: 0, left: 0, bottom: headerRows - 1, right: lastCol });
35297
35976
  break;
35298
35977
  case "totalRow":
35299
- if (!tableConfig.totalRow)
35978
+ if (!tableConfig.totalRow) {
35300
35979
  break;
35980
+ }
35301
35981
  zones.push({ top: lastRow, left: 0, bottom: lastRow, right: lastCol });
35302
35982
  break;
35303
35983
  case "firstRowStripe":
35304
- if (!tableConfig.bandedRows)
35984
+ if (!tableConfig.bandedRows) {
35305
35985
  break;
35986
+ }
35306
35987
  for (let i = headerRows; i < numberOfRows - totalRows; i += 2) {
35307
35988
  zones.push({ top: i, left: 0, bottom: i, right: lastCol });
35308
35989
  }
35309
35990
  break;
35310
35991
  case "secondRowStripe":
35311
- if (!tableConfig.bandedRows)
35992
+ if (!tableConfig.bandedRows) {
35312
35993
  break;
35994
+ }
35313
35995
  for (let i = headerRows + 1; i < numberOfRows - totalRows; i += 2) {
35314
35996
  zones.push({ top: i, left: 0, bottom: i, right: lastCol });
35315
35997
  }
35316
35998
  break;
35317
- case "firstColumnStripe":
35318
- if (!tableConfig.bandedColumns)
35999
+ case "firstColumnStripe": {
36000
+ if (!tableConfig.bandedColumns) {
35319
36001
  break;
36002
+ }
36003
+ const bottom = tableMetaData.mode === "pivot" ? lastRow : lastRow - totalRows;
35320
36004
  for (let i = 0; i < numberOfCols; i += 2) {
35321
- zones.push({ top: headerRows, left: i, bottom: lastRow - totalRows, right: i });
36005
+ zones.push({ top: headerRows, left: i, bottom, right: i });
35322
36006
  }
35323
36007
  break;
35324
- case "secondColumnStripe":
35325
- if (!tableConfig.bandedColumns)
36008
+ }
36009
+ case "secondColumnStripe": {
36010
+ if (!tableConfig.bandedColumns) {
35326
36011
  break;
36012
+ }
36013
+ const bottom = tableMetaData.mode === "pivot" ? lastRow : lastRow - totalRows;
35327
36014
  for (let i = 1; i < numberOfCols; i += 2) {
35328
- zones.push({ top: headerRows, left: i, bottom: lastRow - totalRows, right: i });
36015
+ zones.push({ top: headerRows, left: i, bottom, right: i });
36016
+ }
36017
+ break;
36018
+ }
36019
+ case "mainSubHeaderRow":
36020
+ for (const row of tableMetaData.mainSubHeaderRows || []) {
36021
+ zones.push({ top: row, bottom: row, left: 0, right: tableMetaData.numberOfCols - 1 });
36022
+ }
36023
+ break;
36024
+ case "firstAlternatingSubHeaderRow":
36025
+ for (const row of tableMetaData.firstAlternatingSubHeaderRows || []) {
36026
+ zones.push({ top: row, bottom: row, left: 0, right: tableMetaData.numberOfCols - 1 });
36027
+ }
36028
+ break;
36029
+ case "secondAlternatingSubHeaderRow":
36030
+ for (const row of tableMetaData.secondAlternatingSubHeaderRows || []) {
36031
+ zones.push({ top: row, bottom: row, left: 0, right: tableMetaData.numberOfCols - 1 });
36032
+ }
36033
+ break;
36034
+ case "measureHeader":
36035
+ if (tableMetaData.measureRow !== undefined && tableMetaData.numberOfCols > 1) {
36036
+ const row = tableMetaData.measureRow;
36037
+ zones.push({ top: row, bottom: row, left: 1, right: tableMetaData.numberOfCols - 1 });
35329
36038
  }
35330
36039
  break;
35331
36040
  }
@@ -37884,8 +38593,9 @@ class EvaluationPlugin extends CoreViewPlugin {
37884
38593
  */
37885
38594
  getRangeFormattedValues(range) {
37886
38595
  const sheet = this.getters.tryGetSheet(range.sheetId);
37887
- if (sheet === undefined)
38596
+ if (sheet === undefined) {
37888
38597
  return [];
38598
+ }
37889
38599
  return this.mapVisiblePositions(range, (p) => this.getters.getEvaluatedCell(p).formattedValue);
37890
38600
  }
37891
38601
  /**
@@ -37893,8 +38603,9 @@ class EvaluationPlugin extends CoreViewPlugin {
37893
38603
  */
37894
38604
  getRangeValues(range) {
37895
38605
  const sheet = this.getters.tryGetSheet(range.sheetId);
37896
- if (sheet === undefined)
38606
+ if (sheet === undefined) {
37897
38607
  return [];
38608
+ }
37898
38609
  return this.mapVisiblePositions(range, (p) => this.getters.getEvaluatedCell(p).value);
37899
38610
  }
37900
38611
  /**
@@ -37902,8 +38613,9 @@ class EvaluationPlugin extends CoreViewPlugin {
37902
38613
  */
37903
38614
  getRangeFormats(range) {
37904
38615
  const sheet = this.getters.tryGetSheet(range.sheetId);
37905
- if (sheet === undefined)
38616
+ if (sheet === undefined) {
37906
38617
  return [];
38618
+ }
37907
38619
  return this.getters.getEvaluatedCellsInZone(sheet.id, range.zone).map((cell) => cell.format);
37908
38620
  }
37909
38621
  getEvaluatedCell(position) {
@@ -38066,8 +38778,9 @@ function getDefaultContextFont(fontSize, bold = false, italic = false) {
38066
38778
  return `${italicStr} ${weight} ${fontSize}px ${DEFAULT_FONT}`;
38067
38779
  }
38068
38780
  function computeMultilineTextSize(context, textLines, style = {}, fontUnit = "pt") {
38069
- if (!textLines.length)
38781
+ if (!textLines.length) {
38070
38782
  return { width: 0, height: 0 };
38783
+ }
38071
38784
  const font = computeTextFont(style, fontUnit);
38072
38785
  const sizes = textLines.map((line) => computeCachedTextDimension(context, line, font));
38073
38786
  const height = computeTextLinesHeight(sizes[0].height, textLines.length);
@@ -38159,10 +38872,12 @@ function splitWordToSpecificWidth(ctx, word, width, style) {
38159
38872
  * line if it contains NEWLINE characters, or if it's longer than the given width.
38160
38873
  */
38161
38874
  function splitTextToWidth(ctx, text, style, width) {
38162
- if (!style)
38875
+ if (!style) {
38163
38876
  style = {};
38164
- if (isMarkdownLink(text))
38877
+ }
38878
+ if (isMarkdownLink(text)) {
38165
38879
  text = parseMarkdownLink(text).label;
38880
+ }
38166
38881
  const brokenText = [];
38167
38882
  // Checking if text contains NEWLINE before split makes it very slightly slower if text contains it,
38168
38883
  // but 5-10x faster if it doesn't
@@ -38225,10 +38940,12 @@ function splitTextToWidth(ctx, text, style, width) {
38225
38940
  */
38226
38941
  function getFontSizeMatchingWidth(lineWidth, maxFontSize, getTextWidth, precision = 0.25) {
38227
38942
  let minFontSize = 1;
38228
- if (getTextWidth(minFontSize) > lineWidth)
38943
+ if (getTextWidth(minFontSize) > lineWidth) {
38229
38944
  return minFontSize;
38230
- if (getTextWidth(maxFontSize) < lineWidth)
38945
+ }
38946
+ if (getTextWidth(maxFontSize) < lineWidth) {
38231
38947
  return maxFontSize;
38948
+ }
38232
38949
  // Dichotomic search
38233
38950
  let fontSize = (minFontSize + maxFontSize) / 2;
38234
38951
  let currentTextWidth = getTextWidth(fontSize);
@@ -38763,16 +39480,10 @@ class DynamicTablesPlugin extends CoreViewPlugin {
38763
39480
  const tables = [];
38764
39481
  const coreTables = this.getters.getCoreTables(sheetId);
38765
39482
  // First we create the static tables, so we can use them to compute collision with dynamic tables
38766
- for (const table of coreTables) {
38767
- if (table.type === "dynamic")
38768
- continue;
38769
- tables.push(table);
38770
- }
38771
- const staticTables = [...tables];
39483
+ const staticTables = [...coreTables].filter((table) => table.type !== "dynamic");
39484
+ tables.push(...staticTables);
38772
39485
  // Then we create the dynamic tables
38773
- for (const coreTable of coreTables) {
38774
- if (coreTable.type !== "dynamic")
38775
- continue;
39486
+ for (const coreTable of this.getDynamicTables(sheetId)) {
38776
39487
  const table = this.coreTableToTable(sheetId, coreTable);
38777
39488
  let tableZone = table.range.zone;
38778
39489
  // Reduce the zone to avoid collision with static tables. Per design, dynamic tables can't overlap with other
@@ -38786,6 +39497,50 @@ class DynamicTablesPlugin extends CoreViewPlugin {
38786
39497
  }
38787
39498
  return tables;
38788
39499
  }
39500
+ getDynamicTables(sheetId) {
39501
+ const dynamicTablesFromCore = this.getters
39502
+ .getCoreTables(sheetId)
39503
+ .filter((table) => table.type === "dynamic");
39504
+ const pivotTables = this.getTablesFromPivots(sheetId);
39505
+ const pivotRanges = new Set(pivotTables.map((t) => this.getters.getRangeString(t.range, sheetId)));
39506
+ const nonPivotDynamicTables = dynamicTablesFromCore.filter((t) => !pivotRanges.has(this.getters.getRangeString(t.range, sheetId)));
39507
+ return [...pivotTables, ...nonPivotDynamicTables];
39508
+ }
39509
+ getTablesFromPivots(sheetId) {
39510
+ const tables = [];
39511
+ for (const { position, pivotStyle, pivotId } of this.getters.getAllPivotArrayFormulas()) {
39512
+ const spreadZone = this.getters.getSpreadZone(position);
39513
+ const cell = this.getters.getCell(position);
39514
+ if (position.sheetId !== sheetId ||
39515
+ !spreadZone ||
39516
+ !cell ||
39517
+ pivotStyle.tableStyleId === "None") {
39518
+ continue;
39519
+ }
39520
+ tables.push({
39521
+ type: "dynamic",
39522
+ id: "pivot_table_" + pivotId + "_" + cell.id,
39523
+ range: this.getters.getRangeFromZone(sheetId, positionToZone(position)),
39524
+ config: this.getTableConfigFromPivotStyle(pivotId, pivotStyle),
39525
+ isPivotTable: true,
39526
+ });
39527
+ }
39528
+ return tables;
39529
+ }
39530
+ getTableConfigFromPivotStyle(pivotId, pivotStyle) {
39531
+ const pivot = this.getters.getPivot(pivotId);
39532
+ const pivotTable = pivot.getCollapsedTableStructure();
39533
+ return {
39534
+ hasFilters: pivotStyle.hasFilters,
39535
+ totalRow: pivotStyle.displayTotals,
39536
+ firstColumn: true,
39537
+ lastColumn: true,
39538
+ numberOfHeaders: pivotTable.getPivotTableDimensions(pivotStyle).numberOfHeaderRows,
39539
+ bandedRows: pivotStyle.bandedRows,
39540
+ bandedColumns: pivotStyle.bandedColumns,
39541
+ styleId: pivotStyle.tableStyleId,
39542
+ };
39543
+ }
38789
39544
  getFilters(sheetId) {
38790
39545
  return this.getTables(sheetId)
38791
39546
  .filter((table) => table.config.hasFilters)
@@ -38865,7 +39620,7 @@ class DynamicTablesPlugin extends CoreViewPlugin {
38865
39620
  const zone = this.getters.getSpreadZone(tablePosition) ?? table.range.zone;
38866
39621
  const range = this.getters.getRangeFromZone(sheetId, zone);
38867
39622
  const filters = this.getDynamicTableFilters(sheetId, table, zone);
38868
- return { id: table.id, range, filters, config: table.config };
39623
+ return { id: table.id, range, filters, config: table.config, isPivotTable: table.isPivotTable };
38869
39624
  }
38870
39625
  getDynamicTableFilters(sheetId, table, tableZone) {
38871
39626
  const filters = [];
@@ -39653,8 +40408,9 @@ async function chartToImageUrl(runtime, figure, type) {
39653
40408
  }
39654
40409
  // TODO: make a registry of chart types to their rendering functions
39655
40410
  else {
39656
- if (!globalThis.OffscreenCanvas)
40411
+ if (!globalThis.OffscreenCanvas) {
39657
40412
  throw new Error(`converting a ${type} chart to an image using OffscreenCanvas is not supported in this environment`);
40413
+ }
39658
40414
  if (type === "scorecard") {
39659
40415
  const design = getScorecardConfiguration(figure, runtime);
39660
40416
  drawScoreChart(design, canvas);
@@ -39748,8 +40504,9 @@ class EvaluationChartPlugin extends CoreViewPlugin {
39748
40504
  * Get the background and textColor of a chart based on the color of the first cell of the main range of the chart.
39749
40505
  */
39750
40506
  getStyleOfSingleCellChart(chartBackground, mainRange) {
39751
- if (chartBackground)
40507
+ if (chartBackground) {
39752
40508
  return { background: chartBackground, fontColor: chartFontColor(chartBackground) };
40509
+ }
39753
40510
  if (!mainRange) {
39754
40511
  return {
39755
40512
  background: BACKGROUND_CHART_COLOR,
@@ -39904,8 +40661,9 @@ class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
39904
40661
  return value;
39905
40662
  });
39906
40663
  if (this.getRuleResultForTarget(target, { ...cf.rule, values }, preComputedCriterion)) {
39907
- if (!computedStyle[col])
40664
+ if (!computedStyle[col]) {
39908
40665
  computedStyle[col] = [];
40666
+ }
39909
40667
  // we must combine all the properties of all the CF rules applied to the given cell
39910
40668
  computedStyle[col][row] = Object.assign(computedStyle[col]?.[row] || {}, cf.rule.style);
39911
40669
  }
@@ -39920,8 +40678,9 @@ class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
39920
40678
  getComputedIcons(sheetId) {
39921
40679
  const computedIcons = {};
39922
40680
  for (const cf of this.getters.getConditionalFormats(sheetId).reverse()) {
39923
- if (cf.rule.type !== "IconSetRule")
40681
+ if (cf.rule.type !== "IconSetRule") {
39924
40682
  continue;
40683
+ }
39925
40684
  for (const range of cf.ranges) {
39926
40685
  this.applyIcon(sheetId, range, cf.rule, computedIcons);
39927
40686
  }
@@ -39931,8 +40690,9 @@ class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
39931
40690
  getComputedDataBars(sheetId) {
39932
40691
  const computedDataBars = {};
39933
40692
  for (const cf of this.getters.getConditionalFormats(sheetId).reverse()) {
39934
- if (cf.rule.type !== "DataBarRule")
40693
+ if (cf.rule.type !== "DataBarRule") {
39935
40694
  continue;
40695
+ }
39936
40696
  for (const range of cf.ranges) {
39937
40697
  this.applyDataBar(sheetId, range, cf.rule, computedDataBars);
39938
40698
  }
@@ -40024,8 +40784,9 @@ class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
40024
40784
  // values negatives or 0 are ignored
40025
40785
  continue;
40026
40786
  }
40027
- if (!computedDataBars[col])
40787
+ if (!computedDataBars[col]) {
40028
40788
  computedDataBars[col] = [];
40789
+ }
40029
40790
  computedDataBars[col][row] = {
40030
40791
  color: colorNumberToHex(color),
40031
40792
  percentage: (cell.value * 100) / max,
@@ -40058,8 +40819,9 @@ class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
40058
40819
  const cell = this.getters.getEvaluatedCell({ sheetId, col, row });
40059
40820
  if (cell.type === CellValueType.number) {
40060
40821
  const value = clip(cell.value, minValue, maxValue);
40061
- if (!computedStyle[col])
40822
+ if (!computedStyle[col]) {
40062
40823
  computedStyle[col] = [];
40824
+ }
40063
40825
  computedStyle[col][row] = computedStyle[col]?.[row] || {};
40064
40826
  computedStyle[col][row].fillColor = colorScale(value);
40065
40827
  }
@@ -40297,6 +41059,56 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
40297
41059
  }
40298
41060
  }
40299
41061
 
41062
+ const trackedFormulas = ["SUBTOTAL", "PIVOT"];
41063
+ class FormulaTrackerPlugin extends CoreViewPlugin {
41064
+ static getters = ["getCellsWithTrackedFormula"];
41065
+ trackedCells = {};
41066
+ handle(cmd) {
41067
+ switch (cmd.type) {
41068
+ case "START": {
41069
+ for (const formula of trackedFormulas) {
41070
+ this.trackedCells[formula] = {};
41071
+ }
41072
+ for (const sheetId of this.getters.getSheetIds()) {
41073
+ const cells = this.getters.getCells(sheetId);
41074
+ for (const cellId in cells) {
41075
+ const cell = cells[cellId];
41076
+ for (const formula of trackedFormulas) {
41077
+ if (doesCellContainFunction(cell, formula)) {
41078
+ this.history.update("trackedCells", formula, cell.id, true);
41079
+ }
41080
+ }
41081
+ }
41082
+ }
41083
+ break;
41084
+ }
41085
+ case "UPDATE_CELL": {
41086
+ if (!("content" in cmd)) {
41087
+ return;
41088
+ }
41089
+ const cell = this.getters.getCell(cmd);
41090
+ // We don't update `this.trackedCells` and rely on `getCellsWithTrackedFormula` filtering out non-existing cells.
41091
+ // We cannot store the id in the beforeHandle, because the cell is already deleted in the beforeHandle of the sheet plugin
41092
+ if (!cell) {
41093
+ return;
41094
+ }
41095
+ for (const formula of trackedFormulas) {
41096
+ if (doesCellContainFunction(cell, formula)) {
41097
+ this.history.update("trackedCells", formula, cell.id, true);
41098
+ }
41099
+ else if (this.trackedCells[formula][cell.id]) {
41100
+ this.history.update("trackedCells", formula, cell.id, undefined);
41101
+ }
41102
+ }
41103
+ break;
41104
+ }
41105
+ }
41106
+ }
41107
+ getCellsWithTrackedFormula(formula) {
41108
+ return Object.keys(this.trackedCells[formula] || {}).filter((cellId) => this.trackedCells[formula][cellId] && this.getters.tryGetCellPosition(cellId));
41109
+ }
41110
+ }
41111
+
40300
41112
  class HeaderSizeUIPlugin extends CoreViewPlugin {
40301
41113
  static getters = ["getRowSize", "getHeaderSize", "getMaxAnchorOffset"];
40302
41114
  tallestCellInRow = {};
@@ -40587,14 +41399,16 @@ const PERCENT_FORMAT = "0.00%";
40587
41399
  function withPivotPresentationLayer (PivotClass) {
40588
41400
  class PivotPresentationLayer extends PivotClass {
40589
41401
  getters;
41402
+ pivotId;
40590
41403
  cache = {};
40591
41404
  rankAsc = {};
40592
41405
  rankDesc = {};
40593
41406
  runningTotal = {};
40594
41407
  runningTotalInPercent = {};
40595
- constructor(custom, params) {
41408
+ constructor(pivotId, custom, params) {
40596
41409
  super(custom, params);
40597
41410
  this.getters = params.getters;
41411
+ this.pivotId = pivotId;
40598
41412
  }
40599
41413
  markAsDirtyForEvaluation() {
40600
41414
  this.cache = {};
@@ -40644,7 +41458,7 @@ function withPivotPresentationLayer (PivotClass) {
40644
41458
  return handleError(error, measure.aggregator.toUpperCase());
40645
41459
  }
40646
41460
  }
40647
- const formula = this.getters.getMeasureCompiledFormula(measure);
41461
+ const formula = this.getters.getMeasureCompiledFormula(this.pivotId, measure);
40648
41462
  const getSymbolValue = (symbolName) => {
40649
41463
  const { columns, rows } = this.definition;
40650
41464
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
@@ -41155,6 +41969,8 @@ class PivotUIPlugin extends CoreViewPlugin {
41155
41969
  "generateNewCalculatedMeasureName",
41156
41970
  "isPivotUnused",
41157
41971
  "isSpillPivotFormula",
41972
+ "getAllPivotArrayFormulas",
41973
+ "getPivotStyleAtPosition",
41158
41974
  ];
41159
41975
  pivots = {};
41160
41976
  unusedPivotsInFormulas;
@@ -41302,8 +42118,7 @@ class PivotUIPlugin extends CoreViewPlugin {
41302
42118
  if (!pivot.isValid()) {
41303
42119
  return EMPTY_PIVOT_CELL;
41304
42120
  }
41305
- if (functionName === "PIVOT" &&
41306
- !cell.content.replaceAll(" ", "").toUpperCase().startsWith("=PIVOT")) {
42121
+ if (functionName === "PIVOT" && !this.isMainFunctionPivotSpreadFunction(cell)) {
41307
42122
  return EMPTY_PIVOT_CELL;
41308
42123
  }
41309
42124
  if (functionName === "PIVOT") {
@@ -41391,7 +42206,7 @@ class PivotUIPlugin extends CoreViewPlugin {
41391
42206
  const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
41392
42207
  if (!(pivotId in this.pivots)) {
41393
42208
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
41394
- this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
42209
+ this.pivots[pivotId] = new Pivot(pivotId, this.custom, { definition, getters: this.getters });
41395
42210
  }
41396
42211
  else if (recreate) {
41397
42212
  this.pivots[pivotId].onDefinitionChange(definition);
@@ -41418,6 +42233,42 @@ class PivotUIPlugin extends CoreViewPlugin {
41418
42233
  this.unusedPivotsInFormulas = [...unusedPivots];
41419
42234
  return this.unusedPivotsInFormulas;
41420
42235
  }
42236
+ getAllPivotArrayFormulas() {
42237
+ const result = [];
42238
+ for (const cellId of this.getters.getCellsWithTrackedFormula("PIVOT")) {
42239
+ const position = this.getters.getCellPosition(cellId);
42240
+ const pivotInfo = this.getPivotStyleAtPosition(position);
42241
+ if (pivotInfo) {
42242
+ result.push({ position, ...pivotInfo });
42243
+ }
42244
+ }
42245
+ return result;
42246
+ }
42247
+ getPivotStyleAtPosition(position) {
42248
+ const cell = this.getters.getCell(position);
42249
+ if (!cell || !cell.isFormula || !this.isMainFunctionPivotSpreadFunction(cell)) {
42250
+ return undefined;
42251
+ }
42252
+ const pivotFunction = this.getFirstPivotFunction(position.sheetId, cell.compiledFormula.tokens);
42253
+ if (!pivotFunction || pivotFunction.functionName !== "PIVOT") {
42254
+ return undefined;
42255
+ }
42256
+ const pivotIdArg = pivotFunction.args[0];
42257
+ if (!pivotIdArg) {
42258
+ return undefined;
42259
+ }
42260
+ const pivotId = this.getters.getPivotId(pivotIdArg.toString());
42261
+ if (!pivotId) {
42262
+ return undefined;
42263
+ }
42264
+ 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());
42265
+ return { pivotStyle, pivotId };
42266
+ }
42267
+ isMainFunctionPivotSpreadFunction(cell) {
42268
+ const tokens = cell.compiledFormula.tokens;
42269
+ const firstNonSpaceToken = tokens.find((token, i) => i > 0 && token.type !== "SPACE");
42270
+ return (firstNonSpaceToken?.type === "SYMBOL" && firstNonSpaceToken.value.toUpperCase() === "PIVOT");
42271
+ }
41421
42272
  }
41422
42273
 
41423
42274
  /**
@@ -41806,6 +42657,31 @@ function getDateIntervals(dates) {
41806
42657
  return res.slice(1);
41807
42658
  }
41808
42659
 
42660
+ /**
42661
+ * UI plugins handle any transient data required to display a spreadsheet.
42662
+ * They can draw on the grid canvas.
42663
+ */
42664
+ class UIPlugin extends BasePlugin {
42665
+ static layers = [];
42666
+ getters;
42667
+ ui;
42668
+ selection;
42669
+ dispatch;
42670
+ canDispatch;
42671
+ constructor({ getters, stateObserver, dispatch, canDispatch, uiActions, selection, }) {
42672
+ super(stateObserver);
42673
+ this.getters = getters;
42674
+ this.ui = uiActions;
42675
+ this.selection = selection;
42676
+ this.dispatch = dispatch;
42677
+ this.canDispatch = canDispatch;
42678
+ }
42679
+ // ---------------------------------------------------------------------------
42680
+ // Grid rendering
42681
+ // ---------------------------------------------------------------------------
42682
+ drawLayer(ctx, layer) { }
42683
+ }
42684
+
41809
42685
  /**
41810
42686
  * This plugin manage the autofill.
41811
42687
  *
@@ -42656,17 +43532,17 @@ class TableComputedStylePlugin extends UIPlugin {
42656
43532
  }
42657
43533
  computeTableStyle(sheetId, table) {
42658
43534
  return lazy(() => {
42659
- const { config, numberOfCols, numberOfRows } = this.getTableRuntimeConfig(sheetId, table);
42660
43535
  const style = this.getters.getTableStyle(table.config.styleId);
42661
- const relativeTableStyle = getComputedTableStyle(config, style, numberOfCols, numberOfRows);
43536
+ const { tableMetaData, config } = this.getTableMetaData(sheetId, table);
43537
+ const relativeTableStyle = getComputedTableStyle(config, style, tableMetaData);
42662
43538
  // Return the style with sheet coordinates instead of tables coordinates
42663
43539
  const mapping = this.getTableMapping(sheetId, table);
42664
43540
  const absoluteTableStyle = { borders: {}, styles: {} };
42665
- for (let col = 0; col < numberOfCols; col++) {
43541
+ for (let col = 0; col < tableMetaData.numberOfCols; col++) {
42666
43542
  const colInSheet = mapping.colMapping[col];
42667
43543
  absoluteTableStyle.borders[colInSheet] = {};
42668
43544
  absoluteTableStyle.styles[colInSheet] = {};
42669
- for (let row = 0; row < numberOfRows; row++) {
43545
+ for (let row = 0; row < tableMetaData.numberOfRows; row++) {
42670
43546
  const rowInSheet = mapping.rowMapping[row];
42671
43547
  absoluteTableStyle.borders[colInSheet][rowInSheet] = relativeTableStyle.borders[col][row];
42672
43548
  absoluteTableStyle.styles[colInSheet][rowInSheet] = relativeTableStyle.styles[col][row];
@@ -42675,6 +43551,58 @@ class TableComputedStylePlugin extends UIPlugin {
42675
43551
  return absoluteTableStyle;
42676
43552
  });
42677
43553
  }
43554
+ getTableMetaData(sheetId, table) {
43555
+ const { config, numberOfCols, numberOfRows } = this.getTableRuntimeConfig(sheetId, table);
43556
+ if (!table.isPivotTable) {
43557
+ return { tableMetaData: { numberOfCols, numberOfRows, mode: "table" }, config };
43558
+ }
43559
+ const mainPosition = { sheetId, col: table.range.zone.left, row: table.range.zone.top };
43560
+ const pivotInfo = this.getters.getPivotStyleAtPosition(mainPosition);
43561
+ if (!pivotInfo) {
43562
+ throw new Error("No dynamic pivot info found at pivot table position");
43563
+ }
43564
+ const pivot = this.getters.getPivot(pivotInfo.pivotId);
43565
+ const pivotStyle = pivotInfo.pivotStyle;
43566
+ const maxRowDepth = pivot.getExpandedTableStructure().getNumberOfRowGroupBys();
43567
+ const pivotCells = pivot.getCollapsedTableStructure().getPivotCells(pivotStyle);
43568
+ const mainSubHeaderRows = new Set();
43569
+ const firstAlternatingSubHeaderRows = new Set();
43570
+ const secondAlternatingSubHeaderRows = new Set();
43571
+ let hiddenRowsOffset = 0;
43572
+ for (let row = 0; row < pivotCells[0].length; row++) {
43573
+ const isRowHidden = this.getters.isRowHidden(sheetId, row + table.range.zone.top);
43574
+ if (isRowHidden) {
43575
+ hiddenRowsOffset++;
43576
+ continue;
43577
+ }
43578
+ const cell = pivotCells[0][row];
43579
+ if (cell.type !== "HEADER" || cell.domain.length === 0) {
43580
+ continue;
43581
+ }
43582
+ if (cell.domain.length === 1 && maxRowDepth > 1) {
43583
+ mainSubHeaderRows.add(row - hiddenRowsOffset);
43584
+ }
43585
+ else if (cell.domain.length % 2 === 0 && maxRowDepth > cell.domain.length) {
43586
+ firstAlternatingSubHeaderRows.add(row - hiddenRowsOffset);
43587
+ }
43588
+ else if (cell.domain.length % 2 === 1 && maxRowDepth > cell.domain.length) {
43589
+ secondAlternatingSubHeaderRows.add(row - hiddenRowsOffset);
43590
+ }
43591
+ }
43592
+ const hasMeasureRow = config.numberOfHeaders &&
43593
+ pivotStyle.displayMeasuresRow &&
43594
+ !this.getters.isRowHidden(sheetId, config.numberOfHeaders - 1 + table.range.zone.top);
43595
+ const tableMetaData = {
43596
+ mode: "pivot",
43597
+ numberOfCols,
43598
+ numberOfRows,
43599
+ mainSubHeaderRows,
43600
+ firstAlternatingSubHeaderRows,
43601
+ secondAlternatingSubHeaderRows,
43602
+ measureRow: hasMeasureRow ? config.numberOfHeaders - 1 : undefined,
43603
+ };
43604
+ return { tableMetaData, config };
43605
+ }
42678
43606
  /**
42679
43607
  * Get the actual table config that will be used to compute the table style. It is different from
42680
43608
  * the config of the table because of hidden rows and columns in the sheet. For example remove the
@@ -42819,8 +43747,9 @@ class CellComputedStylePlugin extends UIPlugin {
42819
43747
  for (let col = zone.left; col <= zone.right; col++) {
42820
43748
  for (let row = zone.top; row <= zone.bottom; row++) {
42821
43749
  const position = { sheetId, col, row };
42822
- if (this.borders.get(position) !== undefined)
43750
+ if (this.borders.get(position) !== undefined) {
42823
43751
  continue;
43752
+ }
42824
43753
  const cellBorder = borders.get(position);
42825
43754
  const cellTableBorder = tableBorders.get(position);
42826
43755
  const border = {
@@ -42851,8 +43780,9 @@ class CellComputedStylePlugin extends UIPlugin {
42851
43780
  for (let col = zone.left; col <= zone.right; col++) {
42852
43781
  for (let row = zone.top; row <= zone.bottom; row++) {
42853
43782
  const position = { sheetId, col, row };
42854
- if (this.styles.get(position) !== undefined)
43783
+ if (this.styles.get(position) !== undefined) {
42855
43784
  continue;
43785
+ }
42856
43786
  const computedStyle = {
42857
43787
  ...removeFalsyAttributes(tableStyles.get(position)),
42858
43788
  ...removeFalsyAttributes(this.getters.getDataValidationCellStyle(position)),
@@ -43356,6 +44286,7 @@ class InsertPivotPlugin extends UIPlugin {
43356
44286
  measures: [],
43357
44287
  name: _t("New pivot"),
43358
44288
  type: "SPREADSHEET",
44289
+ style: { tableStyleId: PIVOT_INSERT_TABLE_STYLE_ID },
43359
44290
  },
43360
44291
  });
43361
44292
  const position = this.getters.getSheetIds().findIndex((sheetId) => sheetId === currentSheetId) + 1;
@@ -43406,21 +44337,13 @@ class InsertPivotPlugin extends UIPlugin {
43406
44337
  const pivotTable = new SpreadsheetPivotTable(cols, rows, measures, fieldsType || {});
43407
44338
  const numberOfHeaders = pivotTable.columns.length - 1;
43408
44339
  this.resizeSheet(sheetId, col, row, pivotTable);
43409
- const pivotFormulaId = this.getters.getPivotFormulaId(pivotId);
43410
- let zone;
43411
44340
  if (mode === "dynamic") {
43412
44341
  this.dispatch("UPDATE_CELL", {
43413
44342
  sheetId,
43414
44343
  col,
43415
44344
  row,
43416
- content: `=PIVOT(${pivotFormulaId})`,
44345
+ content: `=PIVOT(${this.getters.getPivotFormulaId(pivotId)})`,
43417
44346
  });
43418
- zone = {
43419
- left: col,
43420
- right: col,
43421
- top: row,
43422
- bottom: row,
43423
- };
43424
44347
  }
43425
44348
  else {
43426
44349
  this.dispatch("INSERT_PIVOT", {
@@ -43430,19 +44353,19 @@ class InsertPivotPlugin extends UIPlugin {
43430
44353
  pivotId,
43431
44354
  table: pivotTable.export(),
43432
44355
  });
43433
- zone = {
44356
+ const zone = {
43434
44357
  left: col,
43435
44358
  right: col + pivotTable.getNumberOfDataColumns(),
43436
44359
  top: row,
43437
44360
  bottom: row + numberOfHeaders + pivotTable.rows.length,
43438
44361
  };
44362
+ this.dispatch("CREATE_TABLE", {
44363
+ tableType: "static",
44364
+ sheetId,
44365
+ ranges: [this.getters.getRangeDataFromZone(sheetId, zone)],
44366
+ config: { ...PIVOT_STATIC_TABLE_CONFIG, numberOfHeaders },
44367
+ });
43439
44368
  }
43440
- this.dispatch("CREATE_TABLE", {
43441
- tableType: mode,
43442
- sheetId,
43443
- ranges: [this.getters.getRangeDataFromZone(sheetId, zone)],
43444
- config: { ...PIVOT_TABLE_CONFIG, numberOfHeaders },
43445
- });
43446
44369
  }
43447
44370
  resizeSheet(sheetId, col, row, table) {
43448
44371
  const colLimit = table.getNumberOfDataColumns() + 1; // +1 for the Top-Left
@@ -43473,7 +44396,9 @@ class InsertPivotPlugin extends UIPlugin {
43473
44396
  }
43474
44397
  }
43475
44398
  splitPivotFormula(sheetId, col, row, pivotId) {
43476
- const spreadZone = this.getters.getSpreadZone({ sheetId, col, row });
44399
+ const position = { sheetId, col, row };
44400
+ const spreadZone = this.getters.getSpreadZone(position);
44401
+ const table = this.getters.getTable(position);
43477
44402
  if (!spreadZone) {
43478
44403
  return;
43479
44404
  }
@@ -43491,15 +44416,16 @@ class InsertPivotPlugin extends UIPlugin {
43491
44416
  content: createPivotFormula(formulaId, pivotCell),
43492
44417
  });
43493
44418
  }
43494
- const table = this.getters.getCoreTable({ sheetId, col, row });
43495
- if (table?.type === "dynamic") {
43496
- const zone = positionToZone({ col, row });
44419
+ if (this.getters.getCoreTable(position)) {
44420
+ this.dispatch("REMOVE_TABLE", { sheetId, target: [positionToZone(position)] });
44421
+ }
44422
+ if (table?.isPivotTable) {
43497
44423
  const rangeData = this.getters.getRangeDataFromZone(sheetId, spreadZone);
43498
- this.dispatch("UPDATE_TABLE", {
43499
- sheetId,
43500
- zone,
43501
- newTableRange: rangeData,
44424
+ this.dispatch("CREATE_TABLE", {
43502
44425
  tableType: "static",
44426
+ sheetId,
44427
+ ranges: [rangeData],
44428
+ config: { ...table.config, styleId: pivotTableStyleIdToTableStyleId(table.config.styleId) },
43503
44429
  });
43504
44430
  }
43505
44431
  }
@@ -43640,8 +44566,9 @@ class HistoryPlugin extends UIPlugin {
43640
44566
  return this.undoStack.length > 0;
43641
44567
  }
43642
44568
  canRedo() {
43643
- if (this.redoStack.length > 0)
44569
+ if (this.redoStack.length > 0) {
43644
44570
  return true;
44571
+ }
43645
44572
  const lastNonRedoRevision = this.getPossibleRevisionToRepeat();
43646
44573
  return canRepeatRevision(lastNonRedoRevision);
43647
44574
  }
@@ -43777,8 +44704,9 @@ class SortPlugin extends UIPlugin {
43777
44704
  *
43778
44705
  */
43779
44706
  hasHeader(sheetId, items) {
43780
- if (items[0].length === 1)
44707
+ if (items[0].length === 1) {
43781
44708
  return false;
44709
+ }
43782
44710
  let cells = items.map((col) => col.map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }).type));
43783
44711
  // ignore left-most column when topLeft cell is empty
43784
44712
  const topLeft = cells[0][0];
@@ -44063,6 +44991,16 @@ class SplitToColumnsPlugin extends UIPlugin {
44063
44991
  }
44064
44992
  }
44065
44993
 
44994
+ class SubtotalEvaluationPlugin extends UIPlugin {
44995
+ handle(cmd) {
44996
+ if (invalidSubtotalFormulasCommands.has(cmd.type)) {
44997
+ this.dispatch("EVALUATE_CELLS", {
44998
+ cellIds: this.getters.getCellsWithTrackedFormula("SUBTOTAL"),
44999
+ });
45000
+ }
45001
+ }
45002
+ }
45003
+
44066
45004
  class TableAutofillPlugin extends UIPlugin {
44067
45005
  handle(cmd) {
44068
45006
  switch (cmd.type) {
@@ -44134,12 +45072,14 @@ class TableResizeUI extends UIPlugin {
44134
45072
  case "RESIZE_TABLE": {
44135
45073
  const table = this.getters.getCoreTableMatchingTopLeft(cmd.sheetId, cmd.zone);
44136
45074
  this.dispatch("UPDATE_TABLE", { ...cmd });
44137
- if (!table)
45075
+ if (!table) {
44138
45076
  return;
45077
+ }
44139
45078
  const newTableZone = this.getters.getRangeFromRangeData(cmd.newTableRange).zone;
44140
45079
  this.selection.selectCell(newTableZone.right, newTableZone.bottom);
44141
- if (!table.config.automaticAutofill)
45080
+ if (!table.config.automaticAutofill) {
44142
45081
  return;
45082
+ }
44143
45083
  const oldTableZone = table.range.zone;
44144
45084
  if (newTableZone.bottom >= oldTableZone.bottom) {
44145
45085
  for (let col = newTableZone.left; col <= newTableZone.right; col++) {
@@ -44401,8 +45341,9 @@ class SheetUIPlugin extends UIPlugin {
44401
45341
  let evaluatedRowSize = 0;
44402
45342
  let tallestCell = undefined;
44403
45343
  for (const [position, evaluatedCell] of this.getters.getEvaluatedCellsPositionInZone(sheetId, this.getters.getRowsZone(sheetId, row, row))) {
44404
- if (evaluatedCell.value === undefined)
45344
+ if (evaluatedCell.value === undefined) {
44405
45345
  continue;
45346
+ }
44406
45347
  const colSize = this.getters.getColSize(sheetId, position.col);
44407
45348
  const style = this.getters.getCellStyle(position);
44408
45349
  const content = evaluatedCell.formattedValue;
@@ -44690,8 +45631,9 @@ async function convertImageToPng(imageUrl) {
44690
45631
  */
44691
45632
  function cellStyleToCss(style) {
44692
45633
  const attributes = cellTextStyleToCss(style);
44693
- if (!style)
45634
+ if (!style) {
44694
45635
  return attributes;
45636
+ }
44695
45637
  if (style.fillColor) {
44696
45638
  attributes["background"] = style.fillColor;
44697
45639
  }
@@ -44702,8 +45644,9 @@ function cellStyleToCss(style) {
44702
45644
  */
44703
45645
  function cellTextStyleToCss(style) {
44704
45646
  const attributes = {};
44705
- if (!style)
45647
+ if (!style) {
44706
45648
  return attributes;
45649
+ }
44707
45650
  if (style.bold) {
44708
45651
  attributes["font-weight"] = "bold";
44709
45652
  }
@@ -44896,14 +45839,33 @@ class ClipboardPlugin extends UIPlugin {
44896
45839
  if (zones.length > 1 || (zones[0].top === 0 && zones[0].bottom === 0)) {
44897
45840
  return "InvalidCopyPasteSelection" /* CommandResult.InvalidCopyPasteSelection */;
44898
45841
  }
44899
- break;
45842
+ const zone = this.getters.getSelectedZone();
45843
+ const copiedData = this.getCopiedDataAbove(zone);
45844
+ return this.isPasteAllowed(zones, copiedData, {
45845
+ isCutOperation: false,
45846
+ });
44900
45847
  }
44901
45848
  case "COPY_PASTE_CELLS_ON_LEFT": {
44902
45849
  const zones = this.getters.getSelectedZones();
44903
45850
  if (zones.length > 1 || (zones[0].left === 0 && zones[0].right === 0)) {
44904
45851
  return "InvalidCopyPasteSelection" /* CommandResult.InvalidCopyPasteSelection */;
44905
45852
  }
44906
- break;
45853
+ const zone = this.getters.getSelectedZone();
45854
+ const copiedData = this.getCopiedDataOnLeft(zone);
45855
+ return this.isPasteAllowed(zones, copiedData, {
45856
+ isCutOperation: false,
45857
+ });
45858
+ }
45859
+ case "COPY_PASTE_CELLS_ON_ZONE": {
45860
+ const zones = this.getters.getSelectedZones();
45861
+ if (zones.length > 1) {
45862
+ return "InvalidCopyPasteSelection" /* CommandResult.InvalidCopyPasteSelection */;
45863
+ }
45864
+ const zone = this.getters.getSelectedZone();
45865
+ const copiedData = this.getCopiedDataOnLeft(zone);
45866
+ return this.isPasteAllowed(zones, copiedData, {
45867
+ isCutOperation: false,
45868
+ });
44907
45869
  }
44908
45870
  case "INSERT_CELL": {
44909
45871
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
@@ -44980,14 +45942,8 @@ class ClipboardPlugin extends UIPlugin {
44980
45942
  case "COPY_PASTE_CELLS_ABOVE":
44981
45943
  {
44982
45944
  const zone = this.getters.getSelectedZone();
44983
- const multipleRowsInSelection = zone.top !== zone.bottom;
44984
- const copyTarget = {
44985
- ...zone,
44986
- bottom: multipleRowsInSelection ? zone.top : zone.top - 1,
44987
- top: multipleRowsInSelection ? zone.top : zone.top - 1,
44988
- };
44989
45945
  this.originSheetId = this.getters.getActiveSheetId();
44990
- const copiedData = this.copy([copyTarget]);
45946
+ const copiedData = this.getCopiedDataAbove(zone);
44991
45947
  this.paste([zone], copiedData, {
44992
45948
  isCutOperation: false,
44993
45949
  selectTarget: true,
@@ -44997,14 +45953,19 @@ class ClipboardPlugin extends UIPlugin {
44997
45953
  case "COPY_PASTE_CELLS_ON_LEFT":
44998
45954
  {
44999
45955
  const zone = this.getters.getSelectedZone();
45000
- const multipleColsInSelection = zone.left !== zone.right;
45001
- const copyTarget = {
45002
- ...zone,
45003
- right: multipleColsInSelection ? zone.left : zone.left - 1,
45004
- left: multipleColsInSelection ? zone.left : zone.left - 1,
45005
- };
45006
45956
  this.originSheetId = this.getters.getActiveSheetId();
45007
- const copiedData = this.copy([copyTarget]);
45957
+ const copiedData = this.getCopiedDataOnLeft(zone);
45958
+ this.paste([zone], copiedData, {
45959
+ isCutOperation: false,
45960
+ selectTarget: true,
45961
+ });
45962
+ }
45963
+ break;
45964
+ case "COPY_PASTE_CELLS_ON_ZONE":
45965
+ {
45966
+ const zone = this.getters.getSelectedZone();
45967
+ this.originSheetId = this.getters.getActiveSheetId();
45968
+ const copiedData = this.getCopiedDataAboveOnLeft(zone);
45008
45969
  this.paste([zone], copiedData, {
45009
45970
  isCutOperation: false,
45010
45971
  selectTarget: true,
@@ -45084,6 +46045,32 @@ class ClipboardPlugin extends UIPlugin {
45084
46045
  }
45085
46046
  }
45086
46047
  }
46048
+ getCopiedDataAbove(zone) {
46049
+ const multipleRowsInSelection = zone.top !== zone.bottom;
46050
+ const copyTarget = {
46051
+ ...zone,
46052
+ bottom: multipleRowsInSelection ? zone.top : zone.top - 1,
46053
+ top: multipleRowsInSelection ? zone.top : zone.top - 1,
46054
+ };
46055
+ return this.copy([copyTarget]);
46056
+ }
46057
+ getCopiedDataOnLeft(zone) {
46058
+ const multipleColsInSelection = zone.left !== zone.right;
46059
+ const copyTarget = {
46060
+ ...zone,
46061
+ right: multipleColsInSelection ? zone.left : zone.left - 1,
46062
+ left: multipleColsInSelection ? zone.left : zone.left - 1,
46063
+ };
46064
+ return this.copy([copyTarget]);
46065
+ }
46066
+ getCopiedDataAboveOnLeft(zone) {
46067
+ const copyTarget = {
46068
+ ...zone,
46069
+ right: zone.left,
46070
+ bottom: zone.top,
46071
+ };
46072
+ return this.copy([copyTarget]);
46073
+ }
45087
46074
  convertTextToClipboardData(clipboardData) {
45088
46075
  const handlers = this.selectClipboardHandlers({ figureId: true }).concat(this.selectClipboardHandlers({}));
45089
46076
  const copiedData = {};
@@ -45534,27 +46521,31 @@ class FilterEvaluationPlugin extends UIPlugin {
45534
46521
  getFilterHiddenValues(position) {
45535
46522
  const id = this.getters.getFilterId(position);
45536
46523
  const sheetId = position.sheetId;
45537
- if (!id || !this.filterValues[sheetId])
46524
+ if (!id || !this.filterValues[sheetId]) {
45538
46525
  return [];
46526
+ }
45539
46527
  const value = this.filterValues[sheetId][id] || [];
45540
46528
  return value.filterType === "values" ? value.hiddenValues : [];
45541
46529
  }
45542
46530
  getFilterCriterionValue(position) {
45543
46531
  const id = this.getters.getFilterId(position);
45544
46532
  const sheetId = position.sheetId;
45545
- if (!id || !this.filterValues[sheetId])
46533
+ if (!id || !this.filterValues[sheetId]) {
45546
46534
  return EMPTY_CRITERION;
46535
+ }
45547
46536
  const value = this.filterValues[sheetId][id];
45548
46537
  return value && value.filterType === "criterion" ? value : EMPTY_CRITERION;
45549
46538
  }
45550
46539
  isFilterActive(position) {
45551
46540
  const id = this.getters.getFilterId(position);
45552
- if (!id)
46541
+ if (!id) {
45553
46542
  return false;
46543
+ }
45554
46544
  const sheetId = position.sheetId;
45555
46545
  const value = this.filterValues[sheetId]?.[id];
45556
- if (!value)
46546
+ if (!value) {
45557
46547
  return false;
46548
+ }
45558
46549
  return value.filterType === "values" ? value.hiddenValues.length > 0 : value.type !== "none";
45559
46550
  }
45560
46551
  getFirstTableInSelection() {
@@ -45564,10 +46555,12 @@ class FilterEvaluationPlugin extends UIPlugin {
45564
46555
  }
45565
46556
  updateFilter({ col, row, value, sheetId }) {
45566
46557
  const id = this.getters.getFilterId({ sheetId, col, row });
45567
- if (!id)
46558
+ if (!id) {
45568
46559
  return;
45569
- if (!this.filterValues[sheetId])
46560
+ }
46561
+ if (!this.filterValues[sheetId]) {
45570
46562
  this.filterValues[sheetId] = {};
46563
+ }
45571
46564
  this.filterValues[sheetId][id] = value;
45572
46565
  }
45573
46566
  updateHiddenRows(sheetId) {
@@ -45587,8 +46580,9 @@ class FilterEvaluationPlugin extends UIPlugin {
45587
46580
  }
45588
46581
  if (filterValue.filterType === "values") {
45589
46582
  const filteredValues = filterValue.hiddenValues?.map(toLowerCase);
45590
- if (!filteredValues)
46583
+ if (!filteredValues) {
45591
46584
  continue;
46585
+ }
45592
46586
  const filteredValuesSet = new Set(filteredValues);
45593
46587
  for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
45594
46588
  const value = this.getCellValueAsString(sheetId, filter.col, row);
@@ -45598,8 +46592,9 @@ class FilterEvaluationPlugin extends UIPlugin {
45598
46592
  }
45599
46593
  }
45600
46594
  else {
45601
- if (filterValue.type === "none")
46595
+ if (filterValue.type === "none") {
45602
46596
  continue;
46597
+ }
45603
46598
  const evaluator = criterionEvaluatorRegistry.get(filterValue.type);
45604
46599
  const preComputedCriterion = evaluator.preComputeCriterion?.(filterValue, [filter.filteredRange], this.getters);
45605
46600
  const evaluatedCriterionValues = filterValue.values.map((value) => {
@@ -45830,6 +46825,7 @@ class GridSelectionPlugin extends UIPlugin {
45830
46825
  "tryGetActiveSheetId",
45831
46826
  "isGridSelectionActive",
45832
46827
  "getSelectecUnboundedZone",
46828
+ "getSelectionRangeString",
45833
46829
  ];
45834
46830
  gridSelection = {
45835
46831
  anchor: {
@@ -46158,6 +47154,38 @@ class GridSelectionPlugin extends UIPlugin {
46158
47154
  }
46159
47155
  return [...new Set(elements)].sort();
46160
47156
  }
47157
+ /**
47158
+ * Same as `getRangeString` but add:
47159
+ * - all necessary merge to the range to make it a valid selection
47160
+ * - the "#" suffix if the range is a spilled reference
47161
+ */
47162
+ getSelectionRangeString(range, forSheetId) {
47163
+ const expandedZone = this.getters.expandZone(range.sheetId, range.zone);
47164
+ const expandedRange = createRange({
47165
+ ...range,
47166
+ zone: {
47167
+ ...expandedZone,
47168
+ bottom: isFullColRange(range) ? undefined : expandedZone.bottom,
47169
+ right: isFullRowRange(range) ? undefined : expandedZone.right,
47170
+ },
47171
+ }, this.getters.getSheetSize);
47172
+ const rangeString = this.getters.getRangeString(expandedRange, forSheetId);
47173
+ if (this.getters.isSingleCellOrMerge(range.sheetId, range.zone)) {
47174
+ const { sheetName, xc } = splitReference(rangeString);
47175
+ return getFullReference(sheetName, xc.split(":")[0]);
47176
+ }
47177
+ const spreaderPosition = this.getters.getArrayFormulaSpreadingOn({
47178
+ sheetId: expandedRange.sheetId,
47179
+ col: expandedRange.zone.left,
47180
+ row: expandedRange.zone.top,
47181
+ });
47182
+ const spreadZone = spreaderPosition && this.getters.getSpreadZone(spreaderPosition, { ignoreSpillError: true });
47183
+ if (spreadZone && isEqual(spreadZone, expandedRange.zone)) {
47184
+ const { sheetName, xc } = splitReference(rangeString);
47185
+ return getFullReference(sheetName, xc.split(":")[0]) + "#";
47186
+ }
47187
+ return rangeString;
47188
+ }
46161
47189
  // ---------------------------------------------------------------------------
46162
47190
  // Other
46163
47191
  // ---------------------------------------------------------------------------
@@ -47522,8 +48550,9 @@ class SheetViewPlugin extends UIPlugin {
47522
48550
  * It returns -1 if no col is found.
47523
48551
  */
47524
48552
  getColIndexLeftOfMainViewport(x) {
47525
- if (x >= 0)
48553
+ if (x >= 0) {
47526
48554
  return -1;
48555
+ }
47527
48556
  const sheetId = this.getters.getActiveSheetId();
47528
48557
  let col = this.getActiveMainViewport().left;
47529
48558
  let colStart = -this.getActiveSheetScrollInfo().scrollX - this.getters.getColRowOffset("COL", col, 0);
@@ -47538,8 +48567,9 @@ class SheetViewPlugin extends UIPlugin {
47538
48567
  * It returns -1 if no row is found.
47539
48568
  */
47540
48569
  getRowIndexTopOfMainViewport(y) {
47541
- if (y >= 0)
48570
+ if (y >= 0) {
47542
48571
  return -1;
48572
+ }
47543
48573
  const sheetId = this.getters.getActiveSheetId();
47544
48574
  let row = this.getActiveMainViewport().top;
47545
48575
  let rowStart = -this.getActiveSheetScrollInfo().scrollY - this.getters.getColRowOffset("ROW", row, 0);
@@ -47698,7 +48728,8 @@ const coreViewsPluginRegistry = new Registry$1()
47698
48728
  .add("dynamic_tables", DynamicTablesPlugin)
47699
48729
  .add("custom_colors", CustomColorsPlugin)
47700
48730
  .add("pivot_ui", PivotUIPlugin)
47701
- .add("cell_icon", CellIconPlugin);
48731
+ .add("cell_icon", CellIconPlugin)
48732
+ .add("formula_tracker", FormulaTrackerPlugin);
47702
48733
 
47703
48734
  class RangeAdapter {
47704
48735
  getters;
@@ -48828,8 +49859,9 @@ function insertTextProperties(fontsize = 12, fontColor = "000000", bold = false,
48828
49859
  `;
48829
49860
  }
48830
49861
  function extractTrendline(trend, dataSetColor) {
48831
- if (!trend)
49862
+ if (!trend) {
48832
49863
  return escapeXml /*xml*/ ``;
49864
+ }
48833
49865
  const { type, order, window } = trend;
48834
49866
  const trendLineNodes = [];
48835
49867
  switch (type) {
@@ -50716,8 +51748,9 @@ function addMerges(merges) {
50716
51748
  </mergeCells>
50717
51749
  `;
50718
51750
  }
50719
- else
51751
+ else {
50720
51752
  return escapeXml ``;
51753
+ }
50721
51754
  }
50722
51755
  function addSheetViews(sheet) {
50723
51756
  const panes = sheet.panes;
@@ -50845,12 +51878,14 @@ function createWorksheets(data, construct) {
50845
51878
  }
50846
51879
  for (const image of sheet.images) {
50847
51880
  const mimeType = image.data.mimetype;
50848
- if (mimeType === undefined)
51881
+ if (mimeType === undefined) {
50849
51882
  continue;
51883
+ }
50850
51884
  const extension = IMAGE_MIMETYPE_TO_EXTENSION_MAPPING[mimeType];
50851
51885
  // only support exporting images with mimetypes specified in the mapping
50852
- if (extension === undefined)
51886
+ if (extension === undefined) {
50853
51887
  continue;
51888
+ }
50854
51889
  const xlsxImageId = convertImageId(image.id);
50855
51890
  const imageFileName = `image${xlsxImageId}.${extension}`;
50856
51891
  const imageRelId = addRelsToFile(construct.relsFiles, `xl/drawings/_rels/drawing${sheetIndex}.xml.rels`, {
@@ -50934,8 +51969,9 @@ function createWorksheets(data, construct) {
50934
51969
  */
50935
51970
  function createTablesForSheet(sheetData, sheetId, startingTableId, construct, files) {
50936
51971
  let currentTableId = startingTableId;
50937
- if (!sheetData.tables.length)
51972
+ if (!sheetData.tables.length) {
50938
51973
  return new XMLString("");
51974
+ }
50939
51975
  const sheetRelFile = `xl/worksheets/_rels/sheet${sheetId}.xml.rels`;
50940
51976
  const tableParts = [];
50941
51977
  for (const table of sheetData.tables) {
@@ -51670,9 +52706,9 @@ function addRenderingLayer(layer, priority) {
51670
52706
 
51671
52707
  const __info__ = {};
51672
52708
 
51673
- export { BadExpressionError, BasePlugin, CellErrorType, CircularDependencyError, DEFAULT_LOCALE, DEFAULT_LOCALES, DIRECTION, DivisionByZeroError, EvaluationError, FunctionCodeBuilder, FunctionRegistry, InvalidReferenceError, Model, NotAvailableError, NumberTooLargeError, OPERATOR_MAP, OP_PRIORITY, OrderedLayers, POSTFIX_UNARY_OPERATORS, Registry$1 as Registry, Scope, SplillBlockedError, StateObserver, TokenizingChars, UNARY_OPERATOR_MAP, UnknownFunctionError, UuidGenerator, __info__, _t, addRenderingLayer, batched, borderStyles, buildSheetLink, categories, cellReference, chartStyleToCellStyle, clip, compile, compileTokens, concat, convertAstNodes, createEmptyStructure, debounce, deepCopy, deepEquals, deepEqualsArray, errorTypes, escapeRegExp, findNextDefinedValue, functionCache, getAddHeaderStartIndex, getCanonicalSymbolName, getFormulaNumberRegex, getFullReference, getSearchRegex, getUniqueText, getUnquotedSheetName, groupConsecutive, includesAll, insertItemsAtIndex, isBoolean, isColHeader, isColReference, isConsecutive, isDefined, isFormula, isMarkdownLink, isMatrix, isNotNull, isNumber, isNumberBetween, isObjectEmptyRecursive, isRowHeader, isRowReference, isSheetUrl, isSingleCellReference, isWebLink, iterateAstNodes, largeMax, largeMin, lazy, linkNext, loopThroughReferenceType, mapAst, markdownLink, memoize, parse, parseMarkdownLink, parseNumber, parseSheetUrl, parseTokens, percentile, range, rangeReference, rangeTokenize, removeDuplicates, removeFalsyAttributes, removeIndexesFromArray, replaceItemAtIndex, replaceNewLines, sanitizeSheetName, setDefaultTranslationMethod, setTranslationMethod, setXcToFixedReferenceType, specialWhiteSpaceRegexp, splitReference, tokenize, transpose2dPOJO, trimContent, unquote, whiteSpaceCharacters };
52709
+ export { BadExpressionError, BasePlugin, CellErrorType, CircularDependencyError, DEFAULT_LOCALE, DEFAULT_LOCALES, DIRECTION, DivisionByZeroError, EvaluationError, FunctionCodeBuilder, FunctionRegistry, InvalidReferenceError, Model, NotAvailableError, NumberTooLargeError, OPERATOR_MAP, OP_PRIORITY, OrderedLayers, POSTFIX_UNARY_OPERATORS, Registry$1 as Registry, Scope, SplillBlockedError, StateObserver, TokenizingChars, UNARY_OPERATOR_MAP, UnknownFunctionError, UuidGenerator, __info__, _t, addRenderingLayer, batched, borderStyles, buildSheetLink, categories, cellReference, chartStyleToCellStyle, clip, compile, compileTokens, concat, convertAstNodes, createEmptyStructure, debounce, deepCopy, deepEquals, deepEqualsArray, doesCellContainFunction, errorTypes, escapeRegExp, findNextDefinedValue, functionCache, getAddHeaderStartIndex, getCanonicalSymbolName, getFormulaNumberRegex, getFullReference, getSearchRegex, getUniqueText, getUnquotedSheetName, groupConsecutive, includesAll, insertItemsAtIndex, isBoolean, isColHeader, isColReference, isConsecutive, isDefined, isFormula, isMarkdownLink, isMatrix, isNotNull, isNumber, isNumberBetween, isObjectEmptyRecursive, isRowHeader, isRowReference, isSheetUrl, isSingleCellReference, isWebLink, iterateAstNodes, largeMax, largeMin, lazy, linkNext, loopThroughReferenceType, mapAst, markdownLink, memoize, parse, parseMarkdownLink, parseNumber, parseSheetUrl, parseTokens, percentile, range, rangeReference, rangeTokenize, removeDuplicates, removeFalsyAttributes, removeIndexesFromArray, replaceItemAtIndex, replaceNewLines, sanitizeSheetName, setDefaultTranslationMethod, setTranslationMethod, setXcToFixedReferenceType, specialWhiteSpaceRegexp, splitReference, tokenize, transpose2dPOJO, trimContent, unquote, whiteSpaceCharacters };
51674
52710
 
51675
52711
 
51676
52712
  __info__.version = "19.1.0-alpha.3";
51677
- __info__.date = "2026-01-07T16:20:57.293Z";
51678
- __info__.hash = "ac2fa3e";
52713
+ __info__.date = "2026-01-14T10:01:30.535Z";
52714
+ __info__.hash = "e5cbf18";