@odoo/o-spreadsheet 17.3.2 → 17.3.4

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,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.3.2
7
- * @date 2024-06-10T09:38:56.657Z
8
- * @hash c3b358f
6
+ * @version 17.3.4
7
+ * @date 2024-06-21T20:00:08.515Z
8
+ * @hash 6efbf3b
9
9
  */
10
10
 
11
11
  (function (exports, owl) {
@@ -2780,7 +2780,7 @@
2780
2780
  return false;
2781
2781
  }
2782
2782
  if (typeof operand === "number" && operator === "=") {
2783
- return toString(value) === toString(operand);
2783
+ return value.toString() === operand.toString();
2784
2784
  }
2785
2785
  if (operator === "<>" || operator === "=") {
2786
2786
  let result;
@@ -2840,14 +2840,13 @@
2840
2840
  if (countArg % 2 === 1) {
2841
2841
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2842
2842
  }
2843
- const dimRow = args[0].length;
2844
- const dimCol = args[0][0].length;
2843
+ const firstArg = toMatrix(args[0]);
2844
+ const dimRow = firstArg.length;
2845
+ const dimCol = firstArg[0].length;
2845
2846
  let predicates = [];
2846
2847
  for (let i = 0; i < countArg - 1; i += 2) {
2847
- const criteriaRange = args[i];
2848
- if (!isMatrix(criteriaRange) ||
2849
- criteriaRange.length !== dimRow ||
2850
- criteriaRange[0].length !== dimCol) {
2848
+ const criteriaRange = toMatrix(args[i]);
2849
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2851
2850
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2852
2851
  }
2853
2852
  const description = toString(args[i + 1]);
@@ -2861,7 +2860,7 @@
2861
2860
  for (let j = 0; j < dimCol; j++) {
2862
2861
  let validatedPredicates = true;
2863
2862
  for (let k = 0; k < countArg - 1; k += 2) {
2864
- const criteriaValue = args[k][i][j].value;
2863
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2865
2864
  const criterion = predicates[k / 2];
2866
2865
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2867
2866
  if (!validatedPredicates) {
@@ -9461,10 +9460,8 @@ stores.inject(MyMetaStore, storeInstance);
9461
9460
  const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
9462
9461
  return isEqual(this.getters.expandZone(activeSheetId, refRange.zone), oldZone);
9463
9462
  });
9464
- // this function assumes that the previous range is always found because
9465
- // it's called when changing a highlight, which exists by definition
9466
9463
  if (!previousRefToken) {
9467
- throw new Error("Previous range not found");
9464
+ return;
9468
9465
  }
9469
9466
  const previousRange = this.getters.getRangeFromSheetXC(activeSheetId, previousRefToken.value);
9470
9467
  this.selectionStart = previousRefToken.start;
@@ -10989,6 +10986,9 @@ stores.inject(MyMetaStore, storeInstance);
10989
10986
  if (types.some((t) => t.startsWith("RANGE"))) {
10990
10987
  result.acceptMatrix = true;
10991
10988
  }
10989
+ if (types.every((t) => t.startsWith("RANGE"))) {
10990
+ result.acceptMatrixOnly = true;
10991
+ }
10992
10992
  return result;
10993
10993
  }
10994
10994
  /**
@@ -11270,11 +11270,16 @@ stores.inject(MyMetaStore, storeInstance);
11270
11270
  compute: function (array, ...columns) {
11271
11271
  const _array = toMatrix(array);
11272
11272
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
11273
- assert(() => _columns.every((col) => col > 0 && col <= _array.length), _t("The columns arguments must be between 1 and %s (got %s).", _array.length.toString(), (_columns.find((col) => col <= 0 || col > _array.length) || 0).toString()));
11273
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
11274
+ assert(() => argOutOfRange.length === 0, _t("The columns arguments must be between -%s and %s (got %s), excluding 0.", _array.length.toString(), _array.length.toString(), argOutOfRange.join(",")));
11274
11275
  const result = Array(_columns.length);
11275
11276
  for (let col = 0; col < _columns.length; col++) {
11276
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
11277
- result[col] = _array[colIndex];
11277
+ if (_columns[col] > 0) {
11278
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
11279
+ }
11280
+ else {
11281
+ result[col] = _array[_array.length + _columns[col]];
11282
+ }
11278
11283
  }
11279
11284
  return result;
11280
11285
  },
@@ -11295,8 +11300,14 @@ stores.inject(MyMetaStore, storeInstance);
11295
11300
  const _array = toMatrix(array);
11296
11301
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
11297
11302
  const _nbColumns = _array.length;
11298
- assert(() => _rows.every((row) => row > 0 && row <= _array[0].length), _t("The rows arguments must be between 1 and %s (got %s).", _array[0].length.toString(), (_rows.find((row) => row <= 0 || row > _array[0].length) || 0).toString()));
11299
- return generateMatrix(_nbColumns, _rows.length, (col, row) => _array[col][_rows[row] - 1]); // -1 because rows arguments are 1-indexed
11303
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
11304
+ assert(() => argOutOfRange.length === 0, _t("The rows arguments must be between -%s and %s (got %s), excluding 0.", _array[0].length.toString(), _array[0].length.toString(), argOutOfRange.join(",")));
11305
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
11306
+ if (_rows[row] > 0) {
11307
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
11308
+ }
11309
+ return _array[col][_array[col].length + _rows[row]];
11310
+ });
11300
11311
  },
11301
11312
  isExported: true,
11302
11313
  };
@@ -19763,6 +19774,9 @@ stores.inject(MyMetaStore, storeInstance);
19763
19774
  }
19764
19775
  args[i] = arg[0][0];
19765
19776
  }
19777
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
19778
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
19779
+ }
19766
19780
  }
19767
19781
  return descr.compute.apply(this, args);
19768
19782
  }
@@ -21357,12 +21371,6 @@ stores.inject(MyMetaStore, storeInstance);
21357
21371
  // detect when an argument need to be evaluated as a meta argument
21358
21372
  const isMeta = argTypes.includes("META");
21359
21373
  const hasRange = argTypes.some((t) => isRangeType(t));
21360
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
21361
- if (isRangeOnly) {
21362
- if (!isRangeInput(currentArg)) {
21363
- throw new BadExpressionError(_t("Function %(function_name)s expects the parameter %(arg_index)s to be a reference to a cell or a range.", { function_name: functionName, arg_index: i + 1 }));
21364
- }
21365
- }
21366
21374
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange));
21367
21375
  }
21368
21376
  return compiledArgs;
@@ -21527,16 +21535,6 @@ stores.inject(MyMetaStore, storeInstance);
21527
21535
  function isRangeType(type) {
21528
21536
  return type.startsWith("RANGE");
21529
21537
  }
21530
- function isRangeInput(arg) {
21531
- if (arg.type === "REFERENCE") {
21532
- return true;
21533
- }
21534
- if (arg.type === "FUNCALL") {
21535
- const fnDef = functions$1[arg.value.toUpperCase()];
21536
- return fnDef && isRangeType(fnDef.returns[0]);
21537
- }
21538
- return false;
21539
- }
21540
21538
 
21541
21539
  const functions = functionRegistry.content;
21542
21540
  function isExportableToExcel(tokens) {
@@ -21965,7 +21963,9 @@ stores.inject(MyMetaStore, storeInstance);
21965
21963
  if (!groupByField) {
21966
21964
  return;
21967
21965
  }
21968
- return dataSource.getPossibleFieldValues(groupByField.split(":")[0]).map(({ value, label }) => {
21966
+ return dataSource
21967
+ .getPossibleFieldValues(groupByField.toString().split(":")[0])
21968
+ .map(({ value, label }) => {
21969
21969
  const isString = typeof value === "string";
21970
21970
  const text = isString ? `"${value}"` : value.toString();
21971
21971
  const color = isString ? tokenColors.STRING : tokenColors.NUMBER;
@@ -25451,7 +25451,7 @@ stores.inject(MyMetaStore, storeInstance);
25451
25451
  if (!anchor)
25452
25452
  return;
25453
25453
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
25454
- const elDims = {
25454
+ let elDims = {
25455
25455
  width: el.getBoundingClientRect().width,
25456
25456
  height: el.getBoundingClientRect().height,
25457
25457
  };
@@ -25459,7 +25459,14 @@ stores.inject(MyMetaStore, storeInstance);
25459
25459
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
25460
25460
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
25461
25461
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
25462
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25462
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
25463
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
25464
+ // Re-compute the dimensions after setting the max-width and max-height
25465
+ elDims = {
25466
+ width: el.getBoundingClientRect().width,
25467
+ height: el.getBoundingClientRect().height,
25468
+ };
25469
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25463
25470
  for (const property of Object.keys(style)) {
25464
25471
  el.style[property] = style[property];
25465
25472
  }
@@ -25522,8 +25529,6 @@ stores.inject(MyMetaStore, storeInstance);
25522
25529
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
25523
25530
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
25524
25531
  const cssProperties = {
25525
- "max-height": maxHeight + "px",
25526
- "max-width": maxWidth + "px",
25527
25532
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
25528
25533
  this.spreadsheetOffset.y -
25529
25534
  verticalOffset +
@@ -31337,10 +31342,8 @@ stores.inject(MyMetaStore, storeInstance);
31337
31342
 
31338
31343
  class AxisDesignEditor extends owl.Component {
31339
31344
  static template = "o-spreadsheet-AxisDesignEditor";
31340
- static components = {
31341
- Section,
31342
- ChartTitle,
31343
- };
31345
+ static components = { Section, ChartTitle };
31346
+ static props = { figureId: String, definition: Object, updateChart: Function, axesList: Array };
31344
31347
  state = owl.useState({ currentAxis: "x" });
31345
31348
  get axisTitleStyle() {
31346
31349
  const axisDesign = this.props.definition.axesDesign?.[this.state.currentAxis] ?? {};
@@ -31491,6 +31494,12 @@ stores.inject(MyMetaStore, storeInstance);
31491
31494
  AxisDesignEditor,
31492
31495
  RoundColorPicker,
31493
31496
  };
31497
+ static props = {
31498
+ figureId: String,
31499
+ definition: Object,
31500
+ canUpdateChart: Function,
31501
+ updateChart: Function,
31502
+ };
31494
31503
  state = owl.useState({ index: 0 });
31495
31504
  get axesList() {
31496
31505
  const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
@@ -31672,14 +31681,6 @@ stores.inject(MyMetaStore, storeInstance);
31672
31681
  const cancelledReasons = [...(this.state.sectionRuleDispatchResult?.reasons || [])];
31673
31682
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
31674
31683
  }
31675
- updateBackgroundColor(color) {
31676
- this.props.updateChart(this.props.figureId, {
31677
- background: color,
31678
- });
31679
- }
31680
- updateTitle(content) {
31681
- this.props.updateChart(this.props.figureId, { title: { text: content } });
31682
- }
31683
31684
  isRangeMinInvalid() {
31684
31685
  return !!(this.state.sectionRuleDispatchResult?.isCancelledBecause("EmptyGaugeRangeMin" /* CommandResult.EmptyGaugeRangeMin */) ||
31685
31686
  this.state.sectionRuleDispatchResult?.isCancelledBecause("GaugeRangeMinNaN" /* CommandResult.GaugeRangeMinNaN */) ||
@@ -31719,9 +31720,6 @@ stores.inject(MyMetaStore, storeInstance);
31719
31720
  sectionRule,
31720
31721
  });
