@odoo/o-spreadsheet 18.2.0-alpha.5 → 18.2.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 18.2.0-alpha.5
6
- * @date 2025-01-31T07:59:30.667Z
7
- * @hash efce841
5
+ * @version 18.2.0-alpha.6
6
+ * @date 2025-02-05T06:50:47.008Z
7
+ * @hash dae9ab2
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -18633,19 +18633,20 @@ stores.inject(MyMetaStore, storeInstance);
18633
18633
  description: _t("Horizontal lookup"),
18634
18634
  args: [
18635
18635
  arg("search_key (string, number, boolean)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18636
- arg("range (range)", _t("The range to consider for the search. The first row in the range is searched for the key specified in search_key.")),
18636
+ arg("range (any, range)", _t("The range to consider for the search. The first row in the range is searched for the key specified in search_key.")),
18637
18637
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18638
18638
  arg(`is_sorted (boolean, default=${DEFAULT_IS_SORTED})`, _t("Indicates whether the row to be searched (the first row of the specified range) is sorted, in which case the closest match for search_key will be returned.")),
18639
18639
  ],
18640
18640
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18641
18641
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18642
- assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18642
+ const _range = toMatrix(range);
18643
+ assert(() => 1 <= _index && _index <= _range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18643
18644
  const getValueFromRange = (range, index) => range[index][0].value;
18644
18645
  const _isSorted = toBoolean(isSorted.value);
18645
18646
  const colIndex = _isSorted
18646
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
18647
- : linearSearch(range, searchKey, "wildcard", range.length, getValueFromRange);
18648
- const col = range[colIndex];
18647
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
18648
+ : linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange);
18649
+ const col = _range[colIndex];
18649
18650
  if (col === undefined) {
18650
18651
  return valueNotAvailable(searchKey);
18651
18652
  }
@@ -18737,35 +18738,37 @@ stores.inject(MyMetaStore, storeInstance);
18737
18738
  description: _t("Look up a value."),
18738
18739
  args: [
18739
18740
  arg("search_key (string, number, boolean)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
18740
- arg("search_array (range)", _t("One method of using this function is to provide a single sorted row or column search_array to look through for the search_key with a second argument result_range. The other way is to combine these two arguments into one search_array where the first row or column is searched and a value is returned from the last row or column in the array. If search_key is not found, a non-exact match may be returned.")),
18741
- arg("result_range (range, optional)", _t("The range from which to return a result. The value returned corresponds to the location where search_key is found in search_range. This range must be only a single row or column and should not be used if using the search_result_array method.")),
18741
+ arg("search_array (any, range)", _t("One method of using this function is to provide a single sorted row or column search_array to look through for the search_key with a second argument result_range. The other way is to combine these two arguments into one search_array where the first row or column is searched and a value is returned from the last row or column in the array. If search_key is not found, a non-exact match may be returned.")),
18742
+ arg("result_range (any, range, optional)", _t("The range from which to return a result. The value returned corresponds to the location where search_key is found in search_range. This range must be only a single row or column and should not be used if using the search_result_array method.")),
18742
18743
  ],
18743
18744
  compute: function (searchKey, searchArray, resultRange) {
18744
- let nbCol = searchArray.length;
18745
- let nbRow = searchArray[0].length;
18745
+ const _searchArray = toMatrix(searchArray);
18746
+ const _resultRange = toMatrix(resultRange);
18747
+ let nbCol = _searchArray.length;
18748
+ let nbRow = _searchArray[0].length;
18746
18749
  const verticalSearch = nbRow >= nbCol;
18747
18750
  const getElement = verticalSearch
18748
18751
  ? (range, index) => range[0][index].value
18749
18752
  : (range, index) => range[index][0].value;
18750
18753
  const rangeLength = verticalSearch ? nbRow : nbCol;
18751
- const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
18754
+ const index = dichotomicSearch(_searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
18752
18755
  if (index === -1 ||
18753
- (verticalSearch && searchArray[0][index] === undefined) ||
18754
- (!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
18756
+ (verticalSearch && _searchArray[0][index] === undefined) ||
18757
+ (!verticalSearch && _searchArray[index][nbRow - 1] === undefined)) {
18755
18758
  return valueNotAvailable(searchKey);
18756
18759
  }
18757
- if (resultRange === undefined) {
18758
- return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
18760
+ if (_resultRange[0].length === 0) {
18761
+ return verticalSearch ? _searchArray[nbCol - 1][index] : _searchArray[index][nbRow - 1];
18759
18762
  }
18760
- nbCol = resultRange.length;
18761
- nbRow = resultRange[0].length;
18763
+ nbCol = _resultRange.length;
18764
+ nbRow = _resultRange[0].length;
18762
18765
  assert(() => nbCol === 1 || nbRow === 1, _t("The result_range must be a single row or a single column."));
18763
18766
  if (nbCol > 1) {
18764
18767
  assert(() => index <= nbCol - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range row value %s.", (index + 1).toString()));
18765
- return resultRange[index][0];
18768
+ return _resultRange[index][0];
18766
18769
  }
18767
18770
  assert(() => index <= nbRow - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range column value %s.", (index + 1).toString()));
18768
- return resultRange[0][index];
18771
+ return _resultRange[0][index];
18769
18772
  },
18770
18773
  isExported: true,
18771
18774
  };
@@ -18782,28 +18785,29 @@ stores.inject(MyMetaStore, storeInstance);
18782
18785
  ],
18783
18786
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
18784
18787
  let _searchType = toNumber(searchType, this.locale);
18785
- const nbCol = range.length;
18786
- const nbRow = range[0].length;
18788
+ const _range = toMatrix(range);
18789
+ const nbCol = _range.length;
18790
+ const nbRow = _range[0].length;
18787
18791
  assert(() => nbCol === 1 || nbRow === 1, _t("The range must be a single row or a single column."));
18788
18792
  let index = -1;
18789
18793
  const getElement = nbCol === 1
18790
- ? (range, index) => range[0][index].value
18791
- : (range, index) => range[index][0].value;
18792
- const rangeLen = nbCol === 1 ? range[0].length : range.length;
18794
+ ? (_range, index) => _range[0][index].value
18795
+ : (_range, index) => _range[index][0].value;
18796
+ const rangeLen = nbCol === 1 ? _range[0].length : _range.length;
18793
18797
  _searchType = Math.sign(_searchType);
18794
18798
  switch (_searchType) {
18795
18799
  case 1:
18796
- index = dichotomicSearch(range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18800
+ index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
18797
18801
  break;
18798
18802
  case 0:
18799
- index = linearSearch(range, searchKey, "wildcard", rangeLen, getElement);
18803
+ index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement);
18800
18804
  break;
18801
18805
  case -1:
18802
- index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18806
+ index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
18803
18807
  break;
18804
18808
  }
18805
- if ((nbCol === 1 && range[0][index] === undefined) ||
18806
- (nbCol !== 1 && range[index] === undefined)) {
18809
+ if ((nbCol === 1 && _range[0][index] === undefined) ||
18810
+ (nbCol !== 1 && _range[index] === undefined)) {
18807
18811
  return valueNotAvailable(searchKey);
18808
18812
  }
18809
18813
  return index + 1;
@@ -18858,13 +18862,14 @@ stores.inject(MyMetaStore, storeInstance);
18858
18862
  ],
18859
18863
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18860
18864
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18861
- assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18865
+ const _range = toMatrix(range);
18866
+ assert(() => 1 <= _index && _index <= _range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18862
18867
  const getValueFromRange = (range, index) => range[0][index].value;
18863
18868
  const _isSorted = toBoolean(isSorted.value);
18864
18869
  const rowIndex = _isSorted
18865
- ? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
18866
- : linearSearch(range, searchKey, "wildcard", range[0].length, getValueFromRange);
18867
- const value = range[_index - 1][rowIndex];
18870
+ ? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
18871
+ : linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange);
18872
+ const value = _range[_index - 1][rowIndex];
18868
18873
  if (value === undefined) {
18869
18874
  return valueNotAvailable(searchKey);
18870
18875
  }
@@ -18901,27 +18906,29 @@ stores.inject(MyMetaStore, storeInstance);
18901
18906
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18902
18907
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18903
18908
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
18904
- assert(() => lookupRange.length === 1 || lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18909
+ const _lookupRange = toMatrix(lookupRange);
18910
+ const _returnRange = toMatrix(returnRange);
18911
+ assert(() => _lookupRange.length === 1 || _lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
18905
18912
  assert(() => [-1, 1, -2, 2].includes(_searchMode), _t("search_mode should be a value in [-1, 1, -2, 2]."));
18906
18913
  assert(() => [-1, 0, 1, 2].includes(_matchMode), _t("match_mode should be a value in [-1, 0, 1, 2]."));
18907
- const lookupDirection = lookupRange.length === 1 ? "col" : "row";
18914
+ const lookupDirection = _lookupRange.length === 1 ? "col" : "row";
18908
18915
  assert(() => !(_matchMode === 2 && [-2, 2].includes(_searchMode)), _t("the search and match mode combination is not supported for XLOOKUP evaluation."));
18909
18916
  assert(() => lookupDirection === "col"
18910
- ? returnRange[0].length === lookupRange[0].length
18911
- : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18917
+ ? _returnRange[0].length === _lookupRange[0].length
18918
+ : _returnRange.length === _lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18912
18919
  const getElement = lookupDirection === "col"
18913
18920
  ? (range, index) => range[0][index].value
18914
18921
  : (range, index) => range[index][0].value;
18915
- const rangeLen = lookupDirection === "col" ? lookupRange[0].length : lookupRange.length;
18922
+ const rangeLen = lookupDirection === "col" ? _lookupRange[0].length : _lookupRange.length;
18916
18923
  const mode = MATCH_MODE[_matchMode];
18917
18924
  const reverseSearch = _searchMode === -1;
18918
18925
  const index = _searchMode === 2 || _searchMode === -2
18919
- ? dichotomicSearch(lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18920
- : linearSearch(lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
18926
+ ? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
18927
+ : linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
18921
18928
  if (index !== -1) {
18922
18929
  return lookupDirection === "col"
18923
- ? returnRange.map((col) => [col[index]])
18924
- : [returnRange[index]];
18930
+ ? _returnRange.map((col) => [col[index]])
18931
+ : [_returnRange[index]];
18925
18932
  }
18926
18933
  if (defaultValue === undefined) {
18927
18934
  return valueNotAvailable(searchKey);
@@ -28457,11 +28464,7 @@ stores.inject(MyMetaStore, storeInstance);
28457
28464
  if (values.length < 2 || labels.length < 2 || newLabels.length === 0) {
28458
28465
  return [];
28459
28466
  }
28460
- const labelMin = Math.min(...labels);
28461
- const labelMax = Math.max(...labels);
28462
- const labelRange = labelMax - labelMin;
28463
- const normalizedLabels = labels.map((v) => (v - labelMin) / labelRange);
28464
- const normalizedNewLabels = newLabels.map((v) => (v - labelMin) / labelRange);
28467
+ const { normalizedLabels, normalizedNewLabels } = normalizeLabels(labels, newLabels, config);
28465
28468
  try {
28466
28469
  switch (config.type) {
28467
28470
  case "polynomial": {
@@ -28506,6 +28509,30 @@ stores.inject(MyMetaStore, storeInstance);
28506
28509
  return newLabels.map((x) => ({ x, y: NaN }));
28507
28510
  }
28508
28511
  }
28512
+ function normalizeLabels(labels, newLabels, config) {
28513
+ let normalizedLabels = [];
28514
+ let normalizedNewLabels = [];
28515
+ if (config.type === "logarithmic") {
28516
+ // Logarithmic trends in charts are used to visualize proportional growth or
28517
+ // relative changes. Therefore, we change the normalization technique for
28518
+ // logarithmic trend lines for a better fit. The method used here is Max Absolute
28519
+ // Scaling. This Technique is ideal for data spanning several orders of magnitude,
28520
+ // as it balances differences between small and large values by compressing larger
28521
+ // values while preserving proportionality and ensuring all values are scaled relative
28522
+ // to the largest magnitude.
28523
+ const labelMax = Math.max(...labels.map(Math.abs));
28524
+ normalizedLabels = labels.map((l) => l / labelMax);
28525
+ normalizedNewLabels = newLabels.map((l) => l / labelMax);
28526
+ }
28527
+ else {
28528
+ const labelMax = Math.max(...labels);
28529
+ const labelMin = Math.min(...labels);
28530
+ const labelRange = labelMax - labelMin;
28531
+ normalizedLabels = labels.map((l) => (l - labelMax) / labelRange);
28532
+ normalizedNewLabels = newLabels.map((l) => (l - labelMax) / labelRange);
28533
+ }
28534
+ return { normalizedLabels, normalizedNewLabels };
28535
+ }
28509
28536
  function getChartAxisType(chart, labelRange, getters) {
28510
28537
  if (isDateChart(chart, labelRange, getters) && isLuxonTimeAdapterInstalled()) {
28511
28538
  return "time";
@@ -37173,7 +37200,7 @@ stores.inject(MyMetaStore, storeInstance);
37173
37200
  }
37174
37201
  const { x: offsetCorrectionX, y: offsetCorrectionY } = getters.getMainViewportCoordinates();
37175
37202
  let { top, left, bottom, right } = getters.getActiveMainViewport();
37176
- let { scrollX, scrollY } = getters.getActiveSheetDOMScrollInfo();
37203
+ let { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
37177
37204
  const { xSplit, ySplit } = getters.getPaneDivisions(sheetId);
37178
37205
  let canEdgeScroll = false;
37179
37206
  let timeoutDelay = MAX_DELAY;
@@ -41346,6 +41373,16 @@ stores.inject(MyMetaStore, storeInstance);
41346
41373
  }
41347
41374
  return providersDefinitions;
41348
41375
  }
41376
+ /**
41377
+ * Replace the current reference selected by the new one.
41378
+ * */
41379
+ getZoneReference(zone) {
41380
+ const res = super.getZoneReference(zone);
41381
+ if (this.args().defaultStatic) {
41382
+ return setXcToFixedReferenceType(res, "colrow");
41383
+ }
41384
+ return res;
41385
+ }
41349
41386
  getComposerContent() {
41350
41387
  if (this.editionMode === "inactive") {
41351
41388
  // References in the content might not be linked to the current active sheet
@@ -41411,6 +41448,7 @@ stores.inject(MyMetaStore, storeInstance);
41411
41448
  static props = {
41412
41449
  composerContent: { type: String, optional: true },
41413
41450
  defaultRangeSheetId: { type: String, optional: true },
41451
+ defaultStatic: { type: Boolean, optional: true },
41414
41452
  onConfirm: Function,
41415
41453
  contextualAutocomplete: { type: Object, optional: true },
41416
41454
  placeholder: { type: String, optional: true },
@@ -41421,6 +41459,7 @@ stores.inject(MyMetaStore, storeInstance);
41421
41459
  static components = { Composer };
41422
41460
  static defaultProps = {
41423
41461
  composerContent: "",
41462
+ defaultStatic: false,
41424
41463
  };
41425
41464
  composerFocusStore;
41426
41465
  standaloneComposerStore;
@@ -41431,6 +41470,7 @@ stores.inject(MyMetaStore, storeInstance);
41431
41470
  const standaloneComposerStore = useLocalStore(StandaloneComposerStore, () => ({
41432
41471
  onConfirm: this.props.onConfirm,
41433
41472
  content: this.props.composerContent,
41473
+ defaultStatic: this.props.defaultStatic ?? false,
41434
41474
  contextualAutocomplete: this.props.contextualAutocomplete,
41435
41475
  defaultRangeSheetId: this.props.defaultRangeSheetId,
41436
41476
  getContextualColoredSymbolToken: this.props.getContextualColoredSymbolToken,
@@ -42166,6 +42206,7 @@ stores.inject(MyMetaStore, storeInstance);
42166
42206
  },
42167
42207
  composerContent: this.state.rules.cellIs.values[valueIndex],
42168
42208
  placeholder: _t("Value or formula"),
42209
+ defaultStatic: true,
42169
42210
  invalid: isInvalid,
42170
42211
  class: "o-sidePanel-composer",
42171
42212
  defaultRangeSheetId: this.env.model.getters.getActiveSheetId(),
@@ -42184,6 +42225,7 @@ stores.inject(MyMetaStore, storeInstance);
42184
42225
  },
42185
42226
  composerContent: threshold.value || "",
42186
42227
  placeholder: _t("Formula"),
42228
+ defaultStatic: true,
42187
42229
  invalid: isInvalid,
42188
42230
  class: "o-sidePanel-composer",
42189
42231
  defaultRangeSheetId: this.env.model.getters.getActiveSheetId(),
@@ -42199,6 +42241,7 @@ stores.inject(MyMetaStore, storeInstance);
42199
42241
  },
42200
42242
  composerContent: inflection.value || "",
42201
42243
  placeholder: _t("Formula"),
42244
+ defaultStatic: true,
42202
42245
  invalid: isInvalid,
42203
42246
  class: "o-sidePanel-composer",
42204
42247
  defaultRangeSheetId: this.env.model.getters.getActiveSheetId(),
@@ -49807,7 +49850,7 @@ stores.inject(MyMetaStore, storeInstance);
49807
49850
  });
49808
49851
  this.props.focusGrid();
49809
49852
  // After adding new rows, scroll down to the new last row
49810
- const { scrollX } = this.env.model.getters.getActiveSheetDOMScrollInfo();
49853
+ const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
49811
49854
  const { end } = this.env.model.getters.getRowDimensions(activeSheetId, rowNumber + quantity - 1);
49812
49855
  this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
49813
49856
  offsetX: scrollX,
@@ -50065,7 +50108,7 @@ stores.inject(MyMetaStore, storeInstance);
50065
50108
  resizeObserver.disconnect();
50066
50109
  });
50067
50110
  useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
50068
- const { scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
50111
+ const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
50069
50112
  return scrollY > 0;
50070
50113
  });
50071
50114
  this.cellPopovers = useStore(CellPopoverStore);
@@ -50719,17 +50762,6 @@ stores.inject(MyMetaStore, storeInstance);
50719
50762
  get renderingLayers() {
50720
50763
  return ["Background", "Headers"];
50721
50764
  }
50722
- /**
50723
- * Get the offset of a header (see getColRowOffsetInViewport), adjusted with the header
50724
- * size (HEADER_HEIGHT and HEADER_WIDTH)
50725
- */
50726
- getHeaderOffset(dimension, start, index) {
50727
- let size = this.getters.getColRowOffsetInViewport(dimension, start, index);
50728
- if (!this.getters.isDashboard()) {
50729
- size += dimension === "ROW" ? HEADER_HEIGHT : HEADER_WIDTH;
50730
- }
50731
- return size;
50732
- }
50733
50765
  // ---------------------------------------------------------------------------
50734
50766
  // Grid rendering
50735
50767
  // ---------------------------------------------------------------------------
@@ -50737,11 +50769,10 @@ stores.inject(MyMetaStore, storeInstance);
50737
50769
  switch (layer) {
50738
50770
  case "Background":
50739
50771
  this.drawGlobalBackground(renderingContext);
50740
- for (const zone of this.getters.getAllActiveViewportsZones()) {
50772
+ for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
50741
50773
  const { ctx } = renderingContext;
50742
50774
  ctx.save();
50743
50775
  ctx.beginPath();
50744
- const rect = this.getters.getVisibleRect(zone);
50745
50776
  ctx.rect(rect.x, rect.y, rect.width, rect.height);
50746
50777
  ctx.clip();
50747
50778
  const boxes = this.getGridBoxes(zone);
@@ -51017,10 +51048,8 @@ stores.inject(MyMetaStore, storeInstance);
51017
51048
  const { ctx, thinLineWidth } = renderingContext;
51018
51049
  const visibleCols = this.getters.getSheetViewVisibleCols();
51019
51050
  const left = visibleCols[0];
51020
- const right = visibleCols[visibleCols.length - 1];
51021
51051
  const visibleRows = this.getters.getSheetViewVisibleRows();
51022
51052
  const top = visibleRows[0];
51023
- const bottom = visibleRows[visibleRows.length - 1];
51024
51053
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
51025
51054
  const selection = this.getters.getSelectedZones();
51026
51055
  const selectedCols = getZonesCols(selection);
@@ -51036,7 +51065,7 @@ stores.inject(MyMetaStore, storeInstance);
51036
51065
  ctx.lineWidth = thinLineWidth;
51037
51066
  ctx.strokeStyle = "#333";
51038
51067
  // Columns headers background
51039
- for (let col = left; col <= right; col++) {
51068
+ for (const col of visibleCols) {
51040
51069
  const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
51041
51070
  const { x, width } = this.getters.getVisibleRect(colZone);
51042
51071
  const isColActive = activeCols.has(col);
@@ -51053,7 +51082,7 @@ stores.inject(MyMetaStore, storeInstance);
51053
51082
  ctx.fillRect(x, 0, width, HEADER_HEIGHT);
51054
51083
  }
51055
51084
  // Rows headers background
51056
- for (let row = top; row <= bottom; row++) {
51085
+ for (const row of visibleRows) {
51057
51086
  const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
51058
51087
  const { y, height } = this.getters.getVisibleRect(rowZone);
51059
51088
  const isRowActive = activeRows.has(row);
@@ -51077,27 +51106,41 @@ stores.inject(MyMetaStore, storeInstance);
51077
51106
  ctx.lineTo(width, HEADER_HEIGHT);
51078
51107
  ctx.strokeStyle = HEADER_BORDER_COLOR;
51079
51108
  ctx.stroke();
51080
- ctx.beginPath();
51081
51109
  // column text + separator
51082
- for (const i of visibleCols) {
51083
- const colSize = this.getters.getColSize(sheetId, i);
51084
- const colName = numberToLetters(i);
51085
- ctx.fillStyle = activeCols.has(i) ? "#fff" : TEXT_HEADER_COLOR;
51086
- let colStart = this.getHeaderOffset("COL", left, i);
51110
+ for (const col of visibleCols) {
51111
+ const colName = numberToLetters(col);
51112
+ ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
51113
+ const zone = { left: col, right: col, top: top, bottom: top };
51114
+ const { x: colStart, width: colSize } = this.getters.getRect(zone);
51115
+ const { x, width } = this.getters.getVisibleRect(zone);
51116
+ ctx.save();
51117
+ ctx.beginPath();
51118
+ ctx.rect(x, 0, width, HEADER_HEIGHT);
51119
+ ctx.clip();
51087
51120
  ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
51121
+ ctx.restore();
51122
+ ctx.beginPath();
51088
51123
  ctx.moveTo(colStart + colSize, 0);
51089
51124
  ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
51125
+ ctx.stroke();
51090
51126
  }
51091
51127
  // row text + separator
51092
- for (const i of visibleRows) {
51093
- const rowSize = this.getters.getRowSize(sheetId, i);
51094
- ctx.fillStyle = activeRows.has(i) ? "#fff" : TEXT_HEADER_COLOR;
51095
- let rowStart = this.getHeaderOffset("ROW", top, i);
51096
- ctx.fillText(String(i + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
51128
+ for (const row of visibleRows) {
51129
+ ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
51130
+ const zone = { top: row, bottom: row, left: left, right: left };
51131
+ const { y: rowStart, height: rowSize } = this.getters.getRect(zone);
51132
+ const { y, height } = this.getters.getVisibleRect(zone);
51133
+ ctx.save();
51134
+ ctx.beginPath();
51135
+ ctx.rect(0, y, HEADER_WIDTH, height);
51136
+ ctx.clip();
51137
+ ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
51138
+ ctx.restore();
51139
+ ctx.beginPath();
51097
51140
  ctx.moveTo(0, rowStart + rowSize);
51098
51141
  ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
51142
+ ctx.stroke();
51099
51143
  }
51100
- ctx.stroke();
51101
51144
  }
51102
51145
  drawFrozenPanesHeaders(renderingContext) {
51103
51146
  const { ctx, thinLineWidth } = renderingContext;
@@ -51400,6 +51443,9 @@ stores.inject(MyMetaStore, storeInstance);
51400
51443
  canvas.width = width * dpr;
51401
51444
  canvas.height = height * dpr;
51402
51445
  canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
51446
+ if (width === 0 || height === 0) {
51447
+ return;
51448
+ }
51403
51449
  // Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
51404
51450
  // are the edges of the squares. If you draw a one-unit-wide line between whole-number
51405
51451
  // coordinates, it will overlap opposite sides of the pixel square, and the resulting
@@ -51743,7 +51789,7 @@ stores.inject(MyMetaStore, storeInstance);
51743
51789
  leftOffset: 0,
51744
51790
  };
51745
51791
  get offset() {
51746
- return this.env.model.getters.getActiveSheetDOMScrollInfo().scrollX;
51792
+ return this.env.model.getters.getActiveSheetScrollInfo().scrollX;
51747
51793
  }
51748
51794
  get width() {
51749
51795
  return this.env.model.getters.getMainViewportRect().width;
@@ -51762,7 +51808,7 @@ stores.inject(MyMetaStore, storeInstance);
51762
51808
  };
51763
51809
  }
51764
51810
  onScroll(offset) {
51765
- const { scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
51811
+ const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
51766
51812
  this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
51767
51813
  offsetX: offset,
51768
51814
  offsetY: scrollY, // offsetY is the same
@@ -51788,7 +51834,7 @@ stores.inject(MyMetaStore, storeInstance);
51788
51834
  topOffset: 0,
51789
51835
  };
51790
51836
  get offset() {
51791
- return this.env.model.getters.getActiveSheetDOMScrollInfo().scrollY;
51837
+ return this.env.model.getters.getActiveSheetScrollInfo().scrollY;
51792
51838
  }
51793
51839
  get height() {
51794
51840
  return this.env.model.getters.getMainViewportRect().height;
@@ -51807,7 +51853,7 @@ stores.inject(MyMetaStore, storeInstance);
51807
51853
  };
51808
51854
  }
51809
51855
  onScroll(offset) {
51810
- const { scrollX } = this.env.model.getters.getActiveSheetDOMScrollInfo();
51856
+ const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
51811
51857
  this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
51812
51858
  offsetX: scrollX, // offsetX is the same
51813
51859
  offsetY: offset,
@@ -52278,7 +52324,7 @@ stores.inject(MyMetaStore, storeInstance);
52278
52324
  });
52279
52325
  }
52280
52326
  moveCanvas(deltaX, deltaY) {
52281
- const { scrollX, scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
52327
+ const { scrollX, scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
52282
52328
  this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
52283
52329
  offsetX: scrollX + deltaX,
52284
52330
  offsetY: scrollY + deltaY,
@@ -67159,8 +67205,6 @@ stores.inject(MyMetaStore, storeInstance);
67159
67205
  right;
67160
67206
  offsetX;
67161
67207
  offsetY;
67162
- offsetScrollbarX;
67163
- offsetScrollbarY;
67164
67208
  canScrollVertically;
67165
67209
  canScrollHorizontally;
67166
67210
  viewportWidth;
@@ -67171,10 +67215,17 @@ stores.inject(MyMetaStore, storeInstance);
67171
67215
  this.getters = getters;
67172
67216
  this.sheetId = sheetId;
67173
67217
  this.boundaries = boundaries;
67174
- this.viewportWidth = sizeInGrid.width;
67175
- this.viewportHeight = sizeInGrid.height;
67176
- this.offsetScrollbarX = offsets.x;
67177
- this.offsetScrollbarY = offsets.y;
67218
+ if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
67219
+ throw new Error("Viewport size cannot be negative");
67220
+ }
67221
+ this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
67222
+ this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
67223
+ this.top = boundaries.top;
67224
+ this.bottom = boundaries.bottom;
67225
+ this.left = boundaries.left;
67226
+ this.right = boundaries.right;
67227
+ this.offsetX = offsets.x;
67228
+ this.offsetY = offsets.y;
67178
67229
  this.canScrollVertically = options.canScrollVertically;
67179
67230
  this.canScrollHorizontally = options.canScrollHorizontally;
67180
67231
  this.offsetCorrectionX = this.getters.getColDimensions(this.sheetId, this.boundaries.left).start;
@@ -67215,9 +67266,9 @@ stores.inject(MyMetaStore, storeInstance);
67215
67266
  Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
67216
67267
  );
67217
67268
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
67218
- }
67219
- if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
67220
- height += FOOTER_HEIGHT;
67269
+ if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
67270
+ height += FOOTER_HEIGHT;
67271
+ }
67221
67272
  }
67222
67273
  return { width, height };
67223
67274
  }
@@ -67230,7 +67281,7 @@ stores.inject(MyMetaStore, storeInstance);
67230
67281
  if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
67231
67282
  return -1;
67232
67283
  }
67233
- return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left);
67284
+ return this.searchHeaderIndex("COL", x - this.offsetCorrectionX + this.snapCorrection.x, this.left);
67234
67285
  }
67235
67286
  /**
67236
67287
  * Return the index of a row given an offset y, based on the pane top
@@ -67241,7 +67292,7 @@ stores.inject(MyMetaStore, storeInstance);
67241
67292
  if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
67242
67293
  return -1;
67243
67294
  }
67244
- return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top);
67295
+ return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY + this.snapCorrection.y, this.top);
67245
67296
  }
67246
67297
  /**
67247
67298
  * This function will make sure that the provided cell position (or current selected position) is part of
@@ -67261,55 +67312,29 @@ stores.inject(MyMetaStore, storeInstance);
67261
67312
  }
67262
67313
  adjustPositionX(targetCol) {
67263
67314
  const sheetId = this.sheetId;
67264
- const { end } = this.getters.getColDimensions(sheetId, targetCol);
67265
- if (this.offsetX + this.offsetCorrectionX + this.viewportWidth < end) {
67266
- const maxCol = this.getters.getNumberCols(sheetId);
67267
- let finalTarget = targetCol;
67268
- while (this.getters.isColHidden(sheetId, finalTarget) && finalTarget < maxCol) {
67269
- finalTarget++;
67270
- }
67271
- const finalTargetEnd = this.getters.getColDimensions(sheetId, finalTarget).end;
67272
- const startIndex = this.searchHeaderIndex("COL", finalTargetEnd - this.viewportWidth - this.offsetCorrectionX, this.boundaries.left);
67273
- this.offsetScrollbarX =
67274
- this.getters.getColDimensions(sheetId, startIndex).end - this.offsetCorrectionX;
67275
- }
67276
- else if (this.left > targetCol) {
67277
- let finalTarget = targetCol;
67278
- while (this.getters.isColHidden(sheetId, finalTarget) && finalTarget > 0) {
67279
- finalTarget--;
67280
- }
67281
- this.offsetScrollbarX =
67282
- this.getters.getColDimensions(sheetId, finalTarget).start - this.offsetCorrectionX;
67315
+ const { start, end } = this.getters.getColDimensions(sheetId, targetCol);
67316
+ if (this.offsetX + this.viewportWidth + this.offsetCorrectionX < end) {
67317
+ this.offsetX = end - this.viewportWidth;
67318
+ }
67319
+ else if (this.offsetX + this.offsetCorrectionX > start) {
67320
+ this.offsetX = start - this.offsetCorrectionX;
67283
67321
  }
67284
67322
  this.adjustViewportZoneX();
67285
67323
  }
67286
67324
  adjustPositionY(targetRow) {
67287
67325
  const sheetId = this.sheetId;
67288
- const { end } = this.getters.getRowDimensions(sheetId, targetRow);
67326
+ const { start, end } = this.getters.getRowDimensions(sheetId, targetRow);
67289
67327
  if (this.offsetY + this.viewportHeight + this.offsetCorrectionY < end) {
67290
- const maxRow = this.getters.getNumberRows(sheetId);
67291
- let finalTarget = targetRow;
67292
- while (this.getters.isRowHidden(sheetId, finalTarget) && finalTarget < maxRow) {
67293
- finalTarget++;
67294
- }
67295
- const finalTargetEnd = this.getters.getRowDimensions(sheetId, finalTarget).end;
67296
- const startIndex = this.searchHeaderIndex("ROW", finalTargetEnd - this.viewportHeight - this.offsetCorrectionY, this.boundaries.top);
67297
- this.offsetScrollbarY =
67298
- this.getters.getRowDimensions(sheetId, startIndex).end - this.offsetCorrectionY;
67328
+ this.offsetY = end - this.viewportHeight;
67299
67329
  }
67300
- else if (this.top > targetRow) {
67301
- let finalTarget = targetRow;
67302
- while (this.getters.isRowHidden(sheetId, finalTarget) && finalTarget > 0) {
67303
- finalTarget--;
67304
- }
67305
- this.offsetScrollbarY =
67306
- this.getters.getRowDimensions(sheetId, finalTarget).start - this.offsetCorrectionY;
67330
+ else if (this.offsetY + this.offsetCorrectionY > start) {
67331
+ this.offsetY = start - this.offsetCorrectionY;
67307
67332
  }
67308
67333
  this.adjustViewportZoneY();
67309
67334
  }
67310
67335
  willNewOffsetScrollViewport(offsetX, offsetY) {
67311
- return ((this.canScrollHorizontally && this.offsetScrollbarX !== offsetX) ||
67312
- (this.canScrollVertically && this.offsetScrollbarY !== offsetY));
67336
+ return ((this.canScrollHorizontally && this.offsetX !== offsetX) ||
67337
+ (this.canScrollVertically && this.offsetY !== offsetY));
67313
67338
  }
67314
67339
  setViewportOffset(offsetX, offsetY) {
67315
67340
  this.setViewportOffsetX(offsetX);
@@ -67326,11 +67351,19 @@ stores.inject(MyMetaStore, storeInstance);
67326
67351
  */
67327
67352
  getVisibleRect(zone) {
67328
67353
  const targetZone = intersection(zone, this);
67354
+ const scrollDeltaX = this.snapCorrection.x;
67355
+ const scrollDeltaY = this.snapCorrection.y;
67329
67356
  if (targetZone) {
67330
- const x = this.getters.getColRowOffset("COL", this.left, targetZone.left) + this.offsetCorrectionX;
67331
- const y = this.getters.getColRowOffset("ROW", this.top, targetZone.top) + this.offsetCorrectionY;
67332
- const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
67333
- const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
67357
+ const x = this.getters.getColRowOffset("COL", this.left, targetZone.left) +
67358
+ this.offsetCorrectionX -
67359
+ (this.left !== targetZone.left ? scrollDeltaX : 0);
67360
+ const y = this.getters.getColRowOffset("ROW", this.top, targetZone.top) +
67361
+ this.offsetCorrectionY -
67362
+ (this.top !== targetZone.top ? scrollDeltaY : 0);
67363
+ const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1) -
67364
+ (this.left === targetZone.left ? scrollDeltaX : 0), this.viewportWidth);
67365
+ const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1) -
67366
+ (this.top === targetZone.top ? scrollDeltaY : 0), this.viewportHeight);
67334
67367
  return { x, y, width, height };
67335
67368
  }
67336
67369
  return undefined;
@@ -67342,12 +67375,14 @@ stores.inject(MyMetaStore, storeInstance);
67342
67375
  */
67343
67376
  getFullRect(zone) {
67344
67377
  const targetZone = intersection(zone, this);
67378
+ const scrollDeltaX = this.snapCorrection.x;
67379
+ const scrollDeltaY = this.snapCorrection.y;
67345
67380
  if (targetZone) {
67346
67381
  const x = this.getters.getColRowOffset("COL", this.left, zone.left) + this.offsetCorrectionX;
67347
67382
  const y = this.getters.getColRowOffset("ROW", this.top, zone.top) + this.offsetCorrectionY;
67348
67383
  const width = this.getters.getColRowOffset("COL", zone.left, zone.right + 1);
67349
67384
  const height = this.getters.getColRowOffset("ROW", zone.top, zone.bottom + 1);
67350
- return { x, y, width, height };
67385
+ return { x: x - scrollDeltaX, y: y - scrollDeltaY, width, height };
67351
67386
  }
67352
67387
  return undefined;
67353
67388
  }
@@ -67358,6 +67393,9 @@ stores.inject(MyMetaStore, storeInstance);
67358
67393
  !this.getters.isRowHidden(this.sheetId, row));
67359
67394
  }
67360
67395
  searchHeaderIndex(dimension, position, startIndex = 0) {
67396
+ if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
67397
+ return -1;
67398
+ }
67361
67399
  const sheetId = this.sheetId;
67362
67400
  const headers = this.getters.getNumberHeaders(sheetId, dimension);
67363
67401
  // using a binary search:
@@ -67383,36 +67421,36 @@ stores.inject(MyMetaStore, storeInstance);
67383
67421
  if (!this.canScrollHorizontally) {
67384
67422
  return;
67385
67423
  }
67386
- this.offsetScrollbarX = offsetX;
67424
+ this.offsetX = offsetX;
67387
67425
  this.adjustViewportZoneX();
67388
67426
  }
67389
67427
  setViewportOffsetY(offsetY) {
67390
67428
  if (!this.canScrollVertically) {
67391
67429
  return;
67392
67430
  }
67393
- this.offsetScrollbarY = offsetY;
67431
+ this.offsetY = offsetY;
67394
67432
  this.adjustViewportZoneY();
67395
67433
  }
67396
67434
  /** Corrects the viewport's horizontal offset based on the current structure
67397
- * To make sure that at least on column is visible inside the viewport.
67435
+ * To make sure that at least one column is visible inside the viewport.
67398
67436
  */
67399
67437
  adjustViewportOffsetX() {
67400
67438
  if (this.canScrollHorizontally) {
67401
67439
  const { width: viewportWidth } = this.getMaxSize();
67402
- if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
67403
- this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
67440
+ if (this.viewportWidth + this.offsetX > viewportWidth) {
67441
+ this.offsetX = Math.max(0, viewportWidth - this.viewportWidth);
67404
67442
  }
67405
67443
  }
67406
67444
  this.adjustViewportZoneX();
67407
67445
  }
67408
67446
  /** Corrects the viewport's vertical offset based on the current structure
67409
- * To make sure that at least on row is visible inside the viewport.
67447
+ * To make sure that at least one row is visible inside the viewport.
67410
67448
  */
67411
67449
  adjustViewportOffsetY() {
67412
67450
  if (this.canScrollVertically) {
67413
67451
  const { height: paneHeight } = this.getMaxSize();
67414
- if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
67415
- this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
67452
+ if (this.viewportHeight + this.offsetY > paneHeight) {
67453
+ this.offsetY = Math.max(0, paneHeight - this.viewportHeight);
67416
67454
  }
67417
67455
  }
67418
67456
  this.adjustViewportZoneY();
@@ -67420,34 +67458,47 @@ stores.inject(MyMetaStore, storeInstance);
67420
67458
  /** Updates the pane zone and snapped offset based on its horizontal
67421
67459
  * offset (will find Left) and its width (will find Right) */
67422
67460
  adjustViewportZoneX() {
67423
- const sheetId = this.sheetId;
67424
- this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
67425
- this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
67461
+ this.left = this.searchHeaderIndex("COL", this.offsetX, this.boundaries.left);
67462
+ this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL",
67463
+ // if we hit the border of two cells, we want to match the previous
67464
+ Math.max(this.viewportWidth + this.snapCorrection.x - 0.1), this.left));
67465
+ if (!this.viewportWidth) {
67466
+ return;
67467
+ }
67426
67468
  if (this.left === -1) {
67427
67469
  this.left = this.boundaries.left;
67428
67470
  }
67429
67471
  if (this.right === -1) {
67430
- this.right = this.getters.getNumberCols(sheetId) - 1;
67472
+ this.right = this.boundaries.right;
67431
67473
  }
67432
- this.offsetX =
67433
- this.getters.getColDimensions(sheetId, this.left).start -
67434
- this.getters.getColDimensions(sheetId, this.boundaries.left).start;
67435
67474
  }
67436
67475
  /** Updates the pane zone and snapped offset based on its vertical
67437
67476
  * offset (will find Top) and its width (will find Bottom) */
67438
67477
  adjustViewportZoneY() {
67439
- const sheetId = this.sheetId;
67440
- this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
67441
- this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
67478
+ this.top = this.searchHeaderIndex("ROW", this.offsetY, this.boundaries.top);
67479
+ this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW",
67480
+ // if we hit the border of two cells, we want to match the previous
67481
+ Math.max(this.viewportHeight + this.snapCorrection.y - 0.1, 0), this.top));
67482
+ if (!this.viewportHeight) {
67483
+ return;
67484
+ }
67442
67485
  if (this.top === -1) {
67443
67486
  this.top = this.boundaries.top;
67444
67487
  }
67445
67488
  if (this.bottom === -1) {
67446
- this.bottom = this.getters.getNumberRows(sheetId) - 1;
67489
+ this.bottom = this.boundaries.bottom;
67447
67490
  }
67448
- this.offsetY =
67449
- this.getters.getRowDimensions(sheetId, this.top).start -
67450
- this.getters.getRowDimensions(sheetId, this.boundaries.top).start;
67491
+ }
67492
+ /** represents the part of the header on the topLeft that could be partially
67493
+ * hidden due to the scroll
67494
+ * */
67495
+ get snapCorrection() {
67496
+ return {
67497
+ x: Math.abs(this.offsetX -
67498
+ this.getters.getColRowOffset("COL", this.boundaries.left, Math.max(0, this.left))),
67499
+ y: Math.abs(this.offsetY -
67500
+ this.getters.getColRowOffset("ROW", this.boundaries.top, Math.max(0, this.top))),
67501
+ };
67451
67502
  }
