@odoo/o-spreadsheet 17.0.78 → 17.0.82

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 17.0.78
6
- * @date 2025-11-24T07:39:26.523Z
7
- * @hash 498c3fc
5
+ * @version 17.0.82
6
+ * @date 2025-12-26T10:17:37.110Z
7
+ * @hash df7c781
8
8
  */
9
9
 
10
10
  'use strict';
@@ -2879,17 +2879,41 @@ function toCriterionDateNumber(dateValue) {
2879
2879
  const today = DateTime.now();
2880
2880
  switch (dateValue) {
2881
2881
  case "today":
2882
- return jsDateToNumber(today);
2883
- case "yesterday":
2884
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
2885
- case "tomorrow":
2886
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
2882
+ return Math.floor(jsDateToNumber(today));
2883
+ case "yesterday": {
2884
+ today.setDate(today.getDate() - 1);
2885
+ return Math.floor(jsDateToNumber(today));
2886
+ }
2887
+ case "tomorrow": {
2888
+ today.setDate(today.getDate() + 1);
2889
+ return Math.floor(jsDateToNumber(today));
2890
+ }
2887
2891
  case "lastWeek":
2888
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
2889
- case "lastMonth":
2890
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
2892
+ today.setDate(today.getDate() - 6);
2893
+ return Math.floor(jsDateToNumber(today));
2894
+ case "lastMonth": {
2895
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
2896
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
2897
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
2898
+ today.setDate(1);
2899
+ }
2900
+ else {
2901
+ today.setDate(today.getDate() + 1);
2902
+ today.setMonth(today.getMonth() - 1);
2903
+ }
2904
+ return Math.floor(jsDateToNumber(today));
2905
+ }
2891
2906
  case "lastYear":
2892
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
2907
+ // Handle leap year case
2908
+ if (today.getMonth() === 1 && today.getDate() === 29) {
2909
+ today.setDate(28);
2910
+ today.setFullYear(today.getFullYear() - 1);
2911
+ }
2912
+ else {
2913
+ today.setDate(today.getDate() + 1);
2914
+ today.setFullYear(today.getFullYear() - 1);
2915
+ }
2916
+ return Math.floor(jsDateToNumber(today));
2893
2917
  }
2894
2918
  }
2895
2919
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -23479,17 +23503,10 @@ css /* scss */ `
23479
23503
  }
23480
23504
  .o-cf-preview-icon {
23481
23505
  border: 1px solid lightgrey;
23482
- position: absolute;
23483
23506
  height: 50px;
23484
23507
  width: 50px;
23485
23508
  }
23486
23509
  .o-cf-preview-description {
23487
- left: 65px;
23488
- margin-bottom: auto;
23489
- margin-right: 8px;
23490
- margin-top: auto;
23491
- position: relative;
23492
- width: 142px;
23493
23510
  .o-cf-preview-description-rule {
23494
23511
  margin-bottom: 4px;
23495
23512
  font-weight: 600;
@@ -23501,16 +23518,11 @@ css /* scss */ `
23501
23518
  font-size: 12px;
23502
23519
  }
23503
23520
  }
23504
- .o-cf-delete {
23505
- left: 90%;
23506
- top: 39%;
23507
- position: absolute;
23508
- }
23509
23521
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
23510
23522
  display: none !important;
23511
23523
  }
