@odoo/o-spreadsheet 18.3.28 → 18.3.32

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.28
6
- * @date 2025-12-02T05:34:06.602Z
7
- * @hash a205f91
5
+ * @version 18.3.32
6
+ * @date 2026-01-14T10:00:27.532Z
7
+ * @hash 8d1d321
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -6044,17 +6044,41 @@
6044
6044
  const today = DateTime.now();
6045
6045
  switch (dateValue) {
6046
6046
  case "today":
6047
- return jsDateToNumber(today);
6048
- case "yesterday":
6049
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
6050
- case "tomorrow":
6051
- 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
+ }
6052
6056
  case "lastWeek":
6053
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
6054
- case "lastMonth":
6055
- 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
+ }
6056
6071
  case "lastYear":
6057
- 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));
6058
6082
  }
6059
6083
  }
6060
6084
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -18390,9 +18414,10 @@ stores.inject(MyMetaStore, storeInstance);
18390
18414
  throw new EvaluationError(_t("Function PIVOT takes an even number of arguments."));
18391
18415
  }
18392
18416
  }
18393
- function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
18417
+ function addPivotDependencies(evalContext, pivotId, forMeasures) {
18394
18418
  //TODO This function can be very costly when used with PIVOT.VALUE and PIVOT.HEADER
18395
18419
  const dependencies = [];
18420
+ const coreDefinition = evalContext.getters.getPivotCoreDefinition(pivotId);
18396
18421
  if (coreDefinition.type === "SPREADSHEET" && coreDefinition.dataSet) {
18397
18422
  const { sheetId, zone } = coreDefinition.dataSet;
18398
18423
  const xc = zoneToXc(zone);
@@ -18409,8 +18434,7 @@ stores.inject(MyMetaStore, storeInstance);
18409
18434
  }
18410
18435
  for (const measure of forMeasures) {
18411
18436
  if (measure.computedBy) {
18412
- const formula = evalContext.getters.getMeasureCompiledFormula(measure);
18413
- dependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
18437
+ dependencies.push(...evalContext.getters.getMeasureFullDependencies(pivotId, measure));
18414
18438
  }
18415
18439
  }
18416
18440
  const originPosition = evalContext.__originCellPosition;
@@ -18845,7 +18869,7 @@ stores.inject(MyMetaStore, storeInstance);
18845
18869
  assertDomainLength(domainArgs);
18846
18870
  const pivot = this.getters.getPivot(pivotId);
18847
18871
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
18848
- addPivotDependencies(this, coreDefinition, coreDefinition.measures.filter((m) => m.id === _measure));
18872
+ addPivotDependencies(this, pivotId, coreDefinition.measures.filter((m) => m.id === _measure));
18849
18873
  pivot.init({ reload: pivot.needsReevaluation });
18850
18874
  const error = pivot.assertIsValid({ throwOnError: false });
18851
18875
  if (error) {
@@ -18878,8 +18902,7 @@ stores.inject(MyMetaStore, storeInstance);
18878
18902
  const _pivotId = getPivotId(_pivotFormulaId, this.getters);
18879
18903
  assertDomainLength(domainArgs);
18880
18904
  const pivot = this.getters.getPivot(_pivotId);
18881
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
18882
- addPivotDependencies(this, coreDefinition, []);
18905
+ addPivotDependencies(this, _pivotId, []);
18883
18906
  pivot.init({ reload: pivot.needsReevaluation });
18884
18907
  const error = pivot.assertIsValid({ throwOnError: false });
18885
18908
  if (error) {
@@ -18933,7 +18956,7 @@ stores.inject(MyMetaStore, storeInstance);
18933
18956
  const pivotId = getPivotId(_pivotFormulaId, this.getters);
18934
18957
  const pivot = this.getters.getPivot(pivotId);
18935
18958
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
18936
- addPivotDependencies(this, coreDefinition, coreDefinition.measures);
18959
+ addPivotDependencies(this, pivotId, coreDefinition.measures);
18937
18960
  pivot.init({ reload: pivot.needsReevaluation });
18938
18961
  const error = pivot.assertIsValid({ throwOnError: false });
18939
18962
  if (error) {
@@ -23205,7 +23228,7 @@ stores.inject(MyMetaStore, storeInstance);
23205
23228
  }
23206
23229
  captureSelection(zone, col, row) {
23207
23230
  this.model.selection.capture(this, {
23208
- cell: { col: col ?? zone.left, row: row ?? zone.right },
23231
+ cell: { col: col ?? zone.left, row: row ?? zone.top },
23209
23232
  zone,
23210
23233
  }, {
23211
23234
  handleEvent: this.handleEvent.bind(this),
@@ -29439,7 +29462,6 @@ stores.inject(MyMetaStore, storeInstance);
29439
29462
  static template = "o-spreadsheet-ChartFigure";
29440
29463
  static props = {
29441
29464
  figureUI: Object,
29442
- onFigureDeleted: Function,
29443
29465
  };
29444
29466
  static components = {};
29445
29467
  onDoubleClick() {
@@ -29463,7 +29485,6 @@ stores.inject(MyMetaStore, storeInstance);
29463
29485
  static template = "o-spreadsheet-ImageFigure";
29464
29486
  static props = {
29465
29487
  figureUI: Object,
29466
- onFigureDeleted: Function,
29467
29488
  };
29468
29489
  static components = {};
29469
29490
  // ---------------------------------------------------------------------------
@@ -30131,7 +30152,7 @@ stores.inject(MyMetaStore, storeInstance);
30131
30152
  borderWidth: 0,
30132
30153
  menuBuilder: getImageMenuRegistry,
30133
30154
  });
30134
- function getChartMenu(figureId, onFigureDeleted, env) {
30155
+ function getChartMenu(figureId, env) {
30135
30156
  const menuItemSpecs = [
30136
30157
  {
30137
30158
  id: "edit",
@@ -30183,11 +30204,11 @@ stores.inject(MyMetaStore, storeInstance);
30183
30204
  downloadFile(url, "chart");
30184
30205
  },
30185
30206
  },
30186
- getDeleteMenuItem(figureId, onFigureDeleted, env),
30207
+ getDeleteMenuItem(figureId, env),
30187
30208
  ];
30188
30209
  return createActions(menuItemSpecs);
30189
30210
  }
30190
- function getImageMenuRegistry(figureId, onFigureDeleted, env) {
30211
+ function getImageMenuRegistry(figureId, env) {
30191
30212
  const menuItemSpecs = [
30192
30213
  getCopyMenuItem(figureId, env),
30193
30214
  getCutMenuItem(figureId, env),
@@ -30232,7 +30253,7 @@ stores.inject(MyMetaStore, storeInstance);
30232
30253
  },
30233
30254
  icon: "o-spreadsheet-Icon.DOWNLOAD",
30234
30255
  },
30235
- getDeleteMenuItem(figureId, onFigureDeleted, env),
30256
+ getDeleteMenuItem(figureId, env),
30236
30257
  ];
30237
30258
  return createActions(menuItemSpecs);
30238
30259
  }
@@ -30265,7 +30286,7 @@ stores.inject(MyMetaStore, storeInstance);
30265
30286
  icon: "o-spreadsheet-Icon.CUT",
30266
30287
  };
30267
30288
  }
30268
- function getDeleteMenuItem(figureId, onFigureDeleted, env) {
30289
+ function getDeleteMenuItem(figureId, env) {
30269
30290
  return {
30270
30291
  id: "delete",
30271
30292
  name: _t("Delete"),
@@ -30275,7 +30296,6 @@ stores.inject(MyMetaStore, storeInstance);
30275
30296
  sheetId: env.model.getters.getActiveSheetId(),
30276
30297
  figureId,
30277
30298
  });
30278
- onFigureDeleted();
30279
30299
  },
30280
30300
  icon: "o-spreadsheet-Icon.TRASH",
30281
30301
  };
@@ -45377,7 +45397,7 @@ stores.inject(MyMetaStore, storeInstance);
45377
45397
  }
