@odoo/o-spreadsheet 18.3.27 → 18.3.31

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.3.27
6
- * @date 2025-11-24T07:40:29.469Z
7
- * @hash 57b11b8
5
+ * @version 18.3.31
6
+ * @date 2025-12-26T10:18:10.765Z
7
+ * @hash 1e143e1
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -3468,7 +3468,6 @@
3468
3468
  "REDO",
3469
3469
  "ADD_MERGE",
3470
3470
  "REMOVE_MERGE",
3471
- "DUPLICATE_SHEET",
3472
3471
  "UPDATE_LOCALE",
3473
3472
  "ADD_PIVOT",
3474
3473
  "UPDATE_PIVOT",
@@ -6045,17 +6044,41 @@
6045
6044
  const today = DateTime.now();
6046
6045
  switch (dateValue) {
6047
6046
  case "today":
6048
- return jsDateToNumber(today);
6049
- case "yesterday":
6050
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
6051
- case "tomorrow":
6052
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
6047
+ return Math.floor(jsDateToNumber(today));
6048
+ case "yesterday": {
6049
+ today.setDate(today.getDate() - 1);
6050
+ return Math.floor(jsDateToNumber(today));
6051
+ }
6052
+ case "tomorrow": {
6053
+ today.setDate(today.getDate() + 1);
6054
+ return Math.floor(jsDateToNumber(today));
6055
+ }
6053
6056
  case "lastWeek":
6054
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
6055
- case "lastMonth":
6056
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
6057
+ today.setDate(today.getDate() - 6);
6058
+ return Math.floor(jsDateToNumber(today));
6059
+ case "lastMonth": {
6060
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
6061
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
6062
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
6063
+ today.setDate(1);
6064
+ }
6065
+ else {
6066
+ today.setDate(today.getDate() + 1);
6067
+ today.setMonth(today.getMonth() - 1);
6068
+ }
6069
+ return Math.floor(jsDateToNumber(today));
6070
+ }
6057
6071
  case "lastYear":
6058
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
6072
+ // Handle leap year case
6073
+ if (today.getMonth() === 1 && today.getDate() === 29) {
6074
+ today.setDate(28);
6075
+ today.setFullYear(today.getFullYear() - 1);
6076
+ }
6077
+ else {
6078
+ today.setDate(today.getDate() + 1);
6079
+ today.setFullYear(today.getFullYear() - 1);
6080
+ }
6081
+ return Math.floor(jsDateToNumber(today));
6059
6082
  }
6060
6083
  }
6061
6084
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -22990,7 +23013,7 @@ stores.inject(MyMetaStore, storeInstance);
22990
23013
  }
22991
23014
  this.selectionStart = start;
22992
23015
  this.selectionEnd = end;
22993
- this.editionMode = "editing";
23016
+ this.stopComposerRangeSelection();
22994
23017
  this.computeFormulaCursorContext();
22995
23018
  this.computeParenthesisRelatedToCursor();
22996
23019
  }
@@ -24872,11 +24895,18 @@ stores.inject(MyMetaStore, storeInstance);
24872
24895
  // we have to add the canvas to the DOM otherwise it won't be rendered
24873
24896
  document.body.append(div);
24874
24897
  if ("chartJsConfig" in runtime) {
24898
+ const extensionsLoaded = areChartJSExtensionsLoaded();
24899
+ if (!extensionsLoaded) {
24900
+ registerChartJSExtensions();
24901
+ }
24875
24902
  const config = deepCopy(runtime.chartJsConfig);
24876
24903
  config.plugins = [backgroundColorChartJSPlugin];
24877
24904
  const chart = new window.Chart(canvas, config);
24878
24905
  imageContent = chart.toBase64Image();
24879
24906
  chart.destroy();
24907
+ if (!extensionsLoaded) {
24908
+ unregisterChartJsExtensions();
24909
+ }
24880
24910
  }
