@odoo/o-spreadsheet 18.4.19 → 18.4.23

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.4.19
6
- * @date 2025-12-02T05:34:03.902Z
7
- * @hash 95b1252
5
+ * @version 18.4.23
6
+ * @date 2026-01-07T16:21:07.502Z
7
+ * @hash a0135e8
8
8
  */
9
9
 
10
10
  'use strict';
@@ -5215,17 +5215,41 @@ function toCriterionDateNumber(dateValue) {
5215
5215
  const today = DateTime.now();
5216
5216
  switch (dateValue) {
5217
5217
  case "today":
5218
- return jsDateToNumber(today);
5219
- case "yesterday":
5220
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
5221
- case "tomorrow":
5222
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
5218
+ return Math.floor(jsDateToNumber(today));
5219
+ case "yesterday": {
5220
+ today.setDate(today.getDate() - 1);
5221
+ return Math.floor(jsDateToNumber(today));
5222
+ }
5223
+ case "tomorrow": {
5224
+ today.setDate(today.getDate() + 1);
5225
+ return Math.floor(jsDateToNumber(today));
5226
+ }
5223
5227
  case "lastWeek":
5224
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
5225
- case "lastMonth":
5226
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
5228
+ today.setDate(today.getDate() - 6);
5229
+ return Math.floor(jsDateToNumber(today));
5230
+ case "lastMonth": {
5231
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
5232
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
5233
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
5234
+ today.setDate(1);
5235
+ }
5236
+ else {
5237
+ today.setDate(today.getDate() + 1);
5238
+ today.setMonth(today.getMonth() - 1);
5239
+ }
5240
+ return Math.floor(jsDateToNumber(today));
5241
+ }
5227
5242
  case "lastYear":
5228
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
5243
+ // Handle leap year case
5244
+ if (today.getMonth() === 1 && today.getDate() === 29) {
5245
+ today.setDate(28);
5246
+ today.setFullYear(today.getFullYear() - 1);
5247
+ }
5248
+ else {
5249
+ today.setDate(today.getDate() + 1);
5250
+ today.setFullYear(today.getFullYear() - 1);
5251
+ }
5252
+ return Math.floor(jsDateToNumber(today));
5229
5253
  }
5230
5254
  }
5231
5255
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -29720,7 +29744,7 @@ function escapeQueryNameSpaces(query) {
29720
29744
  return query.replaceAll(/([a-zA-Z0-9]+):([a-zA-Z0-9]+)/g, "NAMESPACE" + "$1" + "NAMESPACE" + "$2");
29721
29745
  }
29722
29746
 
29723
- function getChartMenuActions(figureId, onFigureDeleted, env) {
29747
+ function getChartMenuActions(figureId, env) {
29724
29748
  const menuItemSpecs = [
29725
29749
  {
29726
29750
  id: "edit",
@@ -29771,11 +29795,11 @@ function getChartMenuActions(figureId, onFigureDeleted, env) {
29771
29795
  },
29772
29796
  isReadonlyAllowed: true,
29773
29797
  },
29774
- getDeleteMenuItem(figureId, onFigureDeleted, env),
29798
+ getDeleteMenuItem(figureId, env),
29775
29799
  ];
29776
29800
  return createActions(menuItemSpecs).filter((action) => env.model.getters.isReadonly() ? action.isReadonlyAllowed : true);
29777
29801
  }
29778
- function getImageMenuActions(figureId, onFigureDeleted, env) {
29802
+ function getImageMenuActions(figureId, env) {
29779
29803
  const menuItemSpecs = [
29780
29804
  getCopyMenuItem(figureId, env, _t("Image copied to clipboard")),
29781
29805
  getCutMenuItem(figureId, env),
@@ -29820,7 +29844,7 @@ function getImageMenuActions(figureId, onFigureDeleted, env) {
29820
29844
  },
29821
29845
  icon: "o-spreadsheet-Icon.DOWNLOAD",
29822
29846
  },
29823
- getDeleteMenuItem(figureId, onFigureDeleted, env),
29847
+ getDeleteMenuItem(figureId, env),
29824
29848
  ];
29825
29849
  return createActions(menuItemSpecs);
29826
29850
  }
@@ -29856,7 +29880,7 @@ function getCutMenuItem(figureId, env) {
29856
29880
  icon: "o-spreadsheet-Icon.CUT",
29857
29881
  };
29858
29882
  }