45378
45398
 
45379
45399
  css /* scss */ `
45380
- .o-cf-preview {
45400
+ .o-spreadsheet .o-cf-preview {
45381
45401
  &.o-cf-cursor-ptr {
45382
45402
  cursor: pointer;
45383
45403
  }
@@ -45385,6 +45405,7 @@ stores.inject(MyMetaStore, storeInstance);
45385
45405
  border-bottom: 1px solid ${GRAY_300};
45386
45406
  height: 80px;
45387
45407
  padding: 10px;
45408
+ box-sizing: border-box;
45388
45409
  position: relative;
45389
45410
  cursor: pointer;
45390
45411
  &:hover,
@@ -45398,7 +45419,6 @@ stores.inject(MyMetaStore, storeInstance);
45398
45419
  .o-cf-preview-icon {
45399
45420
  border: 1px solid ${GRAY_300};
45400
45421
  background-color: #fff;
45401
- position: absolute;
45402
45422
  height: 50px;
45403
45423
  width: 50px;
45404
45424
  .o-icon {
@@ -45407,12 +45427,6 @@ stores.inject(MyMetaStore, storeInstance);
45407
45427
  }
45408
45428
  }
45409
45429
  .o-cf-preview-description {
45410
- left: 65px;
45411
- margin-bottom: auto;
45412
- margin-right: 8px;
45413
- margin-top: auto;
45414
- position: relative;
45415
- width: 142px;
45416
45430
  .o-cf-preview-description-rule {
45417
45431
  margin-bottom: 4px;
45418
45432
  max-height: 2.8em;
@@ -45422,16 +45436,11 @@ stores.inject(MyMetaStore, storeInstance);
45422
45436
  font-size: 12px;
45423
45437
  }
45424
45438
  }
45425
- .o-cf-delete {
45426
- left: 90%;
45427
- top: 39%;
45428
- position: absolute;
45429
- }
45430
45439
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
45431
45440
  display: none !important;
45432
45441
  }
45433
45442
  .o-cf-drag-handle {
45434
- left: -8px;
45443
+ left: 2px;
45435
45444
  cursor: move;
45436
45445
  .o-icon {
45437
45446
  width: 6px;
@@ -46420,7 +46429,7 @@ stores.inject(MyMetaStore, storeInstance);
46420
46429
  return false;
46421
46430
  }
46422
46431
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
46423
- const today = jsDateToRoundNumber(DateTime.now());
46432
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
46424
46433
  return isDateBetween(dateValue, today, criterionValue);
46425
46434
  }
46426
46435
  return areDatesSameDay(dateValue, criterionValue);
@@ -47607,6 +47616,12 @@ stores.inject(MyMetaStore, storeInstance);
47607
47616
  case "ACTIVATE_SHEET":
47608
47617
  this.isSearchDirty = true;
47609
47618
  this.shouldFinalizeUpdateSelection = true;
47619
+ if (this.searchOptions.specificRange) {
47620
+ this.searchOptions.specificRange = {
47621
+ ...this.searchOptions.specificRange,
47622
+ sheetId: this.getters.getActiveSheetId(),
47623
+ };
47624
+ }
47610
47625
  break;
47611
47626
  case "REPLACE_SEARCH":
47612
47627
  for (const match of cmd.matches) {
@@ -48028,9 +48043,20 @@ stores.inject(MyMetaStore, storeInstance);
48028
48043
  const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
48029
48044
  this.store.updateSearchOptions({ specificRange });
48030
48045
  }
48046
+ get specificRange() {
48047
+ const range = this.store.searchOptions.specificRange;
48048
+ return range ? this.env.model.getters.getRangeString(range, "forceSheetReference") : "";
48049
+ }
48031
48050
  get pendingSearch() {
48032
48051
  return this.updateSearchContent.isDebouncePending();
48033
48052
  }
48053
+ get selectionInputKey() {
48054
+ // Selections input are made to work with objects linked to a sheet id. They store the active sheet id at their creation,
48055
+ // and have specific behaviour linked to it (eg. go back to the initial sheet after confirmation).
48056
+ // We don't want all those behaviors here, so we force the recreation of the component when the active sheet changes.
48057
+ // The only drawback is that the input loses focus when changing sheet.
48058
+ return this.env.model.getters.getActiveSheetId();
48059
+ }
48034
48060
  }
48035
48061
 
48036
48062
  css /* scss */ `
