@odoo/o-spreadsheet 18.1.8 → 18.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 18.1.8
6
- * @date 2025-02-14T08:42:08.322Z
7
- * @hash 02682f4
5
+ * @version 18.1.9
6
+ * @date 2025-02-25T05:59:45.472Z
7
+ * @hash 6789c1c
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -2219,17 +2219,7 @@
2219
2219
  */
2220
2220
  function toUnboundedZone(xc) {
2221
2221
  const zone = toZoneWithoutBoundaryChanges(xc);
2222
- if (zone.right !== undefined && zone.right < zone.left) {
2223
- const tmp = zone.left;
2224
- zone.left = zone.right;
2225
- zone.right = tmp;
2226
- }
2227
- if (zone.bottom !== undefined && zone.bottom < zone.top) {
2228
- const tmp = zone.top;
2229
- zone.top = zone.bottom;
2230
- zone.bottom = tmp;
2231
- }
2232
- return zone;
2222
+ return reorderZone(zone);
2233
2223
  }
2234
2224
  /**
2235
2225
  * Convert from a cartesian reference to a Zone.
@@ -2503,11 +2493,11 @@
2503
2493
  return positions;
2504
2494
  }
2505
2495
  function reorderZone(zone) {
2506
- if (zone.left > zone.right) {
2507
- zone = { left: zone.right, right: zone.left, top: zone.top, bottom: zone.bottom };
2496
+ if (zone.right !== undefined && zone.left > zone.right) {
2497
+ zone = { ...zone, left: zone.right, right: zone.left };
2508
2498
  }
2509
- if (zone.top > zone.bottom) {
2510
- zone = { left: zone.left, right: zone.right, top: zone.bottom, bottom: zone.top };
2499
+ if (zone.bottom !== undefined && zone.top > zone.bottom) {
2500
+ zone = { ...zone, top: zone.bottom, bottom: zone.top };
2511
2501
  }
2512
2502
  return zone;
2513
2503
  }
@@ -3412,12 +3402,12 @@
3412
3402
  function isRangeDependant(cmd) {
3413
3403
  return "ranges" in cmd;
3414
3404
  }
3415
- function isZoneDependent(cmd) {
3416
- return "zone" in cmd;
3417
- }
3418
3405
  function isPositionDependent(cmd) {
3419
3406
  return "col" in cmd && "row" in cmd && "sheetId" in cmd;
3420
3407
  }
3408
+ function isZoneDependent(cmd) {
3409
+ return "sheetId" in cmd && "zone" in cmd;
3410
+ }
3421
3411
  const invalidateEvaluationCommands = new Set([
3422
3412
  "RENAME_SHEET",
3423
3413
  "DELETE_SHEET",
@@ -3429,6 +3419,7 @@
3429
3419
  "REDO",
3430
3420
  "ADD_MERGE",
3431
3421
  "REMOVE_MERGE",
3422
+ "DUPLICATE_SHEET",
3432
3423
  "UPDATE_LOCALE",
3433
3424
  "ADD_PIVOT",
3434
3425
  "UPDATE_PIVOT",
@@ -3458,7 +3449,6 @@
3458
3449
  ]);
3459
3450
  const invalidateDependenciesCommands = new Set(["MOVE_RANGES"]);
3460
3451
  const invalidateCFEvaluationCommands = new Set([
3461
- "DUPLICATE_SHEET",
3462
3452
  "EVALUATE_CELLS",
3463
3453
  "ADD_CONDITIONAL_FORMAT",
3464
3454
  "REMOVE_CONDITIONAL_FORMAT",
@@ -3628,6 +3618,7 @@
3628
3618
  CommandResult["InvalidRange"] = "InvalidRange";
3629
3619
  CommandResult["InvalidZones"] = "InvalidZones";
3630
3620
  CommandResult["InvalidSheetId"] = "InvalidSheetId";
3621
+ CommandResult["InvalidCellId"] = "InvalidCellId";
3631
3622
  CommandResult["InvalidFigureId"] = "InvalidFigureId";
3632
3623
  CommandResult["InputAlreadyFocused"] = "InputAlreadyFocused";
3633
3624
  CommandResult["MaximumRangesReached"] = "MaximumRangesReached";
@@ -4459,7 +4450,7 @@
4459
4450
  * @param reverseSearch if true, search in the array starting from the end.
4460
4451
 
4461
4452
  */