29859
- function getDeleteMenuItem(figureId, onFigureDeleted, env) {
29883
+ function getDeleteMenuItem(figureId, env) {
29860
29884
  return {
29861
29885
  id: "delete",
29862
29886
  name: _t("Delete"),
@@ -29866,7 +29890,6 @@ function getDeleteMenuItem(figureId, onFigureDeleted, env) {
29866
29890
  sheetId: env.model.getters.getActiveSheetId(),
29867
29891
  figureId,
29868
29892
  });
29869
- onFigureDeleted();
29870
29893
  },
29871
29894
  icon: "o-spreadsheet-Icon.TRASH",
29872
29895
  };
@@ -30711,7 +30734,7 @@ class ChartDashboardMenu extends owl.Component {
30711
30734
  openContextMenu(ev) {
30712
30735
  this.menuState.isOpen = true;
30713
30736
  this.menuState.anchorRect = getBoundingRectAsPOJO(ev.currentTarget);
30714
- this.menuState.menuItems = getChartMenuActions(this.props.figureUI.id, () => { }, this.env);
30737
+ this.menuState.menuItems = getChartMenuActions(this.props.figureUI.id, this.env);
30715
30738
  }
30716
30739
  get fullScreenMenuItem() {
30717
30740
  const definition = this.env.model.getters.getChartDefinition(this.props.figureUI.id);
@@ -30753,7 +30776,6 @@ class ChartFigure extends owl.Component {
30753
30776
  static template = "o-spreadsheet-ChartFigure";
30754
30777
  static props = {
30755
30778
  figureUI: Object,
30756
- onFigureDeleted: Function,
30757
30779
  };
30758
30780
  static components = { ChartDashboardMenu };
30759
30781
  onDoubleClick() {
@@ -30777,7 +30799,6 @@ class ImageFigure extends owl.Component {
30777
30799
  static template = "o-spreadsheet-ImageFigure";
30778
30800
  static props = {
30779
30801
  figureUI: Object,
30780
- onFigureDeleted: Function,
30781
30802
  };
30782
30803
  static components = {};
30783
30804
  // ---------------------------------------------------------------------------
@@ -30888,13 +30909,11 @@ class FigureComponent extends owl.Component {
30888
30909
  static props = {
30889
30910
  figureUI: Object,
30890
30911
  style: { type: String, optional: true },
30891
- onFigureDeleted: { type: Function, optional: true },
30892
30912
  onMouseDown: { type: Function, optional: true },
30893
30913
  onClickAnchor: { type: Function, optional: true },
30894
30914
  };
30895
30915
  static components = { MenuPopover };
30896
30916
  static defaultProps = {
30897
- onFigureDeleted: () => { },
30898
30917
  onMouseDown: () => { },
30899
30918
  onClickAnchor: () => { },
30900
30919
  };
@@ -30971,9 +30990,6 @@ class FigureComponent extends owl.Component {
30971
30990
  this.props.figureUI.id,
30972
30991
  this.figureRef.el,
30973
30992
  ]);
30974
- owl.onWillUnmount(() => {
30975
- this.props.onFigureDeleted();
30976
- });
30977
30993
  }
30978
30994
  clickAnchor(dirX, dirY, ev) {
30979
30995
  this.props.onClickAnchor(dirX, dirY, ev);
@@ -30997,7 +31013,6 @@ class FigureComponent extends owl.Component {
30997
31013
  sheetId: this.env.model.getters.getActiveSheetId(),
30998
31014
  figureId: this.props.figureUI.id,
30999
31015
  });
31000
- this.props.onFigureDeleted();
31001
31016
  ev.preventDefault();
31002
31017
  ev.stopPropagation();
31003
31018
  break;
@@ -31090,7 +31105,7 @@ class FigureComponent extends owl.Component {
31090
31105
  this.menuState.anchorRect = anchorRect;
31091
31106
  this.menuState.menuItems = figureRegistry
31092
31107
  .get(this.props.figureUI.tag)
31093
- .menuBuilder(this.props.figureUI.id, this.props.onFigureDeleted, this.env);
31108
+ .menuBuilder(this.props.figureUI.id, this.env);
31094
31109
  }
31095
31110
  }
31096
31111
 
@@ -31455,7 +31470,7 @@ criterionEvaluatorRegistry.add("dateIs", {
31455
31470
  return false;
31456
31471
  }
31457
31472
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
31458
- const today = jsDateToRoundNumber(DateTime.now());
31473
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
31459
31474
  return isDateBetween(dateValue, today, criterionValue);
31460
31475
  }
31461
31476
  return areDatesSameDay(dateValue, criterionValue);
@@ -45257,7 +45272,6 @@ class ArrayFormulaHighlight extends SpreadsheetStore {
45257
45272
  }
45258
45273
  get highlights() {
45259
45274
  const position = this.model.getters.getActivePosition();
45260
- const cell = this.getters.getEvaluatedCell(position);
45261
45275
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
45262
45276
  const zone = spreader
45263
45277
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
@@ -45265,10 +45279,11 @@ class ArrayFormulaHighlight extends SpreadsheetStore {
45265
45279
  if (!zone) {
45266
45280
  return [];
45267
45281
  }
45282
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
45268
45283
  return [
45269
45284
  {
45270
45285
  range: this.model.getters.getRangeFromZone(position.sheetId, zone),
45271
- dashed: cell.value === CellErrorType.SpilledBlocked,
45286
+ dashed: isArrayFormulaBlocked,
45272
45287
  color: "#17A2B8",
45273
45288
  noFill: true,
45274
45289
  thinLine: true,
@@ -46366,9 +46381,7 @@ css /*SCSS*/ `
46366
46381
  */
46367
46382
  class FiguresContainer extends owl.Component {
46368
46383
  static template = "o-spreadsheet-FiguresContainer";
46369
- static props = {
46370
- onFigureDeleted: Function,
46371
- };
46384
+ static props = {};
46372
46385
  static components = { FigureComponent };
46373
46386
  dnd = owl.useState({
46374
46387
  draggedFigure: undefined,
@@ -46743,16 +46756,16 @@ css /* scss */ `
46743
46756
  `;
46744
46757
  class GridAddRowsFooter extends owl.Component {
46745
46758
  static template = "o-spreadsheet-GridAddRowsFooter";
46746
- static props = {
46747
- focusGrid: Function,
46748
- };
46759
+ static props = {};
46749
46760
  static components = { ValidationMessages };
46761
+ DOMFocusableElementStore;
46750
46762
  inputRef = owl.useRef("inputRef");
46751
46763
  state = owl.useState({
46752
46764
  inputValue: "100",
46753
46765
  errorFlag: false,
46754
46766
  });
46755
46767
  setup() {
46768
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
46756
46769
  owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
46757
46770
  }
46758
46771
  get addRowsPosition() {
@@ -46770,7 +46783,7 @@ class GridAddRowsFooter extends owl.Component {
46770
46783
  }
46771
46784
  onKeydown(ev) {
46772
46785
  if (ev.key.toUpperCase() === "ESCAPE") {
46773
- this.props.focusGrid();
46786
+ this.focusDefaultElement();
46774
46787
  }
46775
46788
  else if (ev.key.toUpperCase() === "ENTER") {
46776
46789
  this.onConfirm();
@@ -46797,7 +46810,7 @@ class GridAddRowsFooter extends owl.Component {
46797
46810
  quantity,
46798
46811
  dimension: "ROW",
46799
46812
  });
46800
- this.props.focusGrid();
46813
+ this.focusDefaultElement();
46801
46814
  // After adding new rows, scroll down to the new last row
46802
46815
  const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
46803
46816
  const { end } = this.env.model.getters.getRowDimensions(activeSheetId, rowNumber + quantity - 1);
@@ -46810,7 +46823,12 @@ class GridAddRowsFooter extends owl.Component {
46810
46823
  if (this.inputRef.el !== document.activeElement || ev.target === this.inputRef.el) {
46811
46824
  return;
46812
46825
  }
46813
- this.props.focusGrid();
46826
+ this.focusDefaultElement();
46827
+ }
46828
+ focusDefaultElement() {
46829
+ if (document.activeElement === this.inputRef.el) {
46830
+ this.DOMFocusableElementStore.focus();
46831
+ }
46814
46832
  }
46815
46833
  }
46816
46834
 
@@ -47085,11 +47103,9 @@ class GridOverlay extends owl.Component {
47085
47103
  onCellClicked: { type: Function, optional: true },
47086
47104
  onCellRightClicked: { type: Function, optional: true },
47087
47105
  onGridResized: { type: Function, optional: true },
47088
- onFigureDeleted: { type: Function, optional: true },
47089
47106
  onGridMoved: Function,
47090
47107
  gridOverlayDimensions: String,
47091
47108
  slots: { type: Object, optional: true },
47092
- getGridSize: Function,
47093
47109
  };
47094
47110
  static components = {
47095
47111
  FiguresContainer,
@@ -47100,7 +47116,6 @@ class GridOverlay extends owl.Component {
47100
47116
  onCellClicked: () => { },
47101
47117
  onCellRightClicked: () => { },
47102
47118
  onGridResized: () => { },
47103
- onFigureDeleted: () => { },
47104
47119
  };
47105
47120
  gridOverlay = owl.useRef("gridOverlay");
47106
47121
  cellPopovers;
@@ -47109,14 +47124,7 @@ class GridOverlay extends owl.Component {
47109
47124
  setup() {
47110
47125
  useCellHovered(this.env, this.gridOverlay);
47111
47126
  const resizeObserver = new ResizeObserver(() => {
47112
- const boundingRect = this.gridOverlayEl.getBoundingClientRect();
47113
- const { width, height } = this.props.getGridSize();
47114
- this.props.onGridResized({
47115
- x: boundingRect.left,
47116
- y: boundingRect.top,
47117
- height: height,
47118
- width: width,
47119
- });
47127
+ this.props.onGridResized();
47120
47128
  });
47121
47129
  owl.onMounted(() => {
47122
47130
  resizeObserver.observe(this.gridOverlayEl);
@@ -51959,7 +51967,7 @@ function useHighlights(highlightProvider) {
51959
51967
  }
51960
51968
 
51961
51969
  css /* scss */ `
51962
- .o-cf-preview {
51970
+ .o-spreadsheet .o-cf-preview {
51963
51971
  &.o-cf-cursor-ptr {
51964
51972
  cursor: pointer;
51965
51973
  }
@@ -51967,6 +51975,7 @@ css /* scss */ `
51967
51975
  border-bottom: 1px solid ${GRAY_300};
51968
51976
  height: 80px;
51969
51977
  padding: 10px;
51978
+ box-sizing: border-box;
51970
51979
  position: relative;
51971
51980
  cursor: pointer;
51972
51981
  &:hover,
@@ -51980,7 +51989,6 @@ css /* scss */ `
51980
51989
  .o-cf-preview-icon {
51981
51990
  border: 1px solid ${GRAY_300};
51982
51991
  background-color: #fff;
51983
- position: absolute;
51984
51992
  height: 50px;
51985
51993
  width: 50px;
51986
51994
  .o-icon {
@@ -51989,12 +51997,6 @@ css /* scss */ `
51989
51997
  }
51990
51998
  }
51991
51999
  .o-cf-preview-description {
51992
- left: 65px;
51993
- margin-bottom: auto;
51994
- margin-right: 8px;
51995
- margin-top: auto;
51996
- position: relative;
51997
- width: 142px;
51998
52000
  .o-cf-preview-description-rule {
51999
52001
  margin-bottom: 4px;
52000
52002
  max-height: 2.8em;
@@ -52004,16 +52006,11 @@ css /* scss */ `
52004
52006
  font-size: 12px;
52005
52007
  }
52006
52008
  }
52007
- .o-cf-delete {
52008
- left: 90%;
52009
- top: 39%;
52010
- position: absolute;
52011
- }
52012
52009
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
52013
52010
  display: none !important;
52014
52011
  }
52015
52012
  .o-cf-drag-handle {
52016
- left: -8px;
52013
+ left: 2px;
52017
52014
  cursor: move;
52018
52015
  .o-icon {
52019
52016
  width: 6px;
@@ -56062,7 +56059,37 @@ pivotRegistry.add("SPREADSHEET", {
56062
56059
  datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
56063
56060
  isMeasureCandidate: (field) => field.type !== "boolean",
56064
56061
  isGroupable: () => true,
56062
+ adaptRanges: (getters, definition, applyChange) => {
56063
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
56064
+ return definition;
56065
+ }
56066
+ const { sheetId, zone } = definition.dataSet;
56067
+ const range = getters.getRangeFromZone(sheetId, zone);
56068
+ const adaptedRange = adaptPivotRange(range, applyChange);
56069
+ if (adaptedRange === range) {
56070
+ return definition;
56071
+ }
56072
+ const dataSet = adaptedRange && {
56073
+ sheetId: adaptedRange.sheetId,
56074
+ zone: adaptedRange.zone,
56075
+ };
56076
+ return { ...definition, dataSet };
56077
+ },
56065
56078
  });
56079
+ function adaptPivotRange(range, applyChange) {
56080
+ if (!range) {
56081
+ return undefined;
56082
+ }
56083
+ const change = applyChange(range);
56084
+ switch (change.changeType) {
56085
+ case "NONE":
56086
+ return range;
56087
+ case "REMOVE":
56088
+ return undefined;
56089
+ default:
56090
+ return change.range;
56091
+ }
56092
+ }
56066
56093
 
56067
56094
  class PivotSidePanelStore extends SpreadsheetStore {
56068
56095
  pivotId;
@@ -58033,7 +58060,8 @@ class Grid extends owl.Component {
58033
58060
  });
58034
58061
  return !(rect.width === 0 || rect.height === 0);
58035
58062
  }
58036
- onGridResized({ height, width }) {
58063
+ onGridResized() {
58064
+ const { height, width } = this.props.getGridSize();
58037
58065
  this.env.model.dispatch("RESIZE_SHEETVIEW", {
58038
58066
  width: width - HEADER_WIDTH,
58039
58067
  height: height - HEADER_HEIGHT,
@@ -62215,6 +62243,7 @@ function rangeToMerge(mergeId, range) {
62215
62243
  class RangeAdapter {
62216
62244
  getters;
62217
62245
  providers = [];
62246
+ isAdaptingRanges = false;
62218
62247
  constructor(getters) {
62219
62248
  this.getters = getters;
62220
62249
  }
@@ -62246,6 +62275,9 @@ class RangeAdapter {
62246
62275
  }
62247
62276
  beforeHandle(command) { }
62248
62277
  handle(cmd) {
62278
+ if (this.isAdaptingRanges) {
62279
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
62280
+ }
62249
62281
  const rangeAdapter = getRangeAdapter(cmd);
62250
62282
  if (rangeAdapter?.applyChange) {
62251
62283
  this.executeOnAllRanges(rangeAdapter.applyChange, rangeAdapter.sheetId, rangeAdapter.sheetName);
@@ -62268,10 +62300,12 @@ class RangeAdapter {
62268
62300
  };
62269
62301
  }
62270
62302
  executeOnAllRanges(adaptRange, sheetId, sheetName) {
62303
+ this.isAdaptingRanges = true;
62271
62304
  const func = this.verifyRangeRemoved(adaptRange);
62272
62305
  for (const provider of this.providers) {
62273
62306
  provider(func, sheetId, sheetName);
62274
62307
  }
62308
+ this.isAdaptingRanges = false;
62275
62309
  }
62276
62310
  /**
62277
62311
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -64307,6 +64341,18 @@ class PivotCorePlugin extends CorePlugin {
64307
64341
  }
64308
64342
  }
64309
64343
  adaptRanges(applyChange) {
64344
+ for (const pivotId in this.pivots) {
64345
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
64346
+ if (!definition) {
64347
+ continue;
64348
+ }
64349
+ const newDefinition = pivotRegistry
64350
+ .get(definition.type)
64351
+ ?.adaptRanges?.(this.getters, definition, applyChange);
64352
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
64353
+ this.history.update("pivots", pivotId, "definition", newDefinition);
64354
+ }
64355
+ }
64310
64356
  for (const sheetId in this.compiledMeasureFormulas) {
64311
64357
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
64312
64358
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -64451,17 +64497,10 @@ class PivotCorePlugin extends CorePlugin {
64451
64497
  if (!pivot) {
64452
64498
  continue;
64453
64499
  }
64454
- const def = deepCopy(pivot.definition);
64455
- for (const measure of def.measures) {
64500
+ for (const measure of pivot.definition.measures) {
64456
64501
  if (measure.computedBy?.formula === formulaString) {
64457
- const measureIndex = def.measures.indexOf(measure);
64458
- if (measureIndex !== -1) {
64459
- def.measures[measureIndex].computedBy = {
64460
- formula: newFormulaString,
64461
- sheetId,
64462
- };
64463
- }
64464
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
64502
+ const measureIndex = pivot.definition.measures.indexOf(measure);
64503
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
64465
64504
  }
64466
64505
  }
64467
64506
  }
@@ -64565,20 +64604,6 @@ class SettingsPlugin extends CorePlugin {
64565
64604
  }
64566
64605
  }
64567
64606
 
64568
- function adaptPivotRange(range, applyChange) {
64569
- if (!range) {
64570
- return undefined;
64571
- }
64572
- const change = applyChange(range);
64573
- switch (change.changeType) {
64574
- case "NONE":
64575
- return range;
64576
- case "REMOVE":
64577
- return undefined;
64578
- default:
64579
- return change.range;
64580
- }
64581
- }
64582
64607
  class SpreadsheetPivotCorePlugin extends CorePlugin {
64583
64608
  allowDispatch(cmd) {
64584
64609
  switch (cmd.type) {
@@ -64589,27 +64614,6 @@ class SpreadsheetPivotCorePlugin extends CorePlugin {
64589
64614
  }
64590
64615
  return "Success" /* CommandResult.Success */;
64591
64616
  }
64592
- adaptRanges(applyChange) {
64593
- for (const pivotId of this.getters.getPivotIds()) {
64594
- const definition = this.getters.getPivotCoreDefinition(pivotId);
64595
- if (definition.type !== "SPREADSHEET") {
64596
- continue;
64597
- }
64598
- if (definition.dataSet) {
64599
- const { sheetId, zone } = definition.dataSet;
64600
- const range = this.getters.getRangeFromZone(sheetId, zone);
64601
- const adaptedRange = adaptPivotRange(range, applyChange);
64602
- if (adaptedRange === range) {
64603
- return;
64604
- }
64605
- const dataSet = adaptedRange && {
64606
- sheetId: adaptedRange.sheetId,
64607
- zone: adaptedRange.zone,
64608
- };
64609
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
64610
- }
64611
- }
64612
- }
64613
64617
  checkDataSetValidity(definition) {
64614
64618
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
64615
64619
  const { zone, sheetId } = definition.dataSet;
@@ -65951,6 +65955,9 @@ class Evaluator {
65951
65955
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
65952
65956
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
65953
65957
  }
65958
+ isArrayFormulaSpillBlocked(position) {
65959
+ return this.blockedArrayFormulas.has(position);
65960
+ }
65954
65961
  updateDependencies(position) {
65955
65962
  // removing dependencies is slow because it requires
65956
65963
  // to traverse the entire r-tree.
@@ -65962,13 +65969,8 @@ class Evaluator {
65962
65969
  addDependencies(position, dependencies) {
65963
65970
  this.formulaDependencies().addDependencies(position, dependencies);
65964
65971
  for (const range of dependencies) {
65965
- const sheetId = range.sheetId;
65966
- const { left, bottom, right, top } = range.zone;
65967
- for (let col = left; col <= right; col++) {
65968
- for (let row = top; row <= bottom; row++) {
65969
- this.computeAndSave({ sheetId, col, row });
65970
- }
65971
- }
65972
+ // ensure that all ranges are computed
65973
+ this.compilationParams.ensureRange(range);
65972
65974
  }
65973
65975
  }
65974
65976
  updateCompilationParameters() {
@@ -66171,6 +66173,10 @@ class Evaluator {
66171
66173
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
66172
66174
  const nbColumns = formulaReturn.length;
66173
66175
  const nbRows = formulaReturn[0].length;
66176
+ if (nbRows === 0) {
66177
+ // empty matrix
66178
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
66179
+ }
66174
66180
  const resultZone = {
66175
66181
  top: formulaPosition.row,
66176
66182
  bottom: formulaPosition.row + nbRows - 1,
@@ -66446,6 +66452,7 @@ class EvaluationPlugin extends CoreViewPlugin {
66446
66452
  "getEvaluatedCellsPositions",
66447
66453
  "getSpreadZone",
66448
66454
  "getArrayFormulaSpreadingOn",
66455
+ "isArrayFormulaSpillBlocked",
66449
66456
  "isEmpty",
66450
66457
  ];
66451
66458
  shouldRebuildDependenciesGraph = true;
@@ -66558,6 +66565,9 @@ class EvaluationPlugin extends CoreViewPlugin {
66558
66565
  getArrayFormulaSpreadingOn(position) {
66559
66566
  return this.evaluator.getArrayFormulaSpreadingOn(position);
66560
66567
  }
66568
+ isArrayFormulaSpillBlocked(position) {
66569
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
66570
+ }
66561
66571
  /**
66562
66572
  * Check if a zone only contains empty cells
66563
66573
  */
@@ -78157,10 +78167,8 @@ class SpreadsheetDashboard extends owl.Component {
78157
78167
  });
78158
78168
  }
78159
78169
  get gridContainer() {
78160
- const sheetId = this.env.model.getters.getActiveSheetId();
78161
- const { right } = this.env.model.getters.getSheetZone(sheetId);
78162
- const { end } = this.env.model.getters.getColDimensions(sheetId, right);
78163
- return cssPropertiesToCss({ "max-width": `${end}px` });
78170
+ const maxWidth = this.getMaxSheetWidth();
78171
+ return cssPropertiesToCss({ "max-width": `${maxWidth}px` });
78164
78172
  }
78165
78173
  get gridOverlayDimensions() {
78166
78174
  return cssPropertiesToCss({
@@ -78192,10 +78200,12 @@ class SpreadsheetDashboard extends owl.Component {
78192
78200
  onClosePopover() {
78193
78201
  this.cellPopovers.close();
78194
78202
  }
78195
- onGridResized({ height, width }) {
78203
+ onGridResized() {
78204
+ const { height, width } = this.props.getGridSize();
78205
+ const maxWidth = this.getMaxSheetWidth();
78196
78206
  this.env.model.dispatch("RESIZE_SHEETVIEW", {
78197
- width: width,
78198
- height: height,
78207
+ width: Math.min(maxWidth, width),
78208
+ height,
78199
78209
  gridOffsetX: 0,
78200
78210
  gridOffsetY: 0,
78201
78211
  });
@@ -78213,6 +78223,11 @@ class SpreadsheetDashboard extends owl.Component {
78213
78223
  ...this.env.model.getters.getSheetViewDimensionWithHeaders(),
78214
78224
  };
78215
78225
  }
78226
+ getMaxSheetWidth() {
78227
+ const sheetId = this.env.model.getters.getActiveSheetId();
78228
+ const { right } = this.env.model.getters.getSheetZone(sheetId);
78229
+ return this.env.model.getters.getColDimensions(sheetId, right).end;
78230
+ }
78216
78231
  }
78217
78232
 
78218
78233
  css /* scss */ `
@@ -80360,7 +80375,7 @@ class Spreadsheet extends owl.Component {
80360
80375
  document.activeElement?.contains(this.spreadsheetRef.el)) {
80361
80376
  this.focusGrid();
80362
80377
  }
80363
- }, () => [this.env.model.getters.getActiveSheetId()]);
80378
+ });
80364
80379
  owl.useExternalListener(window, "resize", () => this.render(true));
80365
80380
  // For some reason, the wheel event is not properly registered inside templates
80366
80381
  // in Chromium-based browsers based on chromium 125
@@ -80453,22 +80468,20 @@ class Spreadsheet extends owl.Component {
80453
80468
  return this.env.model.getters.getVisibleGroupLayers(sheetId, "COL");
80454
80469
  }
80455
80470
  getGridSize() {
80456
- const topBarHeight = this.spreadsheetRef.el
80457
- ?.querySelector(".o-spreadsheet-topbar-wrapper")
80458
- ?.getBoundingClientRect().height || 0;
80459
- const bottomBarHeight = this.spreadsheetRef.el
80460
- ?.querySelector(".o-spreadsheet-bottombar-wrapper")
80461
- ?.getBoundingClientRect().height || 0;
80462
- const gridWidth = this.spreadsheetRef.el?.querySelector(".o-grid")?.getBoundingClientRect().width || 0;
80463
- const gridHeight = (this.spreadsheetRef.el?.getBoundingClientRect().height || 0) -
80464
- (this.spreadsheetRef.el?.querySelector(".o-column-groups")?.getBoundingClientRect().height ||
80465
- 0) -
80466
- topBarHeight -
80467
- bottomBarHeight;
80468
- return {
80469
- width: Math.max(gridWidth - SCROLLBAR_WIDTH, 0),
80470
- height: Math.max(gridHeight - SCROLLBAR_WIDTH, 0),
80471
- };
80471
+ const el = this.spreadsheetRef.el;
80472
+ if (!el) {
80473
+ return { width: 0, height: 0 };
80474
+ }
80475
+ const getHeight = (selector) => el.querySelector(selector)?.getBoundingClientRect().height || 0;
80476
+ const getWidth = (selector) => el.querySelector(selector)?.getBoundingClientRect().width || 0;
80477
+ const rect = el.getBoundingClientRect();
80478
+ const topBarHeight = getHeight(".o-spreadsheet-topbar-wrapper");
80479
+ const bottomBarHeight = getHeight(".o-spreadsheet-bottombar-wrapper");
80480
+ const colGroupHeight = getHeight(".o-column-groups");
80481
+ const gridWidth = getWidth(".o-grid");
80482
+ const width = Math.max(gridWidth - SCROLLBAR_WIDTH, 0);
80483
+ const height = Math.max(rect.height - topBarHeight - bottomBarHeight - colGroupHeight - SCROLLBAR_WIDTH, 0);
80484
+ return { width, height };
80472
80485
  }
80473
80486
  }
80474
80487
 
@@ -85001,6 +85014,6 @@ exports.tokenColors = tokenColors;
85001
85014
  exports.tokenize = tokenize;
85002
85015
 
85003
85016
 
85004
- __info__.version = "18.4.19";
85005
- __info__.date = "2025-12-02T05:34:03.902Z";
85006
- __info__.hash = "95b1252";
85017
+ __info__.version = "18.4.23";
85018
+ __info__.date = "2026-01-07T16:21:07.502Z";
85019
+ __info__.hash = "a0135e8";