24881
24911
  else if (type === "scorecard") {
24882
24912
  const design = getScorecardConfiguration(figure, runtime);
@@ -24906,11 +24936,18 @@ stores.inject(MyMetaStore, storeInstance);
24906
24936
  document.body.append(div);
24907
24937
  let chartBlob = null;
24908
24938
  if ("chartJsConfig" in runtime) {
24939
+ const extensionsLoaded = areChartJSExtensionsLoaded();
24940
+ if (!extensionsLoaded) {
24941
+ registerChartJSExtensions();
24942
+ }
24909
24943
  const config = deepCopy(runtime.chartJsConfig);
24910
24944
  config.plugins = [backgroundColorChartJSPlugin];
24911
24945
  const chart = new window.Chart(canvas, config);
24912
24946
  chartBlob = await new Promise((resolve) => canvas.toBlob(resolve, "image/png"));
24913
24947
  chart.destroy();
24948
+ if (!extensionsLoaded) {
24949
+ unregisterChartJsExtensions();
24950
+ }
24914
24951
  }
24915
24952
  else if (type === "scorecard") {
24916
24953
  const design = getScorecardConfiguration(figure, runtime);
@@ -29426,7 +29463,6 @@ stores.inject(MyMetaStore, storeInstance);
29426
29463
  static template = "o-spreadsheet-ChartFigure";
29427
29464
  static props = {
29428
29465
  figureUI: Object,
29429
- onFigureDeleted: Function,
29430
29466
  };
29431
29467
  static components = {};
29432
29468
  onDoubleClick() {
@@ -29450,7 +29486,6 @@ stores.inject(MyMetaStore, storeInstance);
29450
29486
  static template = "o-spreadsheet-ImageFigure";
29451
29487
  static props = {
29452
29488
  figureUI: Object,
29453
- onFigureDeleted: Function,
29454
29489
  };
29455
29490
  static components = {};
29456
29491
  // ---------------------------------------------------------------------------
@@ -30118,7 +30153,7 @@ stores.inject(MyMetaStore, storeInstance);
30118
30153
  borderWidth: 0,
30119
30154
  menuBuilder: getImageMenuRegistry,
30120
30155
  });
30121
- function getChartMenu(figureId, onFigureDeleted, env) {
30156
+ function getChartMenu(figureId, env) {
30122
30157
  const menuItemSpecs = [
30123
30158
  {
30124
30159
  id: "edit",
@@ -30170,11 +30205,11 @@ stores.inject(MyMetaStore, storeInstance);
30170
30205
  downloadFile(url, "chart");
30171
30206
  },
30172
30207
  },
30173
- getDeleteMenuItem(figureId, onFigureDeleted, env),
30208
+ getDeleteMenuItem(figureId, env),
30174
30209
  ];
30175
30210
  return createActions(menuItemSpecs);
30176
30211
  }
30177
- function getImageMenuRegistry(figureId, onFigureDeleted, env) {
30212
+ function getImageMenuRegistry(figureId, env) {
30178
30213
  const menuItemSpecs = [
30179
30214
  getCopyMenuItem(figureId, env),
30180
30215
  getCutMenuItem(figureId, env),
@@ -30219,7 +30254,7 @@ stores.inject(MyMetaStore, storeInstance);
30219
30254
  },
30220
30255
  icon: "o-spreadsheet-Icon.DOWNLOAD",
30221
30256
  },
30222
- getDeleteMenuItem(figureId, onFigureDeleted, env),
30257
+ getDeleteMenuItem(figureId, env),
30223
30258
  ];
30224
30259
  return createActions(menuItemSpecs);
30225
30260
  }
@@ -30252,7 +30287,7 @@ stores.inject(MyMetaStore, storeInstance);
30252
30287
  icon: "o-spreadsheet-Icon.CUT",
30253
30288
  };
30254
30289
  }
30255
- function getDeleteMenuItem(figureId, onFigureDeleted, env) {
30290
+ function getDeleteMenuItem(figureId, env) {
30256
30291
  return {
30257
30292
  id: "delete",
30258
30293
  name: _t("Delete"),
@@ -30262,7 +30297,6 @@ stores.inject(MyMetaStore, storeInstance);
30262
30297
  sheetId: env.model.getters.getActiveSheetId(),
30263
30298
  figureId,
30264
30299
  });
30265
- onFigureDeleted();
30266
30300
  },