67452
67503
  }
67453
67504
 
@@ -67510,14 +67561,13 @@ stores.inject(MyMetaStore, storeInstance);
67510
67561
  "getColRowOffsetInViewport",
67511
67562
  "getMainViewportCoordinates",
67512
67563
  "getActiveSheetScrollInfo",
67513
- "getActiveSheetDOMScrollInfo",
67514
67564
  "getSheetViewVisibleCols",
67515
67565
  "getSheetViewVisibleRows",
67516
67566
  "getFrozenSheetViewRatio",
67517
67567
  "isPixelPositionVisible",
67518
67568
  "getColDimensionsInViewport",
67519
67569
  "getRowDimensionsInViewport",
67520
- "getAllActiveViewportsZones",
67570
+ "getAllActiveViewportsZonesAndRect",
67521
67571
  "getRect",
67522
67572
  ];
67523
67573
  viewports = {};
@@ -67720,8 +67770,8 @@ stores.inject(MyMetaStore, storeInstance);
67720
67770
  return this.getMainViewport(sheetId);
67721
67771
  }
67722
67772
  /**
67723
- * Return the scroll info of the active sheet, ie. the offset between the viewport left/top side and
67724
- * the grid left/top side, snapped to the columns/rows.
67773
+ * Return the DOM scroll info of the active sheet, ie. the offset between the viewport left/top side and
67774
+ * the grid left/top side, corresponding to the scroll of the scrollbars and not snapped to the grid.
67725
67775
  */
