@odoo/o-spreadsheet 19.0.12 → 19.0.15

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 19.0.12
6
- * @date 2025-12-02T05:34:17.495Z
7
- * @hash 32203f1
5
+ * @version 19.0.15
6
+ * @date 2025-12-26T10:19:23.408Z
7
+ * @hash fe625c9
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -1894,21 +1894,25 @@
1894
1894
  function profilesContainsZone(profilesStartingPosition, profiles, zone) {
1895
1895
  const leftValue = zone.left;
1896
1896
  const rightValue = zone.right;
1897
- const topValue = zone.top;
1898
- const bottomValue = zone.bottom + 1;
1899
1897
  const leftIndex = binaryPredecessorSearch(profilesStartingPosition, leftValue, 0);
1900
- const rightIndex = binaryPredecessorSearch(profilesStartingPosition, rightValue, leftIndex);
1901
- if (leftIndex === -1 || rightIndex === -1) {
1902
- return false;
1903
- }
1898
+ const rightIndex = rightValue === undefined
1899
+ ? profilesStartingPosition.length - 1
1900
+ : binaryPredecessorSearch(profilesStartingPosition, rightValue, leftIndex);
1901
+ /**
1902
+ * The `profilesStartingPosition` array always contains at least the value `0` at its first position,
1903
+ * ensuring that applying `binaryPredecessorSearch` will always return a valid index.
1904
+ * Therefore, it is not necessary to check if the result of `binaryPredecessorSearch` equals `-1`.
1905
+ */
1906
+ const topValue = zone.top;
1907
+ const bottomValue = zone.bottom === undefined ? undefined : zone.bottom + 1;
1904
1908
  for (let i = leftIndex; i <= rightIndex; i++) {
1905
1909
  const profile = profiles.get(profilesStartingPosition[i]);
1906
- const topPredIndex = binaryPredecessorSearch(profile, topValue, 0, true);
1907
- const bottomSuccIndex = binarySuccessorSearch(profile, bottomValue, 0, true);
1910
+ const topPredIndex = binaryPredecessorSearch(profile, topValue, 0);
1908
1911
  if (topPredIndex === -1 || topPredIndex % 2 !== 0) {
1909
1912
  return false;
1910
1913
  }
1911
- if (topValue < profile[topPredIndex] || bottomValue > profile[bottomSuccIndex]) {
1914
+ const bottomSuccIndex = bottomValue === undefined ? profile.length : binarySuccessorSearch(profile, bottomValue, 0);
1915
+ if (topPredIndex + 1 !== bottomSuccIndex) {
1912
1916
  return false;
1913
1917
  }
1914
1918
  }
@@ -6594,17 +6598,41 @@
6594
6598
  const today = DateTime.now();
6595
6599
  switch (dateValue) {
6596
6600
  case "today":
6597
- return jsDateToNumber(today);
6598
- case "yesterday":
6599
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
6600
- case "tomorrow":
6601
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
6601
+ return Math.floor(jsDateToNumber(today));
6602
+ case "yesterday": {
6603
+ today.setDate(today.getDate() - 1);
6604
+ return Math.floor(jsDateToNumber(today));
6605
+ }
6606
+ case "tomorrow": {
6607
+ today.setDate(today.getDate() + 1);
6608
+ return Math.floor(jsDateToNumber(today));
6609
+ }
6602
6610
  case "lastWeek":
6603
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
6604
- case "lastMonth":
6605
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
6611
+ today.setDate(today.getDate() - 6);
6612
+ return Math.floor(jsDateToNumber(today));
6613
+ case "lastMonth": {
6614
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
6615
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
6616
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
6617
+ today.setDate(1);
6618
+ }
6619
+ else {
6620
+ today.setDate(today.getDate() + 1);
6621
+ today.setMonth(today.getMonth() - 1);
6622
+ }
6623
+ return Math.floor(jsDateToNumber(today));
6624
+ }
6606
6625
  case "lastYear":
6607
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
6626
+ // Handle leap year case
6627
+ if (today.getMonth() === 1 && today.getDate() === 29) {
6628
+ today.setDate(28);
6629
+ today.setFullYear(today.getFullYear() - 1);
6630
+ }
6631
+ else {
6632
+ today.setDate(today.getDate() + 1);
6633
+ today.setFullYear(today.getFullYear() - 1);
6634
+ }
6635
+ return Math.floor(jsDateToNumber(today));
6608
6636
  }
6609
6637
  }
6610
6638
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -6777,67 +6805,6 @@
6777
6805
  return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
6778
6806
  }
6779
6807
 