4462
- function linearSearch(data, target, mode, numberOfValues, getValueInData, reverseSearch = false) {
4453
+ function linearSearch(data, target, mode, numberOfValues, getValueInData, lookupCaches, reverseSearch = false) {
4463
4454
  if (target === undefined || target.value === null) {
4464
4455
  return -1;
4465
4456
  }
@@ -4468,17 +4459,48 @@
4468
4459
  }
4469
4460
  const _target = normalizeValue(target.value);
4470
4461
  const getValue = reverseSearch
4471
- ? (data, i) => getValueInData(data, numberOfValues - i - 1)
4472
- : getValueInData;
4462
+ ? (data, i) => normalizeValue(getValueInData(data, numberOfValues - i - 1))
4463
+ : (data, i) => normalizeValue(getValueInData(data, i));
4464
+ // first check if the target is in the cache
4465
+ const isNotWildcardTarget = mode !== "wildcard" ||
4466
+ typeof _target !== "string" ||
4467
+ !(_target.includes("*") || _target.includes("?"));
4468
+ if (lookupCaches && isNotWildcardTarget) {
4469
+ const searchMode = reverseSearch ? "reverseSearch" : "forwardSearch";
4470
+ let cache = lookupCaches[searchMode].get(data);
4471
+ if (cache === undefined) {
4472
+ // build the cache for all the values
4473
+ cache = new Map();
4474
+ for (let i = 0; i < numberOfValues; i++) {
4475
+ const value = getValue(data, i) ?? null;
4476
+ if (!cache.has(value)) {
4477
+ cache.set(value, i);
4478
+ }
4479
+ }
4480
+ lookupCaches[searchMode].set(data, cache);
4481
+ }
4482
+ if (cache.has(_target)) {
4483
+ const resultIndex = cache.get(_target);
4484
+ return reverseSearch ? numberOfValues - resultIndex - 1 : resultIndex;
4485
+ }
4486
+ if (mode === "strict") {
4487
+ return -1;
4488
+ }
4489
+ }
4490
+ // else perform the linear search
4491
+ const resultIndex = _linearSearch(data, _target, mode, numberOfValues, getValue);
4492
+ return reverseSearch && resultIndex !== -1 ? numberOfValues - resultIndex - 1 : resultIndex;
4493
+ }
4494
+ function _linearSearch(data, _target, mode, numberOfValues, getNormalizeValue) {
4473
4495
  let indexMatchTarget = (i) => {
4474
- return normalizeValue(getValue(data, i)) === _target;
4496
+ return getNormalizeValue(data, i) === _target;
4475
4497
  };
4476
4498
  if (mode === "wildcard" &&
4477
4499
  typeof _target === "string" &&
4478
4500
  (_target.includes("*") || _target.includes("?"))) {
4479
4501
  const regExp = wildcardToRegExp(_target);
4480
4502
  indexMatchTarget = (i) => {
4481
- const value = normalizeValue(getValue(data, i));
4503
+ const value = getNormalizeValue(data, i);
4482
4504
  if (typeof value === "string") {
4483
4505
  return regExp.test(value);
4484
4506
  }
@@ -4489,7 +4511,7 @@
4489
4511
  let closestMatchIndex = -1;
4490
4512
  if (mode === "nextSmaller") {
4491
4513
  indexMatchTarget = (i) => {
4492
- const value = normalizeValue(getValue(data, i));
4514
+ const value = getNormalizeValue(data, i);
4493
4515
  if ((!closestMatch && compareCellValues(_target, value) >= 0) ||
4494
4516
  (compareCellValues(_target, value) >= 0 && compareCellValues(value, closestMatch) > 0)) {
4495
4517
  closestMatch = value;
@@ -4500,7 +4522,7 @@
4500
4522
  }
4501
4523
  if (mode === "nextGreater") {
4502
4524
  indexMatchTarget = (i) => {
4503
- const value = normalizeValue(getValue(data, i));
4525
+ const value = getNormalizeValue(data, i);
4504
4526
  if ((!closestMatch && compareCellValues(_target, value) <= 0) ||
4505
4527
  (compareCellValues(_target, value) <= 0 && compareCellValues(value, closestMatch) < 0)) {
4506
4528
  closestMatch = value;
@@ -4511,12 +4533,10 @@
4511
4533
  }
4512
4534
  for (let i = 0; i < numberOfValues; i++) {
4513
4535
  if (indexMatchTarget(i)) {
4514
- return reverseSearch ? numberOfValues - i - 1 : i;
4536
+ return i;
4515
4537
  }
4516
4538
  }
4517
- return reverseSearch && closestMatchIndex !== -1
4518
- ? numberOfValues - closestMatchIndex - 1
4519
- : closestMatchIndex;
4539
+ return closestMatchIndex;
4520
4540
  }
4521
4541
  /**
4522
4542
  * Normalize a value.
@@ -6490,10 +6510,11 @@
6490
6510
  *
6491
6511
  */
6492
6512
  smallUuid() {
6493
- //@ts-ignore
6494
- if (window.crypto && window.crypto.getRandomValues) {
6495
- //@ts-ignore
6496
- return ([1e7] + -1e3).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
6513
+ if (window.crypto) {
6514
+ return "10000000-1000".replace(/[01]/g, (c) => {
6515
+ const n = Number(c);
6516
+ return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
6517
+ });
6497
6518
  }
6498
6519
  else {
6499
6520
  // mainly for jest and other browsers that do not have the crypto functionality
@@ -6508,10 +6529,11 @@
6508
6529
  * This method should be used when you need to avoid collisions at all costs, like the id of a revision.
6509
6530
  */
6510
6531
  uuidv4() {
6511
- //@ts-ignore
6512
- if (window.crypto && window.crypto.getRandomValues) {
6513
- //@ts-ignore
6514
- return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
6532
+ if (window.crypto) {
6533
+ return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => {
6534
+ const n = Number(c);
6535
+ return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
6536
+ });
6515
6537
  }
6516
6538
  else {
6517
6539
  // mainly for jest and other browsers that do not have the crypto functionality
@@ -12064,6 +12086,25 @@ stores.inject(MyMetaStore, storeInstance);
12064
12086
  isExported: true,
12065
12087
  };
12066
12088
  // -----------------------------------------------------------------------------
12089
+ // LOG
12090
+ // -----------------------------------------------------------------------------
12091
+ const LOG = {
12092
+ description: _t("The logarithm of a number, for a given base."),
12093
+ args: [
12094
+ arg("value (number)", _t("The value for which to calculate the logarithm.")),
12095
+ arg("base (number, default=10)", _t("The base of the logarithm.")),
12096
+ ],
12097
+ compute: function (value, base = { value: 10 }) {
12098
+ const _value = toNumber(value, this.locale);
12099
+ const _base = toNumber(base, this.locale);
12100
+ assert(() => _value > 0, _t("The value (%s) must be strictly positive.", _value.toString()));
12101
+ assert(() => _base > 0, _t("The base (%s) must be strictly positive.", _base.toString()));
12102
+ assert(() => _base !== 1, _t("The base must be different from 1."));
12103
+ return Math.log10(_value) / Math.log10(_base);
12104
+ },
12105
+ isExported: true,
12106
+ };
12107
+ // -----------------------------------------------------------------------------
12067
12108
  // MOD
12068
12109
  // -----------------------------------------------------------------------------
12069
12110
  function mod(dividend, divisor) {
@@ -12603,6 +12644,7 @@ stores.inject(MyMetaStore, storeInstance);
12603
12644
  ISODD: ISODD,
12604
12645
  ISO_CEILING: ISO_CEILING,
12605
12646
  LN: LN,
12647
+ LOG: LOG,
12606
12648
  MOD: MOD,
12607
12649
  MUNIT: MUNIT,
12608
12650
  ODD: ODD,
@@ -18501,7 +18543,7 @@ stores.inject(MyMetaStore, storeInstance);
18501
18543
  const _isSorted = toBoolean(isSorted.value);
18502
18544
  const colIndex = _isSorted
18503
18545
  ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
18504
- : linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange);
18546
+ : linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange, this.lookupCaches);
18505
18547
  const col = _range[colIndex];
18506
18548
  if (col === undefined) {
18507
18549
  return valueNotAvailable(searchKey);
@@ -18656,7 +18698,7 @@ stores.inject(MyMetaStore, storeInstance);
18656
18698
  index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18657
18699
  break;
18658
18700
  case 0:
18659
- index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement);
18701
+ index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement, this.lookupCaches);
18660
18702
  break;
18661
18703
  case -1:
18662
18704
  index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
@@ -18724,7 +18766,7 @@ stores.inject(MyMetaStore, storeInstance);
18724
18766
  const _isSorted = toBoolean(isSorted.value);
18725
18767
  const rowIndex = _isSorted
18726
18768
  ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
18727
- : linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange);
18769
+ : linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange, this.lookupCaches);
18728
18770
  const value = _range[_index - 1][rowIndex];
18729
18771
  if (value === undefined) {
18730
18772
  return valueNotAvailable(searchKey);
@@ -18780,7 +18822,7 @@ stores.inject(MyMetaStore, storeInstance);
18780
18822
  const reverseSearch = _searchMode === -1;
18781
18823
  const index = _searchMode === 2 || _searchMode === -2
18782
18824
  ? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18783
- : linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
18825
+ : linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, this.lookupCaches, reverseSearch);
18784
18826
  if (index !== -1) {
18785
18827
  return lookupDirection === "col"
18786
18828
  ? _returnRange.map((col) => [col[index]])
@@ -28268,7 +28310,7 @@ stores.inject(MyMetaStore, storeInstance);
28268
28310
  }
28269
28311
  function getPyramidChartData(definition, dataSets, labelRange, getters) {
28270
28312
  const barChartData = getBarChartData(definition, dataSets, labelRange, getters);
28271
- const barDataset = barChartData.dataSetsValues;
28313
+ const barDataset = barChartData.dataSetsValues.filter((ds) => !ds.hidden);
28272
28314
  const pyramidDatasetValues = [];
28273
28315
  if (barDataset[0]) {
28274
28316
  const pyramidData = barDataset[0].data.map((value) => (value > 0 ? value : 0));
@@ -28745,10 +28787,8 @@ stores.inject(MyMetaStore, storeInstance);
28745
28787
  function getChartDatasetValues(getters, dataSets) {
28746
28788
  const datasetValues = [];
28747
28789
  for (const [dsIndex, ds] of Object.entries(dataSets)) {
28748
- if (getters.isColHidden(ds.dataRange.sheetId, ds.dataRange.zone.left)) {
28749
- continue;
28750
- }
28751
28790
  let label;
28791
+ let hidden = getters.isColHidden(ds.dataRange.sheetId, ds.dataRange.zone.left);
28752
28792
  if (ds.labelCell) {
28753
28793
  const labelRange = ds.labelCell;
28754
28794
  const cell = labelRange
@@ -28775,9 +28815,9 @@ stores.inject(MyMetaStore, storeInstance);
28775
28815
  data.fill(1);
28776
28816
  }
28777
28817
  else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(), DEFAULT_LOCALE))) {
28778
- continue;
28818
+ hidden = true;
28779
28819
  }
28780
- datasetValues.push({ data, label });
28820
+ datasetValues.push({ data, label, hidden });
28781
28821
  }
28782
28822
  return datasetValues;
28783
28823
  }
@@ -28788,12 +28828,13 @@ stores.inject(MyMetaStore, storeInstance);
28788
28828
  const colors = getChartColorsGenerator(definition, dataSetsValues.length);
28789
28829
  const trendDatasets = [];
28790
28830
  for (const index in dataSetsValues) {
28791
- let { label, data } = dataSetsValues[index];
28831
+ let { label, data, hidden } = dataSetsValues[index];
28792
28832
  label = definition.dataSets?.[index].label || label;
28793
28833
  const backgroundColor = colors.next();
28794
28834
  const dataset = {
28795
28835
  label,
28796
28836
  data,
28837
+ hidden,
28797
28838
  borderColor: definition.background || BACKGROUND_CHART_COLOR,
28798
28839
  borderWidth: definition.stacked ? 1 : 0,
28799
28840
  backgroundColor,
@@ -28826,6 +28867,9 @@ stores.inject(MyMetaStore, storeInstance);
28826
28867
  const labelsWithSubTotals = [];
28827
28868
  let lastValue = 0;
28828
28869
  for (const dataSetsValue of dataSetsValues) {
28870
+ if (dataSetsValue.hidden) {
28871
+ continue;
28872
+ }
28829
28873
  for (let i = 0; i < dataSetsValue.data.length; i++) {
28830
28874
  const data = dataSetsValue.data[i];
28831
28875
  labelsWithSubTotals.push(labels[i]);
@@ -28861,7 +28905,7 @@ stores.inject(MyMetaStore, storeInstance);
28861
28905
  const trendDatasets = [];
28862
28906
  const colors = getChartColorsGenerator(definition, dataSetsValues.length);
28863
28907
  for (let index = 0; index < dataSetsValues.length; index++) {
28864
- let { label, data } = dataSetsValues[index];
28908
+ let { label, data, hidden } = dataSetsValues[index];
28865
28909
  label = definition.dataSets?.[index].label || label;
28866
28910
  const color = colors.next();
28867
28911
  if (axisType && ["linear", "time"].includes(axisType)) {
@@ -28871,6 +28915,7 @@ stores.inject(MyMetaStore, storeInstance);
28871
28915
  const dataset = {
28872
28916
  label,
28873
28917
  data,
28918
+ hidden,
28874
28919
  tension: 0, // 0 -> render straight lines, which is much faster
28875
28920
  borderColor: color,
28876
28921
  backgroundColor: areaChart ? setColorAlpha(color, LINE_FILL_TRANSPARENCY) : color,
@@ -28903,11 +28948,13 @@ stores.inject(MyMetaStore, storeInstance);
28903
28948
  const dataSets = [];
28904
28949
  const dataSetsLength = Math.max(0, ...dataSetsValues.map((ds) => ds?.data?.length ?? 0));
28905
28950
  const backgroundColor = getPieColors(new ColorGenerator(dataSetsLength), dataSetsValues);
28906
- for (const { label, data } of dataSetsValues) {
28951
+ for (const { label, data, hidden } of dataSetsValues) {
28952
+ if (hidden)
28953
+ continue;
28907
28954
  const dataset = {
28908
28955
  label,
28909
28956
  data,
28910
- borderColor: BACKGROUND_CHART_COLOR,
28957
+ borderColor: definition.background || "#FFFFFF",
28911
28958
  backgroundColor,
28912
28959
  hoverOffset: 30,
28913
28960
  };
@@ -28921,7 +28968,7 @@ stores.inject(MyMetaStore, storeInstance);
28921
28968
  const colors = getChartColorsGenerator(definition, dataSetsValues.length);
28922
28969
  const trendDatasets = [];
28923
28970
  for (let index = 0; index < dataSetsValues.length; index++) {
28924
- let { label, data } = dataSetsValues[index];
28971
+ let { label, data, hidden } = dataSetsValues[index];
28925
28972
  label = definition.dataSets?.[index].label || label;
28926
28973
  const design = definition.dataSets?.[index];
28927
28974
  const color = colors.next();
@@ -28929,6 +28976,7 @@ stores.inject(MyMetaStore, storeInstance);
28929
28976
  const dataset = {
28930
28977
  label: label,
28931
28978
  data,
28979
+ hidden,
28932
28980
  borderColor: color,
28933
28981
  backgroundColor: color,
28934
28982
  yAxisID: definition.dataSets?.[index].yAxisId || "y",
@@ -28953,7 +29001,7 @@ stores.inject(MyMetaStore, storeInstance);
28953
29001
  const fill = definition.fillArea ?? false;
28954
29002
  const colors = getChartColorsGenerator(definition, dataSetsValues.length);
28955
29003
  for (let i = 0; i < dataSetsValues.length; i++) {
28956
- let { label, data } = dataSetsValues[i];
29004
+ let { label, data, hidden } = dataSetsValues[i];
28957
29005
  if (definition.dataSets?.[i]?.label) {
28958
29006
  label = definition.dataSets[i].label;
28959
29007
  }
@@ -28961,6 +29009,7 @@ stores.inject(MyMetaStore, storeInstance);
28961
29009
  const dataset = {
28962
29010
  label,
28963
29011
  data,
29012
+ hidden,
28964
29013
  borderColor,
28965
29014
  backgroundColor: borderColor,
28966
29015
  };
@@ -29106,6 +29155,11 @@ stores.inject(MyMetaStore, storeInstance);
29106
29155
  hidden: false,
29107
29156
  lineWidth: 2,
29108
29157
  })),
29158
+ filter: (legendItem, data) => {
29159
+ return "datasetIndex" in legendItem
29160
+ ? !data.datasets[legendItem.datasetIndex].hidden
29161
+ : true;
29162
+ },
29109
29163
  },
29110
29164
  };
29111
29165
  }
@@ -29167,6 +29221,11 @@ stores.inject(MyMetaStore, storeInstance);
29167
29221
  }
29168
29222
  return legendValues;
29169
29223
  },
29224
+ filter: (legendItem, data) => {
29225
+ return "datasetIndex" in legendItem
29226
+ ? !data.datasets[legendItem.datasetIndex].hidden
29227
+ : true;
29228
+ },
29170
29229
  },
29171
29230
  onClick: () => { }, // Disables click interaction with the waterfall chart legend items
29172
29231
  };
@@ -29250,6 +29309,11 @@ stores.inject(MyMetaStore, storeInstance);
29250
29309
  ...legendLabelConfig,
29251
29310
  };
29252
29311
  }),
29312
+ filter: (legendItem, data) => {
29313
+ return "datasetIndex" in legendItem
29314
+ ? !data.datasets[legendItem.datasetIndex].hidden
29315
+ : true;
29316
+ },
29253
29317
  },
29254
29318
  };
29255
29319
  }
@@ -33039,6 +33103,100 @@ stores.inject(MyMetaStore, storeInstance);
33039
33103
  function getOpenedMenus() {
33040
33104
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
33041
33105
  }
33106
+ function getCurrentSelection(el) {
33107
+ let { startElement, endElement, startSelectionOffset, endSelectionOffset } = getStartAndEndSelection(el);
33108
+ let startSizeBefore = findSelectionIndex(el, startElement, startSelectionOffset);
33109
+ let endSizeBefore = findSelectionIndex(el, endElement, endSelectionOffset);
33110
+ return {
33111
+ start: startSizeBefore,
33112
+ end: endSizeBefore,
33113
+ };
33114
+ }
33115
+ function getStartAndEndSelection(el) {
33116
+ const selection = document.getSelection();
33117
+ return {
33118
+ startElement: selection.anchorNode || el,
33119
+ startSelectionOffset: selection.anchorOffset,
33120
+ endElement: selection.focusNode || el,
33121
+ endSelectionOffset: selection.focusOffset,
33122
+ };
33123
+ }
33124
+ /**
33125
+ * Computes the text 'index' inside this.el based on the currently selected node and its offset.
33126
+ * The selected node is either a Text node or an Element node.
33127
+ *
33128
+ * case 1 -Text node:
33129
+ * the offset is the number of characters from the start of the node. We have to add this offset to the
33130
+ * content length of all previous nodes.
33131
+ *
33132
+ * case 2 - Element node:
33133
+ * the offset is the number of child nodes before the selected node. We have to add the content length of
33134
+ * all the nodes prior to the selected node as well as the content of the child node before the offset.
33135
+ *
33136
+ * See the MDN documentation for more details.
33137
+ * https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
33138
+ * https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
33139
+ *
33140
+ */
33141
+ function findSelectionIndex(el, nodeToFind, nodeOffset) {
33142
+ let usedCharacters = 0;
33143
+ let it = iterateChildren(el);
33144
+ let current = it.next();
33145
+ let isFirstParagraph = true;
33146
+ while (!current.done && current.value !== nodeToFind) {
33147
+ if (!current.value.hasChildNodes()) {
33148
+ if (current.value.textContent) {
33149
+ usedCharacters += current.value.textContent.length;
33150
+ }
33151
+ }
33152
+ // One new paragraph = one new line character, except for the first paragraph
33153
+ if (current.value.nodeName === "P" ||
33154
+ (current.value.nodeName === "DIV" && current.value !== el) // On paste, the HTML may contain <div> instead of <p>
33155
+ ) {
33156
+ if (isFirstParagraph) {
33157
+ isFirstParagraph = false;
33158
+ }
33159
+ else {
33160
+ usedCharacters++;
33161
+ }
33162
+ }
33163
+ current = it.next();
33164
+ }
33165
+ if (current.value !== nodeToFind) {
33166
+ /** This situation can happen if the code is called while the selection is not currently on the element.
33167
+ * In this case, we return 0 because we don't know the size of the text before the selection.
33168
+ *
33169
+ * A known occurrence is triggered since the introduction of commit d4663158 (PR #2038).
33170
+ */
33171
+ return 0;
33172
+ }
33173
+ else {
33174
+ if (!current.value.hasChildNodes()) {
33175
+ usedCharacters += nodeOffset;
33176
+ }
33177
+ else {
33178
+ const children = [...current.value.childNodes].slice(0, nodeOffset);
33179
+ usedCharacters += children.reduce((acc, child, index) => {
33180
+ if (child.textContent !== null) {
33181
+ // need to account for paragraph nodes that implicitly add a new line
33182
+ // except for the last paragraph
33183
+ let chars = child.textContent.length;
33184
+ if (child.nodeName === "P" && index !== children.length - 1) {
33185
+ chars++;
33186
+ }
33187
+ return acc + chars;
33188
+ }
33189
+ else {
33190
+ return acc;
33191
+ }
33192
+ }, 0);
33193
+ }
33194
+ }
33195
+ if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
33196
+ usedCharacters++;
33197
+ }
33198
+ return usedCharacters;
33199
+ }
33042
33200
  const letterRegex = /^[a-zA-Z]$/;