67726
67776
  getActiveSheetScrollInfo() {
67727
67777
  const sheetId = this.getters.getActiveSheetId();
@@ -67731,28 +67781,16 @@ stores.inject(MyMetaStore, storeInstance);
67731
67781
  scrollY: viewport.offsetY,
67732
67782
  };
67733
67783
  }
67734
- /**
67735
- * Return the DOM scroll info of the active sheet, ie. the offset between the viewport left/top side and
67736
- * the grid left/top side, corresponding to the scroll of the scrollbars and not snapped to the grid.
67737
- */
67738
- getActiveSheetDOMScrollInfo() {
67739
- const sheetId = this.getters.getActiveSheetId();
67740
- const viewport = this.getMainInternalViewport(sheetId);
67741
- return {
67742
- scrollX: viewport.offsetScrollbarX,
67743
- scrollY: viewport.offsetScrollbarY,
67744
- };
67745
- }
67746
67784
  getSheetViewVisibleCols() {
67747
67785
  const sheetId = this.getters.getActiveSheetId();
67748
67786
  const viewports = this.getSubViewports(sheetId);
67749
67787
  //TODO ake another commit to eimprove this
67750
- return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
67788
+ return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
67751
67789
  }
67752
67790
  getSheetViewVisibleRows() {
67753
67791
  const sheetId = this.getters.getActiveSheetId();
67754
67792
  const viewports = this.getSubViewports(sheetId);
67755
- return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
67793
+ return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
67756
67794
  }