6780
- function createDefaultRows(rowNumber) {
6781
- const rows = [];
6782
- for (let i = 0; i < rowNumber; i++) {
6783
- const row = {
6784
- cells: {},
6785
- };
6786
- rows.push(row);
6787
- }
6788
- return rows;
6789
- }
6790
- function moveHeaderIndexesOnHeaderAddition(indexHeaderAdded, numberAdded, headers) {
6791
- return headers.map((header) => {
6792
- if (header >= indexHeaderAdded) {
6793
- return header + numberAdded;
6794
- }
6795
- return header;
6796
- });
6797
- }
6798
- function moveHeaderIndexesOnHeaderDeletion(deletedHeaders, headers) {
6799
- deletedHeaders = [...deletedHeaders].sort((a, b) => b - a);
6800
- return headers
6801
- .map((header) => {
6802
- for (const deletedHeader of deletedHeaders) {
6803
- if (header > deletedHeader) {
6804
- header--;
6805
- }
6806
- else if (header === deletedHeader) {
6807
- return undefined;
6808
- }
6809
- }
6810
- return header;
6811
- })
6812
- .filter(isDefined);
6813
- }
6814
- function getNextSheetName(existingNames, baseName = "Sheet") {
6815
- let i = 1;
6816
- let name = `${baseName}${i}`;
6817
- while (existingNames.includes(name)) {
6818
- name = `${baseName}${i}`;
6819
- i++;
6820
- }
6821
- return name;
6822
- }
6823
- function getDuplicateSheetName(nameToDuplicate, existingNames) {
6824
- let i = 1;
6825
- const baseName = _t("Copy of %s", nameToDuplicate);
6826
- let name = baseName.toString();
6827
- while (existingNames.includes(name)) {
6828
- name = `${baseName} (${i})`;
6829
- i++;
6830
- }
6831
- return name;
6832
- }
6833
- function isSheetNameEqual(name1, name2) {
6834
- if (name1 === undefined || name2 === undefined) {
6835
- return false;
6836
- }
6837
- return (getUnquotedSheetName(name1.trim().toUpperCase()) ===
6838
- getUnquotedSheetName(name2.trim().toUpperCase()));
6839
- }
6840
-
6841
6808
  function createRange(args, getSheetSize) {
6842
6809
  const unboundedZone = args.zone;
6843
6810
  const zone = boundUnboundedZone(unboundedZone, getSheetSize(args.sheetId));
@@ -7085,7 +7052,7 @@
7085
7052
  elements.sort((a, b) => b - a);
7086
7053
  const groups = groupConsecutive(elements);
7087
7054
  return (range) => {
7088
- if (!isSheetNameEqual(range.sheetId, cmd.sheetId)) {
7055
+ if (range.sheetId !== cmd.sheetId) {
7089
7056
  return { changeType: "NONE" };
7090
7057
  }
7091
7058
  let newRange = range;
@@ -7292,6 +7259,69 @@
7292
7259
  return results.map((r) => r.elem);
7293
7260
  }
7294
7261
 
7262
+ function createDefaultRows(rowNumber) {
7263
+ const rows = [];
7264
+ for (let i = 0; i < rowNumber; i++) {
7265
+ const row = {
7266
+ cells: {},
7267
+ };
7268
+ rows.push(row);
7269
+ }
7270
+ return rows;
7271
+ }
7272
+ function moveHeaderIndexesOnHeaderAddition(indexHeaderAdded, numberAdded, headers) {
7273
+ return headers.map((header) => {
7274
+ if (header >= indexHeaderAdded) {
7275
+ return header + numberAdded;
7276
+ }
7277
+ return header;
7278
+ });
7279
+ }
7280
+ function moveHeaderIndexesOnHeaderDeletion(deletedHeaders, headers) {
7281
+ deletedHeaders = [...deletedHeaders].sort((a, b) => b - a);
7282
+ return headers
7283
+ .map((header) => {
7284
+ for (const deletedHeader of deletedHeaders) {
7285
+ if (header > deletedHeader) {
7286
+ header--;
7287
+ }
7288
+ else if (header === deletedHeader) {
7289
+ return undefined;
7290
+ }
7291
+ }
7292
+ return header;
7293
+ })
7294
+ .filter(isDefined);
7295
+ }
7296
+ function getNextSheetName(existingNames, baseName = "Sheet") {
7297
+ let i = 1;
7298
+ let name = `${baseName}${i}`;
7299
+ while (existingNames.includes(name)) {
7300
+ name = `${baseName}${i}`;
7301
+ i++;
7302
+ }
7303
+ return name;
7304
+ }
7305
+ function getDuplicateSheetName(nameToDuplicate, existingNames) {
7306
+ let i = 1;
7307
+ const baseName = _t("Copy of %s", nameToDuplicate);
7308
+ let name = baseName.toString();
7309
+ while (existingNames.includes(name)) {
7310
+ name = `${baseName} (${i})`;
7311
+ i++;
7312
+ }
7313
+ return name;
7314
+ }
7315
+ const toStandardizedSheetName = memoize(function toStandardizedSheetName(name) {
7316
+ return getUnquotedSheetName(name.trim().toUpperCase());
7317
+ });
7318
+ function isSheetNameEqual(name1, name2) {
7319
+ if (name1 === undefined || name2 === undefined) {
7320
+ return false;
7321
+ }
7322
+ return toStandardizedSheetName(name1) === toStandardizedSheetName(name2);
7323
+ }
7324
+
7295
7325
  function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
7296
7326
  return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
7297
7327
  }
@@ -31420,7 +31450,7 @@ stores.inject(MyMetaStore, storeInstance);
31420
31450
  return query.replaceAll(/([a-zA-Z0-9]+):([a-zA-Z0-9]+)/g, "NAMESPACE" + "$1" + "NAMESPACE" + "$2");
31421
31451
  }
31422
31452
 
