@odoo/o-spreadsheet 17.1.5 → 17.1.7

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.7
6
+ * @date 2024-03-12T07:56:10.783Z
7
+ * @hash 3a9f334
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';
@@ -6098,8 +6098,10 @@ function getGroup(cell, cells, filter) {
6098
6098
  if (x === cell) {
6099
6099
  found = true;
6100
6100
  }
6101
- const cellValue = evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
6102
- if (filter(cellValue)) {
6101
+ const cellValue = x?.isFormula
6102
+ ? undefined
6103
+ : evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
6104
+ if (cellValue && filter(cellValue)) {
6103
6105
  group.push(cellValue);
6104
6106
  }
6105
6107
  else {
@@ -6323,11 +6325,14 @@ function cellTextStyleToCss(style) {
6323
6325
  * Transform CSS properties into a CSS string.
6324
6326
  */
6325
6327
  function cssPropertiesToCss(attributes) {
6326
- const str = Object.entries(attributes)
6327
- .filter(([attName, attValue]) => attValue !== undefined)
6328
- .map(([attName, attValue]) => `${attName}:${attValue};`)
6329
- .join(" ");
6330
- return str;
6328
+ let styleStr = "";
6329
+ for (const attName in attributes) {
6330
+ if (!attributes[attName]) {
6331
+ continue;
6332
+ }
6333
+ styleStr += `${attName}:${attributes[attName]}; `;
6334
+ }
6335
+ return styleStr;
6331
6336
  }
6332
6337
  function getElementMargins(el) {
6333
6338
  const style = window.getComputedStyle(el);
@@ -13051,6 +13056,18 @@ const TRUNC = {
13051
13056
  },
13052
13057
  isExported: true,
13053
13058
  };
13059
+ // -----------------------------------------------------------------------------
13060
+ // INT
13061
+ // -----------------------------------------------------------------------------
13062
+ const INT = {
13063
+ description: _t("Rounds a number down to the nearest integer that is less than or equal to it."),
13064
+ args: [arg("value (number)", _t("The number to round down to the nearest integer."))],
13065
+ returns: ["NUMBER"],
13066
+ compute: function (value) {
13067
+ return Math.floor(toNumber(value, this.locale));
13068
+ },
13069
+ isExported: true,
13070
+ };
13054
13071
 
13055
13072
  var math = /*#__PURE__*/Object.freeze({
13056
13073
  __proto__: null,
@@ -13084,6 +13101,7 @@ var math = /*#__PURE__*/Object.freeze({
13084
13101
  FLOOR: FLOOR,
13085
13102
  FLOOR_MATH: FLOOR_MATH,
13086
13103
  FLOOR_PRECISE: FLOOR_PRECISE,
13104
+ INT: INT,
13087
13105
  ISEVEN: ISEVEN,
13088
13106
  ISODD: ISODD,
13089
13107
  ISO_CEILING: ISO_CEILING,
@@ -18610,10 +18628,11 @@ const DEFAULT_IS_SORTED = true;
18610
18628
  const DEFAULT_MATCH_MODE = 0;
18611
18629
  const DEFAULT_SEARCH_MODE = 1;
18612
18630
  const DEFAULT_ABSOLUTE_RELATIVE_MODE = 1;
18613
- function assertAvailable(variable, searchKey) {
18614
- if (variable === undefined) {
18615
- throw new NotAvailableError(_t("Did not find value '%s' in [[FUNCTION_NAME]] evaluation.", toString(searchKey)));
18616
- }
18631
+ function valueNotAvailable(searchKey) {
18632
+ return {
18633
+ value: CellErrorType.NotAvailable,
18634
+ message: _t("Did not find value '%s' in [[FUNCTION_NAME]] evaluation.", toString(searchKey)),
18635
+ };
18617
18636
  }
18618
18637
  // -----------------------------------------------------------------------------
18619
18638
  // ADDRESS
@@ -18710,7 +18729,9 @@ const HLOOKUP = {
18710
18729
  ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
18711
18730
  : linearSearch(range, searchKey, "strict", range.length, getValueFromRange);
18712
18731
  const col = range[colIndex];
18713
- assertAvailable(col, searchKey?.value);
18732
+ if (col === undefined) {
18733
+ return valueNotAvailable(searchKey);
18734
+ }
18714
18735
  return col[_index - 1];
18715
18736
  },
18716
18737
  isExported: true,
@@ -18767,11 +18788,11 @@ const LOOKUP = {
18767
18788
  : (range, index) => range[index][0].value;
18768
18789
  const rangeLength = verticalSearch ? nbRow : nbCol;
18769
18790
  const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
18770
- if (index === -1)
18771
- assertAvailable(undefined, searchKey?.value);
18772
- verticalSearch
18773
- ? assertAvailable(searchArray[0][index], searchKey?.value)
18774
- : assertAvailable(searchArray[index][nbRow - 1], searchKey?.value);
18791
+ if (index === -1 ||
18792
+ (verticalSearch && searchArray[0][index] === undefined) ||
18793
+ (!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
18794
+ return valueNotAvailable(searchKey);
18795
+ }
18775
18796
  if (resultRange === undefined) {
18776
18797
  return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
18777
18798
  }
@@ -18821,7 +18842,10 @@ const MATCH = {
18821
18842
  index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18822
18843
  break;
18823
18844
  }
18824
- assertAvailable(nbCol === 1 ? range[0][index] : range[index], searchKey);
18845
+ if ((nbCol === 1 && range[0][index] === undefined) ||
18846
+ (nbCol !== 1 && range[index] === undefined)) {
18847
+ return valueNotAvailable(searchKey);
18848
+ }
18825
18849
  return index + 1;
18826
18850
  },
18827
18851
  isExported: true,
@@ -18880,7 +18904,9 @@ const VLOOKUP = {
18880
18904
  ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
18881
18905
  : linearSearch(range, searchKey, "strict", range[0].length, getValueFromRange);
18882
18906
  const value = range[_index - 1][rowIndex];
18883
- assertAvailable(value, searchKey);
18907
+ if (value === undefined) {
18908
+ return valueNotAvailable(searchKey);
18909
+ }
18884
18910
  return value;
18885
18911
  },
18886
18912
  isExported: true,
@@ -18930,7 +18956,9 @@ const XLOOKUP = {
18930
18956
  ? returnRange.map((col) => [col[index]])
18931
18957
  : [returnRange[index]];
18932
18958
  }
18933
- assertAvailable(defaultValue, searchKey);
18959
+ if (defaultValue === undefined) {
18960
+ return valueNotAvailable(searchKey);
18961
+ }
18934
18962
  return [[defaultValue]];
18935
18963
  },
18936
18964
  isExported: true,
@@ -19702,8 +19730,7 @@ class FunctionRegistry extends Registry {
19702
19730
  function addErrorHandling(compute, functionName) {
19703
19731
  return function (...args) {
19704
19732
  try {
19705
- const computeFormula = compute.bind(this);
19706
- return computeFormula(...args);
19733
+ return compute.apply(this, args);
19707
19734
  }
19708
19735
  catch (e) {
19709
19736
  return handleError(e, functionName);
@@ -19737,8 +19764,7 @@ function hasStringMessage(obj) {
19737
19764
  }
19738
19765
  function addResultHandling(compute) {
19739
19766
  return function (...args) {
19740
- const computeResult = compute.bind(this);
19741
- const result = computeResult(...args);
19767
+ const result = compute.apply(this, args);
19742
19768
  if (!isMatrix(result)) {
19743
19769
  if (typeof result === "object" && result !== null && "value" in result) {
19744
19770
  return result;
@@ -21705,7 +21731,7 @@ class SelectionInput extends Component {
21705
21731
  ? existingSelectionRanges
21706
21732
  : this.props.ranges().map((xc, id) => ({
21707
21733
  xc,
21708
- id,
21734
+ id: id + 1,
21709
21735
  isFocused: false,
21710
21736
  }));
21711
21737
  return ranges.map((range) => ({
@@ -27745,7 +27771,11 @@ class GridComposer extends Component {
27745
27771
  }
27746
27772
  }
27747
27773
  updateCellReferenceVisibility() {
27748
- if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
27774
+ if (this.env.model.getters.getEditionMode() === "inactive") {
27775
+ this.isCellReferenceVisible = false;
27776
+ return;
27777
+ }
27778
+ if (this.isCellReferenceVisible) {
27749
27779
  return;
27750
27780
  }
27751
27781
  const sheetId = this.env.model.getters.getActiveSheetId();
@@ -27774,19 +27804,21 @@ class GridCellIcon extends Component {
27774
27804
  slots: Object,
27775
27805
  };
27776
27806
  get iconStyle() {
27777
- const x = this.getIconHorizontalPosition();
27778
- const y = this.getIconVerticalPosition();
27807
+ const cellPosition = this.props.cellPosition;
27808
+ const merge = this.env.model.getters.getMerge(cellPosition);
27809
+ const zone = merge || positionToZone(cellPosition);
27810
+ const rect = this.env.model.getters.getVisibleRectWithoutHeaders(zone);
27811
+ const x = this.getIconHorizontalPosition(rect, cellPosition);
27812
+ const y = this.getIconVerticalPosition(rect, cellPosition);
27779
27813
  return cssPropertiesToCss({
27780
27814
  top: `${y + (this.props.offset?.y || 0)}px`,
27781
27815
  left: `${x + (this.props.offset?.x || 0)}px`,
27782
27816
  });
27783
27817
  }
27784
- getIconVerticalPosition() {
27785
- const { sheetId, row } = this.props.cellPosition;
27786
- const merge = this.env.model.getters.getMerge(this.props.cellPosition);
27787
- const start = this.env.model.getters.getRowDimensionsInViewport(sheetId, row).start;
27788
- const end = this.env.model.getters.getRowDimensionsInViewport(sheetId, merge ? merge.bottom : row).end;
27789
- const cell = this.env.model.getters.getCell(this.props.cellPosition);
27818
+ getIconVerticalPosition(rect, cellPosition) {
27819
+ const start = rect.y;
27820
+ const end = rect.y + rect.height;
27821
+ const cell = this.env.model.getters.getCell(cellPosition);
27790
27822
  const align = this.props.verticalAlign || cell?.style?.verticalAlign || DEFAULT_VERTICAL_ALIGN;
27791
27823
  switch (align) {
27792
27824
  case "bottom":
@@ -27798,13 +27830,11 @@ class GridCellIcon extends Component {
27798
27830
  return end - GRID_ICON_EDGE_LENGTH - centeringOffset;
27799
27831
  }
27800
27832
  }
27801
- getIconHorizontalPosition() {
27802
- const { sheetId, col } = this.props.cellPosition;
27803
- const merge = this.env.model.getters.getMerge(this.props.cellPosition);
27804
- const start = this.env.model.getters.getColDimensionsInViewport(sheetId, col).start;
27805
- const end = this.env.model.getters.getColDimensionsInViewport(sheetId, merge ? merge.right : col).end;
27806
- const cell = this.env.model.getters.getCell(this.props.cellPosition);
27807
- const evaluatedCell = this.env.model.getters.getEvaluatedCell(this.props.cellPosition);
27833
+ getIconHorizontalPosition(rect, cellPosition) {
27834
+ const start = rect.x;
27835
+ const end = rect.x + rect.width;
27836
+ const cell = this.env.model.getters.getCell(cellPosition);
27837
+ const evaluatedCell = this.env.model.getters.getEvaluatedCell(cellPosition);
27808
27838
  const align = this.props.horizontalAlign || cell?.style?.align || evaluatedCell.defaultAlign;
27809
27839
  switch (align) {
27810
27840
  case "right":
@@ -27888,6 +27918,8 @@ css /* scss */ `
27888
27918
  height: ${CHECKBOX_WIDTH}px;
27889
27919
  accent-color: #808080;
27890
27920
  margin: ${MARGIN}px;
27921
+ /** required to prevent the checkbox position to be sensible to the font-size (affects Firefox) */
27922
+ position: absolute;
27891
27923
  }
27892
27924
  `;
27893
27925
  class DataValidationCheckbox extends Component {
@@ -27906,7 +27938,7 @@ class DataValidationCheckbox extends Component {
27906
27938
  }
27907
27939
  get isDisabled() {
27908
27940
  const cell = this.env.model.getters.getCell(this.props.cellPosition);
27909
- return !!cell?.isFormula;
27941
+ return this.env.model.getters.isReadonly() || !!cell?.isFormula;
27910
27942
  }
27911
27943
  }
27912
27944
 
@@ -27946,12 +27978,17 @@ class DataValidationOverlay extends Component {
27946
27978
  static props = {};
27947
27979
  static components = { GridCellIcon, DataValidationCheckbox, DataValidationListIcon };
27948
27980
  get checkBoxCellPositions() {
27949
- return this.env.model.getters.getDataValidationCheckBoxCellPositions();
27981
+ return this.env.model.getters
27982
+ .getVisibleCellPositions()
27983
+ .filter(this.env.model.getters.isCellValidCheckbox);
27950
27984
  }
27951
27985
  get listIconsCellPositions() {
27952
- return this.env.model.getters.isReadonly()
27953
- ? []
27954
- : this.env.model.getters.getDataValidationListCellsPositions();
27986
+ if (this.env.model.getters.isReadonly()) {
27987
+ return [];
27988
+ }
27989
+ return this.env.model.getters
27990
+ .getVisibleCellPositions()
27991
+ .filter(this.env.model.getters.cellHasListDataValidationIcon);
27955
27992
  }
27956
27993
  }
27957
27994
 
@@ -34313,29 +34350,12 @@ const MIGRATIONS = [
34313
34350
  from: 12,
34314
34351
  to: 12.5,
34315
34352
  applyMigration(data) {
34316
- for (let sheet of data.sheets || []) {
34317
- let knownDataFilterZones = [];
34318
- for (let filterTable of sheet.filterTables || []) {
34319
- const zone = toZone(filterTable.range);
34320
- // See commit message for the details
34321
- const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
34322
- if (intersectZoneIndex !== -1) {
34323
- knownDataFilterZones[intersectZoneIndex] = zone;
34324
- }
34325
- else {
34326
- knownDataFilterZones.push(zone);
34327
- }
34328
- }
34329
- sheet.filterTables = knownDataFilterZones.map((zone) => ({
34330
- range: zoneToXc(zone),
34331
- }));
34332
- }
34333
- return data;
34353
+ return fixOverlappingFilters(data);
34334
34354
  },
34335
34355
  },
34336
34356
  {
34337
34357
  description: "Change Border description structure",
34338
- from: 12,
34358
+ from: 12.5,
34339
34359
  to: 13,
34340
34360
  applyMigration(data) {
34341
34361
  for (const borderId in data.borders) {
@@ -34366,6 +34386,14 @@ const MIGRATIONS = [
34366
34386
  return data;
34367
34387
  },
34368
34388
  },
34389
+ {
34390
+ description: "Fix datafilter duplication (post saas-16.4)",
34391
+ from: 14,
34392
+ to: 14.5,
34393
+ applyMigration(data) {
34394
+ return fixOverlappingFilters(data);
34395
+ },
34396
+ },
34369
34397
  ];
34370
34398
  /**
34371
34399
  * This function is used to repair faulty data independently of the migration.
@@ -34523,6 +34551,26 @@ function fixChartDefinitions(data, initialMessages) {
34523
34551
  }
34524
34552
  return messages;
34525
34553
  }
34554
+ function fixOverlappingFilters(data) {
34555
+ for (let sheet of data.sheets || []) {
34556
+ let knownDataFilterZones = [];
34557
+ for (let filterTable of sheet.filterTables || []) {
34558
+ const zone = toZone(filterTable.range);
34559
+ // See commit message of https://github.com/odoo/o-spreadsheet/pull/3632 of more details
34560
+ const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
34561
+ if (intersectZoneIndex !== -1) {
34562
+ knownDataFilterZones[intersectZoneIndex] = zone;
34563
+ }
34564
+ else {
34565
+ knownDataFilterZones.push(zone);
34566
+ }
34567
+ }
34568
+ sheet.filterTables = knownDataFilterZones.map((zone) => ({
34569
+ range: zoneToXc(zone),
34570
+ }));
34571
+ }
34572
+ return data;
34573
+ }
34526
34574
  // -----------------------------------------------------------------------------
34527
34575
  // Helpers
34528
34576
  // -----------------------------------------------------------------------------
@@ -39044,7 +39092,6 @@ class SheetPlugin extends CorePlugin {
39044
39092
  "getNumberHeaders",
39045
39093
  "getGridLinesVisibility",
39046
39094
  "getNextSheetName",
39047
- "isEmpty",
39048
39095
  "getSheetSize",
39049
39096
  "getSheetZone",
39050
39097
  "getPaneDivisions",
@@ -39419,14 +39466,6 @@ class SheetPlugin extends CorePlugin {
39419
39466
  // ---------------------------------------------------------------------------
39420
39467
  // Row/Col manipulation
39421
39468
  // ---------------------------------------------------------------------------
39422
- /**
39423
- * Check if a zone only contains empty cells
39424
- */
39425
- isEmpty(sheetId, zone) {
39426
- return positions(zone)
39427
- .map(({ col, row }) => this.getCell({ sheetId, col, row }))
39428
- .every((cell) => !cell || cell.content === "");
39429
- }
39430
39469
  getCommandZones(cmd) {
39431
39470
  const zones = [];
39432
39471
  if ("zone" in cmd) {
@@ -41541,7 +41580,7 @@ class Evaluator {
41541
41580
  : evaluateLiteral(cell.content, localeFormat);
41542
41581
  }
41543
41582
  catch (e) {
41544
- return createEvaluatedCell(e.value, localeFormat, e.message);
41583
+ return createEvaluatedCell(e?.value || CellErrorType.GenericError, localeFormat, e?.message || implementationErrorMessage);
41545
41584
  }
41546
41585
  finally {
41547
41586
  this.cellsBeingComputed.delete(cellId);
@@ -41875,6 +41914,7 @@ class EvaluationPlugin extends UIPlugin {
41875
41914
  "getEvaluatedCellsInZone",
41876
41915
  "getSpreadPositionsOf",
41877
41916
  "getArrayFormulaSpreadingOn",
41917
+ "isEmpty",
41878
41918
  ];
41879
41919
  shouldRebuildDependenciesGraph = true;
41880
41920
  evaluator;
@@ -41980,6 +42020,14 @@ class EvaluationPlugin extends UIPlugin {
41980
42020
  getArrayFormulaSpreadingOn(position) {
41981
42021
  return this.evaluator.getArrayFormulaSpreadingOn(position);
41982
42022
  }
42023
+ /**
42024
+ * Check if a zone only contains empty cells
42025
+ */
42026
+ isEmpty(sheetId, zone) {
42027
+ return positions(zone)
42028
+ .map(({ col, row }) => this.getEvaluatedCell({ sheetId, col, row }))
42029
+ .every((cell) => cell.type === CellValueType.empty);
42030
+ }
41983
42031
  // ---------------------------------------------------------------------------
41984
42032
  // Export
41985
42033
  // ---------------------------------------------------------------------------
@@ -42627,8 +42675,6 @@ const VALID_RESULT = { isValid: true };
42627
42675
  class EvaluationDataValidationPlugin extends UIPlugin {
42628
42676
  static getters = [
42629
42677
  "getDataValidationInvalidCriterionValueMessage",
42630
- "getDataValidationCheckBoxCellPositions",
42631
- "getDataValidationListCellsPositions",
42632
42678
  "getInvalidDataValidationMessage",
42633
42679
  "getValidationResultForCellValue",
42634
42680
  "isCellValidCheckbox",
@@ -42692,19 +42738,6 @@ class EvaluationDataValidationPlugin extends UIPlugin {
42692
42738
  const error = this.getRuleErrorForCellValue(cellValue, cellPosition, rule);
42693
42739
  return error ? { error, rule, isValid: false } : VALID_RESULT;
42694
42740
  }
42695
- getDataValidationCheckBoxCellPositions() {
42696
- const rules = this.getters
42697
- .getDataValidationRules(this.getters.getActiveSheetId())
42698
- .filter((rule) => rule.criterion.type === "isBoolean");
42699
- return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat()).filter((position) => this.isCellValidCheckbox(position));
42700
- }
42701
- getDataValidationListCellsPositions() {
42702
- const rules = this.getters
42703
- .getDataValidationRules(this.getters.getActiveSheetId())
42704
- .filter((rule) => (rule.criterion.type === "isValueInList" || rule.criterion.type === "isValueInRange") &&
42705
- rule.criterion.displayStyle === "arrow");
42706
- return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat());
42707
- }
42708
42741
  getValidationResultForCell(cellPosition) {
42709
42742
  const { col, row, sheetId } = cellPosition;
42710
42743
  if (!this.validationResults[sheetId]) {
@@ -45673,6 +45706,8 @@ class FindAndReplacePlugin extends UIPlugin {
45673
45706
  sheetIdFrom: this.getters.getActiveSheetId(),
45674
45707
  sheetIdTo: selectedMatch.sheetId,
45675
45708
  });
45709
+ // We do not want to reset the selection at finalize in this case
45710
+ this.isSearchDirty = false;
45676
45711
  }
45677
45712
  // we want grid selection to capture the selection stream
45678
45713
  this.selection.getBackToDefault();
@@ -46974,19 +47009,17 @@ class SelectionInputsManagerPlugin extends UIPlugin {
46974
47009
  break;
46975
47010
  case "FOCUS_RANGE":
46976
47011
  case "CHANGE_RANGE":
46977
- if (cmd.id !== this.focusedInputId) {
46978
- const input = this.inputs[cmd.id];
46979
- const range = input.ranges.find((range) => range.id === cmd.rangeId);
46980
- if (this.isRangeValid(range?.xc || "A1")) {
46981
- const sheetId = this.getters.getActiveSheetId();
46982
- const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
46983
- this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, {
46984
- handleEvent: input.handleEvent.bind(input),
46985
- release: () => (this.focusedInputId = null),
46986
- });
46987
- }
46988
- this.focusedInputId = cmd.id;
47012
+ const input = this.inputs[cmd.id];
47013
+ const range = input.ranges.find((range) => range.id === cmd.rangeId);
47014
+ if (range) {
47015
+ const sheetId = this.getters.getActiveSheetId();
47016
+ const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
47017
+ this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, {
47018
+ handleEvent: input.handleEvent.bind(input),
47019
+ release: () => (this.focusedInputId = null),
47020
+ });
46989
47021
  }
47022
+ this.focusedInputId = cmd.id;
46990
47023
  break;
46991
47024
  }
46992
47025
  this.currentInput?.handle(cmd);
@@ -50405,6 +50438,8 @@ class SheetViewPlugin extends UIPlugin {
50405
50438
  "getEdgeScrollRow",
50406
50439
  "getVisibleFigures",
50407
50440
  "getVisibleRect",
50441
+ "getVisibleRectWithoutHeaders",
50442
+ "getVisibleCellPositions",
50408
50443
  "getColRowOffsetInViewport",
50409
50444
  "getMainViewportCoordinates",
50410
50445
  "getActiveSheetScrollInfo",
@@ -50648,6 +50683,26 @@ class SheetViewPlugin extends UIPlugin {
50648
50683
  const viewports = this.getSubViewports(sheetId);
50649
50684
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
50650
50685
  }
50686
+ /**
50687
+ * Get the positions of all the cells that are visible in the viewport, taking merges into account.
50688
+ */
50689
+ getVisibleCellPositions() {
50690
+ const visibleCols = this.getSheetViewVisibleCols();
50691
+ const visibleRows = this.getSheetViewVisibleRows();
50692
+ const sheetId = this.getters.getActiveSheetId();
50693
+ const positions = [];
50694
+ for (const col of visibleCols) {
50695
+ for (const row of visibleRows) {
50696
+ const position = { sheetId, col, row };
50697
+ const mainPosition = this.getters.getMainCellPosition(position);
50698
+ if (mainPosition.row !== row || mainPosition.col !== col) {
50699
+ continue;
50700
+ }
50701
+ positions.push(position);
50702
+ }
50703
+ }
50704
+ return positions;
50705
+ }
50651
50706
  /**
50652
50707
  * Return the main viewport maximum size relative to the client size.
50653
50708
  */
@@ -50767,6 +50822,13 @@ class SheetViewPlugin extends UIPlugin {
50767
50822
  * Computes the coordinates and size to draw the zone on the canvas
50768
50823
  */
50769
50824
  getVisibleRect(zone) {
50825
+ const rect = this.getVisibleRectWithoutHeaders(zone);
50826
+ return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
50827
+ }
50828
+ /**
50829
+ * Computes the coordinates and size to draw the zone without taking the grid offset into account
50830
+ */
50831
+ getVisibleRectWithoutHeaders(zone) {
50770
50832
  const sheetId = this.getters.getActiveSheetId();
50771
50833
  const viewportRects = this.getSubViewports(sheetId)
50772
50834
  .map((viewport) => viewport.getRect(zone))
@@ -50778,12 +50840,7 @@ class SheetViewPlugin extends UIPlugin {
50778
50840
  const y = Math.min(...viewportRects.map((rect) => rect.y));
50779
50841
  const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
50780
50842
  const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
50781
- return {
50782
- x: x + this.gridOffsetX,
50783
- y: y + this.gridOffsetY,
50784
- width,
50785
- height,
50786
- };
50843
+ return { x, y, width, height };
50787
50844
  }
50788
50845
  /**
50789
50846
  * Returns the position of the MainViewport relatively to the start of the grid (without headers)
@@ -51007,13 +51064,8 @@ class HeaderPositionsUIPlugin extends UIPlugin {
51007
51064
  }
51008
51065
  break;
51009
51066
  case "UPDATE_CELL":
51010
- if ("content" in cmd || "format" in cmd) {
51011
- this.headerPositions = {};
51012
- this.isDirty = true;
51013
- }
51014
- else {
51015
- this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
51016
- }
51067
+ this.headerPositions = {};
51068
+ this.isDirty = true;
51017
51069
  break;
51018
51070
  case "UPDATE_FILTER":
51019
51071
  case "REMOVE_FILTER_TABLE":
@@ -57186,6 +57238,6 @@ const constants = {
57186
57238
  export { AbstractChart, CellErrorType, 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 };
57187
57239
 
57188
57240
 
57189
- __info__.version = "17.1.5";
57190
- __info__.date = "2024-02-16T14:23:54.651Z";
57191
- __info__.hash = "29d8ad6";
57241
+ __info__.version = "17.1.7";
57242
+ __info__.date = "2024-03-12T07:56:10.783Z";
57243
+ __info__.hash = "3a9f334";