67757
67795
  /**
67758
67796
  * Get the positions of all the cells that are visible in the viewport, taking merges into account.
@@ -67795,19 +67833,19 @@ stores.inject(MyMetaStore, storeInstance);
67795
67833
  maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
67796
67834
  };
67797
67835
  }
67798
- getColRowOffsetInViewport(dimension, referenceIndex, index) {
67799
- const sheetId = this.getters.getActiveSheetId();
67800
- const visibleCols = this.getters.getSheetViewVisibleCols();
67801
- const visibleRows = this.getters.getSheetViewVisibleRows();
67802
- if (index < referenceIndex) {
67803
- return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
67836
+ getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
67837
+ if (targetHeaderIndex < referenceHeaderIndex) {
67838
+ return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
67804
67839
  }
67840
+ const sheetId = this.getters.getActiveSheetId();
67841
+ const visibleHeaders = dimension === "COL"
67842
+ ? this.getters.getSheetViewVisibleCols()
67843
+ : this.getters.getSheetViewVisibleRows();
67844
+ const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
67845
+ const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
67846
+ const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
67805
67847
  let offset = 0;
67806
- const visibleIndexes = dimension === "COL" ? visibleCols : visibleRows;
67807
- for (let i = referenceIndex; i < index; i++) {
67808
- if (!visibleIndexes.includes(i)) {
67809
- continue;
67810
- }
67848
+ for (const i of relevantIndexes) {
67811
67849
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
67812
67850
  }
67813
67851
  return offset;
@@ -67854,7 +67892,7 @@ stores.inject(MyMetaStore, storeInstance);
67854
67892
  }
67855
67893
  return { canEdgeScroll, direction, delay };
67856
67894
  }
67857
- getEdgeScrollRow(y, previousY, tartingY) {
67895
+ getEdgeScrollRow(y, previousY, startingY) {
67858
67896
  let canEdgeScroll = false;
67859
67897
  let direction = 0;
67860
67898
  let delay = 0;
@@ -67875,7 +67913,7 @@ stores.inject(MyMetaStore, storeInstance);
67875
67913
  delay = scrollDelay(y - height);
67876
67914
  direction = 1;
67877
67915
  }
67878
- else if (y < offsetCorrectionY && tartingY >= offsetCorrectionY && currentOffsetY > 0) {
67916
+ else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
67879
67917
  // 2
67880
67918
  canEdgeScroll = true;
67881
67919
  delay = scrollDelay(offsetCorrectionY - y);
@@ -67901,13 +67939,7 @@ stores.inject(MyMetaStore, storeInstance);
67901
67939
  */