30267
30301
  icon: "o-spreadsheet-Icon.TRASH",
30268
30302
  };
@@ -45364,7 +45398,7 @@ stores.inject(MyMetaStore, storeInstance);
45364
45398
  }
45365
45399
 
45366
45400
  css /* scss */ `
45367
- .o-cf-preview {
45401
+ .o-spreadsheet .o-cf-preview {
45368
45402
  &.o-cf-cursor-ptr {
45369
45403
  cursor: pointer;
45370
45404
  }
@@ -45372,6 +45406,7 @@ stores.inject(MyMetaStore, storeInstance);
45372
45406
  border-bottom: 1px solid ${GRAY_300};
45373
45407
  height: 80px;
45374
45408
  padding: 10px;
45409
+ box-sizing: border-box;
45375
45410
  position: relative;
45376
45411
  cursor: pointer;
45377
45412
  &:hover,
@@ -45385,7 +45420,6 @@ stores.inject(MyMetaStore, storeInstance);
45385
45420
  .o-cf-preview-icon {
45386
45421
  border: 1px solid ${GRAY_300};
45387
45422
  background-color: #fff;
45388
- position: absolute;
45389
45423
  height: 50px;
45390
45424
  width: 50px;
45391
45425
  .o-icon {
@@ -45394,12 +45428,6 @@ stores.inject(MyMetaStore, storeInstance);
45394
45428
  }
45395
45429
  }
45396
45430
  .o-cf-preview-description {
45397
- left: 65px;
45398
- margin-bottom: auto;
45399
- margin-right: 8px;
45400
- margin-top: auto;
45401
- position: relative;
45402
- width: 142px;
45403
45431
  .o-cf-preview-description-rule {
45404
45432
  margin-bottom: 4px;
45405
45433
  max-height: 2.8em;
@@ -45409,16 +45437,11 @@ stores.inject(MyMetaStore, storeInstance);
45409
45437
  font-size: 12px;
45410
45438
  }
45411
45439
  }
45412
- .o-cf-delete {
45413
- left: 90%;
45414
- top: 39%;
45415
- position: absolute;
45416
- }
45417
45440
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
45418
45441
  display: none !important;
45419
45442
  }
45420
45443
  .o-cf-drag-handle {
45421
- left: -8px;
45444
+ left: 2px;
45422
45445
  cursor: move;
45423
45446
  .o-icon {
45424
45447
  width: 6px;
@@ -46407,7 +46430,7 @@ stores.inject(MyMetaStore, storeInstance);
46407
46430
  return false;
46408
46431
  }
46409
46432
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
46410
- const today = jsDateToRoundNumber(DateTime.now());
46433
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
46411
46434
  return isDateBetween(dateValue, today, criterionValue);
46412
46435
  }
46413
46436
  return areDatesSameDay(dateValue, criterionValue);
@@ -50260,12 +50283,41 @@ stores.inject(MyMetaStore, storeInstance);
50260
50283
  pivotRegistry.add("SPREADSHEET", {
50261
50284
  ui: SpreadsheetPivot,
50262
50285
  definition: SpreadsheetPivotRuntimeDefinition,
50263
- externalData: false,
50264
50286
  dateGranularities: [...dateGranularities],
50265
50287
  datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
50266
50288
  isMeasureCandidate: (field) => field.type !== "boolean",
50267
50289
  isGroupable: () => true,
50290
+ adaptRanges: (getters, definition, applyChange) => {
50291
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
50292
+ return definition;
50293
+ }
50294
+ const { sheetId, zone } = definition.dataSet;
50295
+ const range = getters.getRangeFromZone(sheetId, zone);
50296
+ const adaptedRange = adaptPivotRange(range, applyChange);
50297
+ if (adaptedRange === range) {
50298
+ return definition;
50299
+ }
50300
+ const dataSet = adaptedRange && {
50301
+ sheetId: adaptedRange.sheetId,
50302
+ zone: adaptedRange.zone,
50303
+ };
50304
+ return { ...definition, dataSet };
50305
+ },
50268
50306
  });
50307
+ function adaptPivotRange(range, applyChange) {
50308
+ if (!range) {
50309
+ return undefined;
50310
+ }
50311
+ const change = applyChange(range);
50312
+ switch (change.changeType) {
50313
+ case "NONE":
50314
+ return range;
50315
+ case "REMOVE":
50316
+ return undefined;
50317
+ default:
50318
+ return change.range;
50319
+ }
50320
+ }
50269
50321
 
50270
50322
  class PivotSidePanelStore extends SpreadsheetStore {
50271
50323
  pivotId;
@@ -51905,13 +51957,11 @@ stores.inject(MyMetaStore, storeInstance);
51905
51957
  static props = {
51906
51958
  figureUI: Object,
51907
51959
  style: { type: String, optional: true },
51908
- onFigureDeleted: { type: Function, optional: true },
51909
51960
  onMouseDown: { type: Function, optional: true },
51910
51961
  onClickAnchor: { type: Function, optional: true },
51911
51962
  };
51912
51963
  static components = { Menu };
51913
51964
  static defaultProps = {
51914
- onFigureDeleted: () => { },
51915
51965
  onMouseDown: () => { },
51916
51966
  onClickAnchor: () => { },
51917
51967
  };
@@ -51989,9 +52039,6 @@ stores.inject(MyMetaStore, storeInstance);
51989
52039
  this.props.figureUI.id,
51990
52040
  this.figureRef.el,
51991
52041
  ]);
51992
- owl.onWillUnmount(() => {
51993
- this.props.onFigureDeleted();
51994
- });
51995
52042
  }
51996
52043
  clickAnchor(dirX, dirY, ev) {
51997
52044
  this.props.onClickAnchor(dirX, dirY, ev);
@@ -52008,7 +52055,6 @@ stores.inject(MyMetaStore, storeInstance);
52008
52055
  sheetId: this.env.model.getters.getActiveSheetId(),
52009
52056
  figureId: this.props.figureUI.id,
52010
52057
  });
52011
- this.props.onFigureDeleted();
52012
52058
  ev.preventDefault();
52013
52059
  ev.stopPropagation();
52014
52060
  break;
@@ -52101,7 +52147,7 @@ stores.inject(MyMetaStore, storeInstance);
52101
52147
  this.menuState.anchorRect = anchorRect;
52102
52148
  this.menuState.menuItems = figureRegistry
52103
52149
  .get(this.props.figureUI.tag)
52104
- .menuBuilder(this.props.figureUI.id, this.props.onFigureDeleted, this.env);
52150
+ .menuBuilder(this.props.figureUI.id, this.env);
52105
52151
  }
52106
52152
  }
52107
52153
 
@@ -52214,21 +52260,20 @@ stores.inject(MyMetaStore, storeInstance);
52214
52260
  this.highlightStore.register(this);
52215
52261
  }
52216
52262
  get highlights() {
52217
- let zone;
52218
52263
  const position = this.model.getters.getActivePosition();
52219
- const cell = this.getters.getEvaluatedCell(position);
52220
52264
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
52221
- zone = spreader
52265
+ const zone = spreader
52222
52266
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
52223
52267
  : this.model.getters.getSpreadZone(position, { ignoreSpillError: true });
52224
52268
  if (!zone) {
52225
52269
  return [];
52226
52270
  }
52271
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
52227
52272
  return [
52228
52273
  {
52229
52274
  sheetId: position.sheetId,
52230
52275
  zone,
52231
- dashed: cell.value === CellErrorType.SpilledBlocked,
52276
+ dashed: isArrayFormulaBlocked,
52232
52277
  color: "#17A2B8",
52233
52278
  noFill: true,
52234
52279
  thinLine: true,
@@ -53396,9 +53441,7 @@ stores.inject(MyMetaStore, storeInstance);
53396
53441
  */
53397
53442
  class FiguresContainer extends owl.Component {
53398
53443
  static template = "o-spreadsheet-FiguresContainer";
53399
- static props = {
53400
- onFigureDeleted: Function,
53401
- };
53444
+ static props = {};
53402
53445
  static components = { FigureComponent };
53403
53446
  dnd = owl.useState({
53404
53447
  draggedFigure: undefined,
@@ -53789,16 +53832,16 @@ stores.inject(MyMetaStore, storeInstance);
53789
53832
  `;