@@ -50277,7 +50303,37 @@ stores.inject(MyMetaStore, storeInstance);
50277
50303
  datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
50278
50304
  isMeasureCandidate: (field) => field.type !== "boolean",
50279
50305
  isGroupable: () => true,
50306
+ adaptRanges: (getters, definition, applyChange) => {
50307
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
50308
+ return definition;
50309
+ }
50310
+ const { sheetId, zone } = definition.dataSet;
50311
+ const range = getters.getRangeFromZone(sheetId, zone);
50312
+ const adaptedRange = adaptPivotRange(range, applyChange);
50313
+ if (adaptedRange === range) {
50314
+ return definition;
50315
+ }
50316
+ const dataSet = adaptedRange && {
50317
+ sheetId: adaptedRange.sheetId,
50318
+ zone: adaptedRange.zone,
50319
+ };
50320
+ return { ...definition, dataSet };
50321
+ },
50280
50322
  });
50323
+ function adaptPivotRange(range, applyChange) {
50324
+ if (!range) {
50325
+ return undefined;
50326
+ }
50327
+ const change = applyChange(range);
50328
+ switch (change.changeType) {
50329
+ case "NONE":
50330
+ return range;
50331
+ case "REMOVE":
50332
+ return undefined;
50333
+ default:
50334
+ return change.range;
50335
+ }
50336
+ }
50281
50337
 
50282
50338
  class PivotSidePanelStore extends SpreadsheetStore {
50283
50339
  pivotId;
@@ -51917,13 +51973,11 @@ stores.inject(MyMetaStore, storeInstance);
51917
51973
  static props = {
51918
51974
  figureUI: Object,
51919
51975
  style: { type: String, optional: true },
51920
- onFigureDeleted: { type: Function, optional: true },
51921
51976
  onMouseDown: { type: Function, optional: true },
51922
51977
  onClickAnchor: { type: Function, optional: true },
51923
51978
  };
51924
51979
  static components = { Menu };
51925
51980
  static defaultProps = {
51926
- onFigureDeleted: () => { },
51927
51981
  onMouseDown: () => { },
51928
51982
  onClickAnchor: () => { },
51929
51983
  };
@@ -52001,9 +52055,6 @@ stores.inject(MyMetaStore, storeInstance);
52001
52055
  this.props.figureUI.id,
52002
52056
  this.figureRef.el,
52003
52057
  ]);