67902
67940
  getVisibleRectWithoutHeaders(zone) {
67903
67941
  const sheetId = this.getters.getActiveSheetId();
67904
- const viewportRects = this.getSubViewports(sheetId)
67905
- .map((viewport) => viewport.getVisibleRect(zone))
67906
- .filter(isDefined);
67907
- if (viewportRects.length === 0) {
67908
- return { x: 0, y: 0, width: 0, height: 0 };
67909
- }
67910
- return this.recomposeRect(viewportRects);
67942
+ return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
67911
67943
  }
67912
67944
  /**
67913
67945
  * Computes the actual size and position (:Rect) of the zone on the canvas
@@ -67915,13 +67947,7 @@ stores.inject(MyMetaStore, storeInstance);
67915
67947
  */
67916
67948
  getRect(zone) {
67917
67949
  const sheetId = this.getters.getActiveSheetId();
67918
- const viewportRects = this.getSubViewports(sheetId)
67919
- .map((viewport) => viewport.getFullRect(zone))
67920
- .filter(isDefined);
67921
- if (viewportRects.length === 0) {
67922
- return { x: 0, y: 0, width: 0, height: 0 };
67923
- }
67924
- const rect = this.recomposeRect(viewportRects);
67950
+ const rect = this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
67925
67951
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
67926
67952
  }