31721
31722
  }
31722
- get backgroundColorTitle() {
31723
- return ChartTerms.BackgroundColor;
31724
- }
31725
31723
  }
31726
31724
 
31727
31725
  class LineConfigPanel extends GenericChartConfigPanel {
@@ -31904,9 +31902,6 @@ stores.inject(MyMetaStore, storeInstance);
31904
31902
  get humanizeNumbersLabel() {
31905
31903
  return _t("Humanize numbers");
31906
31904
  }
31907
- updateTitle(content) {
31908
- this.props.updateChart(this.props.figureId, { title: { text: content } });
31909
- }
31910
31905
  updateHumanizeNumbers(humanize) {
31911
31906
  this.props.updateChart(this.props.figureId, { humanize });
31912
31907
  }
@@ -31929,9 +31924,6 @@ stores.inject(MyMetaStore, storeInstance);
31929
31924
  break;
31930
31925
  }
31931
31926
  }
31932
- get backgroundColorTitle() {
31933
- return ChartTerms.BackgroundColor;
31934
- }
31935
31927
  }
31936
31928
 
31937
31929
  class WaterfallChartDesignPanel extends owl.Component {
@@ -33432,13 +33424,17 @@ stores.inject(MyMetaStore, storeInstance);
33432
33424
  class: { type: String, optional: true },
33433
33425
  };