31423
- function getChartMenuActions(figureId, onFigureDeleted, env) {
31453
+ function getChartMenuActions(figureId, env) {
31424
31454
  const chartId = env.model.getters.getChartIdFromFigureId(figureId);
31425
31455
  if (!chartId) {
31426
31456
  return [];
@@ -31440,11 +31470,11 @@ stores.inject(MyMetaStore, storeInstance);
31440
31470
  getCutMenuItem(figureId, env),
31441
31471
  getCopyAsImageMenuItem(figureId, env),
31442
31472
  getDownloadChartMenuItem(figureId, env),
31443
- getDeleteMenuItem(figureId, onFigureDeleted, env),
31473
+ getDeleteMenuItem(figureId, env),
31444
31474
  ];
31445
31475
  return createActions(menuItemSpecs).filter((action) => env.model.getters.isReadonly() ? action.isReadonlyAllowed : true);
31446
31476
  }
31447
- function getImageMenuActions(figureId, onFigureDeleted, env) {
31477
+ function getImageMenuActions(figureId, env) {
31448
31478
  const menuItemSpecs = [
31449
31479
  getCopyMenuItem(figureId, env, _t("Image copied to clipboard")),
31450
31480
  getCutMenuItem(figureId, env),
@@ -31487,11 +31517,11 @@ stores.inject(MyMetaStore, storeInstance);
31487
31517
  },
31488
31518
  icon: "o-spreadsheet-Icon.DOWNLOAD",
31489
31519
  },
31490
- getDeleteMenuItem(figureId, onFigureDeleted, env),
31520
+ getDeleteMenuItem(figureId, env),
31491
31521
  ];
31492
31522
  return createActions(menuItemSpecs);
31493
31523
  }
31494
- function getCarouselMenuActions(figureId, onFigureDeleted, env) {
31524
+ function getCarouselMenuActions(figureId, env) {
31495
31525
  const isChartSelected = (env) => env.model.getters.getSelectedCarouselItem(figureId)?.type === "chart";
31496
31526
  const menuItemSpecs = [
31497
31527
  {
@@ -31510,7 +31540,7 @@ stores.inject(MyMetaStore, storeInstance);
31510
31540
  },
31511
31541
  { ...getCutMenuItem(figureId, env), name: _t("Cut carousel") },
31512
31542
  {
31513
- ...getDeleteMenuItem(figureId, onFigureDeleted, env),
31543
+ ...getDeleteMenuItem(figureId, env),
31514
31544
  name: _t("Delete carousel"),
31515
31545
  separator: true,
31516
31546
  },
@@ -31653,7 +31683,7 @@ stores.inject(MyMetaStore, storeInstance);
31653
31683
  isReadonlyAllowed: true,
31654
31684
  };
31655
31685
  }
31656
- function getDeleteMenuItem(figureId, onFigureDeleted, env) {
31686
+ function getDeleteMenuItem(figureId, env) {
31657
31687
  return {
31658
31688
  id: "delete",
31659
31689
  name: _t("Delete"),
@@ -31662,7 +31692,6 @@ stores.inject(MyMetaStore, storeInstance);
31662
31692
  sheetId: env.model.getters.getActiveSheetId(),
31663
31693
  figureId,
31664
31694
  });
31665
- onFigureDeleted();
31666
31695
  },
31667
31696
  icon: "o-spreadsheet-Icon.TRASH",
31668
31697
  };
@@ -32475,7 +32504,7 @@ stores.inject(MyMetaStore, storeInstance);
32475
32504
  this.menuState.isOpen = true;
32476
32505
  this.menuState.anchorRect = getBoundingRectAsPOJO(ev.currentTarget);
32477
32506
  const figureId = this.env.model.getters.getFigureIdFromChartId(this.props.chartId);
32478
- this.menuState.menuItems = getChartMenuActions(figureId, () => { }, this.env);
32507
+ this.menuState.menuItems = getChartMenuActions(figureId, this.env);
32479
32508
  }
32480
32509
  get fullScreenMenuItem() {
32481
32510
  if (!this.props.hasFullScreenButton) {
@@ -32502,7 +32531,6 @@ stores.inject(MyMetaStore, storeInstance);
32502
32531
  static template = "o-spreadsheet-CarouselFigure";
32503
32532
  static props = {
32504
32533
  figureUI: Object,
32505
- onFigureDeleted: Function,
32506
32534
  editFigureStyle: { type: Function, optional: true },
32507
32535
  isFullScreen: { type: Boolean, optional: true },
32508
32536
  openContextMenu: { type: Function, optional: true },
@@ -32651,7 +32679,6 @@ stores.inject(MyMetaStore, storeInstance);
32651
32679
  static template = "o-spreadsheet-ChartFigure";
32652
32680
  static props = {
32653
32681
  figureUI: Object,
32654
- onFigureDeleted: Function,
32655
32682
  editFigureStyle: { type: Function, optional: true },
32656
32683
  isFullScreen: { type: Boolean, optional: true },
32657
32684
  openContextMenu: { type: Function, optional: true },
@@ -32685,7 +32712,6 @@ stores.inject(MyMetaStore, storeInstance);
32685
32712
  static template = "o-spreadsheet-ImageFigure";
32686
32713
  static props = {
32687
32714
  figureUI: Object,
32688
- onFigureDeleted: Function,
32689
32715
  editFigureStyle: { type: Function, optional: true },
32690
32716
  openContextMenu: { type: Function, optional: true },
32691
32717
  };
@@ -32804,13 +32830,11 @@ stores.inject(MyMetaStore, storeInstance);
32804
32830
  figureUI: Object,
32805
32831
  style: { type: String, optional: true },
32806
32832
  class: { type: String, optional: true },
32807
- onFigureDeleted: { type: Function, optional: true },
32808
32833
  onMouseDown: { type: Function, optional: true },
32809
32834
  onClickAnchor: { type: Function, optional: true },
32810
32835
  };
32811
32836
  static components = { MenuPopover };
32812
32837
  static defaultProps = {
32813
- onFigureDeleted: () => { },
32814
32838
  onMouseDown: () => { },
32815
32839
  onClickAnchor: () => { },
32816
32840
  };
@@ -32888,9 +32912,6 @@ stores.inject(MyMetaStore, storeInstance);
32888
32912
  this.props.figureUI.id,
32889
32913
  this.figureRef.el,
32890
32914
  ]);
32891
- owl.onWillUnmount(() => {
32892
- this.props.onFigureDeleted();
32893
- });
32894
32915
  }