33043
33201
  /**
33044
33202
  * Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
@@ -38274,7 +38432,7 @@ stores.inject(MyMetaStore, storeInstance);
38274
38432
  .o-font-size-editor {
38275
38433
  height: calc(100% - 4px);
38276
38434
  input.o-font-size {
38277
- outline-color: ${SELECTION_BORDER_COLOR};
38435
+ outline: none;
38278
38436
  height: 20px;
38279
38437
  width: 23px;
38280
38438
  }
@@ -39887,6 +40045,10 @@ stores.inject(MyMetaStore, storeInstance);
39887
40045
  if (currentStart === start && currentEnd === end) {
39888
40046
  return;
39889
40047
  }
40048
+ if (selection.rangeCount === 0) {
40049
+ const range = document.createRange();
40050
+ selection.addRange(range);
40051
+ }
39890
40052
  const currentRange = selection.getRangeAt(0);
39891
40053
  let range;
39892
40054
  if (this.el.contains(currentRange.startContainer)) {
@@ -39914,8 +40076,16 @@ stores.inject(MyMetaStore, storeInstance);
39914
40076
  }
39915
40077
  let startNode = this.findChildAtCharacterIndex(start);
39916
40078
  let endNode = this.findChildAtCharacterIndex(end);
39917
- range.setStart(startNode.node, startNode.offset);
39918
- range.setEnd(endNode.node, endNode.offset);
40079
+ // setEnd (setStart) will result in a collapsed range if the end point is before the start point
40080
+ // https://developer.mozilla.org/en-US/docs/Web/API/Range/setEnd
40081
+ if (start <= end) {
40082
+ range.setStart(startNode.node, startNode.offset);
40083
+ range.setEnd(endNode.node, endNode.offset);
40084
+ }
40085
+ else {
40086
+ range.setStart(endNode.node, endNode.offset);
40087
+ range.setEnd(startNode.node, startNode.offset);
40088
+ }
39919
40089
  }
39920
40090
  }
39921
40091
  /**
@@ -40049,7 +40219,7 @@ stores.inject(MyMetaStore, storeInstance);
40049
40219
  if (!focusedNode || !this.el.contains(focusedNode))
40050
40220
  return;
40051
40221
  const element = focusedNode instanceof HTMLElement ? focusedNode : focusedNode.parentElement;
40052
- element?.scrollIntoView({ block: "nearest" });
40222
+ element?.scrollIntoView?.({ block: "nearest" });
40053
40223
  }
40054
40224
  /**
40055
40225
  * remove the current selection of the user
@@ -40069,100 +40239,7 @@ stores.inject(MyMetaStore, storeInstance);
40069
40239
  * finds the indexes of the current selection.
40070
40240
  * */