53790
53833
  class GridAddRowsFooter extends owl.Component {
53791
53834
  static template = "o-spreadsheet-GridAddRowsFooter";
53792
- static props = {
53793
- focusGrid: Function,
53794
- };
53835
+ static props = {};
53795
53836
  static components = { ValidationMessages };
53837
+ DOMFocusableElementStore;
53796
53838
  inputRef = owl.useRef("inputRef");
53797
53839
  state = owl.useState({
53798
53840
  inputValue: "100",
53799
53841
  errorFlag: false,
53800
53842
  });
53801
53843
  setup() {
53844
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
53802
53845
  owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
53803
53846
  }
53804
53847
  get addRowsPosition() {
@@ -53816,7 +53859,7 @@ stores.inject(MyMetaStore, storeInstance);
53816
53859
  }
53817
53860
  onKeydown(ev) {
53818
53861
  if (ev.key.toUpperCase() === "ESCAPE") {
53819
- this.props.focusGrid();
53862
+ this.focusDefaultElement();
53820
53863
  }
53821
53864
  else if (ev.key.toUpperCase() === "ENTER") {
53822
53865
  this.onConfirm();
@@ -53843,7 +53886,7 @@ stores.inject(MyMetaStore, storeInstance);
53843
53886
  quantity,
53844
53887
  dimension: "ROW",
53845
53888
  });
53846
- this.props.focusGrid();
53889
+ this.focusDefaultElement();
53847
53890
  // After adding new rows, scroll down to the new last row
53848
53891
  const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
53849
53892
  const { end } = this.env.model.getters.getRowDimensions(activeSheetId, rowNumber + quantity - 1);
@@ -53856,7 +53899,12 @@ stores.inject(MyMetaStore, storeInstance);
53856
53899
  if (this.inputRef.el !== document.activeElement || ev.target === this.inputRef.el) {
53857
53900
  return;
53858
53901
  }
53859
- this.props.focusGrid();
53902
+ this.focusDefaultElement();
53903
+ }
53904
+ focusDefaultElement() {
53905
+ if (document.activeElement === this.inputRef.el) {
53906
+ this.DOMFocusableElementStore.focus();
53907
+ }
53860
53908
  }