32895
32916
  clickAnchor(dirX, dirY, ev) {
32896
32917
  this.props.onClickAnchor(dirX, dirY, ev);
@@ -32914,7 +32935,6 @@ stores.inject(MyMetaStore, storeInstance);
32914
32935
  sheetId: this.env.model.getters.getActiveSheetId(),
32915
32936
  figureId: this.props.figureUI.id,
32916
32937
  });
32917
- this.props.onFigureDeleted();
32918
32938
  ev.preventDefault();
32919
32939
  ev.stopPropagation();
32920
32940
  break;
@@ -33007,7 +33027,7 @@ stores.inject(MyMetaStore, storeInstance);
33007
33027
  this.menuState.anchorRect = anchorRect;
33008
33028
  this.menuState.menuItems = figureRegistry
33009
33029
  .get(this.props.figureUI.tag)
33010
- .menuBuilder(this.props.figureUI.id, this.props.onFigureDeleted, this.env);
33030
+ .menuBuilder(this.props.figureUI.id, this.env);
33011
33031
  }
33012
33032
  editWrapperStyle(properties) {
33013
33033
  if (this.figureWrapperRef.el) {
@@ -33379,7 +33399,7 @@ stores.inject(MyMetaStore, storeInstance);
33379
33399
  return false;
33380
33400
  }
33381
33401
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
33382
- const today = jsDateToRoundNumber(DateTime.now());
33402
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
33383
33403
  return isDateBetween(dateValue, today, criterionValue);
33384
33404
  }
33385
33405
  return areDatesSameDay(dateValue, criterionValue);
@@ -37493,6 +37513,12 @@ stores.inject(MyMetaStore, storeInstance);
37493
37513
  }