40071
40241
  getCurrentSelection() {
40072
- let { startElement, endElement, startSelectionOffset, endSelectionOffset } = this.getStartAndEndSelection();
40073
- let startSizeBefore = this.findSelectionIndex(startElement, startSelectionOffset);
40074
- let endSizeBefore = this.findSelectionIndex(endElement, endSelectionOffset);
40075
- return {
40076
- start: startSizeBefore,
40077
- end: endSizeBefore,
40078
- };
40079
- }
40080
- /**
40081
- * Computes the text 'index' inside this.el based on the currently selected node and its offset.
40082
- * The selected node is either a Text node or an Element node.
40083
- *
40084
- * case 1 -Text node:
40085
- * the offset is the number of characters from the start of the node. We have to add this offset to the
40086
- * content length of all previous nodes.
40087
- *
40088
- * case 2 - Element node:
40089
- * the offset is the number of child nodes before the selected node. We have to add the content length of
40090
- * all the bnodes prior to the selected node as well as the content of the child node before the offset.
40091
- *
40092
- * See the MDN documentation for more details.
40093
- * https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
40094
- * https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
40095
- *
40096
- */
40097
- findSelectionIndex(nodeToFind, nodeOffset) {
40098
- let usedCharacters = 0;
40099
- let it = iterateChildren(this.el);
40100
- let current = it.next();
40101
- let isFirstParagraph = true;
40102
- while (!current.done && current.value !== nodeToFind) {
40103
- if (!current.value.hasChildNodes()) {
40104
- if (current.value.textContent) {
40105
- usedCharacters += current.value.textContent.length;
40106
- }
40107
- }
40108
- // One new paragraph = one new line character, except for the first paragraph
40109
- if (current.value.nodeName === "P" ||
40110
- (current.value.nodeName === "DIV" && current.value !== this.el) // On paste, the HTML may contain <div> instead of <p>
40111
- ) {
40112
- if (isFirstParagraph) {
40113
- isFirstParagraph = false;
40114
- }
40115
- else {
40116
- usedCharacters++;
40117
- }
40118
- }
40119
- current = it.next();
40120
- }
40121
- if (current.value !== nodeToFind) {
40122
- /** This situation can happen if the code is called while the selection is not currently on the ContentEditableHelper.
40123
- * In this case, we return 0 because we don't know the size of the text before the selection.
40124
- *
40125
- * A known occurence is triggered since the introduction of commit d4663158 (PR #2038).
40126
- *
40127
- * FIXME: find a way to test eventhough the selection API is not available in jsDOM.
40128
- */
40129
- return 0;
40130
- }
40131
- else {
40132
- if (!current.value.hasChildNodes()) {
40133
- usedCharacters += nodeOffset;
40134
- }
40135
- else {
40136
- const children = [...current.value.childNodes].slice(0, nodeOffset);
40137
- usedCharacters += children.reduce((acc, child, index) => {
40138
- if (child.textContent !== null) {
40139
- // need to account for paragraph nodes that implicitely add a new line
40140
- // except for the last paragraph
40141
- let chars = child.textContent.length;
40142
- if (child.nodeName === "P" && index !== children.length - 1) {
40143
- chars++;
40144
- }
40145
- return acc + chars;
40146
- }
40147
- else {
40148
- return acc;
40149
- }
40150
- }, 0);
40151
- }
40152
- }
40153
- if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
40154
- usedCharacters++;
40155
- }
40156
- return usedCharacters;
40157
- }
40158
- getStartAndEndSelection() {
40159
- const selection = document.getSelection();
40160
- return {
40161
- startElement: selection.anchorNode || this.el,
40162
- startSelectionOffset: selection.anchorOffset,
40163
- endElement: selection.focusNode || this.el,
40164
- endSelectionOffset: selection.focusOffset,
40165
- };
40242
+ return getCurrentSelection(this.el);
40166
40243
  }