53861
53909
  }
53862
53910
 
@@ -54101,7 +54149,6 @@ stores.inject(MyMetaStore, storeInstance);
54101
54149
  onCellClicked: { type: Function, optional: true },
54102
54150
  onCellRightClicked: { type: Function, optional: true },
54103
54151
  onGridResized: { type: Function, optional: true },
54104
- onFigureDeleted: { type: Function, optional: true },
54105
54152
  onGridMoved: Function,
54106
54153
  gridOverlayDimensions: String,
54107
54154
  slots: { type: Object, optional: true },
@@ -54117,7 +54164,6 @@ stores.inject(MyMetaStore, storeInstance);
54117
54164
  onCellClicked: () => { },
54118
54165
  onCellRightClicked: () => { },
54119
54166
  onGridResized: () => { },
54120
- onFigureDeleted: () => { },
54121
54167
  };
54122
54168
  gridOverlay = owl.useRef("gridOverlay");
54123
54169
  gridOverlayRect = useAbsoluteBoundingRect(this.gridOverlay);
@@ -60686,6 +60732,7 @@ stores.inject(MyMetaStore, storeInstance);
60686
60732
  class RangeAdapter {
60687
60733
  getters;
60688
60734
  providers = [];
60735
+ isAdaptingRanges = false;
60689
60736
  constructor(getters) {
60690
60737
  this.getters = getters;
60691
60738
  }
@@ -60717,6 +60764,9 @@ stores.inject(MyMetaStore, storeInstance);
60717
60764
  }
60718
60765
  beforeHandle(command) { }
