@odoo/o-spreadsheet 17.1.5 → 17.1.8

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.1.5
6
- * @date 2024-02-16T14:23:54.651Z
7
- * @hash 29d8ad6
5
+ * @version 17.1.8
6
+ * @date 2024-03-15T10:59:39.362Z
7
+ * @hash bd0c9e0
8
8
  */
9
9
 
10
10
  'use strict';
@@ -6100,8 +6100,10 @@ function getGroup(cell, cells, filter) {
6100
6100
  if (x === cell) {
6101
6101
  found = true;
6102
6102
  }
6103
- const cellValue = evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
6104
- if (filter(cellValue)) {
6103
+ const cellValue = x?.isFormula
6104
+ ? undefined
6105
+ : evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
6106
+ if (cellValue && filter(cellValue)) {
6105
6107
  group.push(cellValue);
6106
6108
  }
6107
6109
  else {
@@ -6325,11 +6327,14 @@ function cellTextStyleToCss(style) {
6325
6327
  * Transform CSS properties into a CSS string.
6326
6328
  */
6327
6329
  function cssPropertiesToCss(attributes) {
6328
- const str = Object.entries(attributes)
6329
- .filter(([attName, attValue]) => attValue !== undefined)
6330
- .map(([attName, attValue]) => `${attName}:${attValue};`)
6331
- .join(" ");
6332
- return str;
6330
+ let styleStr = "";
6331
+ for (const attName in attributes) {
6332
+ if (!attributes[attName]) {
6333
+ continue;
6334
+ }
6335
+ styleStr += `${attName}:${attributes[attName]}; `;
6336
+ }
6337
+ return styleStr;
6333
6338
  }
6334
6339
  function getElementMargins(el) {
6335
6340
  const style = window.getComputedStyle(el);
@@ -13053,6 +13058,18 @@ const TRUNC = {
13053
13058
  },
13054
13059
  isExported: true,
13055
13060
  };
13061
+ // -----------------------------------------------------------------------------
13062
+ // INT
13063
+ // -----------------------------------------------------------------------------
13064
+ const INT = {
13065
+ description: _t("Rounds a number down to the nearest integer that is less than or equal to it."),
13066
+ args: [arg("value (number)", _t("The number to round down to the nearest integer."))],
13067
+ returns: ["NUMBER"],
13068
+ compute: function (value) {
13069
+ return Math.floor(toNumber(value, this.locale));
13070
+ },
13071
+ isExported: true,
13072
+ };
13056
13073
 
13057
13074
  var math = /*#__PURE__*/Object.freeze({
13058
13075
  __proto__: null,
@@ -13086,6 +13103,7 @@ var math = /*#__PURE__*/Object.freeze({
13086
13103
  FLOOR: FLOOR,
13087
13104
  FLOOR_MATH: FLOOR_MATH,
13088
13105
  FLOOR_PRECISE: FLOOR_PRECISE,
13106
+ INT: INT,
13089
13107
  ISEVEN: ISEVEN,
13090
13108
  ISODD: ISODD,
13091
13109
  ISO_CEILING: ISO_CEILING,
@@ -18612,10 +18630,11 @@ const DEFAULT_IS_SORTED = true;
18612
18630
  const DEFAULT_MATCH_MODE = 0;
18613
18631
  const DEFAULT_SEARCH_MODE = 1;
18614
18632
  const DEFAULT_ABSOLUTE_RELATIVE_MODE = 1;
18615
- function assertAvailable(variable, searchKey) {
18616
- if (variable === undefined) {
18617
- throw new NotAvailableError(_t("Did not find value '%s' in [[FUNCTION_NAME]] evaluation.", toString(searchKey)));
18618
- }
18633
+ function valueNotAvailable(searchKey) {
18634
+ return {
18635
+ value: CellErrorType.NotAvailable,
18636
+ message: _t("Did not find value '%s' in [[FUNCTION_NAME]] evaluation.", toString(searchKey)),
18637
+ };
18619
18638
  }
18620
18639
  // -----------------------------------------------------------------------------
18621
18640
  // ADDRESS
@@ -18712,7 +18731,9 @@ const HLOOKUP = {
18712
18731
  ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
18713
18732
  : linearSearch(range, searchKey, "strict", range.length, getValueFromRange);
18714
18733
  const col = range[colIndex];
18715
- assertAvailable(col, searchKey?.value);
18734
+ if (col === undefined) {
18735
+ return valueNotAvailable(searchKey);
18736
+ }
18716
18737
  return col[_index - 1];
18717
18738
  },
18718
18739
  isExported: true,
@@ -18769,11 +18790,11 @@ const LOOKUP = {
18769
18790
  : (range, index) => range[index][0].value;
18770
18791
  const rangeLength = verticalSearch ? nbRow : nbCol;
18771
18792
  const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
18772
- if (index === -1)
18773
- assertAvailable(undefined, searchKey?.value);
18774
- verticalSearch
18775
- ? assertAvailable(searchArray[0][index], searchKey?.value)
18776
- : assertAvailable(searchArray[index][nbRow - 1], searchKey?.value);
18793
+ if (index === -1 ||
18794
+ (verticalSearch && searchArray[0][index] === undefined) ||
18795
+ (!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
18796
+ return valueNotAvailable(searchKey);
18797
+ }
18777
18798
  if (resultRange === undefined) {
18778
18799
  return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
18779
18800
  }
@@ -18823,7 +18844,10 @@ const MATCH = {
18823
18844
  index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18824
18845
  break;
18825
18846
  }
18826
- assertAvailable(nbCol === 1 ? range[0][index] : range[index], searchKey);
18847
+ if ((nbCol === 1 && range[0][index] === undefined) ||
18848
+ (nbCol !== 1 && range[index] === undefined)) {
18849
+ return valueNotAvailable(searchKey);
18850
+ }
18827
18851
  return index + 1;
18828
18852
  },
18829
18853
  isExported: true,
@@ -18882,7 +18906,9 @@ const VLOOKUP = {
18882
18906
  ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
18883
18907
  : linearSearch(range, searchKey, "strict", range[0].length, getValueFromRange);
18884
18908
  const value = range[_index - 1][rowIndex];
18885
- assertAvailable(value, searchKey);
18909
+ if (value === undefined) {
18910
+ return valueNotAvailable(searchKey);
18911
+ }
18886
18912
  return value;
18887
18913
  },
18888
18914
  isExported: true,
@@ -18932,7 +18958,9 @@ const XLOOKUP = {
18932
18958
  ? returnRange.map((col) => [col[index]])
18933
18959
  : [returnRange[index]];
18934
18960
  }
18935
- assertAvailable(defaultValue, searchKey);
18961
+ if (defaultValue === undefined) {
18962
+ return valueNotAvailable(searchKey);
18963
+ }
18936
18964
  return [[defaultValue]];
18937
18965
  },
18938
18966
  isExported: true,
@@ -19704,8 +19732,7 @@ class FunctionRegistry extends Registry {
19704
19732
  function addErrorHandling(compute, functionName) {
19705
19733
  return function (...args) {
19706
19734
  try {
19707
- const computeFormula = compute.bind(this);
19708
- return computeFormula(...args);
19735
+ return compute.apply(this, args);
19709
19736
  }
19710
19737
  catch (e) {
19711
19738
  return handleError(e, functionName);
@@ -19739,8 +19766,7 @@ function hasStringMessage(obj) {
19739
19766
  }
19740
19767
  function addResultHandling(compute) {
19741
19768
  return function (...args) {
19742
- const computeResult = compute.bind(this);
19743
- const result = computeResult(...args);
19769
+ const result = compute.apply(this, args);
19744
19770
  if (!isMatrix(result)) {
19745
19771
  if (typeof result === "object" && result !== null && "value" in result) {
19746
19772
  return result;
@@ -21707,7 +21733,7 @@ class SelectionInput extends owl.Component {
21707
21733
  ? existingSelectionRanges
21708
21734
  : this.props.ranges().map((xc, id) => ({
21709
21735
  xc,
21710
- id,
21736
+ id: id + 1,
21711
21737
  isFocused: false,
21712
21738
  }));
21713
21739
  return ranges.map((range) => ({
@@ -27747,7 +27773,11 @@ class GridComposer extends owl.Component {
27747
27773
  }
27748
27774
  }
27749
27775
  updateCellReferenceVisibility() {
27750
- if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
27776
+ if (this.env.model.getters.getEditionMode() === "inactive") {
27777
+ this.isCellReferenceVisible = false;
27778
+ return;
27779
+ }
27780
+ if (this.isCellReferenceVisible) {
27751
27781
  return;
27752
27782
  }
27753
27783
  const sheetId = this.env.model.getters.getActiveSheetId();
@@ -27776,19 +27806,21 @@ class GridCellIcon extends owl.Component {
27776
27806
  slots: Object,
27777
27807
  };
27778
27808
  get iconStyle() {
27779
- const x = this.getIconHorizontalPosition();
27780
- const y = this.getIconVerticalPosition();
27809
+ const cellPosition = this.props.cellPosition;
27810
+ const merge = this.env.model.getters.getMerge(cellPosition);
27811
+ const zone = merge || positionToZone(cellPosition);
27812
+ const rect = this.env.model.getters.getVisibleRectWithoutHeaders(zone);
27813
+ const x = this.getIconHorizontalPosition(rect, cellPosition);
27814
+ const y = this.getIconVerticalPosition(rect, cellPosition);
27781
27815
  return cssPropertiesToCss({
27782
27816
  top: `${y + (this.props.offset?.y || 0)}px`,
27783
27817
  left: `${x + (this.props.offset?.x || 0)}px`,
27784
27818
  });
27785
27819
  }
27786
- getIconVerticalPosition() {
27787
- const { sheetId, row } = this.props.cellPosition;
27788
- const merge = this.env.model.getters.getMerge(this.props.cellPosition);
27789
- const start = this.env.model.getters.getRowDimensionsInViewport(sheetId, row).start;
27790
- const end = this.env.model.getters.getRowDimensionsInViewport(sheetId, merge ? merge.bottom : row).end;
27791
- const cell = this.env.model.getters.getCell(this.props.cellPosition);
27820
+ getIconVerticalPosition(rect, cellPosition) {
27821
+ const start = rect.y;
27822
+ const end = rect.y + rect.height;
27823
+ const cell = this.env.model.getters.getCell(cellPosition);
27792
27824
  const align = this.props.verticalAlign || cell?.style?.verticalAlign || DEFAULT_VERTICAL_ALIGN;
27793
27825
  switch (align) {
27794
27826
  case "bottom":
@@ -27800,13 +27832,11 @@ class GridCellIcon extends owl.Component {
27800
27832
  return end - GRID_ICON_EDGE_LENGTH - centeringOffset;
27801
27833
  }
27802
27834
  }
27803
- getIconHorizontalPosition() {
27804
- const { sheetId, col } = this.props.cellPosition;
27805
- const merge = this.env.model.getters.getMerge(this.props.cellPosition);
27806
- const start = this.env.model.getters.getColDimensionsInViewport(sheetId, col).start;
27807
- const end = this.env.model.getters.getColDimensionsInViewport(sheetId, merge ? merge.right : col).end;
27808
- const cell = this.env.model.getters.getCell(this.props.cellPosition);
27809
- const evaluatedCell = this.env.model.getters.getEvaluatedCell(this.props.cellPosition);
27835
+ getIconHorizontalPosition(rect, cellPosition) {
27836
+ const start = rect.x;
27837
+ const end = rect.x + rect.width;
27838
+ const cell = this.env.model.getters.getCell(cellPosition);
27839
+ const evaluatedCell = this.env.model.getters.getEvaluatedCell(cellPosition);
27810
27840
  const align = this.props.horizontalAlign || cell?.style?.align || evaluatedCell.defaultAlign;
27811
27841
  switch (align) {
27812
27842
  case "right":
@@ -27890,6 +27920,8 @@ css /* scss */ `
27890
27920
  height: ${CHECKBOX_WIDTH}px;
27891
27921
  accent-color: #808080;
27892
27922
  margin: ${MARGIN}px;
27923
+ /** required to prevent the checkbox position to be sensible to the font-size (affects Firefox) */
27924
+ position: absolute;
27893
27925
  }
27894
27926
  `;
27895
27927
  class DataValidationCheckbox extends owl.Component {
@@ -27908,7 +27940,7 @@ class DataValidationCheckbox extends owl.Component {
27908
27940
  }
27909
27941
  get isDisabled() {
27910
27942
  const cell = this.env.model.getters.getCell(this.props.cellPosition);
27911
- return !!cell?.isFormula;
27943
+ return this.env.model.getters.isReadonly() || !!cell?.isFormula;
27912
27944
  }
27913
27945
  }
27914
27946
 
@@ -27948,12 +27980,17 @@ class DataValidationOverlay extends owl.Component {
27948
27980
  static props = {};
27949
27981
  static components = { GridCellIcon, DataValidationCheckbox, DataValidationListIcon };
27950
27982
  get checkBoxCellPositions() {
27951
- return this.env.model.getters.getDataValidationCheckBoxCellPositions();
27983
+ return this.env.model.getters
27984
+ .getVisibleCellPositions()
27985
+ .filter(this.env.model.getters.isCellValidCheckbox);
27952
27986
  }
27953
27987
  get listIconsCellPositions() {
27954
- return this.env.model.getters.isReadonly()
27955
- ? []
27956
- : this.env.model.getters.getDataValidationListCellsPositions();
27988
+ if (this.env.model.getters.isReadonly()) {
27989
+ return [];
27990
+ }
27991
+ return this.env.model.getters
27992
+ .getVisibleCellPositions()
27993
+ .filter(this.env.model.getters.cellHasListDataValidationIcon);
27957
27994
  }
27958
27995
  }
27959
27996
 
@@ -28001,7 +28038,7 @@ function dragFigureForMove({ x: mouseX, y: mouseY }, { x: mouseInitialX, y: mous
28001
28038
  function clamp(value, min, max) {
28002
28039
  return Math.min(Math.max(value, min), max);
28003
28040
  }
28004
- function dragFigureForResize(initialFigure, dirX, dirY, { x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, keepRatio, minFigSize) {
28041
+ function dragFigureForResize(initialFigure, dirX, dirY, { x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, keepRatio, minFigSize, { scrollX, scrollY }) {
28005
28042
  let { x, y, width, height } = initialFigure;
28006
28043
  if (keepRatio && dirX != 0 && dirY != 0) {
28007
28044
  const deltaX = Math.min(dirX * (mouseInitialX - mouseX), initialFigure.width - minFigSize);
@@ -28028,14 +28065,14 @@ function dragFigureForResize(initialFigure, dirX, dirY, { x: mouseX, y: mouseY }
28028
28065
  y = initialFigure.y - deltaY;
28029
28066
  }
28030
28067
  }
28031
- // Restrict resizing if x or y reaches header boundaries
28032
- if (x < 0) {
28033
- width += x;
28034
- x = 0;
28068
+ // Adjusts figure dimensions to ensure it remains within header boundaries and viewport during resizing.
28069
+ if (x + scrollX <= 0) {
28070
+ width = width + x + scrollX;
28071
+ x = -scrollX;
28035
28072
  }
28036
- if (y < 0) {
28037
- height += y;
28038
- y = 0;
28073
+ if (y + scrollY <= 0) {
28074
+ height = height + y + scrollY;
28075
+ y = -scrollY;
28039
28076
  }
28040
28077
  return { ...initialFigure, x, y, width, height };
28041
28078
  }
@@ -28455,7 +28492,7 @@ class FiguresContainer extends owl.Component {
28455
28492
  const minFigSize = figureRegistry.get(figure.tag).minFigSize || MIN_FIG_SIZE;
28456
28493
  const onMouseMove = (ev) => {
28457
28494
  const currentMousePosition = { x: ev.clientX, y: ev.clientY };
28458
- const draggedFigure = dragFigureForResize(initialFig, dirX, dirY, currentMousePosition, initialMousePosition, keepRatio, minFigSize);
28495
+ const draggedFigure = dragFigureForResize(initialFig, dirX, dirY, currentMousePosition, initialMousePosition, keepRatio, minFigSize, this.env.model.getters.getActiveSheetScrollInfo());
28459
28496
  const otherFigures = this.getOtherFigures(figure.id);
28460
28497
  const snapResult = snapForResize(this.env.model.getters, dirX, dirY, draggedFigure, otherFigures);
28461
28498
  this.dnd.draggedFigure = snapResult.snappedFigure;
@@ -34315,29 +34352,12 @@ const MIGRATIONS = [
34315
34352
  from: 12,
34316
34353
  to: 12.5,
34317
34354
  applyMigration(data) {
34318
- for (let sheet of data.sheets || []) {
34319
- let knownDataFilterZones = [];
34320
- for (let filterTable of sheet.filterTables || []) {
34321
- const zone = toZone(filterTable.range);
34322
- // See commit message for the details
34323
- const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
34324
- if (intersectZoneIndex !== -1) {
34325
- knownDataFilterZones[intersectZoneIndex] = zone;
34326
- }
34327
- else {
34328
- knownDataFilterZones.push(zone);
34329
- }
34330
- }
34331
- sheet.filterTables = knownDataFilterZones.map((zone) => ({
34332
- range: zoneToXc(zone),
34333
- }));
34334
- }
34335
- return data;
34355
+ return fixOverlappingFilters(data);
34336
34356
  },
34337
34357
  },
34338
34358
  {
34339
34359
  description: "Change Border description structure",
34340
- from: 12,
34360
+ from: 12.5,
34341
34361
  to: 13,
34342
34362
  applyMigration(data) {
34343
34363
  for (const borderId in data.borders) {
@@ -34368,6 +34388,14 @@ const MIGRATIONS = [
34368
34388
  return data;
34369
34389
  },
34370
34390
  },
34391
+ {
34392
+ description: "Fix datafilter duplication (post saas-16.4)",
34393
+ from: 14,
34394
+ to: 14.5,
34395
+ applyMigration(data) {
34396
+ return fixOverlappingFilters(data);
34397
+ },
34398
+ },
34371
34399
  ];
34372
34400
  /**
34373
34401
  * This function is used to repair faulty data independently of the migration.
@@ -34525,6 +34553,26 @@ function fixChartDefinitions(data, initialMessages) {
34525
34553
  }
34526
34554
  return messages;
34527
34555
  }
34556
+ function fixOverlappingFilters(data) {
34557
+ for (let sheet of data.sheets || []) {
34558
+ let knownDataFilterZones = [];
34559
+ for (let filterTable of sheet.filterTables || []) {
34560
+ const zone = toZone(filterTable.range);
34561
+ // See commit message of https://github.com/odoo/o-spreadsheet/pull/3632 of more details
34562
+ const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
34563
+ if (intersectZoneIndex !== -1) {
34564
+ knownDataFilterZones[intersectZoneIndex] = zone;
34565
+ }
34566
+ else {
34567
+ knownDataFilterZones.push(zone);
34568
+ }
34569
+ }
34570
+ sheet.filterTables = knownDataFilterZones.map((zone) => ({
34571
+ range: zoneToXc(zone),
34572
+ }));
34573
+ }
34574
+ return data;
34575
+ }
34528
34576
  // -----------------------------------------------------------------------------
34529
34577
  // Helpers
34530
34578
  // -----------------------------------------------------------------------------
@@ -37260,6 +37308,15 @@ class FigurePlugin extends CorePlugin {
37260
37308
  return "Success" /* CommandResult.Success */;
37261
37309
  }
37262
37310
  }
37311
+ beforeHandle(cmd) {
37312
+ switch (cmd.type) {
37313
+ case "DELETE_SHEET":
37314
+ this.getters.getFigures(cmd.sheetId).forEach((figure) => {
37315
+ this.dispatch("DELETE_FIGURE", { id: figure.id, sheetId: cmd.sheetId });
37316
+ });
37317
+ break;
37318
+ }
37319
+ }
37263
37320
  handle(cmd) {
37264
37321
  switch (cmd.type) {
37265
37322
  case "CREATE_SHEET":
@@ -39046,7 +39103,6 @@ class SheetPlugin extends CorePlugin {
39046
39103
  "getNumberHeaders",
39047
39104
  "getGridLinesVisibility",
39048
39105
  "getNextSheetName",
39049
- "isEmpty",
39050
39106
  "getSheetSize",
39051
39107
  "getSheetZone",
39052
39108
  "getPaneDivisions",
@@ -39421,14 +39477,6 @@ class SheetPlugin extends CorePlugin {
39421
39477
  // ---------------------------------------------------------------------------
39422
39478
  // Row/Col manipulation
39423
39479
  // ---------------------------------------------------------------------------
39424
- /**
39425
- * Check if a zone only contains empty cells
39426
- */
39427
- isEmpty(sheetId, zone) {
39428
- return positions(zone)
39429
- .map(({ col, row }) => this.getCell({ sheetId, col, row }))
39430
- .every((cell) => !cell || cell.content === "");
39431
- }
39432
39480
  getCommandZones(cmd) {
39433
39481
  const zones = [];
39434
39482
  if ("zone" in cmd) {
@@ -41543,7 +41591,7 @@ class Evaluator {
41543
41591
  : evaluateLiteral(cell.content, localeFormat);
41544
41592
  }
41545
41593
  catch (e) {
41546
- return createEvaluatedCell(e.value, localeFormat, e.message);
41594
+ return createEvaluatedCell(e?.value || CellErrorType.GenericError, localeFormat, e?.message || implementationErrorMessage);
41547
41595
  }
41548
41596
  finally {
41549
41597
  this.cellsBeingComputed.delete(cellId);
@@ -41877,6 +41925,7 @@ class EvaluationPlugin extends UIPlugin {
41877
41925
  "getEvaluatedCellsInZone",
41878
41926
  "getSpreadPositionsOf",
41879
41927
  "getArrayFormulaSpreadingOn",
41928
+ "isEmpty",
41880
41929
  ];
41881
41930
  shouldRebuildDependenciesGraph = true;
41882
41931
  evaluator;
@@ -41982,6 +42031,14 @@ class EvaluationPlugin extends UIPlugin {
41982
42031
  getArrayFormulaSpreadingOn(position) {
41983
42032
  return this.evaluator.getArrayFormulaSpreadingOn(position);
41984
42033
  }
42034
+ /**
42035
+ * Check if a zone only contains empty cells
42036
+ */
42037
+ isEmpty(sheetId, zone) {
42038
+ return positions(zone)
42039
+ .map(({ col, row }) => this.getEvaluatedCell({ sheetId, col, row }))
42040
+ .every((cell) => cell.type === CellValueType.empty);
42041
+ }
41985
42042
  // ---------------------------------------------------------------------------
41986
42043
  // Export
41987
42044
  // ---------------------------------------------------------------------------
@@ -42629,8 +42686,6 @@ const VALID_RESULT = { isValid: true };
42629
42686
  class EvaluationDataValidationPlugin extends UIPlugin {
42630
42687
  static getters = [
42631
42688
  "getDataValidationInvalidCriterionValueMessage",
42632
- "getDataValidationCheckBoxCellPositions",
42633
- "getDataValidationListCellsPositions",
42634
42689
  "getInvalidDataValidationMessage",
42635
42690
  "getValidationResultForCellValue",
42636
42691
  "isCellValidCheckbox",
@@ -42694,19 +42749,6 @@ class EvaluationDataValidationPlugin extends UIPlugin {
42694
42749
  const error = this.getRuleErrorForCellValue(cellValue, cellPosition, rule);
42695
42750
  return error ? { error, rule, isValid: false } : VALID_RESULT;
42696
42751
  }
42697
- getDataValidationCheckBoxCellPositions() {
42698
- const rules = this.getters
42699
- .getDataValidationRules(this.getters.getActiveSheetId())
42700
- .filter((rule) => rule.criterion.type === "isBoolean");
42701
- return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat()).filter((position) => this.isCellValidCheckbox(position));
42702
- }
42703
- getDataValidationListCellsPositions() {
42704
- const rules = this.getters
42705
- .getDataValidationRules(this.getters.getActiveSheetId())
42706
- .filter((rule) => (rule.criterion.type === "isValueInList" || rule.criterion.type === "isValueInRange") &&
42707
- rule.criterion.displayStyle === "arrow");
42708
- return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat());
42709
- }
42710
42752
  getValidationResultForCell(cellPosition) {
42711
42753
  const { col, row, sheetId } = cellPosition;
42712
42754
  if (!this.validationResults[sheetId]) {
@@ -45675,6 +45717,8 @@ class FindAndReplacePlugin extends UIPlugin {
45675
45717
  sheetIdFrom: this.getters.getActiveSheetId(),
45676
45718
  sheetIdTo: selectedMatch.sheetId,
45677
45719
  });
45720
+ // We do not want to reset the selection at finalize in this case
45721
+ this.isSearchDirty = false;
45678
45722
  }
45679
45723
  // we want grid selection to capture the selection stream
45680
45724
  this.selection.getBackToDefault();
@@ -46976,19 +47020,17 @@ class SelectionInputsManagerPlugin extends UIPlugin {
46976
47020
  break;
46977
47021
  case "FOCUS_RANGE":
46978
47022
  case "CHANGE_RANGE":
46979
- if (cmd.id !== this.focusedInputId) {
46980
- const input = this.inputs[cmd.id];
46981
- const range = input.ranges.find((range) => range.id === cmd.rangeId);
46982
- if (this.isRangeValid(range?.xc || "A1")) {
46983
- const sheetId = this.getters.getActiveSheetId();
46984
- const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
46985
- this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, {
46986
- handleEvent: input.handleEvent.bind(input),
46987
- release: () => (this.focusedInputId = null),
46988
- });
46989
- }
46990
- this.focusedInputId = cmd.id;
47023
+ const input = this.inputs[cmd.id];
47024
+ const range = input.ranges.find((range) => range.id === cmd.rangeId);
47025
+ if (range) {
47026
+ const sheetId = this.getters.getActiveSheetId();
47027
+ const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
47028
+ this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, {
47029
+ handleEvent: input.handleEvent.bind(input),
47030
+ release: () => (this.focusedInputId = null),
47031
+ });
46991
47032
  }
47033
+ this.focusedInputId = cmd.id;
46992
47034
  break;
46993
47035
  }
46994
47036
  this.currentInput?.handle(cmd);
@@ -50407,6 +50449,8 @@ class SheetViewPlugin extends UIPlugin {
50407
50449
  "getEdgeScrollRow",
50408
50450
  "getVisibleFigures",
50409
50451
  "getVisibleRect",
50452
+ "getVisibleRectWithoutHeaders",
50453
+ "getVisibleCellPositions",
50410
50454
  "getColRowOffsetInViewport",
50411
50455
  "getMainViewportCoordinates",
50412
50456
  "getActiveSheetScrollInfo",
@@ -50650,6 +50694,26 @@ class SheetViewPlugin extends UIPlugin {
50650
50694
  const viewports = this.getSubViewports(sheetId);
50651
50695
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
50652
50696
  }
50697
+ /**
50698
+ * Get the positions of all the cells that are visible in the viewport, taking merges into account.
50699
+ */
50700
+ getVisibleCellPositions() {
50701
+ const visibleCols = this.getSheetViewVisibleCols();
50702
+ const visibleRows = this.getSheetViewVisibleRows();
50703
+ const sheetId = this.getters.getActiveSheetId();
50704
+ const positions = [];
50705
+ for (const col of visibleCols) {
50706
+ for (const row of visibleRows) {
50707
+ const position = { sheetId, col, row };
50708
+ const mainPosition = this.getters.getMainCellPosition(position);
50709
+ if (mainPosition.row !== row || mainPosition.col !== col) {
50710
+ continue;
50711
+ }
50712
+ positions.push(position);
50713
+ }
50714
+ }
50715
+ return positions;
50716
+ }
50653
50717
  /**
50654
50718
  * Return the main viewport maximum size relative to the client size.
50655
50719
  */
@@ -50769,6 +50833,13 @@ class SheetViewPlugin extends UIPlugin {
50769
50833
  * Computes the coordinates and size to draw the zone on the canvas
50770
50834
  */
50771
50835
  getVisibleRect(zone) {
50836
+ const rect = this.getVisibleRectWithoutHeaders(zone);
50837
+ return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
50838
+ }
50839
+ /**
50840
+ * Computes the coordinates and size to draw the zone without taking the grid offset into account
50841
+ */
50842
+ getVisibleRectWithoutHeaders(zone) {
50772
50843
  const sheetId = this.getters.getActiveSheetId();
50773
50844
  const viewportRects = this.getSubViewports(sheetId)
50774
50845
  .map((viewport) => viewport.getRect(zone))
@@ -50780,12 +50851,7 @@ class SheetViewPlugin extends UIPlugin {
50780
50851
  const y = Math.min(...viewportRects.map((rect) => rect.y));
50781
50852
  const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
50782
50853
  const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
50783
- return {
50784
- x: x + this.gridOffsetX,
50785
- y: y + this.gridOffsetY,
50786
- width,
50787
- height,
50788
- };
50854
+ return { x, y, width, height };
50789
50855
  }
50790
50856
  /**
50791
50857
  * Returns the position of the MainViewport relatively to the start of the grid (without headers)
@@ -51009,13 +51075,8 @@ class HeaderPositionsUIPlugin extends UIPlugin {
51009
51075
  }
51010
51076
  break;
51011
51077
  case "UPDATE_CELL":
51012
- if ("content" in cmd || "format" in cmd) {
51013
- this.headerPositions = {};
51014
- this.isDirty = true;
51015
- }
51016
- else {
51017
- this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
51018
- }
51078
+ this.headerPositions = {};
51079
+ this.isDirty = true;
51019
51080
  break;
51020
51081
  case "UPDATE_FILTER":
51021
51082
  case "REMOVE_FILTER_TABLE":
@@ -51494,6 +51555,9 @@ class BottomBarSheet extends owl.Component {
51494
51555
  this.scrollToSheet();
51495
51556
  }
51496
51557
  onDblClick() {
51558
+ if (this.env.model.getters.isReadonly()) {
51559
+ return;
51560
+ }
51497
51561
  this.startEdition();
51498
51562
  }
51499
51563
  onKeyDown(ev) {
@@ -57224,6 +57288,6 @@ exports.setTranslationMethod = setTranslationMethod;
57224
57288
  exports.tokenize = tokenize;
57225
57289
 
57226
57290
 
57227
- __info__.version = "17.1.5";
57228
- __info__.date = "2024-02-16T14:23:54.651Z";
57229
- __info__.hash = "29d8ad6";
57291
+ __info__.version = "17.1.8";
57292
+ __info__.date = "2024-03-15T10:59:39.362Z";
57293
+ __info__.hash = "bd0c9e0";