67927
67953
  /**
@@ -67941,34 +67967,43 @@ stores.inject(MyMetaStore, storeInstance);
67941
67967
  * column of the current viewport
67942
67968
  */
67943
67969
  getColDimensionsInViewport(sheetId, col) {
67944
- const left = largeMin(this.getters.getSheetViewVisibleCols());
67945
- const start = this.getters.getColRowOffsetInViewport("COL", left, col);
67946
- const size = this.getters.getColSize(sheetId, col);
67947
- const isColHidden = this.getters.isColHidden(sheetId, col);
67948
- return {
67949
- start,
67950
- size: size,
67951
- end: start + (isColHidden ? 0 : size),
67970
+ const zone = {
67971
+ left: col,
67972
+ right: col,
67973
+ top: 0,
67974
+ bottom: this.getters.getNumberRows(sheetId) - 1,
67952
67975
  };
67976
+ const { x, width } = this.getVisibleRect(zone);
67977
+ const start = x - this.gridOffsetX;
67978
+ return { start, size: width, end: start + width };
67953
67979
  }
67954
67980
  /**
67955
67981
  * Returns the size, start and end coordinates of a row relative to the top row
67956
67982
  * of the current viewport
67957
67983
  */
67958
67984
  getRowDimensionsInViewport(sheetId, row) {
67959
- const top = largeMin(this.getters.getSheetViewVisibleRows());
67960
- const start = this.getters.getColRowOffsetInViewport("ROW", top, row);
67961
- const size = this.getters.getRowSize(sheetId, row);
67962
- const isRowHidden = this.getters.isRowHidden(sheetId, row);
67963
- return {
67964
- start,
67965
- size: size,
67966
- end: start + (isRowHidden ? 0 : size),
67985
+ const zone = {
67986
+ left: 0,
67987
+ right: this.getters.getNumberCols(sheetId) - 1,
67988
+ top: row,
67989
+ bottom: row,
67967
67990
  };
67991
+ const { y, height } = this.getVisibleRect(zone);
67992
+ const start = y - this.gridOffsetY;
67993
+ return { start, size: height, end: start + height };
67968
67994
  }
67969
- getAllActiveViewportsZones() {
67995
+ getAllActiveViewportsZonesAndRect() {
67970
67996
  const sheetId = this.getters.getActiveSheetId();
67971
- return this.getSubViewports(sheetId);
67997
+ return this.getSubViewports(sheetId).map((viewport) => {
67998
+ return {
67999
+ zone: viewport,
68000
+ rect: {
68001
+ x: viewport.offsetCorrectionX + this.gridOffsetX,
68002
+ y: viewport.offsetCorrectionY + this.gridOffsetY,
68003
+ ...viewport.getMaxSize(),
68004
+ },
68005
+ };
68006
+ });
67972
68007
  }
67973
68008
  // ---------------------------------------------------------------------------
67974
68009
  // Private
@@ -68027,12 +68062,11 @@ stores.inject(MyMetaStore, storeInstance);
68027
68062
  }
68028
68063
  /** gets rid of deprecated sheetIds */
68029
68064
  cleanViewports() {
68030
- const sheetIds = this.getters.getSheetIds();
68031
- for (let sheetId of Object.keys(this.viewports)) {
68032
- if (!sheetIds.includes(sheetId)) {
68033
- delete this.viewports[sheetId];
68034
- }
68065
+ const newViewport = {};
68066
+ for (const sheetId of this.getters.getSheetIds()) {
68067
+ newViewport[sheetId] = this.viewports[sheetId];
68035
68068
  }
68069
+ this.viewports = newViewport;
68036
68070
  }
68037
68071
  resizeSheetView(height, width, gridOffsetX = 0, gridOffsetY = 0) {
68038
68072
  this.sheetViewHeight = height;
@@ -68042,7 +68076,7 @@ stores.inject(MyMetaStore, storeInstance);
68042
68076
  this.recomputeViewports();
68043
68077
  }
68044
68078
  recomputeViewports() {
68045
- for (let sheetId of Object.keys(this.viewports)) {
68079
+ for (const sheetId of this.getters.getSheetIds()) {
68046
68080
  this.resetViewports(sheetId);
68047
68081
  }
68048
68082
  }
@@ -68053,8 +68087,8 @@ stores.inject(MyMetaStore, storeInstance);
68053
68087
  }
68054
68088
  getViewportOffset(sheetId) {
68055
68089
  return {
68056
- x: this.viewports[sheetId]?.bottomRight.offsetScrollbarX || 0,
68057
- y: this.viewports[sheetId]?.bottomRight.offsetScrollbarY || 0,
68090
+ x: this.viewports[sheetId]?.bottomRight.offsetX || 0,
68091
+ y: this.viewports[sheetId]?.bottomRight.offsetY || 0,
68058
68092
  };
68059
68093
  }
68060
68094
  resetViewports(sheetId) {
@@ -68064,8 +68098,10 @@ stores.inject(MyMetaStore, storeInstance);
68064
68098
  const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
68065
68099
  const nCols = this.getters.getNumberCols(sheetId);
68066
68100
  const nRows = this.getters.getNumberRows(sheetId);
68067
- const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
68068
- const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
68101
+ const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
68102
+ const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
68103
+ const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
68104
+ const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
68069
68105
  const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
68070
68106
  const canScrollHorizontally = xRatio < 1.0;
68071
68107
  const canScrollVertically = yRatio < 1.0;
@@ -68076,14 +68112,14 @@ stores.inject(MyMetaStore, storeInstance);
68076
68112
  new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: 0, bottom: ySplit - 1 }, { width: colOffset, height: rowOffset }, { canScrollHorizontally: false, canScrollVertically: false }, { x: 0, y: 0 })) ||
68077
68113
  undefined,
68078
68114
  topRight: (ySplit &&
68079
- new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: 0, bottom: ySplit - 1 }, { width: this.sheetViewWidth - colOffset, height: rowOffset }, { canScrollHorizontally, canScrollVertically: false }, { x: canScrollHorizontally ? previousOffset.x : 0, y: 0 })) ||
68115
+ new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: 0, bottom: ySplit - 1 }, { width: unfrozenWidth, height: rowOffset }, { canScrollHorizontally, canScrollVertically: false }, { x: canScrollHorizontally ? previousOffset.x : 0, y: 0 })) ||
68080
68116
  undefined,
