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