52004
- owl.onWillUnmount(() => {
52005
- this.props.onFigureDeleted();
52006
- });
52007
52058
  }
52008
52059
  clickAnchor(dirX, dirY, ev) {
52009
52060
  this.props.onClickAnchor(dirX, dirY, ev);
@@ -52020,7 +52071,6 @@ stores.inject(MyMetaStore, storeInstance);
52020
52071
  sheetId: this.env.model.getters.getActiveSheetId(),
52021
52072
  figureId: this.props.figureUI.id,
52022
52073
  });
52023
- this.props.onFigureDeleted();
52024
52074
  ev.preventDefault();
52025
52075
  ev.stopPropagation();
52026
52076
  break;
@@ -52113,7 +52163,7 @@ stores.inject(MyMetaStore, storeInstance);
52113
52163
  this.menuState.anchorRect = anchorRect;
52114
52164
  this.menuState.menuItems = figureRegistry
52115
52165
  .get(this.props.figureUI.tag)
52116
- .menuBuilder(this.props.figureUI.id, this.props.onFigureDeleted, this.env);
52166
+ .menuBuilder(this.props.figureUI.id, this.env);
52117
52167
  }
52118
52168
  }
52119
52169
 
@@ -52226,21 +52276,20 @@ stores.inject(MyMetaStore, storeInstance);
52226
52276
  this.highlightStore.register(this);
52227
52277
  }