40167
40244
  getText() {
40168
40245
  let text = "";
@@ -53117,6 +53194,10 @@ stores.inject(MyMetaStore, storeInstance);
53117
53194
  return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
53118
53195
  case "CLEAR_CELL":
53119
53196
  return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
53197
+ case "UPDATE_CELL_POSITION":
53198
+ return !cmd.cellId || this.cells[cmd.sheetId]?.[cmd.cellId]
53199
+ ? "Success" /* CommandResult.Success */
53200
+ : "InvalidCellId" /* CommandResult.InvalidCellId */;
53120
53201
  default:
53121
53202
  return "Success" /* CommandResult.Success */;
53122
53203
  }
@@ -53161,6 +53242,9 @@ stores.inject(MyMetaStore, storeInstance);
53161
53242
  case "DELETE_CONTENT":
53162
53243
  this.clearZones(cmd.sheetId, cmd.target);
53163
53244
  break;
53245
+ case "DELETE_SHEET": {
53246
+ this.history.update("cells", cmd.sheetId, undefined);
53247
+ }
53164
53248
  }
53165
53249
  }
53166
53250
  clearZones(sheetId, zones) {
@@ -53951,6 +54035,9 @@ stores.inject(MyMetaStore, storeInstance);
53951
54035
  allowDispatch(cmd) {
53952
54036
  switch (cmd.type) {
53953
54037
  case "ADD_CONDITIONAL_FORMAT":
54038
+ if (cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId))) {
54039
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
54040
+ }
53954
54041
  return this.checkValidations(cmd, this.checkCFRule, this.checkEmptyRange, this.checkCFHasChanged);
53955
54042
  case "CHANGE_CONDITIONAL_FORMAT_PRIORITY":
53956
54043
  return this.checkValidPriorityChange(cmd.cfId, cmd.delta, cmd.sheetId);
@@ -54367,8 +54454,17 @@ stores.inject(MyMetaStore, storeInstance);
54367
54454
  allowDispatch(cmd) {
54368
54455
  switch (cmd.type) {
54369
54456
  case "ADD_DATA_VALIDATION_RULE":
54457
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
54458
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
54459
+ }
54460
+ if (cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId))) {
54461
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
54462
+ }
54370
54463
  return this.checkValidations(cmd, this.chainValidations(this.checkEmptyRange, this.checkValidRange, this.checkCriterionTypeIsValid, this.checkCriterionHasValidNumberOfValues, this.checkCriterionValuesAreValid));
54371
54464
  case "REMOVE_DATA_VALIDATION_RULE":
54465
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
54466
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
54467
+ }
54372
54468
  if (!this.rules[cmd.sheetId].find((rule) => rule.id === cmd.id)) {
54373
54469
  return "UnknownDataValidationRule" /* CommandResult.UnknownDataValidationRule */;
54374
54470
  }
@@ -54595,6 +54691,7 @@ stores.inject(MyMetaStore, storeInstance);
54595
54691
  class FigurePlugin extends CorePlugin {
54596
54692
  static getters = ["getFigures", "getFigure", "getFigureSheetId"];
54597
54693
  figures = {};
54694
+ insertionOrders = []; // TODO use a list in master
54598
54695
  // ---------------------------------------------------------------------------
54599
54696
  // Command Handling
54600
54697
  // ---------------------------------------------------------------------------
@@ -54697,11 +54794,14 @@ stores.inject(MyMetaStore, storeInstance);
54697
54794
  }
54698
54795
  addFigure(figure, sheetId) {
54699
54796
  this.history.update("figures", sheetId, figure.id, figure);
54797
+ this.history.update("insertionOrders", this.insertionOrders.length, figure.id);
54700
54798
  }
54701
54799
  deleteSheet(sheetId) {
54800
+ this.history.update("insertionOrders", this.insertionOrders.filter((id) => !this.figures[sheetId]?.[id]));
54702
54801
  this.history.update("figures", sheetId, undefined);
54703
54802
  }