23512
23524
  .o-cf-drag-handle {
23513
- left: -8px;
23525
+ left: 2px;
23514
23526
  cursor: move;
23515
23527
  .o-icon {
23516
23528
  width: 6px;
@@ -24653,7 +24665,7 @@ dataValidationEvaluatorRegistry.add("dateIs", {
24653
24665
  return false;
24654
24666
  }
24655
24667
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
24656
- const today = jsDateToRoundNumber(DateTime.now());
24668
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
24657
24669
  return isDateBetween(dateValue, today, criterionValue);
24658
24670
  }
24659
24671
  return areDatesSameDay(dateValue, criterionValue);
@@ -28777,6 +28789,7 @@ class GridOverlay extends owl.Component {
28777
28789
  // not main button, probably a context menu
28778
28790
  return;
28779
28791
  }
28792
+ ev.preventDefault();
28780
28793
  const [col, row] = this.getCartesianCoordinates(ev);
28781
28794
  this.props.onCellClicked(col, row, {
28782
28795
  expandZone: ev.shiftKey,
@@ -29902,6 +29915,7 @@ class Grid extends owl.Component {
29902
29915
  owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
29903
29916
  owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
29904
29917
  owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
29918
+ owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
29905
29919
  owl.useExternalListener(document.body, "paste", this.paste);
29906
29920
  owl.onMounted(() => this.focusDefaultElement());
29907
29921
  this.props.exposeFocus(() => this.focusDefaultElement());
@@ -30468,6 +30482,12 @@ class Grid extends owl.Component {
30468
30482
  }
30469
30483
  }
30470
30484
  }
30485
+ onExternalClick(ev) {
30486
+ if (isChildEvent(this.gridEl, ev) || ev.target?.closest(".o-popover")) {
30487
+ return;
30488
+ }
30489
+ this.onClosePopover();
30490
+ }
30471
30491
  }
30472
30492
  Grid.props = {
30473
30493
  sidePanelIsOpen: Boolean,
@@ -42298,6 +42318,13 @@ class Evaluator {
42298
42318
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
42299
42319
  const nbColumns = formulaReturn.length;
42300
42320
  const nbRows = formulaReturn[0].length;
42321
+ if (nbRows === 0) {
42322
+ // empty matrix
42323
+ return createEvaluatedCell(null, {
42324
+ format: cellData.format,
42325
+ locale: this.getters.getLocale(),
42326
+ });
42327
+ }
42301
42328
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.updateSpreadRelation(formulaPosition));
42302
42329
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.checkCollision(formulaPosition));
42303
42330
  forEachSpreadPositionInMatrix(nbColumns, nbRows,
@@ -49588,7 +49615,9 @@ class EditionPlugin extends UIPlugin {
49588
49615
  case "CHANGE_COMPOSER_CURSOR_SELECTION":
49589
49616
  this.selectionStart = cmd.start;
49590
49617
  this.selectionEnd = cmd.end;
49591
- this.mode = "editing";
49618
+ if (this.isSelectingForComposer()) {
49619
+ this.mode = "editing";
49620
+ }
49592
49621
  break;
49593
49622
  case "STOP_COMPOSER_RANGE_SELECTION":
49594
49623
  if (this.isSelectingForComposer()) {
@@ -53049,12 +53078,13 @@ class SpreadsheetDashboard extends owl.Component {
53049
53078
  onMouseWheel;
53050
53079
  canvasPosition;
53051
53080
  hoveredCell;
53081
+ gridRef = owl.useRef("grid");
53052
53082
  setup() {
53053
- const gridRef = owl.useRef("grid");
53054
- this.canvasPosition = useAbsoluteBoundingRect(gridRef);
53083
+ this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
53055
53084
  this.hoveredCell = owl.useState({ col: undefined, row: undefined });
53056
53085
  owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
53057
53086
  useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimension());
53087
+ owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
53058
53088
  this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
53059
53089
  this.moveCanvas(deltaX, deltaY);
53060
53090
  this.hoveredCell.col = undefined;
@@ -53151,6 +53181,15 @@ class SpreadsheetDashboard extends owl.Component {
53151
53181
  getGridRect() {
53152
53182
  return { ...this.canvasPosition, ...this.env.model.getters.getSheetViewDimensionWithHeaders() };
53153
53183
  }
53184
+ onExternalClick(ev) {
53185
+ const el = this.gridRef.el;
53186
+ if ((el && isChildEvent(el, ev)) || ev.target?.closest(".o-popover")) {
53187
+ return;
53188
+ }
53189
+ if (this.env.model.getters.hasOpenedPopover()) {
53190
+ this.onClosePopover();
53191
+ }
53192
+ }
53154
53193
  }
53155
53194
  SpreadsheetDashboard.props = {};
53156
53195
 
@@ -58517,6 +58556,6 @@ exports.setTranslationMethod = setTranslationMethod;
58517
58556
  exports.tokenize = tokenize;
58518
58557
 
58519
58558
 
58520
- __info__.version = "17.0.78";
58521
- __info__.date = "2025-11-24T07:39:26.523Z";
58522
- __info__.hash = "498c3fc";
58559
+ __info__.version = "17.0.82";
58560
+ __info__.date = "2025-12-26T10:17:37.110Z";
58561
+ __info__.hash = "df7c781";
@@ -6695,6 +6695,7 @@ declare class SpreadsheetDashboard extends Component<Props$h, SpreadsheetChildEn
6695
6695
  onMouseWheel: (ev: WheelEvent) => void;
6696
6696
  canvasPosition: DOMCoordinates;
6697
6697
  hoveredCell: Partial<Position$1>;
6698
+ private gridRef;
6698
6699
  setup(): void;
6699
6700
  onCellHovered({ col, row }: {
6700
6701
  col: any;
@@ -6716,6 +6717,7 @@ declare class SpreadsheetDashboard extends Component<Props$h, SpreadsheetChildEn
6716
6717
  onGridResized({ height, width }: DOMDimension): void;
6717
6718
  private moveCanvas;
6718
6719
  private getGridRect;
6720
+ private onExternalClick;
6719
6721
  }
6720
6722
 
6721
6723
  interface Props$g {
@@ -7800,6 +7802,7 @@ declare class Grid extends Component<Props$1, SpreadsheetChildEnv> {
7800
7802
  private processHeaderGroupingEventOnHeaders;
7801
7803
  private processHeaderGroupingEventOnWholeSheet;
7802
7804
  private processHeaderGroupingEventOnGrid;
7805
+ private onExternalClick;
7803
7806
  }
7804
7807
 
7805
7808
  type Direction = "horizontal" | "vertical";
@@ -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 17.0.78
6
- * @date 2025-11-24T07:39:26.523Z
7
- * @hash 498c3fc
5
+ * @version 17.0.82
6
+ * @date 2025-12-26T10:17:37.110Z
7
+ * @hash df7c781
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -2877,17 +2877,41 @@ function toCriterionDateNumber(dateValue) {
2877
2877
  const today = DateTime.now();
2878
2878
  switch (dateValue) {
2879
2879
  case "today":
2880
- return jsDateToNumber(today);
2881
- case "yesterday":
2882
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
2883
- case "tomorrow":
2884
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
2880
+ return Math.floor(jsDateToNumber(today));
2881
+ case "yesterday": {
2882
+ today.setDate(today.getDate() - 1);
2883
+ return Math.floor(jsDateToNumber(today));
2884
+ }
2885
+ case "tomorrow": {
2886
+ today.setDate(today.getDate() + 1);
2887
+ return Math.floor(jsDateToNumber(today));
2888
+ }
2885
2889
  case "lastWeek":
2886
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
2887
- case "lastMonth":
2888
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
2890
+ today.setDate(today.getDate() - 6);
2891
+ return Math.floor(jsDateToNumber(today));
2892
+ case "lastMonth": {
2893
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
2894
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
2895
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
2896
+ today.setDate(1);
2897
+ }
2898
+ else {
2899
+ today.setDate(today.getDate() + 1);
2900
+ today.setMonth(today.getMonth() - 1);
2901
+ }
2902
+ return Math.floor(jsDateToNumber(today));
2903
+ }
2889
2904
  case "lastYear":
2890
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
2905
+ // Handle leap year case
2906
+ if (today.getMonth() === 1 && today.getDate() === 29) {
2907
+ today.setDate(28);
2908
+ today.setFullYear(today.getFullYear() - 1);
2909
+ }
2910
+ else {
2911
+ today.setDate(today.getDate() + 1);
2912
+ today.setFullYear(today.getFullYear() - 1);
2913
+ }
2914
+ return Math.floor(jsDateToNumber(today));
2891
2915
  }
2892
2916
  }
2893
2917
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -23477,17 +23501,10 @@ css /* scss */ `
23477
23501
  }
23478
23502
  .o-cf-preview-icon {
23479
23503
  border: 1px solid lightgrey;
23480
- position: absolute;
23481
23504
  height: 50px;
23482
23505
  width: 50px;
23483
23506
  }
23484
23507
  .o-cf-preview-description {
23485
- left: 65px;
23486
- margin-bottom: auto;
23487
- margin-right: 8px;
23488
- margin-top: auto;
23489
- position: relative;
23490
- width: 142px;
23491
23508
  .o-cf-preview-description-rule {
23492
23509
  margin-bottom: 4px;
23493
23510
  font-weight: 600;
@@ -23499,16 +23516,11 @@ css /* scss */ `
23499
23516
  font-size: 12px;
23500
23517
  }
23501
23518
  }
23502
- .o-cf-delete {
23503
- left: 90%;
23504
- top: 39%;
23505
- position: absolute;
23506
- }
23507
23519
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
23508
23520
  display: none !important;
23509
23521
  }
23510
23522
  .o-cf-drag-handle {
23511
- left: -8px;
23523
+ left: 2px;
23512
23524
  cursor: move;
23513
23525
  .o-icon {
23514
23526
  width: 6px;
@@ -24651,7 +24663,7 @@ dataValidationEvaluatorRegistry.add("dateIs", {
24651
24663
  return false;
24652
24664
  }
24653
24665
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
24654
- const today = jsDateToRoundNumber(DateTime.now());
24666
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
24655
24667
  return isDateBetween(dateValue, today, criterionValue);
24656
24668
  }
24657
24669
  return areDatesSameDay(dateValue, criterionValue);
@@ -28775,6 +28787,7 @@ class GridOverlay extends Component {
28775
28787
  // not main button, probably a context menu
28776
28788
  return;
28777
28789
  }
28790
+ ev.preventDefault();
28778
28791
  const [col, row] = this.getCartesianCoordinates(ev);
28779
28792
  this.props.onCellClicked(col, row, {
28780
28793
  expandZone: ev.shiftKey,
@@ -29900,6 +29913,7 @@ class Grid extends Component {
29900
29913
  useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
29901
29914
  useExternalListener(document.body, "cut", this.copy.bind(this, true));
29902
29915
  useExternalListener(document.body, "copy", this.copy.bind(this, false));
29916
+ useExternalListener(window, "click", this.onExternalClick, { capture: true });
29903
29917
  useExternalListener(document.body, "paste", this.paste);
29904
29918
  onMounted(() => this.focusDefaultElement());
29905
29919
  this.props.exposeFocus(() => this.focusDefaultElement());
@@ -30466,6 +30480,12 @@ class Grid extends Component {
30466
30480
  }
30467
30481
  }
30468
30482
  }
30483
+ onExternalClick(ev) {
30484
+ if (isChildEvent(this.gridEl, ev) || ev.target?.closest(".o-popover")) {
30485
+ return;
30486
+ }
30487
+ this.onClosePopover();
30488
+ }
30469
30489
  }
30470
30490
  Grid.props = {
30471
30491
  sidePanelIsOpen: Boolean,
@@ -42296,6 +42316,13 @@ class Evaluator {
42296
42316
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
42297
42317
  const nbColumns = formulaReturn.length;
42298
42318
  const nbRows = formulaReturn[0].length;
42319
+ if (nbRows === 0) {
42320
+ // empty matrix
42321
+ return createEvaluatedCell(null, {
42322
+ format: cellData.format,
42323
+ locale: this.getters.getLocale(),
42324
+ });
42325
+ }
42299
42326
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.updateSpreadRelation(formulaPosition));
42300
42327
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.checkCollision(formulaPosition));
42301
42328
  forEachSpreadPositionInMatrix(nbColumns, nbRows,
@@ -49586,7 +49613,9 @@ class EditionPlugin extends UIPlugin {
49586
49613
  case "CHANGE_COMPOSER_CURSOR_SELECTION":
49587
49614
  this.selectionStart = cmd.start;
49588
49615
  this.selectionEnd = cmd.end;
49589
- this.mode = "editing";
49616
+ if (this.isSelectingForComposer()) {
49617
+ this.mode = "editing";
49618
+ }
49590
49619
  break;
49591
49620
  case "STOP_COMPOSER_RANGE_SELECTION":
49592
49621
  if (this.isSelectingForComposer()) {
@@ -53047,12 +53076,13 @@ class SpreadsheetDashboard extends Component {
53047
53076
  onMouseWheel;
53048
53077
  canvasPosition;
53049
53078
  hoveredCell;
53079
+ gridRef = useRef("grid");
53050
53080
  setup() {
53051
- const gridRef = useRef("grid");
53052
- this.canvasPosition = useAbsoluteBoundingRect(gridRef);
53081
+ this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
53053
53082
  this.hoveredCell = useState({ col: undefined, row: undefined });
53054
53083
  useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
53055
53084
  useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimension());
53085
+ useExternalListener(window, "click", this.onExternalClick, { capture: true });
53056
53086
  this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
53057
53087
  this.moveCanvas(deltaX, deltaY);
53058
53088
  this.hoveredCell.col = undefined;
@@ -53149,6 +53179,15 @@ class SpreadsheetDashboard extends Component {
53149
53179
  getGridRect() {
53150
53180
  return { ...this.canvasPosition, ...this.env.model.getters.getSheetViewDimensionWithHeaders() };
53151
53181
  }
53182
+ onExternalClick(ev) {
53183
+ const el = this.gridRef.el;
53184
+ if ((el && isChildEvent(el, ev)) || ev.target?.closest(".o-popover")) {
53185
+ return;
53186
+ }
53187
+ if (this.env.model.getters.hasOpenedPopover()) {
53188
+ this.onClosePopover();
53189
+ }
53190
+ }
53152
53191
  }
53153
53192
  SpreadsheetDashboard.props = {};
53154
53193
 
@@ -58480,6 +58519,6 @@ const constants = {
58480
58519
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
58481
58520
 
58482
58521
 
58483
- __info__.version = "17.0.78";
58484
- __info__.date = "2025-11-24T07:39:26.523Z";
58485
- __info__.hash = "498c3fc";
58522
+ __info__.version = "17.0.82";
58523
+ __info__.date = "2025-12-26T10:17:37.110Z";
58524
+ __info__.hash = "df7c781";
@@ -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 17.0.78
6
- * @date 2025-11-24T07:39:26.523Z
7
- * @hash 498c3fc
5
+ * @version 17.0.82
6
+ * @date 2025-12-26T10:17:37.110Z
7
+ * @hash df7c781
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -2878,17 +2878,41 @@
2878
2878
  const today = DateTime.now();
2879
2879
  switch (dateValue) {
2880
2880
  case "today":
2881
- return jsDateToNumber(today);
2882
- case "yesterday":
2883
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
2884
- case "tomorrow":
2885
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
2881
+ return Math.floor(jsDateToNumber(today));
2882
+ case "yesterday": {
2883
+ today.setDate(today.getDate() - 1);
2884
+ return Math.floor(jsDateToNumber(today));
2885
+ }
2886
+ case "tomorrow": {
2887
+ today.setDate(today.getDate() + 1);
2888
+ return Math.floor(jsDateToNumber(today));
2889
+ }
2886
2890
  case "lastWeek":
2887
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
2888
- case "lastMonth":
2889
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
2891
+ today.setDate(today.getDate() - 6);
2892
+ return Math.floor(jsDateToNumber(today));
2893
+ case "lastMonth": {
2894
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
2895
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
2896
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
2897
+ today.setDate(1);
2898
+ }
2899
+ else {
2900
+ today.setDate(today.getDate() + 1);
2901
+ today.setMonth(today.getMonth() - 1);
2902
+ }
2903
+ return Math.floor(jsDateToNumber(today));
2904
+ }
2890
2905
  case "lastYear":
2891
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
2906
+ // Handle leap year case
2907
+ if (today.getMonth() === 1 && today.getDate() === 29) {
2908
+ today.setDate(28);
2909
+ today.setFullYear(today.getFullYear() - 1);
2910
+ }
2911
+ else {
2912
+ today.setDate(today.getDate() + 1);
2913
+ today.setFullYear(today.getFullYear() - 1);
2914
+ }
2915
+ return Math.floor(jsDateToNumber(today));
2892
2916
  }
2893
2917
  }
2894
2918
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -23478,17 +23502,10 @@
23478
23502
  }
23479
23503
  .o-cf-preview-icon {
23480
23504
  border: 1px solid lightgrey;
23481
- position: absolute;
23482
23505
  height: 50px;
23483
23506
  width: 50px;
23484
23507
  }
23485
23508
  .o-cf-preview-description {
23486
- left: 65px;
23487
- margin-bottom: auto;
23488
- margin-right: 8px;
23489
- margin-top: auto;
23490
- position: relative;
23491
- width: 142px;
23492
23509
  .o-cf-preview-description-rule {
23493
23510
  margin-bottom: 4px;
23494
23511
  font-weight: 600;
@@ -23500,16 +23517,11 @@
23500
23517
  font-size: 12px;
23501
23518
  }
23502
23519
  }
23503
- .o-cf-delete {
23504
- left: 90%;
23505
- top: 39%;
23506
- position: absolute;
23507
- }
23508
23520
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
23509
23521
  display: none !important;
23510
23522
  }
23511
23523
  .o-cf-drag-handle {
23512
- left: -8px;
23524
+ left: 2px;
23513
23525
  cursor: move;
23514
23526
  .o-icon {
23515
23527
  width: 6px;
@@ -24652,7 +24664,7 @@
24652
24664
  return false;
24653
24665
  }
24654
24666
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
24655
- const today = jsDateToRoundNumber(DateTime.now());
24667
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
24656
24668
  return isDateBetween(dateValue, today, criterionValue);
24657
24669
  }
24658
24670
  return areDatesSameDay(dateValue, criterionValue);
@@ -28776,6 +28788,7 @@
28776
28788
  // not main button, probably a context menu
28777
28789
  return;
28778
28790
  }
28791
+ ev.preventDefault();
28779
28792
  const [col, row] = this.getCartesianCoordinates(ev);
28780
28793
  this.props.onCellClicked(col, row, {
28781
28794
  expandZone: ev.shiftKey,
@@ -29901,6 +29914,7 @@
29901
29914
  owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
29902
29915
  owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
29903
29916
  owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
29917
+ owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
29904
29918
  owl.useExternalListener(document.body, "paste", this.paste);
29905
29919
  owl.onMounted(() => this.focusDefaultElement());
29906
29920
  this.props.exposeFocus(() => this.focusDefaultElement());
@@ -30467,6 +30481,12 @@
30467
30481
  }
30468
30482
  }
30469
30483
  }
30484
+ onExternalClick(ev) {
30485
+ if (isChildEvent(this.gridEl, ev) || ev.target?.closest(".o-popover")) {
30486
+ return;
30487
+ }
30488
+ this.onClosePopover();
30489
+ }
30470
30490
  }
30471
30491
  Grid.props = {
30472
30492
  sidePanelIsOpen: Boolean,
@@ -42297,6 +42317,13 @@
42297
42317
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
42298
42318
  const nbColumns = formulaReturn.length;
42299
42319
  const nbRows = formulaReturn[0].length;
42320
+ if (nbRows === 0) {
42321
+ // empty matrix
42322
+ return createEvaluatedCell(null, {
42323
+ format: cellData.format,
42324
+ locale: this.getters.getLocale(),
42325
+ });
42326
+ }
42300
42327
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.updateSpreadRelation(formulaPosition));
42301
42328
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.checkCollision(formulaPosition));
42302
42329
  forEachSpreadPositionInMatrix(nbColumns, nbRows,
@@ -49587,7 +49614,9 @@
49587
49614
  case "CHANGE_COMPOSER_CURSOR_SELECTION":
49588
49615
  this.selectionStart = cmd.start;
49589
49616
  this.selectionEnd = cmd.end;
49590
- this.mode = "editing";
49617
+ if (this.isSelectingForComposer()) {
49618
+ this.mode = "editing";
49619
+ }
49591
49620
  break;
49592
49621
  case "STOP_COMPOSER_RANGE_SELECTION":
49593
49622
  if (this.isSelectingForComposer()) {
@@ -53048,12 +53077,13 @@
53048
53077
  onMouseWheel;
53049
53078
  canvasPosition;
53050
53079
  hoveredCell;
53080
+ gridRef = owl.useRef("grid");
53051
53081
  setup() {
53052
- const gridRef = owl.useRef("grid");
53053
- this.canvasPosition = useAbsoluteBoundingRect(gridRef);
53082
+ this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
53054
53083
  this.hoveredCell = owl.useState({ col: undefined, row: undefined });
53055
53084
  owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
53056
53085
  useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimension());
53086
+ owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
53057
53087
  this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
53058
53088
  this.moveCanvas(deltaX, deltaY);
53059
53089
  this.hoveredCell.col = undefined;
@@ -53150,6 +53180,15 @@
53150
53180
  getGridRect() {
53151
53181
  return { ...this.canvasPosition, ...this.env.model.getters.getSheetViewDimensionWithHeaders() };
53152
53182
  }
53183
+ onExternalClick(ev) {
53184
+ const el = this.gridRef.el;
53185
+ if ((el && isChildEvent(el, ev)) || ev.target?.closest(".o-popover")) {
53186
+ return;
53187
+ }
53188
+ if (this.env.model.getters.hasOpenedPopover()) {
53189
+ this.onClosePopover();
53190
+ }
53191
+ }
53153
53192
  }
53154
53193
  SpreadsheetDashboard.props = {};
53155
53194
 
@@ -58516,9 +58555,9 @@
58516
58555
  exports.tokenize = tokenize;
58517
58556
 
58518
58557
 
58519
- __info__.version = "17.0.78";
58520
- __info__.date = "2025-11-24T07:39:26.523Z";
58521
- __info__.hash = "498c3fc";
58558
+ __info__.version = "17.0.82";
58559
+ __info__.date = "2025-12-26T10:17:37.110Z";
58560
+ __info__.hash = "df7c781";
58522
58561
 
58523
58562
 
58524
58563
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);