33434
33426
  static components = { Menu };
33427
+ menuId = new UuidGenerator().uuidv4();
33435
33428
  selectRef = owl.useRef("select");
33436
33429
  selectRect = useAbsoluteBoundingRect(this.selectRef);
33437
33430
  state = owl.useState({
33438
33431
  isMenuOpen: false,
33439
33432
  });
33440
- onClick() {
33441
- this.state.isMenuOpen = true;
33433
+ onClick(ev) {
33434
+ if (ev.closedMenuId === this.menuId) {
33435
+ return;
33436
+ }
33437
+ this.state.isMenuOpen = !this.state.isMenuOpen;
33442
33438
  }
33443
33439
  onMenuClosed() {
33444
33440
  this.state.isMenuOpen = false;
@@ -33446,7 +33442,7 @@ stores.inject(MyMetaStore, storeInstance);
33446
33442
  get menuPosition() {
33447
33443
  return {
33448
33444
  x: this.selectRect.x,
33449
- y: this.selectRect.y,
33445
+ y: this.selectRect.y + this.selectRect.height,
33450
33446
  };
33451
33447
  }
33452
33448
  }
@@ -34386,9 +34382,9 @@ stores.inject(MyMetaStore, storeInstance);
34386
34382
  static props = {
34387
34383
  onCloseSidePanel: Function,
34388
34384
  };
34389
- dataRange = "";
34390
34385
  searchInput = owl.useRef("searchInput");
34391
34386
  store;
34387
+ state;
34392
34388
  get hasSearchResult() {
34393
34389
  return this.store.selectedMatchIndex !== null;
34394
34390
  }
@@ -34418,6 +34414,7 @@ stores.inject(MyMetaStore, storeInstance);
34418
34414
  }
