@odoo/o-spreadsheet 18.2.0-alpha.4 → 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.
- package/dist/o-spreadsheet.cjs.js +596 -491
- package/dist/o-spreadsheet.d.ts +31 -66
- package/dist/o-spreadsheet.esm.js +596 -491
- package/dist/o-spreadsheet.iife.js +596 -491
- package/dist/o-spreadsheet.iife.min.js +214 -218
- package/dist/o_spreadsheet.xml +5553 -5540
- package/package.json +8 -5
|
@@ -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.
|
|
6
|
-
* @date 2025-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.2.0-alpha.6
|
|
6
|
+
* @date 2025-02-05T06:50:47.008Z
|
|
7
|
+
* @hash dae9ab2
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -3361,11 +3361,11 @@ const getInvaluableSymbolsRegexp = memoize(function getInvaluableSymbolsRegexp(l
|
|
|
3361
3361
|
* number from the point of view of the isNumber function.
|
|
3362
3362
|
*/
|
|
3363
3363
|
function parseNumber(str, locale) {
|
|
3364
|
+
// remove invaluable characters
|
|
3365
|
+
str = str.replace(getInvaluableSymbolsRegexp(locale), "");
|
|
3364
3366
|
if (locale.decimalSeparator !== ".") {
|
|
3365
3367
|
str = str.replace(locale.decimalSeparator, ".");
|
|
3366
3368
|
}
|
|
3367
|
-
// remove invaluable characters
|
|
3368
|
-
str = str.replace(getInvaluableSymbolsRegexp(locale), "");
|
|
3369
3369
|
let n = Number(str);
|
|
3370
3370
|
if (isNaN(n) && str.includes("%")) {
|
|
3371
3371
|
n = Number(str.split("%")[0]);
|
|
@@ -18634,19 +18634,20 @@ const HLOOKUP = {
|
|
|
18634
18634
|
description: _t("Horizontal lookup"),
|
|
18635
18635
|
args: [
|
|
18636
18636
|
arg("search_key (string, number, boolean)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
|
|
18637
|
-
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.")),
|
|
18637
|
+
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.")),
|
|
18638
18638
|
arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
|
|
18639
18639
|
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.")),
|
|
18640
18640
|
],
|
|
18641
18641
|
compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
|
|
18642
18642
|
const _index = Math.trunc(toNumber(index?.value, this.locale));
|
|
18643
|
-
|
|
18643
|
+
const _range = toMatrix(range);
|
|
18644
|
+
assert(() => 1 <= _index && _index <= _range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
|
|
18644
18645
|
const getValueFromRange = (range, index) => range[index][0].value;
|
|
18645
18646
|
const _isSorted = toBoolean(isSorted.value);
|
|
18646
18647
|
const colIndex = _isSorted
|
|
18647
|
-
? dichotomicSearch(
|
|
18648
|
-
: linearSearch(
|
|
18649
|
-
const col =
|
|
18648
|
+
? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
|
|
18649
|
+
: linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange);
|
|
18650
|
+
const col = _range[colIndex];
|
|
18650
18651
|
if (col === undefined) {
|
|
18651
18652
|
return valueNotAvailable(searchKey);
|
|
18652
18653
|
}
|
|
@@ -18738,35 +18739,37 @@ const LOOKUP = {
|
|
|
18738
18739
|
description: _t("Look up a value."),
|
|
18739
18740
|
args: [
|
|
18740
18741
|
arg("search_key (string, number, boolean)", _t("The value to search for. For example, 42, 'Cats', or I24.")),
|
|
18741
|
-
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.")),
|
|
18742
|
-
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.")),
|
|
18742
|
+
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.")),
|
|
18743
|
+
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.")),
|
|
18743
18744
|
],
|
|
18744
18745
|
compute: function (searchKey, searchArray, resultRange) {
|
|
18745
|
-
|
|
18746
|
-
|
|
18746
|
+
const _searchArray = toMatrix(searchArray);
|
|
18747
|
+
const _resultRange = toMatrix(resultRange);
|
|
18748
|
+
let nbCol = _searchArray.length;
|
|
18749
|
+
let nbRow = _searchArray[0].length;
|
|
18747
18750
|
const verticalSearch = nbRow >= nbCol;
|
|
18748
18751
|
const getElement = verticalSearch
|
|
18749
18752
|
? (range, index) => range[0][index].value
|
|
18750
18753
|
: (range, index) => range[index][0].value;
|
|
18751
18754
|
const rangeLength = verticalSearch ? nbRow : nbCol;
|
|
18752
|
-
const index = dichotomicSearch(
|
|
18755
|
+
const index = dichotomicSearch(_searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
|
|
18753
18756
|
if (index === -1 ||
|
|
18754
|
-
(verticalSearch &&
|
|
18755
|
-
(!verticalSearch &&
|
|
18757
|
+
(verticalSearch && _searchArray[0][index] === undefined) ||
|
|
18758
|
+
(!verticalSearch && _searchArray[index][nbRow - 1] === undefined)) {
|
|
18756
18759
|
return valueNotAvailable(searchKey);
|
|
18757
18760
|
}
|
|
18758
|
-
if (
|
|
18759
|
-
return verticalSearch ?
|
|
18761
|
+
if (_resultRange[0].length === 0) {
|
|
18762
|
+
return verticalSearch ? _searchArray[nbCol - 1][index] : _searchArray[index][nbRow - 1];
|
|
18760
18763
|
}
|
|
18761
|
-
nbCol =
|
|
18762
|
-
nbRow =
|
|
18764
|
+
nbCol = _resultRange.length;
|
|
18765
|
+
nbRow = _resultRange[0].length;
|
|
18763
18766
|
assert(() => nbCol === 1 || nbRow === 1, _t("The result_range must be a single row or a single column."));
|
|
18764
18767
|
if (nbCol > 1) {
|
|
18765
18768
|
assert(() => index <= nbCol - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range row value %s.", (index + 1).toString()));
|
|
18766
|
-
return
|
|
18769
|
+
return _resultRange[index][0];
|
|
18767
18770
|
}
|
|
18768
18771
|
assert(() => index <= nbRow - 1, _t("[[FUNCTION_NAME]] evaluates to an out of range column value %s.", (index + 1).toString()));
|
|
18769
|
-
return
|
|
18772
|
+
return _resultRange[0][index];
|
|
18770
18773
|
},
|
|
18771
18774
|
isExported: true,
|
|
18772
18775
|
};
|
|
@@ -18783,28 +18786,29 @@ const MATCH = {
|
|
|
18783
18786
|
],
|
|
18784
18787
|
compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
|
|
18785
18788
|
let _searchType = toNumber(searchType, this.locale);
|
|
18786
|
-
const
|
|
18787
|
-
const
|
|
18789
|
+
const _range = toMatrix(range);
|
|
18790
|
+
const nbCol = _range.length;
|
|
18791
|
+
const nbRow = _range[0].length;
|
|
18788
18792
|
assert(() => nbCol === 1 || nbRow === 1, _t("The range must be a single row or a single column."));
|
|
18789
18793
|
let index = -1;
|
|
18790
18794
|
const getElement = nbCol === 1
|
|
18791
|
-
? (
|
|
18792
|
-
: (
|
|
18793
|
-
const rangeLen = nbCol === 1 ?
|
|
18795
|
+
? (_range, index) => _range[0][index].value
|
|
18796
|
+
: (_range, index) => _range[index][0].value;
|
|
18797
|
+
const rangeLen = nbCol === 1 ? _range[0].length : _range.length;
|
|
18794
18798
|
_searchType = Math.sign(_searchType);
|
|
18795
18799
|
switch (_searchType) {
|
|
18796
18800
|
case 1:
|
|
18797
|
-
index = dichotomicSearch(
|
|
18801
|
+
index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
|
|
18798
18802
|
break;
|
|
18799
18803
|
case 0:
|
|
18800
|
-
index = linearSearch(
|
|
18804
|
+
index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement);
|
|
18801
18805
|
break;
|
|
18802
18806
|
case -1:
|
|
18803
|
-
index = dichotomicSearch(
|
|
18807
|
+
index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
|
|
18804
18808
|
break;
|
|
18805
18809
|
}
|
|
18806
|
-
if ((nbCol === 1 &&
|
|
18807
|
-
(nbCol !== 1 &&
|
|
18810
|
+
if ((nbCol === 1 && _range[0][index] === undefined) ||
|
|
18811
|
+
(nbCol !== 1 && _range[index] === undefined)) {
|
|
18808
18812
|
return valueNotAvailable(searchKey);
|
|
18809
18813
|
}
|
|
18810
18814
|
return index + 1;
|
|
@@ -18859,13 +18863,14 @@ const VLOOKUP = {
|
|
|
18859
18863
|
],
|
|
18860
18864
|
compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
|
|
18861
18865
|
const _index = Math.trunc(toNumber(index?.value, this.locale));
|
|
18862
|
-
|
|
18866
|
+
const _range = toMatrix(range);
|
|
18867
|
+
assert(() => 1 <= _index && _index <= _range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
|
|
18863
18868
|
const getValueFromRange = (range, index) => range[0][index].value;
|
|
18864
18869
|
const _isSorted = toBoolean(isSorted.value);
|
|
18865
18870
|
const rowIndex = _isSorted
|
|
18866
|
-
? dichotomicSearch(
|
|
18867
|
-
: linearSearch(
|
|
18868
|
-
const value =
|
|
18871
|
+
? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
|
|
18872
|
+
: linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange);
|
|
18873
|
+
const value = _range[_index - 1][rowIndex];
|
|
18869
18874
|
if (value === undefined) {
|
|
18870
18875
|
return valueNotAvailable(searchKey);
|
|
18871
18876
|
}
|
|
@@ -18902,27 +18907,29 @@ const XLOOKUP = {
|
|
|
18902
18907
|
compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
|
|
18903
18908
|
const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
|
|
18904
18909
|
const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
|
|
18905
|
-
|
|
18910
|
+
const _lookupRange = toMatrix(lookupRange);
|
|
18911
|
+
const _returnRange = toMatrix(returnRange);
|
|
18912
|
+
assert(() => _lookupRange.length === 1 || _lookupRange[0].length === 1, _t("lookup_range should be either a single row or single column."));
|
|
18906
18913
|
assert(() => [-1, 1, -2, 2].includes(_searchMode), _t("search_mode should be a value in [-1, 1, -2, 2]."));
|
|
18907
18914
|
assert(() => [-1, 0, 1, 2].includes(_matchMode), _t("match_mode should be a value in [-1, 0, 1, 2]."));
|
|
18908
|
-
const lookupDirection =
|
|
18915
|
+
const lookupDirection = _lookupRange.length === 1 ? "col" : "row";
|
|
18909
18916
|
assert(() => !(_matchMode === 2 && [-2, 2].includes(_searchMode)), _t("the search and match mode combination is not supported for XLOOKUP evaluation."));
|
|
18910
18917
|
assert(() => lookupDirection === "col"
|
|
18911
|
-
?
|
|
18912
|
-
:
|
|
18918
|
+
? _returnRange[0].length === _lookupRange[0].length
|
|
18919
|
+
: _returnRange.length === _lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
|
|
18913
18920
|
const getElement = lookupDirection === "col"
|
|
18914
18921
|
? (range, index) => range[0][index].value
|
|
18915
18922
|
: (range, index) => range[index][0].value;
|
|
18916
|
-
const rangeLen = lookupDirection === "col" ?
|
|
18923
|
+
const rangeLen = lookupDirection === "col" ? _lookupRange[0].length : _lookupRange.length;
|
|
18917
18924
|
const mode = MATCH_MODE[_matchMode];
|
|
18918
18925
|
const reverseSearch = _searchMode === -1;
|
|
18919
18926
|
const index = _searchMode === 2 || _searchMode === -2
|
|
18920
|
-
? dichotomicSearch(
|
|
18921
|
-
: linearSearch(
|
|
18927
|
+
? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
|
|
18928
|
+
: linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
|
|
18922
18929
|
if (index !== -1) {
|
|
18923
18930
|
return lookupDirection === "col"
|
|
18924
|
-
?
|
|
18925
|
-
: [
|
|
18931
|
+
? _returnRange.map((col) => [col[index]])
|
|
18932
|
+
: [_returnRange[index]];
|
|
18926
18933
|
}
|
|
18927
18934
|
if (defaultValue === undefined) {
|
|
18928
18935
|
return valueNotAvailable(searchKey);
|
|
@@ -28458,11 +28465,7 @@ function interpolateData(config, values, labels, newLabels) {
|
|
|
28458
28465
|
if (values.length < 2 || labels.length < 2 || newLabels.length === 0) {
|
|
28459
28466
|
return [];
|
|
28460
28467
|
}
|
|
28461
|
-
const
|
|
28462
|
-
const labelMax = Math.max(...labels);
|
|
28463
|
-
const labelRange = labelMax - labelMin;
|
|
28464
|
-
const normalizedLabels = labels.map((v) => (v - labelMin) / labelRange);
|
|
28465
|
-
const normalizedNewLabels = newLabels.map((v) => (v - labelMin) / labelRange);
|
|
28468
|
+
const { normalizedLabels, normalizedNewLabels } = normalizeLabels(labels, newLabels, config);
|
|
28466
28469
|
try {
|
|
28467
28470
|
switch (config.type) {
|
|
28468
28471
|
case "polynomial": {
|
|
@@ -28507,6 +28510,30 @@ function interpolateData(config, values, labels, newLabels) {
|
|
|
28507
28510
|
return newLabels.map((x) => ({ x, y: NaN }));
|
|
28508
28511
|
}
|
|
28509
28512
|
}
|
|
28513
|
+
function normalizeLabels(labels, newLabels, config) {
|
|
28514
|
+
let normalizedLabels = [];
|
|
28515
|
+
let normalizedNewLabels = [];
|
|
28516
|
+
if (config.type === "logarithmic") {
|
|
28517
|
+
// Logarithmic trends in charts are used to visualize proportional growth or
|
|
28518
|
+
// relative changes. Therefore, we change the normalization technique for
|
|
28519
|
+
// logarithmic trend lines for a better fit. The method used here is Max Absolute
|
|
28520
|
+
// Scaling. This Technique is ideal for data spanning several orders of magnitude,
|
|
28521
|
+
// as it balances differences between small and large values by compressing larger
|
|
28522
|
+
// values while preserving proportionality and ensuring all values are scaled relative
|
|
28523
|
+
// to the largest magnitude.
|
|
28524
|
+
const labelMax = Math.max(...labels.map(Math.abs));
|
|
28525
|
+
normalizedLabels = labels.map((l) => l / labelMax);
|
|
28526
|
+
normalizedNewLabels = newLabels.map((l) => l / labelMax);
|
|
28527
|
+
}
|
|
28528
|
+
else {
|
|
28529
|
+
const labelMax = Math.max(...labels);
|
|
28530
|
+
const labelMin = Math.min(...labels);
|
|
28531
|
+
const labelRange = labelMax - labelMin;
|
|
28532
|
+
normalizedLabels = labels.map((l) => (l - labelMax) / labelRange);
|
|
28533
|
+
normalizedNewLabels = newLabels.map((l) => (l - labelMax) / labelRange);
|
|
28534
|
+
}
|
|
28535
|
+
return { normalizedLabels, normalizedNewLabels };
|
|
28536
|
+
}
|
|
28510
28537
|
function getChartAxisType(chart, labelRange, getters) {
|
|
28511
28538
|
if (isDateChart(chart, labelRange, getters) && isLuxonTimeAdapterInstalled()) {
|
|
28512
28539
|
return "time";
|
|
@@ -32538,36 +32565,58 @@ class ErrorToolTip extends owl.Component {
|
|
|
32538
32565
|
static maxSize = { maxHeight: ERROR_TOOLTIP_MAX_HEIGHT };
|
|
32539
32566
|
static template = "o-spreadsheet-ErrorToolTip";
|
|
32540
32567
|
static props = {
|
|
32541
|
-
|
|
32568
|
+
cellPosition: Object,
|
|
32542
32569
|
onClosed: { type: Function, optional: true },
|
|
32543
32570
|
};
|
|
32571
|
+
get dataValidationErrorMessage() {
|
|
32572
|
+
return this.env.model.getters.getInvalidDataValidationMessage(this.props.cellPosition);
|
|
32573
|
+
}
|
|
32574
|
+
get evaluationError() {
|
|
32575
|
+
const cell = this.env.model.getters.getEvaluatedCell(this.props.cellPosition);
|
|
32576
|
+
if (cell.message) {
|
|
32577
|
+
return cell;
|
|
32578
|
+
}
|
|
32579
|
+
return undefined;
|
|
32580
|
+
}
|
|
32581
|
+
get errorOriginPositionString() {
|
|
32582
|
+
const evaluationError = this.evaluationError;
|
|
32583
|
+
const position = evaluationError?.errorOriginPosition;
|
|
32584
|
+
if (!position || deepEquals(position, this.props.cellPosition)) {
|
|
32585
|
+
return "";
|
|
32586
|
+
}
|
|
32587
|
+
const sheetId = position.sheetId;
|
|
32588
|
+
return this.env.model.getters.getRangeString(this.env.model.getters.getRangeFromZone(sheetId, positionToZone(position)), this.env.model.getters.getActiveSheetId());
|
|
32589
|
+
}
|
|
32590
|
+
selectCell() {
|
|
32591
|
+
const position = this.evaluationError?.errorOriginPosition;
|
|
32592
|
+
if (!position) {
|
|
32593
|
+
return;
|
|
32594
|
+
}
|
|
32595
|
+
const activeSheetId = this.env.model.getters.getActiveSheetId();
|
|
32596
|
+
if (position.sheetId !== activeSheetId) {
|
|
32597
|
+
this.env.model.dispatch("ACTIVATE_SHEET", {
|
|
32598
|
+
sheetIdFrom: activeSheetId,
|
|
32599
|
+
sheetIdTo: position.sheetId,
|
|
32600
|
+
});
|
|
32601
|
+
}
|
|
32602
|
+
this.env.model.selection.selectCell(position.col, position.row);
|
|
32603
|
+
}
|
|
32544
32604
|
}
|
|
32545
32605
|
const ErrorToolTipPopoverBuilder = {
|
|
32546
32606
|
onHover: (position, getters) => {
|
|
32547
32607
|
const cell = getters.getEvaluatedCell(position);
|
|
32548
|
-
|
|
32549
|
-
|
|
32550
|
-
|
|
32551
|
-
|
|
32552
|
-
|
|
32553
|
-
|
|
32554
|
-
|
|
32555
|
-
|
|
32556
|
-
|
|
32557
|
-
|
|
32558
|
-
title: _t("Invalid"),
|
|
32559
|
-
message: validationErrorMessage,
|
|
32560
|
-
});
|
|
32561
|
-
}
|
|
32562
|
-
if (!errors.length) {
|
|
32563
|
-
return { isOpen: false };
|
|
32608
|
+
if ((cell.type === CellValueType.error && !!cell.message) ||
|
|
32609
|
+
getters.getInvalidDataValidationMessage(position)) {
|
|
32610
|
+
return {
|
|
32611
|
+
isOpen: true,
|
|
32612
|
+
props: {
|
|
32613
|
+
cellPosition: position,
|
|
32614
|
+
},
|
|
32615
|
+
Component: ErrorToolTip,
|
|
32616
|
+
cellCorner: "TopRight",
|
|
32617
|
+
};
|
|
32564
32618
|
}
|
|
32565
|
-
return {
|
|
32566
|
-
isOpen: true,
|
|
32567
|
-
props: { errors: errors },
|
|
32568
|
-
Component: ErrorToolTip,
|
|
32569
|
-
cellCorner: "TopRight",
|
|
32570
|
-
};
|
|
32619
|
+
return { isOpen: false };
|
|
32571
32620
|
},
|
|
32572
32621
|
};
|
|
32573
32622
|
|
|
@@ -33131,6 +33180,100 @@ function* iterateChildren(el) {
|
|
|
33131
33180
|
function getOpenedMenus() {
|
|
33132
33181
|
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
33133
33182
|
}
|
|
33183
|
+
function getCurrentSelection(el) {
|
|
33184
|
+
let { startElement, endElement, startSelectionOffset, endSelectionOffset } = getStartAndEndSelection(el);
|
|
33185
|
+
let startSizeBefore = findSelectionIndex(el, startElement, startSelectionOffset);
|
|
33186
|
+
let endSizeBefore = findSelectionIndex(el, endElement, endSelectionOffset);
|
|
33187
|
+
return {
|
|
33188
|
+
start: startSizeBefore,
|
|
33189
|
+
end: endSizeBefore,
|
|
33190
|
+
};
|
|
33191
|
+
}
|
|
33192
|
+
function getStartAndEndSelection(el) {
|
|
33193
|
+
const selection = document.getSelection();
|
|
33194
|
+
return {
|
|
33195
|
+
startElement: selection.anchorNode || el,
|
|
33196
|
+
startSelectionOffset: selection.anchorOffset,
|
|
33197
|
+
endElement: selection.focusNode || el,
|
|
33198
|
+
endSelectionOffset: selection.focusOffset,
|
|
33199
|
+
};
|
|
33200
|
+
}
|
|
33201
|
+
/**
|
|
33202
|
+
* Computes the text 'index' inside this.el based on the currently selected node and its offset.
|
|
33203
|
+
* The selected node is either a Text node or an Element node.
|
|
33204
|
+
*
|
|
33205
|
+
* case 1 -Text node:
|
|
33206
|
+
* the offset is the number of characters from the start of the node. We have to add this offset to the
|
|
33207
|
+
* content length of all previous nodes.
|
|
33208
|
+
*
|
|
33209
|
+
* case 2 - Element node:
|
|
33210
|
+
* the offset is the number of child nodes before the selected node. We have to add the content length of
|
|
33211
|
+
* all the nodes prior to the selected node as well as the content of the child node before the offset.
|
|
33212
|
+
*
|
|
33213
|
+
* See the MDN documentation for more details.
|
|
33214
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
|
|
33215
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
|
|
33216
|
+
*
|
|
33217
|
+
*/
|
|
33218
|
+
function findSelectionIndex(el, nodeToFind, nodeOffset) {
|
|
33219
|
+
let usedCharacters = 0;
|
|
33220
|
+
let it = iterateChildren(el);
|
|
33221
|
+
let current = it.next();
|
|
33222
|
+
let isFirstParagraph = true;
|
|
33223
|
+
while (!current.done && current.value !== nodeToFind) {
|
|
33224
|
+
if (!current.value.hasChildNodes()) {
|
|
33225
|
+
if (current.value.textContent) {
|
|
33226
|
+
usedCharacters += current.value.textContent.length;
|
|
33227
|
+
}
|
|
33228
|
+
}
|
|
33229
|
+
// One new paragraph = one new line character, except for the first paragraph
|
|
33230
|
+
if (current.value.nodeName === "P" ||
|
|
33231
|
+
(current.value.nodeName === "DIV" && current.value !== el) // On paste, the HTML may contain <div> instead of <p>
|
|
33232
|
+
) {
|
|
33233
|
+
if (isFirstParagraph) {
|
|
33234
|
+
isFirstParagraph = false;
|
|
33235
|
+
}
|
|
33236
|
+
else {
|
|
33237
|
+
usedCharacters++;
|
|
33238
|
+
}
|
|
33239
|
+
}
|
|
33240
|
+
current = it.next();
|
|
33241
|
+
}
|
|
33242
|
+
if (current.value !== nodeToFind) {
|
|
33243
|
+
/** This situation can happen if the code is called while the selection is not currently on the element.
|
|
33244
|
+
* In this case, we return 0 because we don't know the size of the text before the selection.
|
|
33245
|
+
*
|
|
33246
|
+
* A known occurrence is triggered since the introduction of commit d4663158 (PR #2038).
|
|
33247
|
+
*/
|
|
33248
|
+
return 0;
|
|
33249
|
+
}
|
|
33250
|
+
else {
|
|
33251
|
+
if (!current.value.hasChildNodes()) {
|
|
33252
|
+
usedCharacters += nodeOffset;
|
|
33253
|
+
}
|
|
33254
|
+
else {
|
|
33255
|
+
const children = [...current.value.childNodes].slice(0, nodeOffset);
|
|
33256
|
+
usedCharacters += children.reduce((acc, child, index) => {
|
|
33257
|
+
if (child.textContent !== null) {
|
|
33258
|
+
// need to account for paragraph nodes that implicitly add a new line
|
|
33259
|
+
// except for the last paragraph
|
|
33260
|
+
let chars = child.textContent.length;
|
|
33261
|
+
if (child.nodeName === "P" && index !== children.length - 1) {
|
|
33262
|
+
chars++;
|
|
33263
|
+
}
|
|
33264
|
+
return acc + chars;
|
|
33265
|
+
}
|
|
33266
|
+
else {
|
|
33267
|
+
return acc;
|
|
33268
|
+
}
|
|
33269
|
+
}, 0);
|
|
33270
|
+
}
|
|
33271
|
+
}
|
|
33272
|
+
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
|
|
33273
|
+
usedCharacters++;
|
|
33274
|
+
}
|
|
33275
|
+
return usedCharacters;
|
|
33276
|
+
}
|
|
33134
33277
|
const letterRegex = /^[a-zA-Z]$/;
|
|
33135
33278
|
/**
|
|
33136
33279
|
* Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
|
|
@@ -37058,7 +37201,7 @@ function dragAndDropBeyondTheViewport(env, cbMouseMove, cbMouseUp, only = false)
|
|
|
37058
37201
|
}
|
|
37059
37202
|
const { x: offsetCorrectionX, y: offsetCorrectionY } = getters.getMainViewportCoordinates();
|
|
37060
37203
|
let { top, left, bottom, right } = getters.getActiveMainViewport();
|
|
37061
|
-
let { scrollX, scrollY } = getters.
|
|
37204
|
+
let { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
|
|
37062
37205
|
const { xSplit, ySplit } = getters.getPaneDivisions(sheetId);
|
|
37063
37206
|
let canEdgeScroll = false;
|
|
37064
37207
|
let timeoutDelay = MAX_DELAY;
|
|
@@ -40338,6 +40481,10 @@ class ContentEditableHelper {
|
|
|
40338
40481
|
if (currentStart === start && currentEnd === end) {
|
|
40339
40482
|
return;
|
|
40340
40483
|
}
|
|
40484
|
+
if (selection.rangeCount === 0) {
|
|
40485
|
+
const range = document.createRange();
|
|
40486
|
+
selection.addRange(range);
|
|
40487
|
+
}
|
|
40341
40488
|
const currentRange = selection.getRangeAt(0);
|
|
40342
40489
|
let range;
|
|
40343
40490
|
if (this.el.contains(currentRange.startContainer)) {
|
|
@@ -40500,7 +40647,7 @@ class ContentEditableHelper {
|
|
|
40500
40647
|
if (!focusedNode || !this.el.contains(focusedNode))
|
|
40501
40648
|
return;
|
|
40502
40649
|
const element = focusedNode instanceof HTMLElement ? focusedNode : focusedNode.parentElement;
|
|
40503
|
-
element?.scrollIntoView({ block: "nearest" });
|
|
40650
|
+
element?.scrollIntoView?.({ block: "nearest" });
|
|
40504
40651
|
}
|
|
40505
40652
|
/**
|
|
40506
40653
|
* remove the current selection of the user
|
|
@@ -40520,100 +40667,7 @@ class ContentEditableHelper {
|
|
|
40520
40667
|
* finds the indexes of the current selection.
|
|
40521
40668
|
* */
|
|
40522
40669
|
getCurrentSelection() {
|
|
40523
|
-
|
|
40524
|
-
let startSizeBefore = this.findSelectionIndex(startElement, startSelectionOffset);
|
|
40525
|
-
let endSizeBefore = this.findSelectionIndex(endElement, endSelectionOffset);
|
|
40526
|
-
return {
|
|
40527
|
-
start: startSizeBefore,
|
|
40528
|
-
end: endSizeBefore,
|
|
40529
|
-
};
|
|
40530
|
-
}
|
|
40531
|
-
/**
|
|
40532
|
-
* Computes the text 'index' inside this.el based on the currently selected node and its offset.
|
|
40533
|
-
* The selected node is either a Text node or an Element node.
|
|
40534
|
-
*
|
|
40535
|
-
* case 1 -Text node:
|
|
40536
|
-
* the offset is the number of characters from the start of the node. We have to add this offset to the
|
|
40537
|
-
* content length of all previous nodes.
|
|
40538
|
-
*
|
|
40539
|
-
* case 2 - Element node:
|
|
40540
|
-
* the offset is the number of child nodes before the selected node. We have to add the content length of
|
|
40541
|
-
* all the bnodes prior to the selected node as well as the content of the child node before the offset.
|
|
40542
|
-
*
|
|
40543
|
-
* See the MDN documentation for more details.
|
|
40544
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
|
|
40545
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
|
|
40546
|
-
*
|
|
40547
|
-
*/
|
|
40548
|
-
findSelectionIndex(nodeToFind, nodeOffset) {
|
|
40549
|
-
let usedCharacters = 0;
|
|
40550
|
-
let it = iterateChildren(this.el);
|
|
40551
|
-
let current = it.next();
|
|
40552
|
-
let isFirstParagraph = true;
|
|
40553
|
-
while (!current.done && current.value !== nodeToFind) {
|
|
40554
|
-
if (!current.value.hasChildNodes()) {
|
|
40555
|
-
if (current.value.textContent) {
|
|
40556
|
-
usedCharacters += current.value.textContent.length;
|
|
40557
|
-
}
|
|
40558
|
-
}
|
|
40559
|
-
// One new paragraph = one new line character, except for the first paragraph
|
|
40560
|
-
if (current.value.nodeName === "P" ||
|
|
40561
|
-
(current.value.nodeName === "DIV" && current.value !== this.el) // On paste, the HTML may contain <div> instead of <p>
|
|
40562
|
-
) {
|
|
40563
|
-
if (isFirstParagraph) {
|
|
40564
|
-
isFirstParagraph = false;
|
|
40565
|
-
}
|
|
40566
|
-
else {
|
|
40567
|
-
usedCharacters++;
|
|
40568
|
-
}
|
|
40569
|
-
}
|
|
40570
|
-
current = it.next();
|
|
40571
|
-
}
|
|
40572
|
-
if (current.value !== nodeToFind) {
|
|
40573
|
-
/** This situation can happen if the code is called while the selection is not currently on the ContentEditableHelper.
|
|
40574
|
-
* In this case, we return 0 because we don't know the size of the text before the selection.
|
|
40575
|
-
*
|
|
40576
|
-
* A known occurence is triggered since the introduction of commit d4663158 (PR #2038).
|
|
40577
|
-
*
|
|
40578
|
-
* FIXME: find a way to test eventhough the selection API is not available in jsDOM.
|
|
40579
|
-
*/
|
|
40580
|
-
return 0;
|
|
40581
|
-
}
|
|
40582
|
-
else {
|
|
40583
|
-
if (!current.value.hasChildNodes()) {
|
|
40584
|
-
usedCharacters += nodeOffset;
|
|
40585
|
-
}
|
|
40586
|
-
else {
|
|
40587
|
-
const children = [...current.value.childNodes].slice(0, nodeOffset);
|
|
40588
|
-
usedCharacters += children.reduce((acc, child, index) => {
|
|
40589
|
-
if (child.textContent !== null) {
|
|
40590
|
-
// need to account for paragraph nodes that implicitely add a new line
|
|
40591
|
-
// except for the last paragraph
|
|
40592
|
-
let chars = child.textContent.length;
|
|
40593
|
-
if (child.nodeName === "P" && index !== children.length - 1) {
|
|
40594
|
-
chars++;
|
|
40595
|
-
}
|
|
40596
|
-
return acc + chars;
|
|
40597
|
-
}
|
|
40598
|
-
else {
|
|
40599
|
-
return acc;
|
|
40600
|
-
}
|
|
40601
|
-
}, 0);
|
|
40602
|
-
}
|
|
40603
|
-
}
|
|
40604
|
-
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
|
|
40605
|
-
usedCharacters++;
|
|
40606
|
-
}
|
|
40607
|
-
return usedCharacters;
|
|
40608
|
-
}
|
|
40609
|
-
getStartAndEndSelection() {
|
|
40610
|
-
const selection = document.getSelection();
|
|
40611
|
-
return {
|
|
40612
|
-
startElement: selection.anchorNode || this.el,
|
|
40613
|
-
startSelectionOffset: selection.anchorOffset,
|
|
40614
|
-
endElement: selection.focusNode || this.el,
|
|
40615
|
-
endSelectionOffset: selection.focusOffset,
|
|
40616
|
-
};
|
|
40670
|
+
return getCurrentSelection(this.el);
|
|
40617
40671
|
}
|
|
40618
40672
|
getText() {
|
|
40619
40673
|
let text = "";
|
|
@@ -40877,6 +40931,12 @@ class Composer extends owl.Component {
|
|
|
40877
40931
|
}
|
|
40878
40932
|
this.contentHelper.updateEl(el);
|
|
40879
40933
|
});
|
|
40934
|
+
this.env.model.selection.observe(this, {
|
|
40935
|
+
handleEvent: () => this.autoCompleteState.hide(),
|
|
40936
|
+
});
|
|
40937
|
+
owl.onWillUnmount(() => {
|
|
40938
|
+
this.env.model.selection.detachObserver(this);
|
|
40939
|
+
});
|
|
40880
40940
|
owl.useEffect(() => {
|
|
40881
40941
|
this.processContent();
|
|
40882
40942
|
if (document.activeElement === this.contentHelper.el &&
|
|
@@ -41314,6 +41374,16 @@ class StandaloneComposerStore extends AbstractComposerStore {
|
|
|
41314
41374
|
}
|
|
41315
41375
|
return providersDefinitions;
|
|
41316
41376
|
}
|
|
41377
|
+
/**
|
|
41378
|
+
* Replace the current reference selected by the new one.
|
|
41379
|
+
* */
|
|
41380
|
+
getZoneReference(zone) {
|
|
41381
|
+
const res = super.getZoneReference(zone);
|
|
41382
|
+
if (this.args().defaultStatic) {
|
|
41383
|
+
return setXcToFixedReferenceType(res, "colrow");
|
|
41384
|
+
}
|
|
41385
|
+
return res;
|
|
41386
|
+
}
|
|
41317
41387
|
getComposerContent() {
|
|
41318
41388
|
if (this.editionMode === "inactive") {
|
|
41319
41389
|
// References in the content might not be linked to the current active sheet
|
|
@@ -41379,6 +41449,7 @@ class StandaloneComposer extends owl.Component {
|
|
|
41379
41449
|
static props = {
|
|
41380
41450
|
composerContent: { type: String, optional: true },
|
|
41381
41451
|
defaultRangeSheetId: { type: String, optional: true },
|
|
41452
|
+
defaultStatic: { type: Boolean, optional: true },
|
|
41382
41453
|
onConfirm: Function,
|
|
41383
41454
|
contextualAutocomplete: { type: Object, optional: true },
|
|
41384
41455
|
placeholder: { type: String, optional: true },
|
|
@@ -41389,6 +41460,7 @@ class StandaloneComposer extends owl.Component {
|
|
|
41389
41460
|
static components = { Composer };
|
|
41390
41461
|
static defaultProps = {
|
|
41391
41462
|
composerContent: "",
|
|
41463
|
+
defaultStatic: false,
|
|
41392
41464
|
};
|
|
41393
41465
|
composerFocusStore;
|
|
41394
41466
|
standaloneComposerStore;
|
|
@@ -41399,6 +41471,7 @@ class StandaloneComposer extends owl.Component {
|
|
|
41399
41471
|
const standaloneComposerStore = useLocalStore(StandaloneComposerStore, () => ({
|
|
41400
41472
|
onConfirm: this.props.onConfirm,
|
|
41401
41473
|
content: this.props.composerContent,
|
|
41474
|
+
defaultStatic: this.props.defaultStatic ?? false,
|
|
41402
41475
|
contextualAutocomplete: this.props.contextualAutocomplete,
|
|
41403
41476
|
defaultRangeSheetId: this.props.defaultRangeSheetId,
|
|
41404
41477
|
getContextualColoredSymbolToken: this.props.getContextualColoredSymbolToken,
|
|
@@ -42134,6 +42207,7 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
42134
42207
|
},
|
|
42135
42208
|
composerContent: this.state.rules.cellIs.values[valueIndex],
|
|
42136
42209
|
placeholder: _t("Value or formula"),
|
|
42210
|
+
defaultStatic: true,
|
|
42137
42211
|
invalid: isInvalid,
|
|
42138
42212
|
class: "o-sidePanel-composer",
|
|
42139
42213
|
defaultRangeSheetId: this.env.model.getters.getActiveSheetId(),
|
|
@@ -42152,6 +42226,7 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
42152
42226
|
},
|
|
42153
42227
|
composerContent: threshold.value || "",
|
|
42154
42228
|
placeholder: _t("Formula"),
|
|
42229
|
+
defaultStatic: true,
|
|
42155
42230
|
invalid: isInvalid,
|
|
42156
42231
|
class: "o-sidePanel-composer",
|
|
42157
42232
|
defaultRangeSheetId: this.env.model.getters.getActiveSheetId(),
|
|
@@ -42167,6 +42242,7 @@ class ConditionalFormattingEditor extends owl.Component {
|
|
|
42167
42242
|
},
|
|
42168
42243
|
composerContent: inflection.value || "",
|
|
42169
42244
|
placeholder: _t("Formula"),
|
|
42245
|
+
defaultStatic: true,
|
|
42170
42246
|
invalid: isInvalid,
|
|
42171
42247
|
class: "o-sidePanel-composer",
|
|
42172
42248
|
defaultRangeSheetId: this.env.model.getters.getActiveSheetId(),
|
|
@@ -49216,7 +49292,7 @@ function isAxisVisible(getters, figure, axis) {
|
|
|
49216
49292
|
axisStartEndPositions.push({ x: axis.position, y: figure.y + figure.height });
|
|
49217
49293
|
break;
|
|
49218
49294
|
}
|
|
49219
|
-
return axisStartEndPositions.some(getters.
|
|
49295
|
+
return axisStartEndPositions.some(getters.isPixelPositionVisible);
|
|
49220
49296
|
}
|
|
49221
49297
|
/**
|
|
49222
49298
|
* Get a snap line for the given figure, if the figure can snap to any other figure
|
|
@@ -49775,7 +49851,7 @@ class GridAddRowsFooter extends owl.Component {
|
|
|
49775
49851
|
});
|
|
49776
49852
|
this.props.focusGrid();
|
|
49777
49853
|
// After adding new rows, scroll down to the new last row
|
|
49778
|
-
const { scrollX } = this.env.model.getters.
|
|
49854
|
+
const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
49779
49855
|
const { end } = this.env.model.getters.getRowDimensions(activeSheetId, rowNumber + quantity - 1);
|
|
49780
49856
|
this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
|
|
49781
49857
|
offsetX: scrollX,
|
|
@@ -50033,7 +50109,7 @@ class GridOverlay extends owl.Component {
|
|
|
50033
50109
|
resizeObserver.disconnect();
|
|
50034
50110
|
});
|
|
50035
50111
|
useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
|
|
50036
|
-
const { scrollY } = this.env.model.getters.
|
|
50112
|
+
const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
50037
50113
|
return scrollY > 0;
|
|
50038
50114
|
});
|
|
50039
50115
|
this.cellPopovers = useStore(CellPopoverStore);
|
|
@@ -50687,17 +50763,6 @@ class GridRenderer {
|
|
|
50687
50763
|
get renderingLayers() {
|
|
50688
50764
|
return ["Background", "Headers"];
|
|
50689
50765
|
}
|
|
50690
|
-
/**
|
|
50691
|
-
* Get the offset of a header (see getColRowOffsetInViewport), adjusted with the header
|
|
50692
|
-
* size (HEADER_HEIGHT and HEADER_WIDTH)
|
|
50693
|
-
*/
|
|
50694
|
-
getHeaderOffset(dimension, start, index) {
|
|
50695
|
-
let size = this.getters.getColRowOffsetInViewport(dimension, start, index);
|
|
50696
|
-
if (!this.getters.isDashboard()) {
|
|
50697
|
-
size += dimension === "ROW" ? HEADER_HEIGHT : HEADER_WIDTH;
|
|
50698
|
-
}
|
|
50699
|
-
return size;
|
|
50700
|
-
}
|
|
50701
50766
|
// ---------------------------------------------------------------------------
|
|
50702
50767
|
// Grid rendering
|
|
50703
50768
|
// ---------------------------------------------------------------------------
|
|
@@ -50705,11 +50770,10 @@ class GridRenderer {
|
|
|
50705
50770
|
switch (layer) {
|
|
50706
50771
|
case "Background":
|
|
50707
50772
|
this.drawGlobalBackground(renderingContext);
|
|
50708
|
-
for (const zone of this.getters.
|
|
50773
|
+
for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
|
|
50709
50774
|
const { ctx } = renderingContext;
|
|
50710
50775
|
ctx.save();
|
|
50711
50776
|
ctx.beginPath();
|
|
50712
|
-
const rect = this.getters.getVisibleRect(zone);
|
|
50713
50777
|
ctx.rect(rect.x, rect.y, rect.width, rect.height);
|
|
50714
50778
|
ctx.clip();
|
|
50715
50779
|
const boxes = this.getGridBoxes(zone);
|
|
@@ -50985,10 +51049,8 @@ class GridRenderer {
|
|
|
50985
51049
|
const { ctx, thinLineWidth } = renderingContext;
|
|
50986
51050
|
const visibleCols = this.getters.getSheetViewVisibleCols();
|
|
50987
51051
|
const left = visibleCols[0];
|
|
50988
|
-
const right = visibleCols[visibleCols.length - 1];
|
|
50989
51052
|
const visibleRows = this.getters.getSheetViewVisibleRows();
|
|
50990
51053
|
const top = visibleRows[0];
|
|
50991
|
-
const bottom = visibleRows[visibleRows.length - 1];
|
|
50992
51054
|
const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
|
|
50993
51055
|
const selection = this.getters.getSelectedZones();
|
|
50994
51056
|
const selectedCols = getZonesCols(selection);
|
|
@@ -51004,7 +51066,7 @@ class GridRenderer {
|
|
|
51004
51066
|
ctx.lineWidth = thinLineWidth;
|
|
51005
51067
|
ctx.strokeStyle = "#333";
|
|
51006
51068
|
// Columns headers background
|
|
51007
|
-
for (
|
|
51069
|
+
for (const col of visibleCols) {
|
|
51008
51070
|
const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
|
|
51009
51071
|
const { x, width } = this.getters.getVisibleRect(colZone);
|
|
51010
51072
|
const isColActive = activeCols.has(col);
|
|
@@ -51021,7 +51083,7 @@ class GridRenderer {
|
|
|
51021
51083
|
ctx.fillRect(x, 0, width, HEADER_HEIGHT);
|
|
51022
51084
|
}
|
|
51023
51085
|
// Rows headers background
|
|
51024
|
-
for (
|
|
51086
|
+
for (const row of visibleRows) {
|
|
51025
51087
|
const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
|
|
51026
51088
|
const { y, height } = this.getters.getVisibleRect(rowZone);
|
|
51027
51089
|
const isRowActive = activeRows.has(row);
|
|
@@ -51045,27 +51107,41 @@ class GridRenderer {
|
|
|
51045
51107
|
ctx.lineTo(width, HEADER_HEIGHT);
|
|
51046
51108
|
ctx.strokeStyle = HEADER_BORDER_COLOR;
|
|
51047
51109
|
ctx.stroke();
|
|
51048
|
-
ctx.beginPath();
|
|
51049
51110
|
// column text + separator
|
|
51050
|
-
for (const
|
|
51051
|
-
const
|
|
51052
|
-
|
|
51053
|
-
|
|
51054
|
-
|
|
51111
|
+
for (const col of visibleCols) {
|
|
51112
|
+
const colName = numberToLetters(col);
|
|
51113
|
+
ctx.fillStyle = activeCols.has(col) ? "#fff" : TEXT_HEADER_COLOR;
|
|
51114
|
+
const zone = { left: col, right: col, top: top, bottom: top };
|
|
51115
|
+
const { x: colStart, width: colSize } = this.getters.getRect(zone);
|
|
51116
|
+
const { x, width } = this.getters.getVisibleRect(zone);
|
|
51117
|
+
ctx.save();
|
|
51118
|
+
ctx.beginPath();
|
|
51119
|
+
ctx.rect(x, 0, width, HEADER_HEIGHT);
|
|
51120
|
+
ctx.clip();
|
|
51055
51121
|
ctx.fillText(colName, colStart + colSize / 2, HEADER_HEIGHT / 2);
|
|
51122
|
+
ctx.restore();
|
|
51123
|
+
ctx.beginPath();
|
|
51056
51124
|
ctx.moveTo(colStart + colSize, 0);
|
|
51057
51125
|
ctx.lineTo(colStart + colSize, HEADER_HEIGHT);
|
|
51126
|
+
ctx.stroke();
|
|
51058
51127
|
}
|
|
51059
51128
|
// row text + separator
|
|
51060
|
-
for (const
|
|
51061
|
-
|
|
51062
|
-
|
|
51063
|
-
|
|
51064
|
-
|
|
51129
|
+
for (const row of visibleRows) {
|
|
51130
|
+
ctx.fillStyle = activeRows.has(row) ? "#fff" : TEXT_HEADER_COLOR;
|
|
51131
|
+
const zone = { top: row, bottom: row, left: left, right: left };
|
|
51132
|
+
const { y: rowStart, height: rowSize } = this.getters.getRect(zone);
|
|
51133
|
+
const { y, height } = this.getters.getVisibleRect(zone);
|
|
51134
|
+
ctx.save();
|
|
51135
|
+
ctx.beginPath();
|
|
51136
|
+
ctx.rect(0, y, HEADER_WIDTH, height);
|
|
51137
|
+
ctx.clip();
|
|
51138
|
+
ctx.fillText(String(row + 1), HEADER_WIDTH / 2, rowStart + rowSize / 2);
|
|
51139
|
+
ctx.restore();
|
|
51140
|
+
ctx.beginPath();
|
|
51065
51141
|
ctx.moveTo(0, rowStart + rowSize);
|
|
51066
51142
|
ctx.lineTo(HEADER_WIDTH, rowStart + rowSize);
|
|
51143
|
+
ctx.stroke();
|
|
51067
51144
|
}
|
|
51068
|
-
ctx.stroke();
|
|
51069
51145
|
}
|
|
51070
51146
|
drawFrozenPanesHeaders(renderingContext) {
|
|
51071
51147
|
const { ctx, thinLineWidth } = renderingContext;
|
|
@@ -51243,8 +51319,8 @@ class GridRenderer {
|
|
|
51243
51319
|
previousColIndex = col;
|
|
51244
51320
|
}
|
|
51245
51321
|
else {
|
|
51246
|
-
nextColIndex = this.findNextEmptyCol(col, right, row);
|
|
51247
|
-
previousColIndex = this.findPreviousEmptyCol(col, left, row);
|
|
51322
|
+
nextColIndex = box.border?.right ? zone.right : this.findNextEmptyCol(col, right, row);
|
|
51323
|
+
previousColIndex = box.border?.left ? zone.left : this.findPreviousEmptyCol(col, left, row);
|
|
51248
51324
|
box.isOverflow = true;
|
|
51249
51325
|
}
|
|
51250
51326
|
switch (align) {
|
|
@@ -51368,6 +51444,9 @@ function useGridDrawing(refName, model, canvasSize) {
|
|
|
51368
51444
|
canvas.width = width * dpr;
|
|
51369
51445
|
canvas.height = height * dpr;
|
|
51370
51446
|
canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
|
|
51447
|
+
if (width === 0 || height === 0) {
|
|
51448
|
+
return;
|
|
51449
|
+
}
|
|
51371
51450
|
// Imagine each pixel as a large square. The whole-number coordinates (0, 1, 2…)
|
|
51372
51451
|
// are the edges of the squares. If you draw a one-unit-wide line between whole-number
|
|
51373
51452
|
// coordinates, it will overlap opposite sides of the pixel square, and the resulting
|
|
@@ -51711,7 +51790,7 @@ class HorizontalScrollBar extends owl.Component {
|
|
|
51711
51790
|
leftOffset: 0,
|
|
51712
51791
|
};
|
|
51713
51792
|
get offset() {
|
|
51714
|
-
return this.env.model.getters.
|
|
51793
|
+
return this.env.model.getters.getActiveSheetScrollInfo().scrollX;
|
|
51715
51794
|
}
|
|
51716
51795
|
get width() {
|
|
51717
51796
|
return this.env.model.getters.getMainViewportRect().width;
|
|
@@ -51730,7 +51809,7 @@ class HorizontalScrollBar extends owl.Component {
|
|
|
51730
51809
|
};
|
|
51731
51810
|
}
|
|
51732
51811
|
onScroll(offset) {
|
|
51733
|
-
const { scrollY } = this.env.model.getters.
|
|
51812
|
+
const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
51734
51813
|
this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
|
|
51735
51814
|
offsetX: offset,
|
|
51736
51815
|
offsetY: scrollY, // offsetY is the same
|
|
@@ -51756,7 +51835,7 @@ class VerticalScrollBar extends owl.Component {
|
|
|
51756
51835
|
topOffset: 0,
|
|
51757
51836
|
};
|
|
51758
51837
|
get offset() {
|
|
51759
|
-
return this.env.model.getters.
|
|
51838
|
+
return this.env.model.getters.getActiveSheetScrollInfo().scrollY;
|
|
51760
51839
|
}
|
|
51761
51840
|
get height() {
|
|
51762
51841
|
return this.env.model.getters.getMainViewportRect().height;
|
|
@@ -51775,7 +51854,7 @@ class VerticalScrollBar extends owl.Component {
|
|
|
51775
51854
|
};
|
|
51776
51855
|
}
|
|
51777
51856
|
onScroll(offset) {
|
|
51778
|
-
const { scrollX } = this.env.model.getters.
|
|
51857
|
+
const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
51779
51858
|
this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
|
|
51780
51859
|
offsetX: scrollX, // offsetX is the same
|
|
51781
51860
|
offsetY: offset,
|
|
@@ -52246,7 +52325,7 @@ class Grid extends owl.Component {
|
|
|
52246
52325
|
});
|
|
52247
52326
|
}
|
|
52248
52327
|
moveCanvas(deltaX, deltaY) {
|
|
52249
|
-
const { scrollX, scrollY } = this.env.model.getters.
|
|
52328
|
+
const { scrollX, scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
52250
52329
|
this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
|
|
52251
52330
|
offsetX: scrollX + deltaX,
|
|
52252
52331
|
offsetY: scrollY + deltaY,
|
|
@@ -52717,7 +52796,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
52717
52796
|
// map and slice preserve empty values and do not set `undefined` instead
|
|
52718
52797
|
const bordersCopy = borders
|
|
52719
52798
|
.slice()
|
|
52720
|
-
.map((col) => col?.slice().map((border) => (
|
|
52799
|
+
.map((col) => col?.slice().map((border) => deepCopy(border)));
|
|
52721
52800
|
this.history.update("borders", cmd.sheetIdTo, bordersCopy);
|
|
52722
52801
|
}
|
|
52723
52802
|
break;
|
|
@@ -52747,32 +52826,12 @@ class BordersPlugin extends CorePlugin {
|
|
|
52747
52826
|
const elements = [...cmd.elements].sort((a, b) => b - a);
|
|
52748
52827
|
for (const group of groupConsecutive(elements)) {
|
|
52749
52828
|
if (cmd.dimension === "COL") {
|
|
52750
|
-
|
|
52751
|
-
for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
|
|
52752
|
-
this.history.update("borders", cmd.sheetId, group[0] + 1, row, "vertical", undefined);
|
|
52753
|
-
}
|
|
52754
|
-
}
|
|
52755
|
-
if (group[group.length - 1] === 0) {
|
|
52756
|
-
for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
|
|
52757
|
-
this.history.update("borders", cmd.sheetId, 0, row, "vertical", undefined);
|
|
52758
|
-
}
|
|
52759
|
-
}
|
|
52760
|
-
const zone = this.getters.getColsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
|
|
52829
|
+
const zone = this.getters.getColsZone(cmd.sheetId, group[group.length - 1], group[0]);
|
|
52761
52830
|
this.clearInsideBorders(cmd.sheetId, [zone]);
|
|
52762
52831
|
this.shiftBordersHorizontally(cmd.sheetId, group[0] + 1, -group.length);
|
|
52763
52832
|
}
|
|
52764
52833
|
else {
|
|
52765
|
-
|
|
52766
|
-
for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
|
|
52767
|
-
this.history.update("borders", cmd.sheetId, col, group[0] + 1, "horizontal", undefined);
|
|
52768
|
-
}
|
|
52769
|
-
}
|
|
52770
|
-
if (group[group.length - 1] === 0) {
|
|
52771
|
-
for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
|
|
52772
|
-
this.history.update("borders", cmd.sheetId, col, 0, "horizontal", undefined);
|
|
52773
|
-
}
|
|
52774
|
-
}
|
|
52775
|
-
const zone = this.getters.getRowsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
|
|
52834
|
+
const zone = this.getters.getRowsZone(cmd.sheetId, group[group.length - 1], group[0]);
|
|
52776
52835
|
this.clearInsideBorders(cmd.sheetId, [zone]);
|
|
52777
52836
|
this.shiftBordersVertically(cmd.sheetId, group[0] + 1, -group.length);
|
|
52778
52837
|
}
|
|
@@ -52797,16 +52856,12 @@ class BordersPlugin extends CorePlugin {
|
|
|
52797
52856
|
let colLeftOfInsertion;
|
|
52798
52857
|
let colRightOfInsertion;
|
|
52799
52858
|
if (cmd.position === "before") {
|
|
52800
|
-
this.shiftBordersHorizontally(cmd.sheetId, cmd.base, cmd.quantity
|
|
52801
|
-
moveFirstLeftBorder: true,
|
|
52802
|
-
});
|
|
52859
|
+
this.shiftBordersHorizontally(cmd.sheetId, cmd.base, cmd.quantity);
|
|
52803
52860
|
colLeftOfInsertion = cmd.base - 1;
|
|
52804
52861
|
colRightOfInsertion = cmd.base + cmd.quantity;
|
|
52805
52862
|
}
|
|
52806
52863
|
else {
|
|
52807
|
-
this.shiftBordersHorizontally(cmd.sheetId, cmd.base + 1, cmd.quantity
|
|
52808
|
-
moveFirstLeftBorder: false,
|
|
52809
|
-
});
|
|
52864
|
+
this.shiftBordersHorizontally(cmd.sheetId, cmd.base + 1, cmd.quantity);
|
|
52810
52865
|
colLeftOfInsertion = cmd.base;
|
|
52811
52866
|
colRightOfInsertion = cmd.base + cmd.quantity + 1;
|
|
52812
52867
|
}
|
|
@@ -52821,16 +52876,12 @@ class BordersPlugin extends CorePlugin {
|
|
|
52821
52876
|
let rowAboveInsertion;
|
|
52822
52877
|
let rowBelowInsertion;
|
|
52823
52878
|
if (cmd.position === "before") {
|
|
52824
|
-
this.shiftBordersVertically(cmd.sheetId, cmd.base, cmd.quantity
|
|
52825
|
-
moveFirstTopBorder: true,
|
|
52826
|
-
});
|
|
52879
|
+
this.shiftBordersVertically(cmd.sheetId, cmd.base, cmd.quantity);
|
|
52827
52880
|
rowAboveInsertion = cmd.base - 1;
|
|
52828
52881
|
rowBelowInsertion = cmd.base + cmd.quantity;
|
|
52829
52882
|
}
|
|
52830
52883
|
else {
|
|
52831
|
-
this.shiftBordersVertically(cmd.sheetId, cmd.base + 1, cmd.quantity
|
|
52832
|
-
moveFirstTopBorder: false,
|
|
52833
|
-
});
|
|
52884
|
+
this.shiftBordersVertically(cmd.sheetId, cmd.base + 1, cmd.quantity);
|
|
52834
52885
|
rowAboveInsertion = cmd.base;
|
|
52835
52886
|
rowBelowInsertion = cmd.base + cmd.quantity + 1;
|
|
52836
52887
|
}
|
|
@@ -52840,16 +52891,8 @@ class BordersPlugin extends CorePlugin {
|
|
|
52840
52891
|
// Getters
|
|
52841
52892
|
// ---------------------------------------------------------------------------
|
|
52842
52893
|
getCellBorder({ sheetId, col, row }) {
|
|
52843
|
-
const border =
|
|
52844
|
-
|
|
52845
|
-
bottom: this.borders[sheetId]?.[col]?.[row + 1]?.horizontal,
|
|
52846
|
-
left: this.borders[sheetId]?.[col]?.[row]?.vertical,
|
|
52847
|
-
right: this.borders[sheetId]?.[col + 1]?.[row]?.vertical,
|
|
52848
|
-
};
|
|
52849
|
-
if (!border.bottom && !border.left && !border.right && !border.top) {
|
|
52850
|
-
return null;
|
|
52851
|
-
}
|
|
52852
|
-
return border;
|
|
52894
|
+
const border = this.borders[sheetId]?.[col]?.[row];
|
|
52895
|
+
return border?.top || border?.bottom || border?.left || border?.right ? deepCopy(border) : null;
|
|
52853
52896
|
}
|
|
52854
52897
|
getBordersColors(sheetId) {
|
|
52855
52898
|
const colors = [];
|
|
@@ -52857,11 +52900,13 @@ class BordersPlugin extends CorePlugin {
|
|
|
52857
52900
|
if (sheetBorders) {
|
|
52858
52901
|
for (const borders of sheetBorders.filter(isDefined)) {
|
|
52859
52902
|
for (const cellBorder of borders) {
|
|
52860
|
-
if (cellBorder
|
|
52861
|
-
|
|
52862
|
-
|
|
52863
|
-
|
|
52864
|
-
|
|
52903
|
+
if (cellBorder) {
|
|
52904
|
+
for (const direction of ["top", "bottom", "left", "right"]) {
|
|
52905
|
+
const color = cellBorder[direction]?.color;
|
|
52906
|
+
if (color) {
|
|
52907
|
+
colors.push(color);
|
|
52908
|
+
}
|
|
52909
|
+
}
|
|
52865
52910
|
}
|
|
52866
52911
|
}
|
|
52867
52912
|
}
|
|
@@ -52914,7 +52959,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
52914
52959
|
getCommonSides(border1, border2) {
|
|
52915
52960
|
const commonBorder = {};
|
|
52916
52961
|
for (let side of ["top", "bottom", "left", "right"]) {
|
|
52917
|
-
if (border1[side] && border1[side]
|
|
52962
|
+
if (border1[side] && deepEquals(border1[side], border2[side])) {
|
|
52918
52963
|
commonBorder[side] = border1[side];
|
|
52919
52964
|
}
|
|
52920
52965
|
}
|
|
@@ -52959,23 +53004,15 @@ class BordersPlugin extends CorePlugin {
|
|
|
52959
53004
|
* @param start starting column (included)
|
|
52960
53005
|
* @param delta how much borders will be moved (negative if moved to the left)
|
|
52961
53006
|
*/
|
|
52962
|
-
shiftBordersHorizontally(sheetId, start, delta
|
|
53007
|
+
shiftBordersHorizontally(sheetId, start, delta) {
|
|
52963
53008
|
const borders = this.borders[sheetId];
|
|
52964
53009
|
if (!borders)
|
|
52965
53010
|
return;
|
|
52966
|
-
if (delta < 0) {
|
|
52967
|
-
this.moveBordersOfColumn(sheetId, start, delta, "vertical", {
|
|
52968
|
-
destructive: false,
|
|
52969
|
-
});
|
|
52970
|
-
}
|
|
52971
53011
|
this.getColumnsWithBorders(sheetId)
|
|
52972
53012
|
.filter((col) => col >= start)
|
|
52973
53013
|
.sort((a, b) => (delta < 0 ? a - b : b - a)) // start by the end when moving up
|
|
52974
53014
|
.forEach((col) => {
|
|
52975
|
-
|
|
52976
|
-
this.moveBordersOfColumn(sheetId, col, delta, "vertical");
|
|
52977
|
-
}
|
|
52978
|
-
this.moveBordersOfColumn(sheetId, col, delta, "horizontal");
|
|
53015
|
+
this.moveBordersOfColumn(sheetId, col, delta);
|
|
52979
53016
|
});
|
|
52980
53017
|
}
|
|
52981
53018
|
/**
|
|
@@ -52984,12 +53021,12 @@ class BordersPlugin extends CorePlugin {
|
|
|
52984
53021
|
* @param start starting row (included)
|
|
52985
53022
|
* @param delta how much borders will be moved (negative if moved to the above)
|
|
52986
53023
|
*/
|
|
52987
|
-
shiftBordersVertically(sheetId, start, delta
|
|
53024
|
+
shiftBordersVertically(sheetId, start, delta) {
|
|
52988
53025
|
const borders = this.borders[sheetId];
|
|
52989
53026
|
if (!borders)
|
|
52990
53027
|
return;
|
|
52991
53028
|
if (delta < 0) {
|
|
52992
|
-
this.moveBordersOfRow(sheetId, start, delta,
|
|
53029
|
+
this.moveBordersOfRow(sheetId, start, delta, {
|
|
52993
53030
|
destructive: false,
|
|
52994
53031
|
});
|
|
52995
53032
|
}
|
|
@@ -52997,10 +53034,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
52997
53034
|
.filter((row) => row >= start)
|
|
52998
53035
|
.sort((a, b) => (delta < 0 ? a - b : b - a)) // start by the end when moving up
|
|
52999
53036
|
.forEach((row) => {
|
|
53000
|
-
|
|
53001
|
-
this.moveBordersOfRow(sheetId, row, delta, "horizontal");
|
|
53002
|
-
}
|
|
53003
|
-
this.moveBordersOfRow(sheetId, row, delta, "vertical");
|
|
53037
|
+
this.moveBordersOfRow(sheetId, row, delta);
|
|
53004
53038
|
});
|
|
53005
53039
|
}
|
|
53006
53040
|
/**
|
|
@@ -53014,15 +53048,15 @@ class BordersPlugin extends CorePlugin {
|
|
|
53014
53048
|
* argument `destructive` is given false, the target border is preserved if
|
|
53015
53049
|
* the moved border is empty
|
|
53016
53050
|
*/
|
|
53017
|
-
moveBordersOfRow(sheetId, row, delta,
|
|
53051
|
+
moveBordersOfRow(sheetId, row, delta, { destructive } = { destructive: true }) {
|
|
53018
53052
|
const borders = this.borders[sheetId];
|
|
53019
53053
|
if (!borders)
|
|
53020
53054
|
return;
|
|
53021
53055
|
this.getColumnsWithBorders(sheetId).forEach((col) => {
|
|
53022
|
-
const targetBorder = borders[col]?.[row + delta]
|
|
53023
|
-
const movedBorder = borders[col]?.[row]
|
|
53024
|
-
this.history.update("borders", sheetId, col, row + delta,
|
|
53025
|
-
this.history.update("borders", sheetId, col, row,
|
|
53056
|
+
const targetBorder = borders[col]?.[row + delta];
|
|
53057
|
+
const movedBorder = borders[col]?.[row];
|
|
53058
|
+
this.history.update("borders", sheetId, col, row + delta, destructive ? movedBorder : movedBorder || targetBorder);
|
|
53059
|
+
this.history.update("borders", sheetId, col, row, undefined);
|
|
53026
53060
|
});
|
|
53027
53061
|
}
|
|
53028
53062
|
/**
|
|
@@ -53036,15 +53070,17 @@ class BordersPlugin extends CorePlugin {
|
|
|
53036
53070
|
* argument `destructive` is given false, the target border is preserved if
|
|
53037
53071
|
* the moved border is empty
|
|
53038
53072
|
*/
|
|
53039
|
-
moveBordersOfColumn(sheetId, col, delta,
|
|
53073
|
+
moveBordersOfColumn(sheetId, col, delta, { destructive } = { destructive: true }) {
|
|
53040
53074
|
const borders = this.borders[sheetId];
|
|
53041
53075
|
if (!borders)
|
|
53042
53076
|
return;
|
|
53043
53077
|
this.getRowsRange(sheetId).forEach((row) => {
|
|
53044
|
-
const targetBorder = borders[col + delta]?.[row]
|
|
53045
|
-
const movedBorder = borders[col]?.[row]
|
|
53046
|
-
this.history.update("borders", sheetId, col + delta, row,
|
|
53047
|
-
|
|
53078
|
+
const targetBorder = borders[col + delta]?.[row];
|
|
53079
|
+
const movedBorder = borders[col]?.[row];
|
|
53080
|
+
this.history.update("borders", sheetId, col + delta, row, destructive ? movedBorder : movedBorder || targetBorder);
|
|
53081
|
+
if (destructive) {
|
|
53082
|
+
this.history.update("borders", sheetId, col, row, undefined);
|
|
53083
|
+
}
|
|
53048
53084
|
});
|
|
53049
53085
|
}
|
|
53050
53086
|
/**
|
|
@@ -53052,33 +53088,69 @@ class BordersPlugin extends CorePlugin {
|
|
|
53052
53088
|
* It overrides the current border if override === true.
|
|
53053
53089
|
*/
|
|
53054
53090
|
setBorder(sheetId, col, row, border, override = true) {
|
|
53055
|
-
|
|
53056
|
-
|
|
53091
|
+
const maxCol = this.getters.getNumberCols(sheetId) - 1;
|
|
53092
|
+
const maxRow = this.getters.getNumberRows(sheetId) - 1;
|
|
53093
|
+
if (override || !this.borders[sheetId]?.[col]?.[row]?.left) {
|
|
53094
|
+
this.history.update("borders", sheetId, col, row, "left", border?.left);
|
|
53095
|
+
if (border?.left &&
|
|
53096
|
+
col > 0 &&
|
|
53097
|
+
!deepEquals(this.getCellBorder({ sheetId, col: col - 1, row })?.right, border?.left)) {
|
|
53098
|
+
this.history.update("borders", sheetId, col - 1, row, "right", undefined);
|
|
53099
|
+
}
|
|
53057
53100
|
}
|
|
53058
|
-
if (override || !this.borders
|
|
53059
|
-
this.history.update("borders", sheetId, col, row, "
|
|
53101
|
+
if (override || !this.borders[sheetId]?.[col]?.[row]?.top) {
|
|
53102
|
+
this.history.update("borders", sheetId, col, row, "top", border?.top);
|
|
53103
|
+
if (border?.top &&
|
|
53104
|
+
row > 0 &&
|
|
53105
|
+
!deepEquals(this.getCellBorder({ sheetId, col, row: row - 1 })?.bottom, border?.top)) {
|
|
53106
|
+
this.history.update("borders", sheetId, col, row - 1, "bottom", undefined);
|
|
53107
|
+
}
|
|
53060
53108
|
}
|
|
53061
|
-
if (override || !this.borders
|
|
53062
|
-
this.history.update("borders", sheetId, col
|
|
53109
|
+
if (override || !this.borders[sheetId]?.[col]?.[row]?.right) {
|
|
53110
|
+
this.history.update("borders", sheetId, col, row, "right", border?.right);
|
|
53111
|
+
if (border?.right &&
|
|
53112
|
+
col < maxCol &&
|
|
53113
|
+
!deepEquals(this.getCellBorder({ sheetId, col: col + 1, row })?.left, border?.right)) {
|
|
53114
|
+
this.history.update("borders", sheetId, col + 1, row, "left", undefined);
|
|
53115
|
+
}
|
|
53063
53116
|
}
|
|
53064
|
-
if (override || !this.borders
|
|
53065
|
-
this.history.update("borders", sheetId, col, row
|
|
53117
|
+
if (override || !this.borders[sheetId]?.[col]?.[row]?.bottom) {
|
|
53118
|
+
this.history.update("borders", sheetId, col, row, "bottom", border?.bottom);
|
|
53119
|
+
if (border?.bottom &&
|
|
53120
|
+
row < maxRow &&
|
|
53121
|
+
!deepEquals(this.getCellBorder({ sheetId, col, row: row + 1 })?.top, border?.bottom)) {
|
|
53122
|
+
this.history.update("borders", sheetId, col, row + 1, "top", undefined);
|
|
53123
|
+
}
|
|
53066
53124
|
}
|
|
53067
53125
|
}
|
|
53068
53126
|
/**
|
|
53069
53127
|
* Remove the borders of a zone
|
|
53070
53128
|
*/
|
|
53071
|
-
clearBorders(sheetId, zones) {
|
|
53129
|
+
clearBorders(sheetId, zones, eraseBoundaries = false) {
|
|
53130
|
+
const maxCol = this.getters.getNumberCols(sheetId) - 1;
|
|
53131
|
+
const maxRow = this.getters.getNumberRows(sheetId) - 1;
|
|
53072
53132
|
for (let zone of recomputeZones(zones)) {
|
|
53073
53133
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
53074
|
-
|
|
53134
|
+
if (eraseBoundaries) {
|
|
53135
|
+
if (zone.left > 0) {
|
|
53136
|
+
this.history.update("borders", sheetId, zone.left - 1, row, "right", undefined);
|
|
53137
|
+
}
|
|
53138
|
+
if (zone.right < maxCol) {
|
|
53139
|
+
this.history.update("borders", sheetId, zone.right + 1, row, "left", undefined);
|
|
53140
|
+
}
|
|
53141
|
+
}
|
|
53075
53142
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
53076
53143
|
this.history.update("borders", sheetId, col, row, undefined);
|
|
53144
|
+
if (eraseBoundaries) {
|
|
53145
|
+
if (zone.top > 0) {
|
|
53146
|
+
this.history.update("borders", sheetId, col, zone.top - 1, "bottom", undefined);
|
|
53147
|
+
}
|
|
53148
|
+
if (zone.bottom < maxRow) {
|
|
53149
|
+
this.history.update("borders", sheetId, col, zone.bottom + 1, "top", undefined);
|
|
53150
|
+
}
|
|
53151
|
+
}
|
|
53077
53152
|
}
|
|
53078
53153
|
}
|
|
53079
|
-
for (let col = zone.left; col <= zone.right; col++) {
|
|
53080
|
-
this.history.update("borders", sheetId, col, zone.bottom + 1, "horizontal", undefined);
|
|
53081
|
-
}
|
|
53082
53154
|
}
|
|
53083
53155
|
}
|
|
53084
53156
|
/**
|
|
@@ -53108,41 +53180,63 @@ class BordersPlugin extends CorePlugin {
|
|
|
53108
53180
|
*/
|
|
53109
53181
|
setBorders(sheetId, zones, position, border) {
|
|
53110
53182
|
if (position === "clear") {
|
|
53111
|
-
return this.clearBorders(sheetId, zones);
|
|
53183
|
+
return this.clearBorders(sheetId, zones, true);
|
|
53112
53184
|
}
|
|
53113
53185
|
for (let zone of recomputeZones(zones)) {
|
|
53114
|
-
if (position === "
|
|
53115
|
-
for (let row = zone.top
|
|
53186
|
+
if (position === "all") {
|
|
53187
|
+
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
53116
53188
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
53117
|
-
this.addBorder(sheetId, col, row, {
|
|
53189
|
+
this.addBorder(sheetId, col, row, {
|
|
53190
|
+
top: border,
|
|
53191
|
+
right: border,
|
|
53192
|
+
bottom: border,
|
|
53193
|
+
left: border,
|
|
53194
|
+
});
|
|
53118
53195
|
}
|
|
53119
53196
|
}
|
|
53120
53197
|
}
|
|
53121
|
-
if (position === "
|
|
53198
|
+
if (position === "h" || position === "hv") {
|
|
53199
|
+
if (zone.top === zone.bottom) {
|
|
53200
|
+
continue;
|
|
53201
|
+
}
|
|
53202
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
53203
|
+
this.addBorder(sheetId, col, zone.top, { bottom: border });
|
|
53204
|
+
for (let row = zone.top + 1; row < zone.bottom; row++) {
|
|
53205
|
+
this.addBorder(sheetId, col, row, { top: border, bottom: border });
|
|
53206
|
+
}
|
|
53207
|
+
this.addBorder(sheetId, col, zone.bottom, { top: border });
|
|
53208
|
+
}
|
|
53209
|
+
}
|
|
53210
|
+
if (position === "v" || position === "hv") {
|
|
53211
|
+
if (zone.left === zone.right) {
|
|
53212
|
+
continue;
|
|
53213
|
+
}
|
|
53122
53214
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
53123
|
-
|
|
53124
|
-
|
|
53215
|
+
this.addBorder(sheetId, zone.left, row, { right: border });
|
|
53216
|
+
for (let col = zone.left + 1; col < zone.right; col++) {
|
|
53217
|
+
this.addBorder(sheetId, col, row, { left: border, right: border });
|
|
53125
53218
|
}
|
|
53219
|
+
this.addBorder(sheetId, zone.right, row, { left: border });
|
|
53126
53220
|
}
|
|
53127
53221
|
}
|
|
53128
|
-
if (position === "left" || position === "
|
|
53222
|
+
if (position === "left" || position === "external") {
|
|
53129
53223
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
53130
53224
|
this.addBorder(sheetId, zone.left, row, { left: border });
|
|
53131
53225
|
}
|
|
53132
53226
|
}
|
|
53133
|
-
if (position === "right" || position === "
|
|
53227
|
+
if (position === "right" || position === "external") {
|
|
53134
53228
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
53135
|
-
this.addBorder(sheetId, zone.right
|
|
53229
|
+
this.addBorder(sheetId, zone.right, row, { right: border });
|
|
53136
53230
|
}
|
|
53137
53231
|
}
|
|
53138
|
-
if (position === "top" || position === "
|
|
53232
|
+
if (position === "top" || position === "external") {
|
|
53139
53233
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
53140
53234
|
this.addBorder(sheetId, col, zone.top, { top: border });
|
|
53141
53235
|
}
|
|
53142
53236
|
}
|
|
53143
|
-
if (position === "bottom" || position === "
|
|
53237
|
+
if (position === "bottom" || position === "external") {
|
|
53144
53238
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
53145
|
-
this.addBorder(sheetId, col, zone.bottom
|
|
53239
|
+
this.addBorder(sheetId, col, zone.bottom, { bottom: border });
|
|
53146
53240
|
}
|
|
53147
53241
|
}
|
|
53148
53242
|
}
|
|
@@ -59887,7 +59981,11 @@ class Evaluator {
|
|
|
59887
59981
|
computeFormulaCell(formulaPosition, cellData) {
|
|
59888
59982
|
const formulaReturn = updateEvalContextAndExecute(cellData.compiledFormula, this.compilationParams, formulaPosition.sheetId, this.buildSafeGetSymbolValue(), formulaPosition);
|
|
59889
59983
|
if (!isMatrix(formulaReturn)) {
|
|
59890
|
-
|
|
59984
|
+
const evaluatedCell = createEvaluatedCell(nullValueToZeroValue(formulaReturn), this.getters.getLocale(), cellData);
|
|
59985
|
+
if (evaluatedCell.type === CellValueType.error) {
|
|
59986
|
+
evaluatedCell.errorOriginPosition = formulaReturn.errorOriginPosition ?? formulaPosition;
|
|
59987
|
+
}
|
|
59988
|
+
return evaluatedCell;
|
|
59891
59989
|
}
|
|
59892
59990
|
this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
|
|
59893
59991
|
const nbColumns = formulaReturn.length;
|
|
@@ -59960,6 +60058,9 @@ class Evaluator {
|
|
|
59960
60058
|
const position = { sheetId, col: i + col, row: j + row };
|
|
59961
60059
|
const cell = this.getters.getCell(position);
|
|
59962
60060
|
const evaluatedCell = createEvaluatedCell(nullValueToZeroValue(matrixResult[i][j]), this.getters.getLocale(), cell);
|
|
60061
|
+
if (evaluatedCell.type === CellValueType.error) {
|
|
60062
|
+
evaluatedCell.errorOriginPosition = matrixResult[i][j].errorOriginPosition ?? position;
|
|
60063
|
+
}
|
|
59963
60064
|
this.evaluatedCells.set(position, evaluatedCell);
|
|
59964
60065
|
};
|
|
59965
60066
|
return spreadValues;
|
|
@@ -61518,7 +61619,7 @@ function withPivotPresentationLayer (PivotClass) {
|
|
|
61518
61619
|
const symbolIndex = rowDomain.findIndex((row) => row.field === symbolName);
|
|
61519
61620
|
return this.getPivotHeaderValueAndFormat(rowDomain.slice(0, symbolIndex + 1));
|
|
61520
61621
|
}
|
|
61521
|
-
return this.
|
|
61622
|
+
return this.getPivotCellValueAndFormat(symbolName, domain);
|
|
61522
61623
|
};
|
|
61523
61624
|
const result = this.getters.evaluateCompiledFormula(measure.computedBy.sheetId, formula, getSymbolValue);
|
|
61524
61625
|
if (isMatrix(result)) {
|
|
@@ -64704,14 +64805,12 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
64704
64805
|
}
|
|
64705
64806
|
break;
|
|
64706
64807
|
case "AUTORESIZE_ROWS":
|
|
64707
|
-
|
|
64708
|
-
|
|
64709
|
-
|
|
64710
|
-
|
|
64711
|
-
|
|
64712
|
-
|
|
64713
|
-
});
|
|
64714
|
-
}
|
|
64808
|
+
this.dispatch("RESIZE_COLUMNS_ROWS", {
|
|
64809
|
+
elements: cmd.rows,
|
|
64810
|
+
dimension: "ROW",
|
|
64811
|
+
size: null,
|
|
64812
|
+
sheetId: cmd.sheetId,
|
|
64813
|
+
});
|
|
64715
64814
|
break;
|
|
64716
64815
|
}
|
|
64717
64816
|
}
|
|
@@ -67107,8 +67206,6 @@ class InternalViewport {
|
|
|
67107
67206
|
right;
|
|
67108
67207
|
offsetX;
|
|
67109
67208
|
offsetY;
|
|
67110
|
-
offsetScrollbarX;
|
|
67111
|
-
offsetScrollbarY;
|
|
67112
67209
|
canScrollVertically;
|
|
67113
67210
|
canScrollHorizontally;
|
|
67114
67211
|
viewportWidth;
|
|
@@ -67119,10 +67216,17 @@ class InternalViewport {
|
|
|
67119
67216
|
this.getters = getters;
|
|
67120
67217
|
this.sheetId = sheetId;
|
|
67121
67218
|
this.boundaries = boundaries;
|
|
67122
|
-
|
|
67123
|
-
|
|
67124
|
-
|
|
67125
|
-
this.
|
|
67219
|
+
if (sizeInGrid.width < 0 || sizeInGrid.height < 0) {
|
|
67220
|
+
throw new Error("Viewport size cannot be negative");
|
|
67221
|
+
}
|
|
67222
|
+
this.viewportWidth = sizeInGrid.height && sizeInGrid.width;
|
|
67223
|
+
this.viewportHeight = sizeInGrid.width && sizeInGrid.height;
|
|
67224
|
+
this.top = boundaries.top;
|
|
67225
|
+
this.bottom = boundaries.bottom;
|
|
67226
|
+
this.left = boundaries.left;
|
|
67227
|
+
this.right = boundaries.right;
|
|
67228
|
+
this.offsetX = offsets.x;
|
|
67229
|
+
this.offsetY = offsets.y;
|
|
67126
67230
|
this.canScrollVertically = options.canScrollVertically;
|
|
67127
67231
|
this.canScrollHorizontally = options.canScrollHorizontally;
|
|
67128
67232
|
this.offsetCorrectionX = this.getters.getColDimensions(this.sheetId, this.boundaries.left).start;
|
|
@@ -67163,9 +67267,9 @@ class InternalViewport {
|
|
|
67163
67267
|
Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
|
|
67164
67268
|
);
|
|
67165
67269
|
height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
|
|
67166
|
-
|
|
67167
|
-
|
|
67168
|
-
|
|
67270
|
+
if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
|
|
67271
|
+
height += FOOTER_HEIGHT;
|
|
67272
|
+
}
|
|
67169
67273
|
}
|
|
67170
67274
|
return { width, height };
|
|
67171
67275
|
}
|
|
@@ -67178,7 +67282,7 @@ class InternalViewport {
|
|
|
67178
67282
|
if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
|
|
67179
67283
|
return -1;
|
|
67180
67284
|
}
|
|
67181
|
-
return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left);
|
|
67285
|
+
return this.searchHeaderIndex("COL", x - this.offsetCorrectionX + this.snapCorrection.x, this.left);
|
|
67182
67286
|
}
|
|
67183
67287
|
/**
|
|
67184
67288
|
* Return the index of a row given an offset y, based on the pane top
|
|
@@ -67189,7 +67293,7 @@ class InternalViewport {
|
|
|
67189
67293
|
if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
|
|
67190
67294
|
return -1;
|
|
67191
67295
|
}
|
|
67192
|
-
return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top);
|
|
67296
|
+
return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY + this.snapCorrection.y, this.top);
|
|
67193
67297
|
}
|
|
67194
67298
|
/**
|
|
67195
67299
|
* This function will make sure that the provided cell position (or current selected position) is part of
|
|
@@ -67209,55 +67313,29 @@ class InternalViewport {
|
|
|
67209
67313
|
}
|
|
67210
67314
|
adjustPositionX(targetCol) {
|
|
67211
67315
|
const sheetId = this.sheetId;
|
|
67212
|
-
const { end } = this.getters.getColDimensions(sheetId, targetCol);
|
|
67213
|
-
if (this.offsetX + this.
|
|
67214
|
-
|
|
67215
|
-
|
|
67216
|
-
|
|
67217
|
-
|
|
67218
|
-
}
|
|
67219
|
-
const finalTargetEnd = this.getters.getColDimensions(sheetId, finalTarget).end;
|
|
67220
|
-
const startIndex = this.searchHeaderIndex("COL", finalTargetEnd - this.viewportWidth - this.offsetCorrectionX, this.boundaries.left);
|
|
67221
|
-
this.offsetScrollbarX =
|
|
67222
|
-
this.getters.getColDimensions(sheetId, startIndex).end - this.offsetCorrectionX;
|
|
67223
|
-
}
|
|
67224
|
-
else if (this.left > targetCol) {
|
|
67225
|
-
let finalTarget = targetCol;
|
|
67226
|
-
while (this.getters.isColHidden(sheetId, finalTarget) && finalTarget > 0) {
|
|
67227
|
-
finalTarget--;
|
|
67228
|
-
}
|
|
67229
|
-
this.offsetScrollbarX =
|
|
67230
|
-
this.getters.getColDimensions(sheetId, finalTarget).start - this.offsetCorrectionX;
|
|
67316
|
+
const { start, end } = this.getters.getColDimensions(sheetId, targetCol);
|
|
67317
|
+
if (this.offsetX + this.viewportWidth + this.offsetCorrectionX < end) {
|
|
67318
|
+
this.offsetX = end - this.viewportWidth;
|
|
67319
|
+
}
|
|
67320
|
+
else if (this.offsetX + this.offsetCorrectionX > start) {
|
|
67321
|
+
this.offsetX = start - this.offsetCorrectionX;
|
|
67231
67322
|
}
|
|
67232
67323
|
this.adjustViewportZoneX();
|
|
67233
67324
|
}
|
|
67234
67325
|
adjustPositionY(targetRow) {
|
|
67235
67326
|
const sheetId = this.sheetId;
|
|
67236
|
-
const { end } = this.getters.getRowDimensions(sheetId, targetRow);
|
|
67327
|
+
const { start, end } = this.getters.getRowDimensions(sheetId, targetRow);
|
|
67237
67328
|
if (this.offsetY + this.viewportHeight + this.offsetCorrectionY < end) {
|
|
67238
|
-
|
|
67239
|
-
let finalTarget = targetRow;
|
|
67240
|
-
while (this.getters.isRowHidden(sheetId, finalTarget) && finalTarget < maxRow) {
|
|
67241
|
-
finalTarget++;
|
|
67242
|
-
}
|
|
67243
|
-
const finalTargetEnd = this.getters.getRowDimensions(sheetId, finalTarget).end;
|
|
67244
|
-
const startIndex = this.searchHeaderIndex("ROW", finalTargetEnd - this.viewportHeight - this.offsetCorrectionY, this.boundaries.top);
|
|
67245
|
-
this.offsetScrollbarY =
|
|
67246
|
-
this.getters.getRowDimensions(sheetId, startIndex).end - this.offsetCorrectionY;
|
|
67329
|
+
this.offsetY = end - this.viewportHeight;
|
|
67247
67330
|
}
|
|
67248
|
-
else if (this.
|
|
67249
|
-
|
|
67250
|
-
while (this.getters.isRowHidden(sheetId, finalTarget) && finalTarget > 0) {
|
|
67251
|
-
finalTarget--;
|
|
67252
|
-
}
|
|
67253
|
-
this.offsetScrollbarY =
|
|
67254
|
-
this.getters.getRowDimensions(sheetId, finalTarget).start - this.offsetCorrectionY;
|
|
67331
|
+
else if (this.offsetY + this.offsetCorrectionY > start) {
|
|
67332
|
+
this.offsetY = start - this.offsetCorrectionY;
|
|
67255
67333
|
}
|
|
67256
67334
|
this.adjustViewportZoneY();
|
|
67257
67335
|
}
|
|
67258
67336
|
willNewOffsetScrollViewport(offsetX, offsetY) {
|
|
67259
|
-
return ((this.canScrollHorizontally && this.
|
|
67260
|
-
(this.canScrollVertically && this.
|
|
67337
|
+
return ((this.canScrollHorizontally && this.offsetX !== offsetX) ||
|
|
67338
|
+
(this.canScrollVertically && this.offsetY !== offsetY));
|
|
67261
67339
|
}
|
|
67262
67340
|
setViewportOffset(offsetX, offsetY) {
|
|
67263
67341
|
this.setViewportOffsetX(offsetX);
|
|
@@ -67274,11 +67352,19 @@ class InternalViewport {
|
|
|
67274
67352
|
*/
|
|
67275
67353
|
getVisibleRect(zone) {
|
|
67276
67354
|
const targetZone = intersection(zone, this);
|
|
67355
|
+
const scrollDeltaX = this.snapCorrection.x;
|
|
67356
|
+
const scrollDeltaY = this.snapCorrection.y;
|
|
67277
67357
|
if (targetZone) {
|
|
67278
|
-
const x = this.getters.getColRowOffset("COL", this.left, targetZone.left) +
|
|
67279
|
-
|
|
67280
|
-
|
|
67281
|
-
const
|
|
67358
|
+
const x = this.getters.getColRowOffset("COL", this.left, targetZone.left) +
|
|
67359
|
+
this.offsetCorrectionX -
|
|
67360
|
+
(this.left !== targetZone.left ? scrollDeltaX : 0);
|
|
67361
|
+
const y = this.getters.getColRowOffset("ROW", this.top, targetZone.top) +
|
|
67362
|
+
this.offsetCorrectionY -
|
|
67363
|
+
(this.top !== targetZone.top ? scrollDeltaY : 0);
|
|
67364
|
+
const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1) -
|
|
67365
|
+
(this.left === targetZone.left ? scrollDeltaX : 0), this.viewportWidth);
|
|
67366
|
+
const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1) -
|
|
67367
|
+
(this.top === targetZone.top ? scrollDeltaY : 0), this.viewportHeight);
|
|
67282
67368
|
return { x, y, width, height };
|
|
67283
67369
|
}
|
|
67284
67370
|
return undefined;
|
|
@@ -67290,12 +67376,14 @@ class InternalViewport {
|
|
|
67290
67376
|
*/
|
|
67291
67377
|
getFullRect(zone) {
|
|
67292
67378
|
const targetZone = intersection(zone, this);
|
|
67379
|
+
const scrollDeltaX = this.snapCorrection.x;
|
|
67380
|
+
const scrollDeltaY = this.snapCorrection.y;
|
|
67293
67381
|
if (targetZone) {
|
|
67294
67382
|
const x = this.getters.getColRowOffset("COL", this.left, zone.left) + this.offsetCorrectionX;
|
|
67295
67383
|
const y = this.getters.getColRowOffset("ROW", this.top, zone.top) + this.offsetCorrectionY;
|
|
67296
67384
|
const width = this.getters.getColRowOffset("COL", zone.left, zone.right + 1);
|
|
67297
67385
|
const height = this.getters.getColRowOffset("ROW", zone.top, zone.bottom + 1);
|
|
67298
|
-
return { x, y, width, height };
|
|
67386
|
+
return { x: x - scrollDeltaX, y: y - scrollDeltaY, width, height };
|
|
67299
67387
|
}
|
|
67300
67388
|
return undefined;
|
|
67301
67389
|
}
|
|
@@ -67306,6 +67394,9 @@ class InternalViewport {
|
|
|
67306
67394
|
!this.getters.isRowHidden(this.sheetId, row));
|
|
67307
67395
|
}
|
|
67308
67396
|
searchHeaderIndex(dimension, position, startIndex = 0) {
|
|
67397
|
+
if (this.viewportWidth <= 0 || this.viewportHeight <= 0) {
|
|
67398
|
+
return -1;
|
|
67399
|
+
}
|
|
67309
67400
|
const sheetId = this.sheetId;
|
|
67310
67401
|
const headers = this.getters.getNumberHeaders(sheetId, dimension);
|
|
67311
67402
|
// using a binary search:
|
|
@@ -67331,36 +67422,36 @@ class InternalViewport {
|
|
|
67331
67422
|
if (!this.canScrollHorizontally) {
|
|
67332
67423
|
return;
|
|
67333
67424
|
}
|
|
67334
|
-
this.
|
|
67425
|
+
this.offsetX = offsetX;
|
|
67335
67426
|
this.adjustViewportZoneX();
|
|
67336
67427
|
}
|
|
67337
67428
|
setViewportOffsetY(offsetY) {
|
|
67338
67429
|
if (!this.canScrollVertically) {
|
|
67339
67430
|
return;
|
|
67340
67431
|
}
|
|
67341
|
-
this.
|
|
67432
|
+
this.offsetY = offsetY;
|
|
67342
67433
|
this.adjustViewportZoneY();
|
|
67343
67434
|
}
|
|
67344
67435
|
/** Corrects the viewport's horizontal offset based on the current structure
|
|
67345
|
-
* To make sure that at least
|
|
67436
|
+
* To make sure that at least one column is visible inside the viewport.
|
|
67346
67437
|
*/
|
|
67347
67438
|
adjustViewportOffsetX() {
|
|
67348
67439
|
if (this.canScrollHorizontally) {
|
|
67349
67440
|
const { width: viewportWidth } = this.getMaxSize();
|
|
67350
|
-
if (this.viewportWidth + this.
|
|
67351
|
-
this.
|
|
67441
|
+
if (this.viewportWidth + this.offsetX > viewportWidth) {
|
|
67442
|
+
this.offsetX = Math.max(0, viewportWidth - this.viewportWidth);
|
|
67352
67443
|
}
|
|
67353
67444
|
}
|
|
67354
67445
|
this.adjustViewportZoneX();
|
|
67355
67446
|
}
|
|
67356
67447
|
/** Corrects the viewport's vertical offset based on the current structure
|
|
67357
|
-
* To make sure that at least
|
|
67448
|
+
* To make sure that at least one row is visible inside the viewport.
|
|
67358
67449
|
*/
|
|
67359
67450
|
adjustViewportOffsetY() {
|
|
67360
67451
|
if (this.canScrollVertically) {
|
|
67361
67452
|
const { height: paneHeight } = this.getMaxSize();
|
|
67362
|
-
if (this.viewportHeight + this.
|
|
67363
|
-
this.
|
|
67453
|
+
if (this.viewportHeight + this.offsetY > paneHeight) {
|
|
67454
|
+
this.offsetY = Math.max(0, paneHeight - this.viewportHeight);
|
|
67364
67455
|
}
|
|
67365
67456
|
}
|
|
67366
67457
|
this.adjustViewportZoneY();
|
|
@@ -67368,34 +67459,47 @@ class InternalViewport {
|
|
|
67368
67459
|
/** Updates the pane zone and snapped offset based on its horizontal
|
|
67369
67460
|
* offset (will find Left) and its width (will find Right) */
|
|
67370
67461
|
adjustViewportZoneX() {
|
|
67371
|
-
|
|
67372
|
-
this.
|
|
67373
|
-
|
|
67462
|
+
this.left = this.searchHeaderIndex("COL", this.offsetX, this.boundaries.left);
|
|
67463
|
+
this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL",
|
|
67464
|
+
// if we hit the border of two cells, we want to match the previous
|
|
67465
|
+
Math.max(this.viewportWidth + this.snapCorrection.x - 0.1), this.left));
|
|
67466
|
+
if (!this.viewportWidth) {
|
|
67467
|
+
return;
|
|
67468
|
+
}
|
|
67374
67469
|
if (this.left === -1) {
|
|
67375
67470
|
this.left = this.boundaries.left;
|
|
67376
67471
|
}
|
|
67377
67472
|
if (this.right === -1) {
|
|
67378
|
-
this.right = this.
|
|
67473
|
+
this.right = this.boundaries.right;
|
|
67379
67474
|
}
|
|
67380
|
-
this.offsetX =
|
|
67381
|
-
this.getters.getColDimensions(sheetId, this.left).start -
|
|
67382
|
-
this.getters.getColDimensions(sheetId, this.boundaries.left).start;
|
|
67383
67475
|
}
|
|
67384
67476
|
/** Updates the pane zone and snapped offset based on its vertical
|
|
67385
67477
|
* offset (will find Top) and its width (will find Bottom) */
|
|
67386
67478
|
adjustViewportZoneY() {
|
|
67387
|
-
|
|
67388
|
-
this.
|
|
67389
|
-
|
|
67479
|
+
this.top = this.searchHeaderIndex("ROW", this.offsetY, this.boundaries.top);
|
|
67480
|
+
this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW",
|
|
67481
|
+
// if we hit the border of two cells, we want to match the previous
|
|
67482
|
+
Math.max(this.viewportHeight + this.snapCorrection.y - 0.1, 0), this.top));
|
|
67483
|
+
if (!this.viewportHeight) {
|
|
67484
|
+
return;
|
|
67485
|
+
}
|
|
67390
67486
|
if (this.top === -1) {
|
|
67391
67487
|
this.top = this.boundaries.top;
|
|
67392
67488
|
}
|
|
67393
67489
|
if (this.bottom === -1) {
|
|
67394
|
-
this.bottom = this.
|
|
67490
|
+
this.bottom = this.boundaries.bottom;
|
|
67395
67491
|
}
|
|
67396
|
-
|
|
67397
|
-
|
|
67398
|
-
|
|
67492
|
+
}
|
|
67493
|
+
/** represents the part of the header on the topLeft that could be partially
|
|
67494
|
+
* hidden due to the scroll
|
|
67495
|
+
* */
|
|
67496
|
+
get snapCorrection() {
|
|
67497
|
+
return {
|
|
67498
|
+
x: Math.abs(this.offsetX -
|
|
67499
|
+
this.getters.getColRowOffset("COL", this.boundaries.left, Math.max(0, this.left))),
|
|
67500
|
+
y: Math.abs(this.offsetY -
|
|
67501
|
+
this.getters.getColRowOffset("ROW", this.boundaries.top, Math.max(0, this.top))),
|
|
67502
|
+
};
|
|
67399
67503
|
}
|
|
67400
67504
|
}
|
|
67401
67505
|
|
|
@@ -67458,14 +67562,13 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
67458
67562
|
"getColRowOffsetInViewport",
|
|
67459
67563
|
"getMainViewportCoordinates",
|
|
67460
67564
|
"getActiveSheetScrollInfo",
|
|
67461
|
-
"getActiveSheetDOMScrollInfo",
|
|
67462
67565
|
"getSheetViewVisibleCols",
|
|
67463
67566
|
"getSheetViewVisibleRows",
|
|
67464
67567
|
"getFrozenSheetViewRatio",
|
|
67465
|
-
"
|
|
67568
|
+
"isPixelPositionVisible",
|
|
67466
67569
|
"getColDimensionsInViewport",
|
|
67467
67570
|
"getRowDimensionsInViewport",
|
|
67468
|
-
"
|
|
67571
|
+
"getAllActiveViewportsZonesAndRect",
|
|
67469
67572
|
"getRect",
|
|
67470
67573
|
];
|
|
67471
67574
|
viewports = {};
|
|
@@ -67668,8 +67771,8 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
67668
67771
|
return this.getMainViewport(sheetId);
|
|
67669
67772
|
}
|
|
67670
67773
|
/**
|
|
67671
|
-
* Return the scroll info of the active sheet, ie. the offset between the viewport left/top side and
|
|
67672
|
-
* the grid left/top side, snapped to the
|
|
67774
|
+
* Return the DOM scroll info of the active sheet, ie. the offset between the viewport left/top side and
|
|
67775
|
+
* the grid left/top side, corresponding to the scroll of the scrollbars and not snapped to the grid.
|
|
67673
67776
|
*/
|
|
67674
67777
|
getActiveSheetScrollInfo() {
|
|
67675
67778
|
const sheetId = this.getters.getActiveSheetId();
|
|
@@ -67679,28 +67782,16 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
67679
67782
|
scrollY: viewport.offsetY,
|
|
67680
67783
|
};
|
|
67681
67784
|
}
|
|
67682
|
-
/**
|
|
67683
|
-
* Return the DOM scroll info of the active sheet, ie. the offset between the viewport left/top side and
|
|
67684
|
-
* the grid left/top side, corresponding to the scroll of the scrollbars and not snapped to the grid.
|
|
67685
|
-
*/
|
|
67686
|
-
getActiveSheetDOMScrollInfo() {
|
|
67687
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
67688
|
-
const viewport = this.getMainInternalViewport(sheetId);
|
|
67689
|
-
return {
|
|
67690
|
-
scrollX: viewport.offsetScrollbarX,
|
|
67691
|
-
scrollY: viewport.offsetScrollbarY,
|
|
67692
|
-
};
|
|
67693
|
-
}
|
|
67694
67785
|
getSheetViewVisibleCols() {
|
|
67695
67786
|
const sheetId = this.getters.getActiveSheetId();
|
|
67696
67787
|
const viewports = this.getSubViewports(sheetId);
|
|
67697
67788
|
//TODO ake another commit to eimprove this
|
|
67698
|
-
return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => !this.getters.isHeaderHidden(sheetId, "COL", col));
|
|
67789
|
+
return [...new Set(viewports.map((v) => range(v.left, v.right + 1)).flat())].filter((col) => col >= 0 && !this.getters.isHeaderHidden(sheetId, "COL", col));
|
|
67699
67790
|
}
|
|
67700
67791
|
getSheetViewVisibleRows() {
|
|
67701
67792
|
const sheetId = this.getters.getActiveSheetId();
|
|
67702
67793
|
const viewports = this.getSubViewports(sheetId);
|
|
67703
|
-
return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
|
|
67794
|
+
return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => row >= 0 && !this.getters.isHeaderHidden(sheetId, "ROW", row));
|
|
67704
67795
|
}
|
|
67705
67796
|
/**
|
|
67706
67797
|
* Get the positions of all the cells that are visible in the viewport, taking merges into account.
|
|
@@ -67743,19 +67834,19 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
67743
67834
|
maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
|
|
67744
67835
|
};
|
|
67745
67836
|
}
|
|
67746
|
-
getColRowOffsetInViewport(dimension,
|
|
67747
|
-
|
|
67748
|
-
|
|
67749
|
-
const visibleRows = this.getters.getSheetViewVisibleRows();
|
|
67750
|
-
if (index < referenceIndex) {
|
|
67751
|
-
return -this.getColRowOffsetInViewport(dimension, index, referenceIndex);
|
|
67837
|
+
getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
|
|
67838
|
+
if (targetHeaderIndex < referenceHeaderIndex) {
|
|
67839
|
+
return -this.getColRowOffsetInViewport(dimension, targetHeaderIndex, referenceHeaderIndex);
|
|
67752
67840
|
}
|
|
67841
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
67842
|
+
const visibleHeaders = dimension === "COL"
|
|
67843
|
+
? this.getters.getSheetViewVisibleCols()
|
|
67844
|
+
: this.getters.getSheetViewVisibleRows();
|
|
67845
|
+
const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
|
|
67846
|
+
const endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
|
|
67847
|
+
const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
|
|
67753
67848
|
let offset = 0;
|
|
67754
|
-
const
|
|
67755
|
-
for (let i = referenceIndex; i < index; i++) {
|
|
67756
|
-
if (!visibleIndexes.includes(i)) {
|
|
67757
|
-
continue;
|
|
67758
|
-
}
|
|
67849
|
+
for (const i of relevantIndexes) {
|
|
67759
67850
|
offset += this.getters.getHeaderSize(sheetId, dimension, i);
|
|
67760
67851
|
}
|
|
67761
67852
|
return offset;
|
|
@@ -67802,7 +67893,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
67802
67893
|
}
|
|
67803
67894
|
return { canEdgeScroll, direction, delay };
|
|
67804
67895
|
}
|
|
67805
|
-
getEdgeScrollRow(y, previousY,
|
|
67896
|
+
getEdgeScrollRow(y, previousY, startingY) {
|
|
67806
67897
|
let canEdgeScroll = false;
|
|
67807
67898
|
let direction = 0;
|
|
67808
67899
|
let delay = 0;
|
|
@@ -67823,7 +67914,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
67823
67914
|
delay = scrollDelay(y - height);
|
|
67824
67915
|
direction = 1;
|
|
67825
67916
|
}
|
|
67826
|
-
else if (y < offsetCorrectionY &&
|
|
67917
|
+
else if (y < offsetCorrectionY && startingY >= offsetCorrectionY && currentOffsetY > 0) {
|
|
67827
67918
|
// 2
|
|
67828
67919
|
canEdgeScroll = true;
|
|
67829
67920
|
delay = scrollDelay(offsetCorrectionY - y);
|
|
@@ -67849,13 +67940,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
67849
67940
|
*/
|
|
67850
67941
|
getVisibleRectWithoutHeaders(zone) {
|
|
67851
67942
|
const sheetId = this.getters.getActiveSheetId();
|
|
67852
|
-
|
|
67853
|
-
.map((viewport) => viewport.getVisibleRect(zone))
|
|
67854
|
-
.filter(isDefined);
|
|
67855
|
-
if (viewportRects.length === 0) {
|
|
67856
|
-
return { x: 0, y: 0, width: 0, height: 0 };
|
|
67857
|
-
}
|
|
67858
|
-
return this.recomposeRect(viewportRects);
|
|
67943
|
+
return this.mapViewportsToRect(sheetId, (viewport) => viewport.getVisibleRect(zone));
|
|
67859
67944
|
}
|
|
67860
67945
|
/**
|
|
67861
67946
|
* Computes the actual size and position (:Rect) of the zone on the canvas
|
|
@@ -67863,13 +67948,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
67863
67948
|
*/
|
|
67864
67949
|
getRect(zone) {
|
|
67865
67950
|
const sheetId = this.getters.getActiveSheetId();
|
|
67866
|
-
const
|
|
67867
|
-
.map((viewport) => viewport.getFullRect(zone))
|
|
67868
|
-
.filter(isDefined);
|
|
67869
|
-
if (viewportRects.length === 0) {
|
|
67870
|
-
return { x: 0, y: 0, width: 0, height: 0 };
|
|
67871
|
-
}
|
|
67872
|
-
const rect = this.recomposeRect(viewportRects);
|
|
67951
|
+
const rect = this.mapViewportsToRect(sheetId, (viewport) => viewport.getFullRect(zone));
|
|
67873
67952
|
return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
|
|
67874
67953
|
}
|
|
67875
67954
|
/**
|
|
@@ -67889,34 +67968,43 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
67889
67968
|
* column of the current viewport
|
|
67890
67969
|
*/
|
|
67891
67970
|
getColDimensionsInViewport(sheetId, col) {
|
|
67892
|
-
const
|
|
67893
|
-
|
|
67894
|
-
|
|
67895
|
-
|
|
67896
|
-
|
|
67897
|
-
start,
|
|
67898
|
-
size: size,
|
|
67899
|
-
end: start + (isColHidden ? 0 : size),
|
|
67971
|
+
const zone = {
|
|
67972
|
+
left: col,
|
|
67973
|
+
right: col,
|
|
67974
|
+
top: 0,
|
|
67975
|
+
bottom: this.getters.getNumberRows(sheetId) - 1,
|
|
67900
67976
|
};
|
|
67977
|
+
const { x, width } = this.getVisibleRect(zone);
|
|
67978
|
+
const start = x - this.gridOffsetX;
|
|
67979
|
+
return { start, size: width, end: start + width };
|
|
67901
67980
|
}
|
|
67902
67981
|
/**
|
|
67903
67982
|
* Returns the size, start and end coordinates of a row relative to the top row
|
|
67904
67983
|
* of the current viewport
|
|
67905
67984
|
*/
|
|
67906
67985
|
getRowDimensionsInViewport(sheetId, row) {
|
|
67907
|
-
const
|
|
67908
|
-
|
|
67909
|
-
|
|
67910
|
-
|
|
67911
|
-
|
|
67912
|
-
start,
|
|
67913
|
-
size: size,
|
|
67914
|
-
end: start + (isRowHidden ? 0 : size),
|
|
67986
|
+
const zone = {
|
|
67987
|
+
left: 0,
|
|
67988
|
+
right: this.getters.getNumberCols(sheetId) - 1,
|
|
67989
|
+
top: row,
|
|
67990
|
+
bottom: row,
|
|
67915
67991
|
};
|
|
67992
|
+
const { y, height } = this.getVisibleRect(zone);
|
|
67993
|
+
const start = y - this.gridOffsetY;
|
|
67994
|
+
return { start, size: height, end: start + height };
|
|
67916
67995
|
}
|
|
67917
|
-
|
|
67996
|
+
getAllActiveViewportsZonesAndRect() {
|
|
67918
67997
|
const sheetId = this.getters.getActiveSheetId();
|
|
67919
|
-
return this.getSubViewports(sheetId)
|
|
67998
|
+
return this.getSubViewports(sheetId).map((viewport) => {
|
|
67999
|
+
return {
|
|
68000
|
+
zone: viewport,
|
|
68001
|
+
rect: {
|
|
68002
|
+
x: viewport.offsetCorrectionX + this.gridOffsetX,
|
|
68003
|
+
y: viewport.offsetCorrectionY + this.gridOffsetY,
|
|
68004
|
+
...viewport.getMaxSize(),
|
|
68005
|
+
},
|
|
68006
|
+
};
|
|
68007
|
+
});
|
|
67920
68008
|
}
|
|
67921
68009
|
// ---------------------------------------------------------------------------
|
|
67922
68010
|
// Private
|
|
@@ -67975,12 +68063,11 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
67975
68063
|
}
|
|
67976
68064
|
/** gets rid of deprecated sheetIds */
|
|
67977
68065
|
cleanViewports() {
|
|
67978
|
-
const
|
|
67979
|
-
for (
|
|
67980
|
-
|
|
67981
|
-
delete this.viewports[sheetId];
|
|
67982
|
-
}
|
|
68066
|
+
const newViewport = {};
|
|
68067
|
+
for (const sheetId of this.getters.getSheetIds()) {
|
|
68068
|
+
newViewport[sheetId] = this.viewports[sheetId];
|
|
67983
68069
|
}
|
|
68070
|
+
this.viewports = newViewport;
|
|
67984
68071
|
}
|
|
67985
68072
|
resizeSheetView(height, width, gridOffsetX = 0, gridOffsetY = 0) {
|
|
67986
68073
|
this.sheetViewHeight = height;
|
|
@@ -67990,7 +68077,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
67990
68077
|
this.recomputeViewports();
|
|
67991
68078
|
}
|
|
67992
68079
|
recomputeViewports() {
|
|
67993
|
-
for (
|
|
68080
|
+
for (const sheetId of this.getters.getSheetIds()) {
|
|
67994
68081
|
this.resetViewports(sheetId);
|
|
67995
68082
|
}
|
|
67996
68083
|
}
|
|
@@ -68001,8 +68088,8 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
68001
68088
|
}
|
|
68002
68089
|
getViewportOffset(sheetId) {
|
|
68003
68090
|
return {
|
|
68004
|
-
x: this.viewports[sheetId]?.bottomRight.
|
|
68005
|
-
y: this.viewports[sheetId]?.bottomRight.
|
|
68091
|
+
x: this.viewports[sheetId]?.bottomRight.offsetX || 0,
|
|
68092
|
+
y: this.viewports[sheetId]?.bottomRight.offsetY || 0,
|
|
68006
68093
|
};
|
|
68007
68094
|
}
|
|
68008
68095
|
resetViewports(sheetId) {
|
|
@@ -68012,8 +68099,10 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
68012
68099
|
const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
|
|
68013
68100
|
const nCols = this.getters.getNumberCols(sheetId);
|
|
68014
68101
|
const nRows = this.getters.getNumberRows(sheetId);
|
|
68015
|
-
const colOffset = this.getters.getColRowOffset("COL", 0, xSplit, sheetId);
|
|
68016
|
-
const rowOffset = this.getters.getColRowOffset("ROW", 0, ySplit, sheetId);
|
|
68102
|
+
const colOffset = Math.min(this.getters.getColRowOffset("COL", 0, xSplit, sheetId), this.sheetViewWidth);
|
|
68103
|
+
const rowOffset = Math.min(this.getters.getColRowOffset("ROW", 0, ySplit, sheetId), this.sheetViewHeight);
|
|
68104
|
+
const unfrozenWidth = Math.max(this.sheetViewWidth - colOffset, 0);
|
|
68105
|
+
const unfrozenHeight = Math.max(this.sheetViewHeight - rowOffset, 0);
|
|
68017
68106
|
const { xRatio, yRatio } = this.getFrozenSheetViewRatio(sheetId);
|
|
68018
68107
|
const canScrollHorizontally = xRatio < 1.0;
|
|
68019
68108
|
const canScrollVertically = yRatio < 1.0;
|
|
@@ -68024,14 +68113,14 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
68024
68113
|
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 })) ||
|
|
68025
68114
|
undefined,
|
|
68026
68115
|
topRight: (ySplit &&
|
|
68027
|
-
new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: 0, bottom: ySplit - 1 }, { width:
|
|
68116
|
+
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 })) ||
|
|
68028
68117
|
undefined,
|
|
68029
68118
|
bottomLeft: (xSplit &&
|
|
68030
|
-
new InternalViewport(this.getters, sheetId, { left: 0, right: xSplit - 1, top: ySplit, bottom: nRows - 1 }, { width: colOffset, height:
|
|
68119
|
+
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 })) ||
|
|
68031
68120
|
undefined,
|
|
68032
68121
|
bottomRight: new InternalViewport(this.getters, sheetId, { left: xSplit, right: nCols - 1, top: ySplit, bottom: nRows - 1 }, {
|
|
68033
|
-
width:
|
|
68034
|
-
height:
|
|
68122
|
+
width: unfrozenWidth,
|
|
68123
|
+
height: unfrozenHeight,
|
|
68035
68124
|
}, { canScrollHorizontally, canScrollVertically }, {
|
|
68036
68125
|
x: canScrollHorizontally ? previousOffset.x : 0,
|
|
68037
68126
|
y: canScrollVertically ? previousOffset.y : 0,
|
|
@@ -68086,7 +68175,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
68086
68175
|
}
|
|
68087
68176
|
return result;
|
|
68088
68177
|
}
|
|
68089
|
-
|
|
68178
|
+
isPixelPositionVisible(position) {
|
|
68090
68179
|
const { scrollX, scrollY } = this.getters.getActiveSheetScrollInfo();
|
|
68091
68180
|
const { x: mainViewportX, y: mainViewportY } = this.getters.getMainViewportCoordinates();
|
|
68092
68181
|
const { width, height } = this.getters.getSheetViewDimension();
|
|
@@ -68108,12 +68197,26 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
68108
68197
|
const height = this.sheetViewHeight + this.gridOffsetY;
|
|
68109
68198
|
return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
|
|
68110
68199
|
}
|
|
68111
|
-
|
|
68112
|
-
|
|
68113
|
-
|
|
68114
|
-
|
|
68115
|
-
|
|
68116
|
-
|
|
68200
|
+
mapViewportsToRect(sheetId, rectCallBack) {
|
|
68201
|
+
let x = Infinity;
|
|
68202
|
+
let y = Infinity;
|
|
68203
|
+
let width = 0;
|
|
68204
|
+
let height = 0;
|
|
68205
|
+
let hasViewports = false;
|
|
68206
|
+
for (const viewport of this.getSubViewports(sheetId)) {
|
|
68207
|
+
const rect = rectCallBack(viewport);
|
|
68208
|
+
if (rect) {
|
|
68209
|
+
hasViewports = true;
|
|
68210
|
+
x = Math.min(x, rect.x);
|
|
68211
|
+
y = Math.min(y, rect.y);
|
|
68212
|
+
width = Math.max(width, rect.x + rect.width);
|
|
68213
|
+
height = Math.max(height, rect.y + rect.height);
|
|
68214
|
+
}
|
|
68215
|
+
}
|
|
68216
|
+
if (!hasViewports) {
|
|
68217
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
68218
|
+
}
|
|
68219
|
+
return { x, y, width: width - x, height: height - y };
|
|
68117
68220
|
}
|
|
68118
68221
|
}
|
|
68119
68222
|
|
|
@@ -69288,7 +69391,7 @@ class SpreadsheetDashboard extends owl.Component {
|
|
|
69288
69391
|
});
|
|
69289
69392
|
}
|
|
69290
69393
|
moveCanvas(deltaX, deltaY) {
|
|
69291
|
-
const { scrollX, scrollY } = this.env.model.getters.
|
|
69394
|
+
const { scrollX, scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
69292
69395
|
this.env.model.dispatch("SET_VIEWPORT_OFFSET", {
|
|
69293
69396
|
offsetX: scrollX + deltaX,
|
|
69294
69397
|
offsetY: scrollY + deltaY,
|
|
@@ -70481,12 +70584,8 @@ css /* scss */ `
|
|
|
70481
70584
|
.o-spreadsheet {
|
|
70482
70585
|
position: relative;
|
|
70483
70586
|
display: grid;
|
|
70484
|
-
color: ${TEXT_BODY};
|
|
70485
70587
|
font-size: 14px;
|
|
70486
70588
|
|
|
70487
|
-
input {
|
|
70488
|
-
background-color: white;
|
|
70489
|
-
}
|
|
70490
70589
|
.text-muted {
|
|
70491
70590
|
color: ${TEXT_BODY_MUTED} !important;
|
|
70492
70591
|
}
|
|
@@ -71733,6 +71832,9 @@ class EventStream {
|
|
|
71733
71832
|
observe(owner, callbacks) {
|
|
71734
71833
|
this.observers.set(owner, { owner, callbacks });
|
|
71735
71834
|
}
|
|
71835
|
+
detachObserver(owner) {
|
|
71836
|
+
this.observers.delete(owner);
|
|
71837
|
+
}
|
|
71736
71838
|
/**
|
|
71737
71839
|
* Capture the stream for yourself
|
|
71738
71840
|
*/
|
|
@@ -71825,6 +71927,9 @@ class SelectionStreamProcessorImpl {
|
|
|
71825
71927
|
observe(owner, callbacks) {
|
|
71826
71928
|
this.stream.observe(owner, callbacks);
|
|
71827
71929
|
}
|
|
71930
|
+
detachObserver(owner) {
|
|
71931
|
+
this.stream.detachObserver(owner);
|
|
71932
|
+
}
|
|
71828
71933
|
release(owner) {
|
|
71829
71934
|
if (this.stream.isListening(owner)) {
|
|
71830
71935
|
this.stream.release(owner);
|
|
@@ -75274,6 +75379,6 @@ exports.tokenColors = tokenColors;
|
|
|
75274
75379
|
exports.tokenize = tokenize;
|
|
75275
75380
|
|
|
75276
75381
|
|
|
75277
|
-
__info__.version = "18.2.0-alpha.
|
|
75278
|
-
__info__.date = "2025-
|
|
75279
|
-
__info__.hash = "
|
|
75382
|
+
__info__.version = "18.2.0-alpha.6";
|
|
75383
|
+
__info__.date = "2025-02-05T06:50:47.008Z";
|
|
75384
|
+
__info__.hash = "dae9ab2";
|