60719
60766
  handle(cmd) {
60767
+ if (this.isAdaptingRanges) {
60768
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
60769
+ }
60720
60770
  const rangeAdapter = getRangeAdapter(cmd);
60721
60771
  if (rangeAdapter?.applyChange) {
60722
60772
  this.executeOnAllRanges(rangeAdapter.applyChange, rangeAdapter.sheetId, rangeAdapter.sheetName);
@@ -60739,10 +60789,12 @@ stores.inject(MyMetaStore, storeInstance);
60739
60789
  };
60740
60790
  }
60741
60791
  executeOnAllRanges(adaptRange, sheetId, sheetName) {
60792
+ this.isAdaptingRanges = true;
60742
60793
  const func = this.verifyRangeRemoved(adaptRange);
60743
60794
  for (const provider of this.providers) {
60744
60795
  provider(func, sheetId, sheetName);
60745
60796
  }
60797
+ this.isAdaptingRanges = false;
60746
60798
  }
60747
60799
  /**
60748
60800
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -62778,6 +62830,18 @@ stores.inject(MyMetaStore, storeInstance);
62778
62830
  }
62779
62831
  }
62780
62832
  adaptRanges(applyChange) {
62833
+ for (const pivotId in this.pivots) {
62834
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
62835
+ if (!definition) {
62836
+ continue;
62837
+ }
62838
+ const newDefinition = pivotRegistry
62839
+ .get(definition.type)
62840
+ ?.adaptRanges?.(this.getters, definition, applyChange);
62841
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
62842
+ this.history.update("pivots", pivotId, "definition", newDefinition);
62843
+ }
62844
+ }
62781
62845
  for (const sheetId in this.compiledMeasureFormulas) {
62782
62846
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
62783
62847
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -63055,20 +63119,6 @@ stores.inject(MyMetaStore, storeInstance);
63055
63119
  }
63056
63120
  }
63057
63121
 
63058
- function adaptPivotRange(range, applyChange) {
63059
- if (!range) {
63060
- return undefined;
63061
- }
63062
- const change = applyChange(range);
63063
- switch (change.changeType) {
63064
- case "NONE":
63065
- return range;
63066
- case "REMOVE":
63067
- return undefined;
63068
- default:
63069
- return change.range;
63070
- }
63071
- }
63072
63122
  class SpreadsheetPivotCorePlugin extends CorePlugin {
63073
63123
  allowDispatch(cmd) {
63074
63124
  switch (cmd.type) {
@@ -63079,24 +63129,6 @@ stores.inject(MyMetaStore, storeInstance);
63079
63129
  }
63080
63130
  return "Success" /* CommandResult.Success */;
63081
63131
  }
63082
- adaptRanges(applyChange) {
63083
- for (const pivotId of this.getters.getPivotIds()) {
63084
- const definition = this.getters.getPivotCoreDefinition(pivotId);
63085
- if (definition.type !== "SPREADSHEET") {
63086
- continue;
63087
- }
63088
- if (definition.dataSet) {
63089
- const { sheetId, zone } = definition.dataSet;
63090
- const range = this.getters.getRangeFromZone(sheetId, zone);
63091
- const adaptedRange = adaptPivotRange(range, applyChange);
63092
- const dataSet = adaptedRange && {
63093
- sheetId: adaptedRange.sheetId,
63094
- zone: adaptedRange.zone,
63095
- };
63096
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
63097
- }
63098
- }
63099
- }
63100
63132
  checkDataSetValidity(definition) {
63101
63133
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
63102
63134
  const { zone, sheetId } = definition.dataSet;
@@ -64438,6 +64470,9 @@ stores.inject(MyMetaStore, storeInstance);
64438
64470
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
64439
64471
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
64440
64472
  }