34419
34415
  setup() {
34420
34416
  this.store = useLocalStore(FindAndReplaceStore);
34417
+ this.state = owl.useState({ dataRange: "" });
34421
34418
  owl.onMounted(() => this.searchInput.el?.focus());
34422
34419
  }
34423
34420
  onFocusSearch() {
@@ -34454,13 +34451,13 @@ stores.inject(MyMetaStore, storeInstance);
34454
34451
  this.store.updateSearchOptions({ searchScope });
34455
34452
  }
34456
34453
  onSearchRangeChanged(ranges) {
34457
- this.dataRange = ranges[0];
34454
+ this.state.dataRange = ranges[0];
34458
34455
  }
34459
34456
  updateDataRange() {
34460
- if (!this.dataRange || this.searchOptions.searchScope !== "specificRange") {
34457
+ if (!this.state.dataRange || this.searchOptions.searchScope !== "specificRange") {
34461
34458
  return;
34462
34459
  }
34463
- const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.dataRange);
34460
+ const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
34464
34461
  this.store.updateSearchOptions({ specificRange });
34465
34462
  }
34466
34463
  }
@@ -34926,7 +34923,7 @@ stores.inject(MyMetaStore, storeInstance);
34926
34923
  function createPivotDimension(fields, dimension) {
34927
34924
  const field = fields[dimension.name];
34928
34925
  const type = field?.type ?? "integer";
34929
- const granularity = field && isDateField(field) ? dimension.granularity ?? "month_number" : undefined;
34926
+ const granularity = field && isDateField(field) ? dimension.granularity : undefined;
34930
34927
  return {
34931
34928
  /**
34932
34929
  * Get the display name of the dimension
@@ -35329,10 +35326,13 @@ stores.inject(MyMetaStore, storeInstance);
35329
35326
  }
35330
35327
 
35331
35328
  function createDate(dimension, value, locale) {
35332
- const granularity = dimension.granularity || "month_number";
35333
- if (!(granularity in MAP_VALUE_DIMENSION_DATE)) {
35329
+ const granularity = dimension.granularity;
35330
+ if (!granularity || !(granularity in MAP_VALUE_DIMENSION_DATE)) {
35334
35331
  throw new Error(`Unknown date granularity: ${granularity}`);
35335
35332
  }
35333
+ if (value === null) {
35334
+ return null;
35335
+ }
35336
35336
  if (!MAP_VALUE_DIMENSION_DATE[granularity].set.has(value)) {
35337
35337
  MAP_VALUE_DIMENSION_DATE[granularity].set.add(value);
35338
35338
  const date = toJsDate(value, locale);
@@ -35559,7 +35559,8 @@ stores.inject(MyMetaStore, storeInstance);
35559
35559
  if (!finalCell) {
35560
35560
  return { value: "" };
35561
35561
  }
35562
- if (finalCell.value === null) {
35562
+ // Value can be null but stringified (e.g. an empty date, as for now every date is stringified)
35563
+ if (finalCell.value === null || finalCell.value === `${null}`) {
35563
35564
  return { value: _t("(Undefined)") };
35564
35565
  }
35565
35566
  if (dimension.type === "date") {
@@ -35595,10 +35596,15 @@ stores.inject(MyMetaStore, storeInstance);
35595
35596
  if (!operator) {
35596
35597
  throw new Error(`Aggregator ${aggregator} does not exist`);
35597
35598
  }
35598
- return {
35599
- value: values.length ? operator.fn([values], this.getters.getLocale()) : "",
35600
- format: operator.format(values[0]),
35601
- };
35599
+ try {
35600
+ return {
35601
+ value: values.length ? operator.fn([values], this.getters.getLocale()) : "",
35602
+ format: operator.format(values[0]),
35603
+ };
35604
+ }
35605
+ catch (e) {
35606
+ return handleError(e, aggregator.toUpperCase());
35607
+ }
35602
35608
  }
35603
35609
  getPossibleFieldValues(groupBy) {
35604
35610
  //TODO This method should be implemented for the autocomplete feature
@@ -36131,6 +36137,7 @@ stores.inject(MyMetaStore, storeInstance);
36131
36137
  class RemoveDuplicatesPanel extends owl.Component {
36132
36138
  static template = "o-spreadsheet-RemoveDuplicatesPanel";
36133
36139
  static components = { ValidationMessages, Section, Checkbox };
36140
+ static props = { onCloseSidePanel: Function };
36134
36141
  state = owl.useState({
36135
36142
  hasHeader: false,
36136
36143
  columns: {},
@@ -38555,7 +38562,7 @@ stores.inject(MyMetaStore, storeInstance);
38555
38562
  });
38556
38563
  }
38557
38564
  getContainerRect(container) {
38558
- const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
38565
+ const { width: viewWidth, height: viewHeight } = this.env.model.getters.getSheetViewDimension();
38559
38566
  const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
38560
38567
  const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
38561
38568
  const width = viewWidth - x;
@@ -51160,22 +51167,6 @@ stores.inject(MyMetaStore, storeInstance);
51160
51167
  this.addPivotFormula(cellPosition, formulaId, pivotCell);
51161
51168
  }
51162
51169
  }
51163
- const pivotZone = {
51164
- top: position.row,
51165
- bottom: position.row + pivotCells[0].length - 1,
51166
- left: position.col,
51167
- right: position.col + pivotCells.length - 1,
51168
- };
51169
- const numberOfHeaders = table.columns.length - 1;
51170
- const cmdContent = {
51171
- sheetId: position.sheetId,
51172
- ranges: [this.getters.getRangeDataFromZone(position.sheetId, pivotZone)],
51173
- config: { ...PIVOT_TABLE_CONFIG, numberOfHeaders },
51174
- tableType: "static",
51175
- };
51176
- if (this.canDispatch("CREATE_TABLE", cmdContent).isSuccessful) {
51177
- this.dispatch("CREATE_TABLE", cmdContent);
51178
- }
51179
51170
  }
51180
51171
  resizeSheet(sheetId, { col, row }, table) {
51181
51172
  const colLimit = table.getNumberOfDataColumns() + 1; // +1 for the Top-Left
@@ -52855,7 +52846,6 @@ stores.inject(MyMetaStore, storeInstance);
52855
52846
  if (!this.blockedArrayFormulas.has(position)) {
52856
52847
  this.invalidateSpreading(position);
52857
52848
  }
52858
- this.spreadingRelations.removeNode(position);
52859
52849
  const cell = this.getters.getCell(position);
52860
52850
  if (cell === undefined) {
52861
52851
  return EMPTY_CELL;
@@ -52897,6 +52887,7 @@ stores.inject(MyMetaStore, storeInstance);
52897
52887
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
52898
52888
  const nbColumns = formulaReturn.length;
52899
52889
  const nbRows = formulaReturn[0].length;
52890
+ this.spreadingRelations.removeNode(formulaPosition);
52900
52891
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.updateSpreadRelation(formulaPosition));
52901
52892
  this.assertNoMergedCellsInSpreadZone(formulaPosition, formulaReturn);
52902
52893
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.checkCollision(formulaPosition));
@@ -55901,7 +55892,10 @@ stores.inject(MyMetaStore, storeInstance);
55901
55892
  /**
55902
55893
  * Notify the server that the user client left the collaborative session
55903
55894
  */
55904
- leave() {
55895
+ leave(data) {
55896
+ if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
55897
+ this.snapshot(data);
55898
+ }
55905
55899
  delete this.clients[this.clientId];
55906
55900
  this.transportService.leave(this.clientId);
55907
55901
  this.transportService.sendMessage({
@@ -55914,6 +55908,9 @@ stores.inject(MyMetaStore, storeInstance);
55914
55908
  * Send a snapshot of the spreadsheet to the collaboration server
55915
55909
  */
55916
55910
  snapshot(data) {
55911
+ if (this.pendingMessages.length !== 0) {
55912
+ return;
55913
+ }
55917
55914
  const snapshotId = this.uuidGenerator.uuidv4();
55918
55915
  this.transportService.sendMessage({
55919
55916
  type: "SNAPSHOT",
@@ -66401,7 +66398,7 @@ stores.inject(MyMetaStore, storeInstance);
66401
66398
  this.session.join(this.config.client);
66402
66399
  }
66403
66400
  leaveSession() {
66404
- this.session.leave();
66401
+ this.session.leave(this.exportData());
66405
66402
  }
66406
66403
  setupUiPlugin(Plugin) {
66407
66404
  const plugin = new Plugin(this.uiPluginConfig);
@@ -66992,9 +66989,9 @@ stores.inject(MyMetaStore, storeInstance);
66992
66989
  exports.tokenize = tokenize;
66993
66990
 
66994
66991
 
66995
- __info__.version = "17.3.2";
66996
- __info__.date = "2024-06-10T09:38:56.657Z";
66997
- __info__.hash = "c3b358f";
66992
+ __info__.version = "17.3.4";
66993
+ __info__.date = "2024-06-21T20:00:08.515Z";
66994
+ __info__.hash = "6efbf3b";
66998
66995
 
66999
66996
 
67000
66997
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);