54704
54803
  removeFigure(id, sheetId) {
54804
+ this.history.update("insertionOrders", this.insertionOrders.filter((figureId) => figureId !== id));
54705
54805
  this.history.update("figures", sheetId, id, undefined);
54706
54806
  }
54707
54807
  checkFigureExists(sheetId, figureId) {
@@ -54720,7 +54820,14 @@ stores.inject(MyMetaStore, storeInstance);
54720
54820
  // Getters
54721
54821
  // ---------------------------------------------------------------------------
54722
54822
  getFigures(sheetId) {
54723
- return Object.values(this.figures[sheetId] || {}).filter(isDefined);
54823
+ const figures = [];
54824
+ for (const figureId of this.insertionOrders) {
54825
+ const figure = this.figures[sheetId]?.[figureId];
54826
+ if (figure) {
54827
+ figures.push(figure);
54828
+ }
54829
+ }
54830
+ return figures;
54724
54831
  }
54725
54832
  getFigure(sheetId, figureId) {
54726
54833
  return this.figures[sheetId]?.[figureId];
@@ -54733,11 +54840,9 @@ stores.inject(MyMetaStore, storeInstance);
54733
54840
  // ---------------------------------------------------------------------------
54734
54841
  import(data) {
54735
54842
  for (let sheet of data.sheets) {
54736
- const figures = {};
54737
- sheet.figures.forEach((figure) => {
54738
- figures[figure.id] = figure;
54739
- });
54740
- this.figures[sheet.id] = figures;
54843
+ for (const figure of sheet.figures) {
54844
+ this.addFigure(figure, sheet.id);
54845
+ }
54741
54846
  }
54742
54847
  }
54743
54848
  export(data) {
@@ -56163,6 +56268,9 @@ stores.inject(MyMetaStore, storeInstance);
56163
56268
  case "CREATE_SHEET": {
56164
56269
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
56165
56270
  }
56271
+ case "DUPLICATE_SHEET": {
56272
+ return this.sheets[cmd.sheetIdTo] ? "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */ : "Success" /* CommandResult.Success */;
56273
+ }
56166
56274
  case "MOVE_SHEET":
56167
56275
  try {
56168
56276
  const currentIndex = this.orderedSheetIds.findIndex((id) => id === cmd.sheetId);
@@ -56974,6 +57082,10 @@ stores.inject(MyMetaStore, storeInstance);
56974
57082
  checkZonesAreInSheet(cmd) {
56975
57083
  if (!("sheetId" in cmd))
56976
57084
  return "Success" /* CommandResult.Success */;
57085
+ if ("ranges" in cmd &&
57086
+ cmd.ranges.some((rangeData) => rangeData._sheetId !== "" && !this.getters.tryGetSheet(rangeData._sheetId))) {
57087
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
57088
+ }
56977
57089
  return this.checkZonesExistInSheet(cmd.sheetId, this.getCommandZones(cmd));
56978
57090
  }
56979
57091
  }
@@ -56982,6 +57094,7 @@ stores.inject(MyMetaStore, storeInstance);
56982
57094
  class TablePlugin extends CorePlugin {
56983
57095
  static getters = ["getCoreTable", "getCoreTables", "getCoreTableMatchingTopLeft"];
56984
57096
  tables = {};
57097
+ insertionOrders = {};
56985
57098
  adaptRanges(applyChange, sheetId) {
56986
57099
  const sheetIds = sheetId ? [sheetId] : this.getters.getSheetIds();
56987
57100
  for (const sheetId of sheetIds) {
@@ -56993,6 +57106,9 @@ stores.inject(MyMetaStore, storeInstance);
56993
57106
  allowDispatch(cmd) {
56994
57107
  switch (cmd.type) {
56995
57108
  case "CREATE_TABLE":
57109
+ if (cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId) || rangeData._sheetId !== cmd.sheetId)) {
57110
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
57111
+ }
56996
57112
  const zones = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData).zone);
56997
57113
  if (!areZonesContinuous(zones)) {
56998
57114
  return "NonContinuousTargets" /* CommandResult.NonContinuousTargets */;
@@ -57023,11 +57139,13 @@ stores.inject(MyMetaStore, storeInstance);
57023
57139
  switch (cmd.type) {
57024
57140
  case "CREATE_SHEET":
57025
57141
  this.history.update("tables", cmd.sheetId, {});
57142
+ this.history.update("insertionOrders", cmd.sheetId, []);
57026
57143
  break;
57027
57144
  case "DELETE_SHEET": {
57028
57145
  const tables = { ...this.tables };
57029
57146
  delete tables[cmd.sheetId];
57030
57147
  this.history.update("tables", tables);
57148
+ this.history.update("insertionOrders", cmd.sheetId, undefined);
57031
57149
  break;
57032
57150
  }
57033
57151
  case "DUPLICATE_SHEET": {
@@ -57039,6 +57157,9 @@ stores.inject(MyMetaStore, storeInstance);
57039
57157
  : this.copyStaticTableForSheet(cmd.sheetIdTo, table);
57040
57158
  }
57041
57159
  this.history.update("tables", cmd.sheetIdTo, newTables);
57160
+ this.history.update("insertionOrders", cmd.sheetIdTo, [
57161
+ ...(this.insertionOrders[cmd.sheetId] ?? []),
57162
+ ]);
57042
57163
  break;
57043
57164
  }
57044
57165
  case "CREATE_TABLE": {
@@ -57052,6 +57173,10 @@ stores.inject(MyMetaStore, storeInstance);
57052
57173
  ? this.createDynamicTable(id, union, config)
57053
57174
  : this.createStaticTable(id, cmd.tableType, union, config);
57054
57175
  this.history.update("tables", cmd.sheetId, newTable.id, newTable);
57176
+ this.history.update("insertionOrders", cmd.sheetId, [
57177
+ ...(this.insertionOrders[cmd.sheetId] ?? []),
57178
+ newTable.id,
57179
+ ]);
57055
57180
  break;
57056
57181
  }
57057
57182
  case "REMOVE_TABLE": {
@@ -57062,6 +57187,7 @@ stores.inject(MyMetaStore, storeInstance);
57062
57187
  }
57063
57188
  }
57064
57189
  this.history.update("tables", cmd.sheetId, tables);
57190
+ this.history.update("insertionOrders", cmd.sheetId, this.insertionOrders[cmd.sheetId]?.filter((id) => id in tables));
57065
57191
  break;
57066
57192
  }
57067
57193
  case "UPDATE_TABLE": {
@@ -57097,7 +57223,14 @@ stores.inject(MyMetaStore, storeInstance);
57097
57223
  }
57098
57224
  }
57099
57225
  getCoreTables(sheetId) {
57100
- return this.tables[sheetId] ? Object.values(this.tables[sheetId]).filter(isDefined) : [];
57226
+ const tables = [];
57227
+ for (const tableId of this.insertionOrders[sheetId] || []) {
57228
+ const table = this.tables[sheetId][tableId];
57229
+ if (table) {
57230
+ tables.push(table);
57231
+ }
57232
+ }
57233
+ return tables;
57101
57234
  }
57102
57235
  getCoreTable({ sheetId, col, row }) {
57103
57236
  return this.getCoreTables(sheetId).find((table) => isInside(col, row, table.range.zone));
@@ -57380,6 +57513,7 @@ stores.inject(MyMetaStore, storeInstance);
57380
57513
  // ---------------------------------------------------------------------------
57381
57514
  import(data) {
57382
57515
  for (const sheet of data.sheets) {
57516
+ const tableIds = [];
57383
57517
  for (const tableData of sheet.tables || []) {
57384
57518
  const uuid = `${nextTableId++}`;
57385
57519
  const tableConfig = tableData.config || DEFAULT_TABLE_CONFIG;
@@ -57389,7 +57523,9 @@ stores.inject(MyMetaStore, storeInstance);
57389
57523
  ? this.createDynamicTable(uuid, range, tableConfig)
57390
57524
  : this.createStaticTable(uuid, tableType, range, tableConfig);
57391
57525
  this.history.update("tables", sheet.id, table.id, table);
57526
+ tableIds.push(table.id);
57392
57527
  }
57528
+ this.history.update("insertionOrders", sheet.id, tableIds);
57393
57529
  }
57394
57530
  }
57395
57531
  export(data) {
@@ -57429,7 +57565,10 @@ stores.inject(MyMetaStore, storeInstance);
57429
57565
  allowDispatch(cmd) {
57430
57566
  switch (cmd.type) {
57431
57567
  case "GROUP_HEADERS": {
57432
- const { start, end } = cmd;
57568
+ const { start, end, sheetId } = cmd;
57569
+ if (!this.getters.tryGetSheet(sheetId)) {
57570
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
57571
+ }
57433
57572
  if (!this.getters.doesHeadersExist(cmd.sheetId, cmd.dimension, [start, end])) {
57434
57573
  return "InvalidHeaderGroupStartEnd" /* CommandResult.InvalidHeaderGroupStartEnd */;
57435
57574
  }
@@ -57442,7 +57581,10 @@ stores.inject(MyMetaStore, storeInstance);
57442
57581
  break;
57443
57582
  }
57444
57583
  case "UNGROUP_HEADERS": {
57445
- const { start, end } = cmd;
57584
+ const { start, end, sheetId } = cmd;
57585
+ if (!this.getters.tryGetSheet(sheetId)) {
57586
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
57587
+ }
57446
57588
  if (!this.getters.doesHeadersExist(cmd.sheetId, cmd.dimension, [start, end])) {
57447
57589
  return "InvalidHeaderGroupStartEnd" /* CommandResult.InvalidHeaderGroupStartEnd */;
57448
57590
  }
@@ -57453,6 +57595,9 @@ stores.inject(MyMetaStore, storeInstance);
57453
57595
  }
57454
57596
  case "UNFOLD_HEADER_GROUP":
57455
57597
  case "FOLD_HEADER_GROUP":
57598
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
57599
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
57600
+ }
57456
57601
  const group = this.findGroupWithStartEnd(cmd.sheetId, cmd.dimension, cmd.start, cmd.end);
57457
57602
  if (!group) {
57458
57603
  return "UnknownHeaderGroup" /* CommandResult.UnknownHeaderGroup */;
@@ -57853,6 +57998,9 @@ stores.inject(MyMetaStore, storeInstance);
57853
57998
  return this.checkDuplicatedMeasureIds(cmd.pivot);
57854
57999
  }
57855
58000
  case "UPDATE_PIVOT": {
58001
+ if (!(cmd.pivotId in this.pivots)) {
58002
+ return "PivotIdNotFound" /* CommandResult.PivotIdNotFound */;
58003
+ }
57856
58004
  if (deepEquals(cmd.pivot, this.pivots[cmd.pivotId]?.definition)) {
57857
58005
  return "NoChanges" /* CommandResult.NoChanges */;
57858
58006
  }
@@ -57869,6 +58017,8 @@ stores.inject(MyMetaStore, storeInstance);
57869
58017
  return "EmptyName" /* CommandResult.EmptyName */;
57870
58018
  }
57871
58019
  break;
58020
+ case "REMOVE_PIVOT":
58021
+ case "DUPLICATE_PIVOT":
57872
58022
  case "INSERT_PIVOT": {
57873
58023
  if (!(cmd.pivotId in this.pivots)) {
57874
58024
  return "PivotIdNotFound" /* CommandResult.PivotIdNotFound */;
@@ -57918,7 +58068,7 @@ stores.inject(MyMetaStore, storeInstance);
57918
58068
  break;
57919
58069
  }
57920
58070
  case "UPDATE_PIVOT": {
57921
- this.history.update("pivots", cmd.pivotId, "definition", cmd.pivot);
58071
+ this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
57922
58072
  this.compileCalculatedMeasures(cmd.pivot.measures);
57923
58073
  break;
57924
58074
  }
@@ -57989,7 +58139,7 @@ stores.inject(MyMetaStore, storeInstance);
57989
58139
  // Private
57990
58140
  // -------------------------------------------------------------------------
57991
58141
  addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
57992
- this.history.update("pivots", pivotId, { definition: pivot, formulaId });
58142
+ this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
57993
58143
  this.compileCalculatedMeasures(pivot.measures);
57994
58144
  this.history.update("formulaIds", formulaId, pivotId);
57995
58145
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
@@ -59575,6 +59725,10 @@ stores.inject(MyMetaStore, storeInstance);
59575
59725
  this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
59576
59726
  this.compilationParams.evalContext.updateDependencies = this.updateDependencies.bind(this);
59577
59727
  this.compilationParams.evalContext.addDependencies = this.addDependencies.bind(this);
59728
+ this.compilationParams.evalContext.lookupCaches = {
59729
+ forwardSearch: new Map(),
59730
+ reverseSearch: new Map(),
59731
+ };
59578
59732
  }
59579
59733
  createEmptyPositionSet() {
59580
59734
  const sheetSizes = {};
@@ -62895,6 +63049,9 @@ stores.inject(MyMetaStore, storeInstance);
62895
63049
  };
62896
63050
  }
62897
63051
  function createSheetTransformation(toTransform, executed) {
63052
+ if (toTransform.sheetId === executed.sheetId) {
63053
+ toTransform = { ...toTransform, sheetId: `${toTransform.sheetId}~` };
63054
+ }
62898
63055
  if (toTransform.name === executed.name) {
62899
63056
  return {
62900
63057
  ...toTransform,
@@ -63538,15 +63695,6 @@ stores.inject(MyMetaStore, storeInstance);
63538
63695
  }
63539
63696
  this.sendPendingMessage();
63540
63697
  }
63541
- dropPendingRevision(revisionId) {
63542
- this.revisions.drop(revisionId);
63543
- const revisionIds = this.pendingMessages
63544
- .filter((message) => message.type === "REMOTE_REVISION")
63545
- .map((message) => message.nextRevisionId);
63546
- this.trigger("pending-revisions-dropped", { revisionIds });
63547
- this.waitingAck = false;
63548
- this.waitingUndoRedoAck = false;
63549
- }
63550
63698
  /**
63551
63699
  * Send the next pending message
63552
63700
  */
@@ -63555,15 +63703,14 @@ stores.inject(MyMetaStore, storeInstance);
63555
63703
  if (!message)
63556
63704
  return;
63557
63705
  if (message.type === "REMOTE_REVISION") {
63558
- const revision = this.revisions.get(message.nextRevisionId);
63706
+ let revision = this.revisions.get(message.nextRevisionId);
63559
63707
  if (revision.commands.length === 0) {
63560
63708
  /**
63561
- * The command is empty, we have to drop all the next local revisions
63709
+ * The command is empty, we have to rebase all the next local revisions
63562
63710
  * to avoid issues with undo/redo
63563
63711
  */
63564
- this.dropPendingRevision(revision.id);
63565
- this.pendingMessages = [];
63566
- return;
63712
+ this.revisions.rebase(revision.id);
63713
+ revision = this.revisions.get(message.nextRevisionId);
63567
63714
  }
63568
63715
  message = {
63569
63716
  ...message,
@@ -63599,18 +63746,16 @@ stores.inject(MyMetaStore, storeInstance);
63599
63746
  case "REVISION_UNDONE": {
63600
63747
  this.waitingAck = false;
63601
63748
  this.pendingMessages = this.pendingMessages.filter((msg) => msg.nextRevisionId !== message.nextRevisionId);
63602
- const pendingRemoteRevisions = this.pendingMessages.filter((message) => message.type === "REMOTE_REVISION");
63603
- const firstTransformedRevisionIndex = pendingRemoteRevisions.findIndex((message) => !deepEquals(message.commands, this.revisions.get(message.nextRevisionId).commands));
63604
- if (firstTransformedRevisionIndex !== -1) {
63749
+ const firstPendingRevisionId = this.pendingMessages.findIndex((message) => message.type === "REMOTE_REVISION");
63750
+ if (firstPendingRevisionId !== -1) {
63605
63751
  /**
63606
63752
  * Some revisions undergo transformations that may cause issues with
63607
63753
  * undo/redo if the transformation is destructive (we don't get back
63608
63754
  * the original command by transforming it with the inverse).
63609
- * To prevent these problems, we must discard all subsequent local
63755
+ * To prevent these problems, we must rebase all subsequent local
63610
63756
  * revisions.
63611
63757
  */
63612
- this.dropPendingRevision(this.pendingMessages[firstTransformedRevisionIndex].nextRevisionId);
63613
- this.pendingMessages = this.pendingMessages.slice(0, firstTransformedRevisionIndex);
63758
+ this.revisions.rebase(this.pendingMessages[firstPendingRevisionId].nextRevisionId);
63614
63759
  }
63615
63760
  this.serverRevisionId = message.nextRevisionId;
63616
63761
  this.processedRevisions.add(message.nextRevisionId);
@@ -64738,6 +64883,10 @@ stores.inject(MyMetaStore, storeInstance);
64738
64883
  */
64739
64884
  checkZonesAreInSheet(cmd) {
64740
64885
  const sheetId = "sheetId" in cmd ? cmd.sheetId : this.getters.tryGetActiveSheetId();
64886
+ if ("ranges" in cmd &&
64887
+ cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId))) {
64888
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
64889
+ }
64741
64890
  const zones = this.getters.getCommandZones(cmd);
64742
64891
  if (!sheetId && zones.length > 0) {
64743
64892
  return "NoActiveSheet" /* CommandResult.NoActiveSheet */;
@@ -65292,7 +65441,6 @@ stores.inject(MyMetaStore, storeInstance);
65292
65441
  super(config);
65293
65442
  this.session = config.session;
65294
65443
  this.session.on("new-local-state-update", this, this.onNewLocalStateUpdate);
65295
- this.session.on("pending-revisions-dropped", this, ({ revisionIds }) => this.drop(revisionIds));
65296
65444
  this.session.on("snapshot", this, () => {
65297
65445
  this.undoStack = [];
65298
65446
  this.redoStack = [];
@@ -65362,10 +65510,6 @@ stores.inject(MyMetaStore, storeInstance);
65362
65510
  const lastNonRedoRevision = this.getPossibleRevisionToRepeat();
65363
65511
  return canRepeatRevision(lastNonRedoRevision);
65364
65512
  }
65365
- drop(revisionIds) {
65366
- this.undoStack = this.undoStack.filter((id) => !revisionIds.includes(id));
65367
- this.redoStack = [];
65368
- }
65369
65513
  onNewLocalStateUpdate({ id }) {
65370
65514
  this.undoStack.push(id);
65371
65515
  this.redoStack = [];
@@ -68069,7 +68213,9 @@ stores.inject(MyMetaStore, storeInstance);
68069
68213
  case "UNGROUP_HEADERS":
68070
68214
  case "GROUP_HEADERS":
68071
68215
  case "CREATE_SHEET":
68072
- this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
68216
+ if (this.getters.tryGetSheet(cmd.sheetId)) {
68217
+ this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
68218
+ }
68073
68219
  break;
68074
68220
  case "DUPLICATE_SHEET":
68075
68221
  this.headerPositions[cmd.sheetIdTo] = deepCopy(this.headerPositions[cmd.sheetId]);
@@ -68077,12 +68223,14 @@ stores.inject(MyMetaStore, storeInstance);
68077
68223
  }
68078
68224
  }
68079
68225
  finalize() {
68080
- if (this.isDirty) {
68081
- for (const sheetId of this.getters.getSheetIds()) {
68226
+ for (const sheetId of this.getters.getSheetIds()) {
68227
+ // sheets can be created without this plugin being aware of it
68228
+ // in concurrent situations.
68229
+ if (this.isDirty || !this.headerPositions[sheetId]) {
68082
68230
  this.headerPositions[sheetId] = this.computeHeaderPositionsOfSheet(sheetId);
68083
68231
  }
68084
- this.isDirty = false;
68085
68232
  }
68233
+ this.isDirty = false;
68086
68234
  }
68087
68235
  /**
68088
68236
  * Returns the size, start and end coordinates of a column on an unfolded sheet
@@ -71503,9 +71651,16 @@ stores.inject(MyMetaStore, storeInstance);
71503
71651
  this.fastForward();
71504
71652
  this.insert(redoId, this.buildEmpty(redoId), insertAfter);
71505
71653
  }
71506
- drop(operationId) {
71654
+ rebase(operationId) {
71655
+ const operation = this.get(operationId);
71656
+ const execution = [...this.tree.execution(this.HEAD_BRANCH).startAfter(operationId)];
71507
71657
  this.revertBefore(operationId);
71658
+ const baseId = this.HEAD_OPERATION.id;
71508
71659
  this.tree.drop(operationId);
71660
+ this.insert(operationId, operation, baseId);
71661
+ for (const { operation } of execution) {
71662
+ this.insert(operation.id, operation.data, this.HEAD_OPERATION.id);
71663
+ }
71509
71664
  }
71510
71665
  /**
71511
71666
  * Revert the state as it was *before* the given operation was executed.
@@ -74616,6 +74771,11 @@ stores.inject(MyMetaStore, storeInstance);
74616
74771
  dispatch: (command) => {
74617
74772
  const result = this.checkDispatchAllowed(command);
74618
74773
  if (!result.isSuccessful) {
74774
+ // core views plugins need to be invalidated
74775
+ this.dispatchToHandlers(this.coreHandlers, {
74776
+ type: "UNDO",
74777
+ commands: [command],
74778
+ });
74619
74779
  return;
74620
74780
  }
74621
74781
  this.isReplayingCommand = true;
@@ -75166,9 +75326,9 @@ stores.inject(MyMetaStore, storeInstance);
75166
75326
  exports.tokenize = tokenize;
75167
75327
 
75168
75328
 
75169
- __info__.version = "18.1.8";
75170
- __info__.date = "2025-02-14T08:42:08.322Z";
75171
- __info__.hash = "02682f4";
75329
+ __info__.version = "18.1.9";
75330
+ __info__.date = "2025-02-25T05:59:45.472Z";
75331
+ __info__.hash = "6789c1c";
75172
75332
 
75173
75333
 
75174
75334
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);