37494
37514
  setup() {
37495
37515
  owl.useEffect(() => this.focusedInput.el?.focus(), () => [this.focusedInput.el]);
37516
+ owl.useEffect(() => {
37517
+ // Check the offsetParent to know if the input or an ancestor is `display: none` (eg. when changing side panel tab)
37518
+ if (this.store.hasFocus && this.selectionRef.el?.offsetParent === null) {
37519
+ this.reset();
37520
+ }
37521
+ });
37496
37522
  this.store = useLocalStore(SelectionInputStore, this.props.ranges, this.props.hasSingleRange || false, this.props.colors, this.props.disabledRanges);
37497
37523
  owl.onWillUpdateProps((nextProps) => {
37498
37524
  if (nextProps.ranges.join() !== this.store.selectionInputValues.join()) {
@@ -45276,7 +45302,7 @@ stores.inject(MyMetaStore, storeInstance);
45276
45302
  const leftOffset = isLeftUnbounded || left?.colFixed ? 0 : colCellOffset;
45277
45303
  const topOffset = isTopUnbounded || left?.rowFixed ? 0 : rowCellOffset;
45278
45304
  const isRightFixed = (!right && left?.colFixed) || right?.colFixed;
45279
- const isBottomFixed = (!right && left.rowFixed) || right?.rowFixed;
45305
+ const isBottomFixed = (!right && left?.rowFixed) || right?.rowFixed;
45280
45306
  const isRightUnbounded = range.unboundedZone.right === undefined;
45281
45307
  const isBottomUnbounded = range.unboundedZone.bottom === undefined;
45282
45308
  const rightOffset = isRightUnbounded || isRightFixed ? 0 : colCellOffset;
@@ -47840,7 +47866,37 @@ stores.inject(MyMetaStore, storeInstance);
47840
47866
  isMeasureCandidate: (field) => field.type !== "boolean",
47841
47867
  isGroupable: () => true,
47842
47868
  canHaveCustomGroup: (field) => field.type === "char" && !field.isCustomField,
47869
+ adaptRanges: (getters, definition, applyChange) => {
47870
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
47871
+ return definition;
47872
+ }
47873
+ const { sheetId, zone } = definition.dataSet;
47874
+ const range = getters.getRangeFromZone(sheetId, zone);
47875
+ const adaptedRange = adaptPivotRange(range, applyChange);
47876
+ if (adaptedRange === range) {
47877
+ return definition;
47878
+ }
47879
+ const dataSet = adaptedRange && {
47880
+ sheetId: adaptedRange.sheetId,
47881
+ zone: adaptedRange.zone,
47882
+ };
47883
+ return { ...definition, dataSet };
47884
+ },
47843
47885
  });
47886
+ function adaptPivotRange(range, applyChange) {
47887
+ if (!range) {
47888
+ return undefined;
47889
+ }
47890
+ const change = applyChange(range);
47891
+ switch (change.changeType) {
47892
+ case "NONE":
47893
+ return range;
47894
+ case "REMOVE":
47895
+ return undefined;
47896
+ default:
47897
+ return change.range;
47898
+ }
47899
+ }
47844
47900
 
47845
47901
  const pivotProperties = {
47846
47902
  name: _t("See pivot properties"),
@@ -49111,7 +49167,6 @@ stores.inject(MyMetaStore, storeInstance);
49111
49167
  }
49112
49168
  get highlights() {
49113
49169
  const position = this.model.getters.getActivePosition();
49114
- const cell = this.getters.getEvaluatedCell(position);
49115
49170
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
49116
49171
  const zone = spreader
49117
49172
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
@@ -49119,10 +49174,11 @@ stores.inject(MyMetaStore, storeInstance);
49119
49174
  if (!zone) {
49120
49175
  return [];
49121
49176
  }
49177
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
49122
49178
  return [
49123
49179
  {
49124
49180
  range: this.model.getters.getRangeFromZone(position.sheetId, zone),
49125
- dashed: cell.value === CellErrorType.SpilledBlocked,
49181
+ dashed: isArrayFormulaBlocked,
49126
49182
  color: "#17A2B8",
49127
49183
  noFill: true,
49128
49184
  thinLine: true,
@@ -50529,9 +50585,7 @@ stores.inject(MyMetaStore, storeInstance);
50529
50585
  */
50530
50586
  class FiguresContainer extends owl.Component {
50531
50587
  static template = "o-spreadsheet-FiguresContainer";
50532
- static props = {
50533
- onFigureDeleted: Function,
50534
- };
50588
+ static props = {};
50535
50589
  static components = { FigureComponent };
50536
50590
  dnd = owl.useState({
50537
50591
  draggedFigure: undefined,
@@ -50741,7 +50795,6 @@ stores.inject(MyMetaStore, storeInstance);
50741
50795
  carouselFigureId: this.dnd.overlappingCarousel.id,
50742
50796
  chartFigureId: figureUI.id,
50743
50797
  });
50744
- this.props.onFigureDeleted();
50745
50798
  }
50746
50799
  this.dnd.draggedFigure = undefined;
50747
50800
  this.dnd.horizontalSnap = undefined;
@@ -50967,16 +51020,16 @@ stores.inject(MyMetaStore, storeInstance);
50967
51020
  `;
50968
51021
  class GridAddRowsFooter extends owl.Component {
50969
51022
  static template = "o-spreadsheet-GridAddRowsFooter";
50970
- static props = {
50971
- focusGrid: Function,
50972
- };
51023
+ static props = {};
50973
51024
  static components = { ValidationMessages };
51025
+ DOMFocusableElementStore;
50974
51026
  inputRef = owl.useRef("inputRef");
50975
51027
  state = owl.useState({
50976
51028
  inputValue: "100",
50977
51029
  errorFlag: false,
50978
51030
  });
50979
51031
  setup() {
51032
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
50980
51033
  owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
50981
51034
  }
50982
51035
  get addRowsPosition() {
@@ -50994,7 +51047,7 @@ stores.inject(MyMetaStore, storeInstance);
50994
51047
  }
50995
51048
  onKeydown(ev) {
50996
51049
  if (ev.key.toUpperCase() === "ESCAPE") {
50997
- this.props.focusGrid();
51050
+ this.focusDefaultElement();
50998
51051
  }
50999
51052
  else if (ev.key.toUpperCase() === "ENTER") {
51000
51053
  this.onConfirm();
@@ -51021,7 +51074,7 @@ stores.inject(MyMetaStore, storeInstance);
51021
51074
  quantity,
51022
51075
  dimension: "ROW",
51023
51076
  });
51024
- this.props.focusGrid();
51077
+ this.focusDefaultElement();
51025
51078
  // After adding new rows, scroll down to the new last row
51026
51079
  const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
51027
51080
  const { end } = this.env.model.getters.getRowDimensions(activeSheetId, rowNumber + quantity - 1);
@@ -51034,7 +51087,12 @@ stores.inject(MyMetaStore, storeInstance);
51034
51087
  if (this.inputRef.el !== document.activeElement || ev.target === this.inputRef.el) {
51035
51088
  return;
51036
51089
  }
51037
- this.props.focusGrid();
51090
+ this.focusDefaultElement();
51091
+ }
51092
+ focusDefaultElement() {
51093
+ if (document.activeElement === this.inputRef.el) {
51094
+ this.DOMFocusableElementStore.focus();
51095
+ }
51038
51096
  }
51039
51097
  }
51040
51098
 
@@ -51309,7 +51367,6 @@ stores.inject(MyMetaStore, storeInstance);
51309
51367
  onCellClicked: { type: Function, optional: true },
51310
51368
  onCellRightClicked: { type: Function, optional: true },
51311
51369
  onGridResized: { type: Function, optional: true },
51312
- onFigureDeleted: { type: Function, optional: true },
51313
51370
  onGridMoved: Function,
51314
51371
  gridOverlayDimensions: String,
51315
51372
  slots: { type: Object, optional: true },
@@ -51324,7 +51381,6 @@ stores.inject(MyMetaStore, storeInstance);
51324
51381
  onCellClicked: () => { },
51325
51382
  onCellRightClicked: () => { },
51326
51383
  onGridResized: () => { },
51327
- onFigureDeleted: () => { },
51328
51384
  };
51329
51385
  gridOverlay = owl.useRef("gridOverlay");
51330
51386
  cellPopovers;
@@ -56590,7 +56646,7 @@ stores.inject(MyMetaStore, storeInstance);
56590
56646
  }
56591
56647
 
56592
56648
  css /* scss */ `
56593
- .o-cf-preview {
56649
+ .o-spreadsheet .o-cf-preview {
56594
56650
  &.o-cf-cursor-ptr {
56595
56651
  cursor: pointer;
56596
56652
  }
@@ -56598,6 +56654,7 @@ stores.inject(MyMetaStore, storeInstance);
56598
56654
  border-bottom: 1px solid ${GRAY_300};
56599
56655
  height: 80px;
56600
56656
  padding: 10px;
56657
+ box-sizing: border-box;
56601
56658
  position: relative;
56602
56659
  cursor: pointer;
56603
56660
  &:hover,
@@ -56611,7 +56668,6 @@ stores.inject(MyMetaStore, storeInstance);
56611
56668
  .o-cf-preview-icon {
56612
56669
  border: 1px solid ${GRAY_300};
56613
56670
  background-color: #fff;
56614
- position: absolute;
56615
56671
  height: 50px;
56616
56672
  width: 50px;
56617
56673
  .o-icon {
@@ -56620,12 +56676,6 @@ stores.inject(MyMetaStore, storeInstance);
56620
56676
  }
56621
56677
  }
56622
56678
  .o-cf-preview-description {
56623
- left: 65px;
56624
- margin-bottom: auto;
56625
- margin-right: 8px;
56626
- margin-top: auto;
56627
- position: relative;
56628
- width: 142px;
56629
56679
  .o-cf-preview-description-rule {
56630
56680
  margin-bottom: 4px;
56631
56681
  max-height: 2.8em;
@@ -56635,16 +56685,11 @@ stores.inject(MyMetaStore, storeInstance);
56635
56685
  font-size: 12px;
56636
56686
  }
56637
56687
  }
56638
- .o-cf-delete {
56639
- left: 90%;
56640
- top: 39%;
56641
- position: absolute;
56642
- }
56643
56688
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
56644
56689
  display: none !important;
56645
56690
  }
56646
56691
  .o-cf-drag-handle {
56647
- left: -8px;
56692
+ left: 2px;
56648
56693
  cursor: move;
56649
56694
  .o-icon {
56650
56695
  width: 6px;
@@ -62449,10 +62494,10 @@ stores.inject(MyMetaStore, storeInstance);
62449
62494
  // existingBorderSideToClear[side] = true means we should clear the border on that
62450
62495
  // side of the existing adjacent zone before adding the new border.
62451
62496
  const existingBorderSideToClear = {
62452
- left: force || !!newBorder?.right,
62453
- right: force || !!newBorder?.left,
62454
- top: force || !!newBorder?.bottom,
62455
- bottom: force || !!newBorder?.top,
62497
+ left: !!newBorder?.right,
62498
+ right: !!newBorder?.left,
62499
+ top: !!newBorder?.bottom,
62500
+ bottom: !!newBorder?.top,
62456
62501
  };
62457
62502
  let editingZone = [zone];
62458
62503
  for (const existingBorder of this.borders[sheetId] ?? []) {
@@ -65445,6 +65490,7 @@ stores.inject(MyMetaStore, storeInstance);
65445
65490
  class RangeAdapter {
65446
65491
  getters;
65447
65492
  providers = [];
65493
+ isAdaptingRanges = false;
65448
65494
  constructor(getters) {
65449
65495
  this.getters = getters;
65450
65496
  }
@@ -65476,6 +65522,9 @@ stores.inject(MyMetaStore, storeInstance);
65476
65522
  }
65477
65523
  beforeHandle(command) { }
65478
65524
  handle(cmd) {
65525
+ if (this.isAdaptingRanges) {
65526
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
65527
+ }
65479
65528
  const rangeAdapter = getRangeAdapter(cmd);
65480
65529
  if (rangeAdapter?.applyChange) {
65481
65530
  this.executeOnAllRanges(rangeAdapter.applyChange, rangeAdapter.sheetId, rangeAdapter.sheetName);
@@ -65498,10 +65547,12 @@ stores.inject(MyMetaStore, storeInstance);
65498
65547
  };
65499
65548
  }
65500
65549
  executeOnAllRanges(adaptRange, sheetId, sheetName) {
65550
+ this.isAdaptingRanges = true;
65501
65551
  const func = this.verifyRangeRemoved(adaptRange);
65502
65552
  for (const provider of this.providers) {
65503
65553
  provider(func, sheetId, sheetName);
65504
65554
  }
65555
+ this.isAdaptingRanges = false;
65505
65556
  }
65506
65557
  /**
65507
65558
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -65818,7 +65869,7 @@ stores.inject(MyMetaStore, storeInstance);
65818
65869
  break;
65819
65870
  case "CREATE_SHEET":
65820
65871
  const sheet = this.createSheet(cmd.sheetId, cmd.name || this.getNextSheetName(), cmd.cols || 26, cmd.rows || 100, cmd.position);
65821
- this.history.update("sheetIdsMapName", sheet.name, sheet.id);
65872
+ this.history.update("sheetIdsMapName", toStandardizedSheetName(sheet.name), sheet.id);
65822
65873
  break;
65823
65874
  case "MOVE_SHEET":
65824
65875
  this.moveSheet(cmd.sheetId, cmd.delta);
@@ -65885,7 +65936,7 @@ stores.inject(MyMetaStore, storeInstance);
65885
65936
  // that depends on a sheet not already imported will not be able to be
65886
65937
  // compiled
65887
65938
  for (const sheet of data.sheets) {
65888
- this.sheetIdsMapName[sheet.name] = sheet.id;
65939
+ this.sheetIdsMapName[toStandardizedSheetName(sheet.name)] = sheet.id;
65889
65940
  }
65890
65941
  for (const sheetData of data.sheets) {
65891
65942
  const name = sheetData.name || "Sheet" + (Object.keys(this.sheets).length + 1);
@@ -65975,12 +66026,7 @@ stores.inject(MyMetaStore, storeInstance);
65975
66026
  }
65976
66027
  getSheetIdByName(name) {
65977
66028
  if (name) {
65978
- const unquotedName = getUnquotedSheetName(name);
65979
- for (const key in this.sheetIdsMapName) {
65980
- if (isSheetNameEqual(key, unquotedName)) {
65981
- return this.sheetIdsMapName[key];
65982
- }
65983
- }
66029
+ return this.sheetIdsMapName[toStandardizedSheetName(name)];
65984
66030
  }
65985
66031
  return undefined;
65986
66032
  }
@@ -66280,8 +66326,8 @@ stores.inject(MyMetaStore, storeInstance);
66280
66326
  const oldName = sheet.name;
66281
66327
  this.history.update("sheets", sheet.id, "name", name.trim());
66282
66328
  const sheetIdsMapName = Object.assign({}, this.sheetIdsMapName);
66283
- delete sheetIdsMapName[oldName];
66284
- sheetIdsMapName[name] = sheet.id;
66329
+ delete sheetIdsMapName[toStandardizedSheetName(oldName)];
66330
+ sheetIdsMapName[toStandardizedSheetName(name)] = sheet.id;
66285
66331
  this.history.update("sheetIdsMapName", sheetIdsMapName);
66286
66332
  }
66287
66333
  hideSheet(sheetId) {
@@ -66319,7 +66365,7 @@ stores.inject(MyMetaStore, storeInstance);
66319
66365
  });
66320
66366
  }
66321
66367
  const sheetIdsMapName = Object.assign({}, this.sheetIdsMapName);
66322
- sheetIdsMapName[newSheet.name] = newSheet.id;
66368
+ sheetIdsMapName[toStandardizedSheetName(newSheet.name)] = newSheet.id;
66323
66369
  this.history.update("sheetIdsMapName", sheetIdsMapName);
66324
66370
  }
66325
66371
  getDuplicateSheetName(sheetName) {
@@ -66336,7 +66382,7 @@ stores.inject(MyMetaStore, storeInstance);
66336
66382
  orderedSheetIds.splice(currentIndex, 1);
66337
66383
  this.history.update("orderedSheetIds", orderedSheetIds);
66338
66384
  const sheetIdsMapName = Object.assign({}, this.sheetIdsMapName);
66339
- delete sheetIdsMapName[name];
66385
+ delete sheetIdsMapName[toStandardizedSheetName(name)];
66340
66386
  this.history.update("sheetIdsMapName", sheetIdsMapName);
66341
66387
  }
66342
66388
  /**
@@ -67656,6 +67702,18 @@ stores.inject(MyMetaStore, storeInstance);
67656
67702
  }
67657
67703
  }
67658
67704
  adaptRanges(applyChange) {
67705
+ for (const pivotId in this.pivots) {
67706
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
67707
+ if (!definition) {
67708
+ continue;
67709
+ }
67710
+ const newDefinition = pivotRegistry
67711
+ .get(definition.type)
67712
+ ?.adaptRanges?.(this.getters, definition, applyChange);
67713
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
67714
+ this.history.update("pivots", pivotId, "definition", newDefinition);
67715
+ }
67716
+ }
67659
67717
  for (const sheetId in this.compiledMeasureFormulas) {
67660
67718
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
67661
67719
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -67800,17 +67858,10 @@ stores.inject(MyMetaStore, storeInstance);
67800
67858
  if (!pivot) {
67801
67859
  continue;
67802
67860
  }
67803
- const def = deepCopy(pivot.definition);
67804
- for (const measure of def.measures) {
67861
+ for (const measure of pivot.definition.measures) {
67805
67862
  if (measure.computedBy?.formula === formulaString) {
67806
- const measureIndex = def.measures.indexOf(measure);
67807
- if (measureIndex !== -1) {
67808
- def.measures[measureIndex].computedBy = {
67809
- formula: newFormulaString,
67810
- sheetId,
67811
- };
67812
- }
67813
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
67863
+ const measureIndex = pivot.definition.measures.indexOf(measure);
67864
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
67814
67865
  }
67815
67866
  }
67816
67867
  }
@@ -67937,20 +67988,6 @@ stores.inject(MyMetaStore, storeInstance);
67937
67988
  }
67938
67989
  }
67939
67990
 
67940
- function adaptPivotRange(range, applyChange) {
67941
- if (!range) {
67942
- return undefined;
67943
- }
67944
- const change = applyChange(range);
67945
- switch (change.changeType) {
67946
- case "NONE":
67947
- return range;
67948
- case "REMOVE":
67949
- return undefined;
67950
- default:
67951
- return change.range;
67952
- }
67953
- }
67954
67991
  class SpreadsheetPivotCorePlugin extends CorePlugin {
67955
67992
  allowDispatch(cmd) {
67956
67993
  switch (cmd.type) {
@@ -67961,27 +67998,6 @@ stores.inject(MyMetaStore, storeInstance);
67961
67998
  }
67962
67999
  return "Success" /* CommandResult.Success */;
67963
68000
  }
67964
- adaptRanges(applyChange) {
67965
- for (const pivotId of this.getters.getPivotIds()) {
67966
- const definition = this.getters.getPivotCoreDefinition(pivotId);
67967
- if (definition.type !== "SPREADSHEET") {
67968
- continue;
67969
- }
67970
- if (definition.dataSet) {
67971
- const { sheetId, zone } = definition.dataSet;
67972
- const range = this.getters.getRangeFromZone(sheetId, zone);
67973
- const adaptedRange = adaptPivotRange(range, applyChange);
67974
- if (adaptedRange === range) {
67975
- return;
67976
- }
67977
- const dataSet = adaptedRange && {
67978
- sheetId: adaptedRange.sheetId,
67979
- zone: adaptedRange.zone,
67980
- };
67981
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
67982
- }
67983
- }
67984
- }
67985
68001
  checkDataSetValidity(definition) {
67986
68002
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
67987
68003
  const { zone, sheetId } = definition.dataSet;
@@ -68980,13 +68996,6 @@ stores.inject(MyMetaStore, storeInstance);
68980
68996
  }
68981
68997
  return result;
68982
68998
  }
68983
- size() {
68984
- let size = 0;
68985
- for (const profile of this.profiles.values()) {
68986
- size += profile.length;
68987
- }
68988
- return size / 2;
68989
- }
68990
68999
  /**
68991
69000
  * iterator of all the zones in the ZoneSet
68992
69001
  */
@@ -69068,13 +69077,6 @@ stores.inject(MyMetaStore, storeInstance);
69068
69077
  clear() {
69069
69078
  this.setsBySheetId = {};
69070
69079
  }
69071
- size() {
69072
- let size = 0;
69073
- for (const sheetId in this.setsBySheetId) {
69074
- size += this.setsBySheetId[sheetId].size();
69075
- }
69076
- return size;
69077
- }
69078
69080
  isEmpty() {
69079
69081
  for (const sheetId in this.setsBySheetId) {
69080
69082
  if (!this.setsBySheetId[sheetId].isEmpty()) {
@@ -69578,6 +69580,9 @@ stores.inject(MyMetaStore, storeInstance);
69578
69580
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
69579
69581
  return arrayFormulas.find((position) => !this.blockedArrayFormulas.has(position));
69580
69582
  }
69583
+ isArrayFormulaSpillBlocked(position) {
69584
+ return this.blockedArrayFormulas.has(position);
69585
+ }
69581
69586
  updateDependencies(position) {
69582
69587
  // removing dependencies is slow because it requires
69583
69588
  // to traverse the entire r-tree.
@@ -69589,13 +69594,8 @@ stores.inject(MyMetaStore, storeInstance);
69589
69594
  addDependencies(position, dependencies) {
69590
69595
  this.formulaDependencies().addDependencies(position, dependencies);
69591
69596
  for (const range of dependencies) {
69592
- const sheetId = range.sheetId;
69593
- const { left, bottom, right, top } = range.zone;
69594
- for (let col = left; col <= right; col++) {
69595
- for (let row = top; row <= bottom; row++) {
69596
- this.computeAndSave({ sheetId, col, row });
69597
- }
69598
- }
69597
+ // ensure that all ranges are computed
69598
+ this.compilationParams.ensureRange(range, false);
69599
69599
  }
69600
69600
  }
69601
69601
  updateCompilationParameters() {
@@ -69823,6 +69823,10 @@ stores.inject(MyMetaStore, storeInstance);
69823
69823
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
69824
69824
  const nbColumns = formulaReturn.length;
69825
69825
  const nbRows = formulaReturn[0].length;
69826
+ if (nbRows === 0) {
69827
+ // empty matrix
69828
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
69829
+ }
69826
69830
  const resultZone = {
69827
69831
  top: formulaPosition.row,
69828
69832
  bottom: formulaPosition.row + nbRows - 1,
@@ -70093,6 +70097,7 @@ stores.inject(MyMetaStore, storeInstance);
70093
70097
  "getEvaluatedCellsPositions",
70094
70098
  "getSpreadZone",
70095
70099
  "getArrayFormulaSpreadingOn",
70100
+ "isArrayFormulaSpillBlocked",
70096
70101
  "isEmpty",
70097
70102
  ];
70098
70103
  shouldRebuildDependenciesGraph = true;
@@ -70212,6 +70217,9 @@ stores.inject(MyMetaStore, storeInstance);
70212
70217
  getArrayFormulaSpreadingOn(position) {
70213
70218
  return this.evaluator.getArrayFormulaSpreadingOn(position);
70214
70219
  }
70220
+ isArrayFormulaSpillBlocked(position) {
70221
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
70222
+ }
70215
70223
  /**
70216
70224
  * Check if a zone only contains empty cells
70217
70225
  */
@@ -84317,7 +84325,7 @@ stores.inject(MyMetaStore, storeInstance);
84317
84325
  document.activeElement?.contains(this.spreadsheetRef.el)) {
84318
84326
  this.focusGrid();
84319
84327
  }
84320
- }, () => [this.env.model.getters.getActiveSheetId()]);
84328
+ });
84321
84329
  owl.useExternalListener(window, "resize", () => this.render(true));
84322
84330
  // For some reason, the wheel event is not properly registered inside templates
84323
84331
  // in Chromium-based browsers based on chromium 125
@@ -89107,9 +89115,9 @@ stores.inject(MyMetaStore, storeInstance);
89107
89115
  exports.tokenize = tokenize;
89108
89116
 
89109
89117
 
89110
- __info__.version = "19.0.12";
89111
- __info__.date = "2025-12-02T05:34:17.495Z";
89112
- __info__.hash = "32203f1";
89118
+ __info__.version = "19.0.15";
89119
+ __info__.date = "2025-12-26T10:19:23.408Z";
89120
+ __info__.hash = "fe625c9";
89113
89121
 
89114
89122
 
89115
89123
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);