52228
52278
  get highlights() {
52229
- let zone;
52230
52279
  const position = this.model.getters.getActivePosition();
52231
- const cell = this.getters.getEvaluatedCell(position);
52232
52280
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
52233
- zone = spreader
52281
+ const zone = spreader
52234
52282
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
52235
52283
  : this.model.getters.getSpreadZone(position, { ignoreSpillError: true });
52236
52284
  if (!zone) {
52237
52285
  return [];
52238
52286
  }
52287
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
52239
52288
  return [
52240
52289
  {
52241
52290
  sheetId: position.sheetId,
52242
52291
  zone,
52243
- dashed: cell.value === CellErrorType.SpilledBlocked,
52292
+ dashed: isArrayFormulaBlocked,
52244
52293
  color: "#17A2B8",
52245
52294
  noFill: true,
52246
52295
  thinLine: true,
@@ -53408,9 +53457,7 @@ stores.inject(MyMetaStore, storeInstance);
53408
53457
  */
53409
53458
  class FiguresContainer extends owl.Component {
53410
53459
  static template = "o-spreadsheet-FiguresContainer";
53411
- static props = {
53412
- onFigureDeleted: Function,
53413
- };
53460
+ static props = {};
53414
53461
  static components = { FigureComponent };
53415
53462
  dnd = owl.useState({
53416
53463
  draggedFigure: undefined,
@@ -53801,16 +53848,16 @@ stores.inject(MyMetaStore, storeInstance);
53801
53848
  `;
53802
53849
  class GridAddRowsFooter extends owl.Component {
53803
53850
  static template = "o-spreadsheet-GridAddRowsFooter";
53804
- static props = {
53805
- focusGrid: Function,
53806
- };
53851
+ static props = {};
53807
53852
  static components = { ValidationMessages };
53853
+ DOMFocusableElementStore;
53808
53854
  inputRef = owl.useRef("inputRef");
53809
53855
  state = owl.useState({
53810
53856
  inputValue: "100",
53811
53857
  errorFlag: false,
53812
53858
  });
53813
53859
  setup() {
53860
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
53814
53861
  owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
53815
53862
  }
53816
53863
  get addRowsPosition() {
@@ -53828,7 +53875,7 @@ stores.inject(MyMetaStore, storeInstance);
53828
53875
  }
53829
53876
  onKeydown(ev) {
53830
53877
  if (ev.key.toUpperCase() === "ESCAPE") {
53831
- this.props.focusGrid();
53878
+ this.focusDefaultElement();
53832
53879
  }
53833
53880
  else if (ev.key.toUpperCase() === "ENTER") {
53834
53881
  this.onConfirm();
@@ -53855,7 +53902,7 @@ stores.inject(MyMetaStore, storeInstance);
53855
53902
  quantity,
53856
53903
  dimension: "ROW",
53857
53904
  });
53858
- this.props.focusGrid();
53905
+ this.focusDefaultElement();
53859
53906
  // After adding new rows, scroll down to the new last row
53860
53907
  const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
53861
53908
  const { end } = this.env.model.getters.getRowDimensions(activeSheetId, rowNumber + quantity - 1);
@@ -53868,7 +53915,12 @@ stores.inject(MyMetaStore, storeInstance);
53868
53915
  if (this.inputRef.el !== document.activeElement || ev.target === this.inputRef.el) {
53869
53916
  return;
53870
53917
  }
53871
- this.props.focusGrid();
53918
+ this.focusDefaultElement();
53919
+ }
53920
+ focusDefaultElement() {
53921
+ if (document.activeElement === this.inputRef.el) {
53922
+ this.DOMFocusableElementStore.focus();
53923
+ }
53872
53924
  }
53873
53925
  }
53874
53926
 
@@ -54113,7 +54165,6 @@ stores.inject(MyMetaStore, storeInstance);
54113
54165
  onCellClicked: { type: Function, optional: true },
54114
54166
  onCellRightClicked: { type: Function, optional: true },
54115
54167
  onGridResized: { type: Function, optional: true },
54116
- onFigureDeleted: { type: Function, optional: true },
54117
54168
  onGridMoved: Function,
54118
54169
  gridOverlayDimensions: String,
54119
54170
  slots: { type: Object, optional: true },
@@ -54129,7 +54180,6 @@ stores.inject(MyMetaStore, storeInstance);
54129
54180
  onCellClicked: () => { },
54130
54181
  onCellRightClicked: () => { },
54131
54182
  onGridResized: () => { },
54132
- onFigureDeleted: () => { },
54133
54183
  };
54134
54184
  gridOverlay = owl.useRef("gridOverlay");
54135
54185
  gridOverlayRect = useAbsoluteBoundingRect(this.gridOverlay);
@@ -60698,6 +60748,7 @@ stores.inject(MyMetaStore, storeInstance);
60698
60748
  class RangeAdapter {
60699
60749
  getters;
60700
60750
  providers = [];
60751
+ isAdaptingRanges = false;
60701
60752
  constructor(getters) {
60702
60753
  this.getters = getters;
60703
60754
  }
@@ -60729,6 +60780,9 @@ stores.inject(MyMetaStore, storeInstance);
60729
60780
  }
60730
60781
  beforeHandle(command) { }
60731
60782
  handle(cmd) {
60783
+ if (this.isAdaptingRanges) {
60784
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
60785
+ }
60732
60786
  const rangeAdapter = getRangeAdapter(cmd);
60733
60787
  if (rangeAdapter?.applyChange) {
60734
60788
  this.executeOnAllRanges(rangeAdapter.applyChange, rangeAdapter.sheetId, rangeAdapter.sheetName);
@@ -60751,10 +60805,12 @@ stores.inject(MyMetaStore, storeInstance);
60751
60805
  };
60752
60806
  }
60753
60807
  executeOnAllRanges(adaptRange, sheetId, sheetName) {
60808
+ this.isAdaptingRanges = true;
60754
60809
  const func = this.verifyRangeRemoved(adaptRange);
60755
60810
  for (const provider of this.providers) {
60756
60811
  provider(func, sheetId, sheetName);
60757
60812
  }
60813
+ this.isAdaptingRanges = false;
60758
60814
  }
60759
60815
  /**
60760
60816
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -62702,6 +62758,7 @@ stores.inject(MyMetaStore, storeInstance);
62702
62758
  "getMeasureCompiledFormula",
62703
62759
  "getPivotName",
62704
62760
  "isExistingPivot",
62761
+ "getMeasureFullDependencies",
62705
62762
  ];
62706
62763
  nextFormulaId = 1;
62707
62764
  pivots = {};
@@ -62784,15 +62841,32 @@ stores.inject(MyMetaStore, storeInstance);
62784
62841
  }
62785
62842
  case "UPDATE_PIVOT": {
62786
62843
  this.history.update("pivots", cmd.pivotId, "definition", this.repairSortedColumn(deepCopy(cmd.pivot)));
62787
- this.compileCalculatedMeasures(cmd.pivot.measures);
62844
+ this.compileCalculatedMeasures(cmd.pivotId, cmd.pivot.measures);
62788
62845
  break;
62789
62846
  }
62790
62847
  }
62791
62848
  }
62792
62849
  adaptRanges(applyChange) {
62793
- for (const sheetId in this.compiledMeasureFormulas) {
62794
- for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
62795
- const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
62850
+ for (const pivotId in this.pivots) {
62851
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
62852
+ if (!definition) {
62853
+ continue;
62854
+ }
62855
+ const newDefinition = pivotRegistry
62856
+ .get(definition.type)
62857
+ ?.adaptRanges?.(this.getters, definition, applyChange);
62858
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
62859
+ this.history.update("pivots", pivotId, "definition", newDefinition);
62860
+ }
62861
+ }
62862
+ for (const pivotId in this.compiledMeasureFormulas) {
62863
+ for (const measureId in this.compiledMeasureFormulas[pivotId]) {
62864
+ const measure = this.pivots[pivotId]?.definition.measures.find((m) => m.id === measureId);
62865
+ if (!measure || !measure.computedBy) {
62866
+ continue;
62867
+ }
62868
+ const sheetId = measure.computedBy.sheetId;
62869
+ const compiledFormula = this.compiledMeasureFormulas[pivotId][measureId].formula;
62796
62870
  const newDependencies = [];
62797
62871
  for (const range of compiledFormula.dependencies) {
62798
62872
  const change = applyChange(range);
@@ -62804,8 +62878,9 @@ stores.inject(MyMetaStore, storeInstance);
62804
62878
  }
62805
62879
  }
62806
62880
  const newFormulaString = this.getters.getFormulaString(sheetId, compiledFormula.tokens, newDependencies);
62807
- if (newFormulaString !== formulaString) {
62808
- this.replaceMeasureFormula(sheetId, formulaString, newFormulaString);
62881
+ const oldFormulaString = measure.computedBy.formula;
62882
+ if (newFormulaString !== oldFormulaString) {
62883
+ this.replaceMeasureFormula(pivotId, measure, newFormulaString);
62809
62884
  }
62810
62885
  }
62811
62886
  }
@@ -62843,12 +62918,17 @@ stores.inject(MyMetaStore, storeInstance);
62843
62918
  isExistingPivot(pivotId) {
62844
62919
  return pivotId in this.pivots;
62845
62920
  }
62846
- getMeasureCompiledFormula(measure) {
62921
+ getMeasureCompiledFormula(pivotId, measure) {
62922
+ if (!measure.computedBy) {
62923
+ throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
62924
+ }
62925
+ return this.compiledMeasureFormulas[pivotId][measure.id].formula;
62926
+ }
62927
+ getMeasureFullDependencies(pivotId, measure) {
62847
62928
  if (!measure.computedBy) {
62848
62929
  throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
62849
62930
  }
62850
- const sheetId = measure.computedBy.sheetId;
62851
- return this.compiledMeasureFormulas[sheetId][measure.computedBy.formula];
62931
+ return this.compiledMeasureFormulas[pivotId][measure.id].dependencies;
62852
62932
  }
62853
62933
  // -------------------------------------------------------------------------
62854
62934
  // Private
@@ -62858,18 +62938,42 @@ stores.inject(MyMetaStore, storeInstance);
62858
62938
  definition: this.repairSortedColumn(deepCopy(pivot)),
62859
62939
  formulaId,
62860
62940
  });
62861
- this.compileCalculatedMeasures(pivot.measures);
62941
+ this.compileCalculatedMeasures(pivotId, pivot.measures);
62862
62942
  this.history.update("formulaIds", formulaId, pivotId);
62863
62943
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
62864
62944
  }
62865
- compileCalculatedMeasures(measures) {
62945
+ compileCalculatedMeasures(pivotId, measures) {
62866
62946
  for (const measure of measures) {
62867
62947
  if (measure.computedBy) {
62868
- const sheetId = measure.computedBy.sheetId;
62869
62948
  const compiledFormula = this.compileMeasureFormula(measure.computedBy.sheetId, measure.computedBy.formula);
62870
- this.history.update("compiledMeasureFormulas", sheetId, measure.computedBy.formula, compiledFormula);
62949
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "formula", compiledFormula);
62950
+ }
62951
+ }
62952
+ for (const measure of measures) {
62953
+ if (measure.computedBy) {
62954
+ const dependencies = this.computeMeasureFullDependencies(pivotId, measure);
62955
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "dependencies", dependencies);
62956
+ }
62957
+ }
62958
+ }
62959
+ computeMeasureFullDependencies(pivotId, measure, exploredMeasures = new Set()) {
62960
+ const rangeDependencies = [];
62961
+ const definition = this.getPivotCoreDefinition(pivotId);
62962
+ const formula = this.getMeasureCompiledFormula(pivotId, measure);
62963
+ exploredMeasures.add(measure.id);
62964
+ for (const token of formula.tokens) {
62965
+ if (token.type !== "SYMBOL") {
62966
+ continue;
62967
+ }
62968
+ const otherMeasure = definition.measures.find((measureCandidate) => getCanonicalSymbolName(measureCandidate.id) === token.value &&
62969
+ measure.id !== measureCandidate.id);
62970
+ if (!otherMeasure || exploredMeasures.has(otherMeasure.id) || !otherMeasure.computedBy) {
62971
+ continue;
62871
62972
  }
62973
+ rangeDependencies.push(...this.computeMeasureFullDependencies(pivotId, otherMeasure, exploredMeasures));
62872
62974
  }
62975
+ rangeDependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
62976
+ return rangeDependencies;
62873
62977
  }
62874
62978
  insertPivot(position, formulaId, table) {
62875
62979
  this.resizeSheet(position.sheetId, position, table);
@@ -62929,28 +63033,17 @@ stores.inject(MyMetaStore, storeInstance);
62929
63033
  dependencies: rangeDependencies,
62930
63034
  };
62931
63035
  }
62932
- replaceMeasureFormula(sheetId, formulaString, newFormulaString) {
62933
- this.history.update("compiledMeasureFormulas", sheetId, formulaString, undefined);
62934
- this.history.update("compiledMeasureFormulas", sheetId, newFormulaString, this.compileMeasureFormula(sheetId, newFormulaString));
62935
- for (const pivotId in this.pivots) {
62936
- const pivot = this.pivots[pivotId];
62937
- if (!pivot) {
62938
- continue;
62939
- }
62940
- const def = deepCopy(pivot.definition);
62941
- for (const measure of def.measures) {
62942
- if (measure.computedBy?.formula === formulaString) {
62943
- const measureIndex = def.measures.indexOf(measure);
62944
- if (measureIndex !== -1) {
62945
- def.measures[measureIndex].computedBy = {
62946
- formula: newFormulaString,
62947
- sheetId,
62948
- };
62949
- }
62950
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
62951
- }
62952
- }
63036
+ replaceMeasureFormula(pivotId, measure, newFormulaString) {
63037
+ const pivot = this.pivots[pivotId];
63038
+ if (!pivot) {
63039
+ return;
62953
63040
  }
63041
+ const measureIndex = pivot.definition.measures.indexOf(measure);
63042
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", {
63043
+ formula: newFormulaString,
63044
+ sheetId: measure.computedBy.sheetId,
63045
+ });
63046
+ this.compileCalculatedMeasures(pivotId, pivot.definition.measures);
62954
63047
  }
62955
63048
  checkSortedColumnInMeasures(definition) {
62956
63049
  definition = this.repairSortedColumn(definition);
@@ -63074,20 +63167,6 @@ stores.inject(MyMetaStore, storeInstance);
63074
63167
  }
63075
63168
  }
63076
63169
 
63077
- function adaptPivotRange(range, applyChange) {
63078
- if (!range) {
63079
- return undefined;
63080
- }
63081
- const change = applyChange(range);
63082
- switch (change.changeType) {
63083
- case "NONE":
63084
- return range;
63085
- case "REMOVE":
63086
- return undefined;
63087
- default:
63088
- return change.range;
63089
- }
63090
- }
63091
63170
  class SpreadsheetPivotCorePlugin extends CorePlugin {
63092
63171
  allowDispatch(cmd) {
63093
63172
  switch (cmd.type) {
@@ -63098,27 +63177,6 @@ stores.inject(MyMetaStore, storeInstance);
63098
63177
  }
63099
63178
  return "Success" /* CommandResult.Success */;
63100
63179
  }
63101
- adaptRanges(applyChange) {
63102
- for (const pivotId of this.getters.getPivotIds()) {
63103
- const definition = this.getters.getPivotCoreDefinition(pivotId);
63104
- if (definition.type !== "SPREADSHEET") {
63105
- continue;
63106
- }
63107
- if (definition.dataSet) {
63108
- const { sheetId, zone } = definition.dataSet;
63109
- const range = this.getters.getRangeFromZone(sheetId, zone);
63110
- const adaptedRange = adaptPivotRange(range, applyChange);
63111
- if (adaptedRange === range) {
63112
- return;
63113
- }
63114
- const dataSet = adaptedRange && {
63115
- sheetId: adaptedRange.sheetId,
63116
- zone: adaptedRange.zone,
63117
- };
63118
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
63119
- }
63120
- }
63121
- }
63122
63180
  checkDataSetValidity(definition) {
63123
63181
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
63124
63182
  const { zone, sheetId } = definition.dataSet;
@@ -64460,6 +64518,9 @@ stores.inject(MyMetaStore, storeInstance);
64460
64518
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
64461
64519
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
64462
64520
  }
64521
+ isArrayFormulaSpillBlocked(position) {
64522
+ return this.blockedArrayFormulas.has(position);
64523
+ }
64463
64524
  updateDependencies(position) {
64464
64525
  // removing dependencies is slow because it requires
64465
64526
  // to traverse the entire r-tree.
@@ -64471,13 +64532,8 @@ stores.inject(MyMetaStore, storeInstance);
64471
64532
  addDependencies(position, dependencies) {
64472
64533
  this.formulaDependencies().addDependencies(position, dependencies);
64473
64534
  for (const range of dependencies) {
64474
- const sheetId = range.sheetId;
64475
- const { left, bottom, right, top } = range.zone;
64476
- for (let col = left; col <= right; col++) {
64477
- for (let row = top; row <= bottom; row++) {
64478
- this.computeAndSave({ sheetId, col, row });
64479
- }
64480
- }
64535
+ // ensure that all ranges are computed
64536
+ this.compilationParams.ensureRange(range);
64481
64537
  }
64482
64538
  }
64483
64539
  updateCompilationParameters() {
@@ -64680,6 +64736,10 @@ stores.inject(MyMetaStore, storeInstance);
64680
64736
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
64681
64737
  const nbColumns = formulaReturn.length;
64682
64738
  const nbRows = formulaReturn[0].length;
64739
+ if (nbRows === 0) {
64740
+ // empty matrix
64741
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
64742
+ }
64683
64743
  const resultZone = {
64684
64744
  top: formulaPosition.row,
64685
64745
  bottom: formulaPosition.row + nbRows - 1,
@@ -64955,6 +65015,7 @@ stores.inject(MyMetaStore, storeInstance);
64955
65015
  "getEvaluatedCellsPositions",
64956
65016
  "getSpreadZone",
64957
65017
  "getArrayFormulaSpreadingOn",
65018
+ "isArrayFormulaSpillBlocked",
64958
65019
  "isEmpty",
64959
65020
  ];
64960
65021
  shouldRebuildDependenciesGraph = true;
@@ -65067,6 +65128,9 @@ stores.inject(MyMetaStore, storeInstance);
65067
65128
  getArrayFormulaSpreadingOn(position) {
65068
65129
  return this.evaluator.getArrayFormulaSpreadingOn(position);
65069
65130
  }
65131
+ isArrayFormulaSpillBlocked(position) {
65132
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
65133
+ }
65070
65134
  /**
65071
65135
  * Check if a zone only contains empty cells
65072
65136
  */
@@ -66269,14 +66333,16 @@ stores.inject(MyMetaStore, storeInstance);
66269
66333
  function withPivotPresentationLayer (PivotClass) {
66270
66334
  class PivotPresentationLayer extends PivotClass {
66271
66335
  getters;
66336
+ pivotId;
66272
66337
  cache = {};
66273
66338
  rankAsc = {};
66274
66339
  rankDesc = {};
66275
66340
  runningTotal = {};
66276
66341
  runningTotalInPercent = {};
66277
- constructor(custom, params) {
66342
+ constructor(pivotId, custom, params) {
66278
66343
  super(custom, params);
66279
66344
  this.getters = params.getters;
66345
+ this.pivotId = pivotId;
66280
66346
  }
66281
66347
  markAsDirtyForEvaluation() {
66282
66348
  this.cache = {};
@@ -66326,7 +66392,7 @@ stores.inject(MyMetaStore, storeInstance);
66326
66392
  return handleError(error, measure.aggregator.toUpperCase());
66327
66393
  }
66328
66394
  }
66329
- const formula = this.getters.getMeasureCompiledFormula(measure);
66395
+ const formula = this.getters.getMeasureCompiledFormula(this.pivotId, measure);
66330
66396
  const getSymbolValue = (symbolName) => {
66331
66397
  const { columns, rows } = this.definition;
66332
66398
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
@@ -67054,7 +67120,7 @@ stores.inject(MyMetaStore, storeInstance);
67054
67120
  const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
67055
67121
  if (!(pivotId in this.pivots)) {
67056
67122
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
67057
- this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
67123
+ this.pivots[pivotId] = new Pivot(pivotId, this.custom, { definition, getters: this.getters });
67058
67124
  }
67059
67125
  else if (recreate) {
67060
67126
  this.pivots[pivotId].onDefinitionChange(definition);
@@ -76520,7 +76586,7 @@ stores.inject(MyMetaStore, storeInstance);
76520
76586
  document.activeElement?.contains(this.spreadsheetRef.el)) {
76521
76587
  this.focusGrid();
76522
76588
  }
76523
- }, () => [this.env.model.getters.getActiveSheetId()]);
76589
+ });
76524
76590
  owl.useExternalListener(window, "resize", () => this.render(true));
76525
76591
  // For some reason, the wheel event is not properly registered inside templates
76526
76592
  // in Chromium-based browsers based on chromium 125
@@ -81097,9 +81163,9 @@ stores.inject(MyMetaStore, storeInstance);
81097
81163
  exports.tokenize = tokenize;
81098
81164
 
81099
81165
 
81100
- __info__.version = "18.3.28";
81101
- __info__.date = "2025-12-02T05:34:06.602Z";
81102
- __info__.hash = "a205f91";
81166
+ __info__.version = "18.3.32";
81167
+ __info__.date = "2026-01-14T10:00:27.532Z";
81168
+ __info__.hash = "8d1d321";
81103
81169
 
81104
81170
 
81105
81171
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);