68081
68117
  bottomLeft: (xSplit &&
68082
- new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: ySplit, bottom: nRows - 1 }, { width: colOffset, height: this.sheetViewHeight - rowOffset }, { canScrollHorizontally: false, canScrollVertically }, { x: 0, y: canScrollVertically ? previousOffset.y : 0 })) ||
68118
+ new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: ySplit, bottom: nRows - 1 }, { width: colOffset, height: unfrozenHeight }, { canScrollHorizontally: false, canScrollVertically }, { x: 0, y: canScrollVertically ? previousOffset.y : 0 })) ||
68083
68119
  undefined,
68084
68120
  bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
68085
- width: this.sheetViewWidth - colOffset,
68086
- height: this.sheetViewHeight - rowOffset,
68121
+ width: unfrozenWidth,
68122
+ height: unfrozenHeight,
68087
68123
  }, { canScrollHorizontally, canScrollVertically }, {
68088
68124
  x: canScrollHorizontally ? previousOffset.x : 0,
68089
68125
  y: canScrollVertically ? previousOffset.y : 0,
@@ -68160,12 +68196,26 @@ stores.inject(MyMetaStore, storeInstance);
68160
68196
  const height = this.sheetViewHeight + this.gridOffsetY;
68161
68197
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
68162
68198
  }