64473
+ isArrayFormulaSpillBlocked(position) {
64474
+ return this.blockedArrayFormulas.has(position);
64475
+ }
64441
64476
  updateDependencies(position) {
64442
64477
  // removing dependencies is slow because it requires
64443
64478
  // to traverse the entire r-tree.
@@ -64449,13 +64484,8 @@ stores.inject(MyMetaStore, storeInstance);
64449
64484
  addDependencies(position, dependencies) {
64450
64485
  this.formulaDependencies().addDependencies(position, dependencies);
64451
64486
  for (const range of dependencies) {
64452
- const sheetId = range.sheetId;
64453
- const { left, bottom, right, top } = range.zone;
64454
- for (let col = left; col <= right; col++) {
64455
- for (let row = top; row <= bottom; row++) {
64456
- this.computeAndSave({ sheetId, col, row });
64457
- }
64458
- }
64487
+ // ensure that all ranges are computed
64488
+ this.compilationParams.ensureRange(range);
64459
64489
  }
64460
64490
  }
64461
64491
  updateCompilationParameters() {
@@ -64658,6 +64688,10 @@ stores.inject(MyMetaStore, storeInstance);
64658
64688
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
64659
64689
  const nbColumns = formulaReturn.length;
64660
64690
  const nbRows = formulaReturn[0].length;
64691
+ if (nbRows === 0) {
64692
+ // empty matrix
64693
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
64694
+ }
64661
64695
  const resultZone = {
64662
64696
  top: formulaPosition.row,
64663
64697
  bottom: formulaPosition.row + nbRows - 1,
@@ -64933,6 +64967,7 @@ stores.inject(MyMetaStore, storeInstance);
64933
64967
  "getEvaluatedCellsPositions",
64934
64968
  "getSpreadZone",
64935
64969
  "getArrayFormulaSpreadingOn",
64970
+ "isArrayFormulaSpillBlocked",
64936
64971
  "isEmpty",
64937
64972
  ];
64938
64973
  shouldRebuildDependenciesGraph = true;
@@ -65045,6 +65080,9 @@ stores.inject(MyMetaStore, storeInstance);
65045
65080
  getArrayFormulaSpreadingOn(position) {
65046
65081
  return this.evaluator.getArrayFormulaSpreadingOn(position);
65047
65082
  }
65083
+ isArrayFormulaSpillBlocked(position) {
65084
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
65085
+ }
65048
65086
  /**
65049
65087
  * Check if a zone only contains empty cells
65050
65088
  */
@@ -66828,9 +66866,7 @@ stores.inject(MyMetaStore, storeInstance);
66828
66866
  handle(cmd) {
66829
66867
  if (invalidateEvaluationCommands.has(cmd.type)) {
66830
66868
  for (const pivotId of this.getters.getPivotIds()) {
66831
- if (!pivotRegistry.get(this.getters.getPivotCoreDefinition(pivotId).type).externalData) {
66832
- this.setupPivot(pivotId, { recreate: true });
66833
- }
66869
+ this.setupPivot(pivotId, { recreate: true });
66834
66870
  }
66835
66871
  }
66836
66872
  switch (cmd.type) {
@@ -67031,7 +67067,7 @@ stores.inject(MyMetaStore, storeInstance);
67031
67067
  pivot.init({ reload: true });
67032
67068
  }
67033
67069
  setupPivot(pivotId, { recreate } = { recreate: false }) {
67034
- const definition = this.getters.getPivotCoreDefinition(pivotId);
67070
+ const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
67035
67071
  if (!(pivotId in this.pivots)) {
67036
67072
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
67037
67073
  this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
@@ -76500,7 +76536,7 @@ stores.inject(MyMetaStore, storeInstance);
76500
76536
  document.activeElement?.contains(this.spreadsheetRef.el)) {
76501
76537
  this.focusGrid();
76502
76538
  }
76503
- }, () => [this.env.model.getters.getActiveSheetId()]);
76539
+ });
76504
76540
  owl.useExternalListener(window, "resize", () => this.render(true));
76505
76541
  // For some reason, the wheel event is not properly registered inside templates
76506
76542
  // in Chromium-based browsers based on chromium 125
@@ -81077,9 +81113,9 @@ stores.inject(MyMetaStore, storeInstance);
81077
81113
  exports.tokenize = tokenize;
81078
81114
 
81079
81115
 
81080
- __info__.version = "18.3.27";
81081
- __info__.date = "2025-11-24T07:40:29.469Z";
81082
- __info__.hash = "57b11b8";
81116
+ __info__.version = "18.3.31";
81117
+ __info__.date = "2025-12-26T10:18:10.765Z";
81118
+ __info__.hash = "1e143e1";
81083
81119
 
81084
81120
 
81085
81121
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);