68163
- recomposeRect(viewportRects) {
68164
- const x = Math.min(...viewportRects.map((rect) => rect.x));
68165
- const y = Math.min(...viewportRects.map((rect) => rect.y));
68166
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
68167
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
68168
- return { x, y, width, height };
68199
+ mapViewportsToRect(sheetId, rectCallBack) {
68200
+ let x = Infinity;
68201
+ let y = Infinity;
68202
+ let width = 0;
68203
+ let height = 0;
68204
+ let hasViewports = false;
68205
+ for (const viewport of this.getSubViewports(sheetId)) {
68206
+ const rect = rectCallBack(viewport);
68207
+ if (rect) {
68208
+ hasViewports = true;
68209
+ x = Math.min(x, rect.x);
68210
+ y = Math.min(y, rect.y);
68211
+ width = Math.max(width, rect.x + rect.width);
68212
+ height = Math.max(height, rect.y + rect.height);
68213
+ }
68214
+ }
68215
+ if (!hasViewports) {
68216
+ return { x: 0, y: 0, width: 0, height: 0 };
68217
+ }
68218
+ return { x, y, width: width - x, height: height - y };
68169
68219
  }
68170
68220
  }
68171
68221
 
@@ -69340,7 +69390,7 @@ stores.inject(MyMetaStore, storeInstance);
69340
69390
  });
69341
69391
  }
69342
69392
  moveCanvas(deltaX, deltaY) {
69343
- const { scrollX, scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
69393
+ const { scrollX, scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
69344
69394
  this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
69345
69395
  offsetX: scrollX + deltaX,
69346
69396
  offsetY: scrollY + deltaY,
@@ -75328,9 +75378,9 @@ stores.inject(MyMetaStore, storeInstance);
75328
75378
  exports.tokenize = tokenize;
75329
75379
 
75330
75380
 
75331
- __info__.version = "18.2.0-alpha.5";
75332
- __info__.date = "2025-01-31T07:59:30.667Z";
75333
- __info__.hash = "efce841";
75381
+ __info__.version = "18.2.0-alpha.6";
75382
+ __info__.date = "2025-02-05T06:50:47.008Z";
75383
+ __info__.hash = "dae9ab2";
75334
75384
 
75335
75385
 
75336
75386
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);