@odoo/o-spreadsheet 17.1.4 → 17.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/o-spreadsheet.cjs.js +274 -183
- package/dist/o-spreadsheet.d.ts +28 -14
- package/dist/o-spreadsheet.esm.js +274 -183
- package/dist/o-spreadsheet.iife.js +274 -183
- package/dist/o-spreadsheet.iife.min.js +294 -291
- package/dist/o_spreadsheet.xml +7 -6
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 17.1.
|
|
6
|
-
* @date 2024-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.1.7
|
|
6
|
+
* @date 2024-03-12T07:56:10.783Z
|
|
7
|
+
* @hash 3a9f334
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -453,8 +453,8 @@ function isObjectEmptyRecursive(argument) {
|
|
|
453
453
|
* If the given item does not exist in the dictionary, it creates one with a new id.
|
|
454
454
|
*/
|
|
455
455
|
function getItemId(item, itemsDic) {
|
|
456
|
-
for (
|
|
457
|
-
if (deepEquals(
|
|
456
|
+
for (const key in itemsDic) {
|
|
457
|
+
if (deepEquals(itemsDic[key], item)) {
|
|
458
458
|
return parseInt(key, 10);
|
|
459
459
|
}
|
|
460
460
|
}
|
|
@@ -553,11 +553,13 @@ function deepEquals(o1, o2) {
|
|
|
553
553
|
if (typeof o1 !== "object")
|
|
554
554
|
return o1 === o2;
|
|
555
555
|
// Objects can have different keys if the values are undefined
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
556
|
+
for (const key in o2) {
|
|
557
|
+
if (!(key in o1) && o2[key] !== undefined) {
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
for (const key in o1) {
|
|
562
|
+
if (typeof o1[key] !== typeof o2[key])
|
|
561
563
|
return false;
|
|
562
564
|
if (typeof o1[key] === "object") {
|
|
563
565
|
if (!deepEquals(o1[key], o2[key]))
|
|
@@ -627,18 +629,18 @@ function isConsecutive(iterable) {
|
|
|
627
629
|
return true;
|
|
628
630
|
}
|
|
629
631
|
class JetSet extends Set {
|
|
630
|
-
|
|
632
|
+
addMany(iterable) {
|
|
631
633
|
for (const element of iterable) {
|
|
632
634
|
super.add(element);
|
|
633
635
|
}
|
|
634
636
|
return this;
|
|
635
637
|
}
|
|
636
|
-
|
|
637
|
-
let
|
|
638
|
+
deleteMany(iterable) {
|
|
639
|
+
let wasDeleted = false;
|
|
638
640
|
for (const element of iterable) {
|
|
639
|
-
|
|
641
|
+
wasDeleted ||= super.delete(element);
|
|
640
642
|
}
|
|
641
|
-
return
|
|
643
|
+
return wasDeleted;
|
|
642
644
|
}
|
|
643
645
|
}
|
|
644
646
|
/**
|
|
@@ -1936,7 +1938,7 @@ class DispatchResult {
|
|
|
1936
1938
|
* Static helper which returns a successful DispatchResult
|
|
1937
1939
|
*/
|
|
1938
1940
|
static get Success() {
|
|
1939
|
-
return
|
|
1941
|
+
return SUCCESS;
|
|
1940
1942
|
}
|
|
1941
1943
|
get isSuccessful() {
|
|
1942
1944
|
return this.reasons.length === 0;
|
|
@@ -1949,6 +1951,7 @@ class DispatchResult {
|
|
|
1949
1951
|
return this.reasons.includes(reason);
|
|
1950
1952
|
}
|
|
1951
1953
|
}
|
|
1954
|
+
const SUCCESS = new DispatchResult();
|
|
1952
1955
|
exports.CommandResult = void 0;
|
|
1953
1956
|
(function (CommandResult) {
|
|
1954
1957
|
CommandResult["Success"] = "Success";
|
|
@@ -6097,8 +6100,10 @@ function getGroup(cell, cells, filter) {
|
|
|
6097
6100
|
if (x === cell) {
|
|
6098
6101
|
found = true;
|
|
6099
6102
|
}
|
|
6100
|
-
const cellValue =
|
|
6101
|
-
|
|
6103
|
+
const cellValue = x?.isFormula
|
|
6104
|
+
? undefined
|
|
6105
|
+
: evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
|
|
6106
|
+
if (cellValue && filter(cellValue)) {
|
|
6102
6107
|
group.push(cellValue);
|
|
6103
6108
|
}
|
|
6104
6109
|
else {
|
|
@@ -6322,11 +6327,14 @@ function cellTextStyleToCss(style) {
|
|
|
6322
6327
|
* Transform CSS properties into a CSS string.
|
|
6323
6328
|
*/
|
|
6324
6329
|
function cssPropertiesToCss(attributes) {
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
+
let styleStr = "";
|
|
6331
|
+
for (const attName in attributes) {
|
|
6332
|
+
if (!attributes[attName]) {
|
|
6333
|
+
continue;
|
|
6334
|
+
}
|
|
6335
|
+
styleStr += `${attName}:${attributes[attName]}; `;
|
|
6336
|
+
}
|
|
6337
|
+
return styleStr;
|
|
6330
6338
|
}
|
|
6331
6339
|
function getElementMargins(el) {
|
|
6332
6340
|
const style = window.getComputedStyle(el);
|
|
@@ -7655,6 +7663,9 @@ function isValidLocale(locale) {
|
|
|
7655
7663
|
if (locale.formulaArgSeparator === locale.decimalSeparator) {
|
|
7656
7664
|
return false;
|
|
7657
7665
|
}
|
|
7666
|
+
if (locale.thousandsSeparator === locale.decimalSeparator) {
|
|
7667
|
+
return false;
|
|
7668
|
+
}
|
|
7658
7669
|
try {
|
|
7659
7670
|
formatValue(1, { locale, format: "#,##0.00" });
|
|
7660
7671
|
formatValue(1, { locale, format: locale.dateFormat });
|
|
@@ -7745,7 +7756,7 @@ function canonicalizeNumberLiteral(content, locale) {
|
|
|
7745
7756
|
if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
|
|
7746
7757
|
return content;
|
|
7747
7758
|
}
|
|
7748
|
-
return content.replace(locale.decimalSeparator, ".");
|
|
7759
|
+
return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
|
|
7749
7760
|
}
|
|
7750
7761
|
/**
|
|
7751
7762
|
* Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
|
|
@@ -10840,6 +10851,12 @@ const INSERT_LINK = (env) => {
|
|
|
10840
10851
|
let { col, row } = env.model.getters.getActivePosition();
|
|
10841
10852
|
env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
|
|
10842
10853
|
};
|
|
10854
|
+
const INSERT_LINK_NAME = (env) => {
|
|
10855
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
10856
|
+
const { col, row } = env.model.getters.getActivePosition();
|
|
10857
|
+
const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
|
|
10858
|
+
return cell && cell.link ? _t("Edit link") : _t("Insert link");
|
|
10859
|
+
};
|
|
10843
10860
|
//------------------------------------------------------------------------------
|
|
10844
10861
|
// Filters action
|
|
10845
10862
|
//------------------------------------------------------------------------------
|
|
@@ -13041,6 +13058,18 @@ const TRUNC = {
|
|
|
13041
13058
|
},
|
|
13042
13059
|
isExported: true,
|
|
13043
13060
|
};
|
|
13061
|
+
// -----------------------------------------------------------------------------
|
|
13062
|
+
// INT
|
|
13063
|
+
// -----------------------------------------------------------------------------
|
|
13064
|
+
const INT = {
|
|
13065
|
+
description: _t("Rounds a number down to the nearest integer that is less than or equal to it."),
|
|
13066
|
+
args: [arg("value (number)", _t("The number to round down to the nearest integer."))],
|
|
13067
|
+
returns: ["NUMBER"],
|
|
13068
|
+
compute: function (value) {
|
|
13069
|
+
return Math.floor(toNumber(value, this.locale));
|
|
13070
|
+
},
|
|
13071
|
+
isExported: true,
|
|
13072
|
+
};
|
|
13044
13073
|
|
|
13045
13074
|
var math = /*#__PURE__*/Object.freeze({
|
|
13046
13075
|
__proto__: null,
|
|
@@ -13074,6 +13103,7 @@ var math = /*#__PURE__*/Object.freeze({
|
|
|
13074
13103
|
FLOOR: FLOOR,
|
|
13075
13104
|
FLOOR_MATH: FLOOR_MATH,
|
|
13076
13105
|
FLOOR_PRECISE: FLOOR_PRECISE,
|
|
13106
|
+
INT: INT,
|
|
13077
13107
|
ISEVEN: ISEVEN,
|
|
13078
13108
|
ISODD: ISODD,
|
|
13079
13109
|
ISO_CEILING: ISO_CEILING,
|
|
@@ -18600,10 +18630,11 @@ const DEFAULT_IS_SORTED = true;
|
|
|
18600
18630
|
const DEFAULT_MATCH_MODE = 0;
|
|
18601
18631
|
const DEFAULT_SEARCH_MODE = 1;
|
|
18602
18632
|
const DEFAULT_ABSOLUTE_RELATIVE_MODE = 1;
|
|
18603
|
-
function
|
|
18604
|
-
|
|
18605
|
-
|
|
18606
|
-
|
|
18633
|
+
function valueNotAvailable(searchKey) {
|
|
18634
|
+
return {
|
|
18635
|
+
value: CellErrorType.NotAvailable,
|
|
18636
|
+
message: _t("Did not find value '%s' in [[FUNCTION_NAME]] evaluation.", toString(searchKey)),
|
|
18637
|
+
};
|
|
18607
18638
|
}
|
|
18608
18639
|
// -----------------------------------------------------------------------------
|
|
18609
18640
|
// ADDRESS
|
|
@@ -18700,7 +18731,9 @@ const HLOOKUP = {
|
|
|
18700
18731
|
? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
|
|
18701
18732
|
: linearSearch(range, searchKey, "strict", range.length, getValueFromRange);
|
|
18702
18733
|
const col = range[colIndex];
|
|
18703
|
-
|
|
18734
|
+
if (col === undefined) {
|
|
18735
|
+
return valueNotAvailable(searchKey);
|
|
18736
|
+
}
|
|
18704
18737
|
return col[_index - 1];
|
|
18705
18738
|
},
|
|
18706
18739
|
isExported: true,
|
|
@@ -18757,11 +18790,11 @@ const LOOKUP = {
|
|
|
18757
18790
|
: (range, index) => range[index][0].value;
|
|
18758
18791
|
const rangeLength = verticalSearch ? nbRow : nbCol;
|
|
18759
18792
|
const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
|
|
18760
|
-
if (index === -1
|
|
18761
|
-
|
|
18762
|
-
|
|
18763
|
-
|
|
18764
|
-
|
|
18793
|
+
if (index === -1 ||
|
|
18794
|
+
(verticalSearch && searchArray[0][index] === undefined) ||
|
|
18795
|
+
(!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
|
|
18796
|
+
return valueNotAvailable(searchKey);
|
|
18797
|
+
}
|
|
18765
18798
|
if (resultRange === undefined) {
|
|
18766
18799
|
return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
|
|
18767
18800
|
}
|
|
@@ -18811,7 +18844,10 @@ const MATCH = {
|
|
|
18811
18844
|
index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
|
|
18812
18845
|
break;
|
|
18813
18846
|
}
|
|
18814
|
-
|
|
18847
|
+
if ((nbCol === 1 && range[0][index] === undefined) ||
|
|
18848
|
+
(nbCol !== 1 && range[index] === undefined)) {
|
|
18849
|
+
return valueNotAvailable(searchKey);
|
|
18850
|
+
}
|
|
18815
18851
|
return index + 1;
|
|
18816
18852
|
},
|
|
18817
18853
|
isExported: true,
|
|
@@ -18870,7 +18906,9 @@ const VLOOKUP = {
|
|
|
18870
18906
|
? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
|
|
18871
18907
|
: linearSearch(range, searchKey, "strict", range[0].length, getValueFromRange);
|
|
18872
18908
|
const value = range[_index - 1][rowIndex];
|
|
18873
|
-
|
|
18909
|
+
if (value === undefined) {
|
|
18910
|
+
return valueNotAvailable(searchKey);
|
|
18911
|
+
}
|
|
18874
18912
|
return value;
|
|
18875
18913
|
},
|
|
18876
18914
|
isExported: true,
|
|
@@ -18920,7 +18958,9 @@ const XLOOKUP = {
|
|
|
18920
18958
|
? returnRange.map((col) => [col[index]])
|
|
18921
18959
|
: [returnRange[index]];
|
|
18922
18960
|
}
|
|
18923
|
-
|
|
18961
|
+
if (defaultValue === undefined) {
|
|
18962
|
+
return valueNotAvailable(searchKey);
|
|
18963
|
+
}
|
|
18924
18964
|
return [[defaultValue]];
|
|
18925
18965
|
},
|
|
18926
18966
|
isExported: true,
|
|
@@ -19692,8 +19732,7 @@ class FunctionRegistry extends Registry {
|
|
|
19692
19732
|
function addErrorHandling(compute, functionName) {
|
|
19693
19733
|
return function (...args) {
|
|
19694
19734
|
try {
|
|
19695
|
-
|
|
19696
|
-
return computeFormula(...args);
|
|
19735
|
+
return compute.apply(this, args);
|
|
19697
19736
|
}
|
|
19698
19737
|
catch (e) {
|
|
19699
19738
|
return handleError(e, functionName);
|
|
@@ -19727,8 +19766,7 @@ function hasStringMessage(obj) {
|
|
|
19727
19766
|
}
|
|
19728
19767
|
function addResultHandling(compute) {
|
|
19729
19768
|
return function (...args) {
|
|
19730
|
-
const
|
|
19731
|
-
const result = computeResult(...args);
|
|
19769
|
+
const result = compute.apply(this, args);
|
|
19732
19770
|
if (!isMatrix(result)) {
|
|
19733
19771
|
if (typeof result === "object" && result !== null && "value" in result) {
|
|
19734
19772
|
return result;
|
|
@@ -20084,7 +20122,7 @@ cellMenuRegistry
|
|
|
20084
20122
|
})
|
|
20085
20123
|
.add("insert_link", {
|
|
20086
20124
|
...insertLink,
|
|
20087
|
-
name:
|
|
20125
|
+
name: INSERT_LINK_NAME,
|
|
20088
20126
|
sequence: 150,
|
|
20089
20127
|
separator: true,
|
|
20090
20128
|
});
|
|
@@ -21695,7 +21733,7 @@ class SelectionInput extends owl.Component {
|
|
|
21695
21733
|
? existingSelectionRanges
|
|
21696
21734
|
: this.props.ranges().map((xc, id) => ({
|
|
21697
21735
|
xc,
|
|
21698
|
-
id,
|
|
21736
|
+
id: id + 1,
|
|
21699
21737
|
isFocused: false,
|
|
21700
21738
|
}));
|
|
21701
21739
|
return ranges.map((range) => ({
|
|
@@ -26527,6 +26565,17 @@ class TextValueProvider extends owl.Component {
|
|
|
26527
26565
|
onValueSelected: Function,
|
|
26528
26566
|
onValueHovered: Function,
|
|
26529
26567
|
};
|
|
26568
|
+
autoCompleteListRef = owl.useRef("autoCompleteList");
|
|
26569
|
+
setup() {
|
|
26570
|
+
owl.useEffect(() => {
|
|
26571
|
+
const selectedIndex = this.props.selectedIndex;
|
|
26572
|
+
if (selectedIndex === undefined) {
|
|
26573
|
+
return;
|
|
26574
|
+
}
|
|
26575
|
+
const selectedElement = this.autoCompleteListRef.el?.children[selectedIndex];
|
|
26576
|
+
selectedElement?.scrollIntoView?.({ block: "nearest" });
|
|
26577
|
+
}, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
|
|
26578
|
+
}
|
|
26530
26579
|
}
|
|
26531
26580
|
|
|
26532
26581
|
class ContentEditableHelper {
|
|
@@ -26971,6 +27020,7 @@ css /* scss */ `
|
|
|
26971
27020
|
position: absolute;
|
|
26972
27021
|
margin: 1px 4px;
|
|
26973
27022
|
pointer-events: none;
|
|
27023
|
+
overflow: auto;
|
|
26974
27024
|
|
|
26975
27025
|
.o-semi-bold {
|
|
26976
27026
|
/** FIXME: to remove in favor of Bootstrap
|
|
@@ -27028,7 +27078,10 @@ class Composer extends owl.Component {
|
|
|
27028
27078
|
if (this.props.delimitation && this.props.rect) {
|
|
27029
27079
|
const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
|
|
27030
27080
|
const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
|
|
27081
|
+
assistantStyle["max-height"] = `${remainingHeight}px`;
|
|
27031
27082
|
if (cellY > remainingHeight) {
|
|
27083
|
+
const availableSpaceAbove = cellY;
|
|
27084
|
+
assistantStyle["max-height"] = `${availableSpaceAbove}px`;
|
|
27032
27085
|
// render top
|
|
27033
27086
|
// We compensate 2 px of margin on the assistant style + 1px for design reasons
|
|
27034
27087
|
assistantStyle.top = `-3px`;
|
|
@@ -27720,7 +27773,11 @@ class GridComposer extends owl.Component {
|
|
|
27720
27773
|
}
|
|
27721
27774
|
}
|
|
27722
27775
|
updateCellReferenceVisibility() {
|
|
27723
|
-
if (this.
|
|
27776
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
27777
|
+
this.isCellReferenceVisible = false;
|
|
27778
|
+
return;
|
|
27779
|
+
}
|
|
27780
|
+
if (this.isCellReferenceVisible) {
|
|
27724
27781
|
return;
|
|
27725
27782
|
}
|
|
27726
27783
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
@@ -27749,19 +27806,21 @@ class GridCellIcon extends owl.Component {
|
|
|
27749
27806
|
slots: Object,
|
|
27750
27807
|
};
|
|
27751
27808
|
get iconStyle() {
|
|
27752
|
-
const
|
|
27753
|
-
const
|
|
27809
|
+
const cellPosition = this.props.cellPosition;
|
|
27810
|
+
const merge = this.env.model.getters.getMerge(cellPosition);
|
|
27811
|
+
const zone = merge || positionToZone(cellPosition);
|
|
27812
|
+
const rect = this.env.model.getters.getVisibleRectWithoutHeaders(zone);
|
|
27813
|
+
const x = this.getIconHorizontalPosition(rect, cellPosition);
|
|
27814
|
+
const y = this.getIconVerticalPosition(rect, cellPosition);
|
|
27754
27815
|
return cssPropertiesToCss({
|
|
27755
27816
|
top: `${y + (this.props.offset?.y || 0)}px`,
|
|
27756
27817
|
left: `${x + (this.props.offset?.x || 0)}px`,
|
|
27757
27818
|
});
|
|
27758
27819
|
}
|
|
27759
|
-
getIconVerticalPosition() {
|
|
27760
|
-
const
|
|
27761
|
-
const
|
|
27762
|
-
const
|
|
27763
|
-
const end = this.env.model.getters.getRowDimensionsInViewport(sheetId, merge ? merge.bottom : row).end;
|
|
27764
|
-
const cell = this.env.model.getters.getCell(this.props.cellPosition);
|
|
27820
|
+
getIconVerticalPosition(rect, cellPosition) {
|
|
27821
|
+
const start = rect.y;
|
|
27822
|
+
const end = rect.y + rect.height;
|
|
27823
|
+
const cell = this.env.model.getters.getCell(cellPosition);
|
|
27765
27824
|
const align = this.props.verticalAlign || cell?.style?.verticalAlign || DEFAULT_VERTICAL_ALIGN;
|
|
27766
27825
|
switch (align) {
|
|
27767
27826
|
case "bottom":
|
|
@@ -27773,13 +27832,11 @@ class GridCellIcon extends owl.Component {
|
|
|
27773
27832
|
return end - GRID_ICON_EDGE_LENGTH - centeringOffset;
|
|
27774
27833
|
}
|
|
27775
27834
|
}
|
|
27776
|
-
getIconHorizontalPosition() {
|
|
27777
|
-
const
|
|
27778
|
-
const
|
|
27779
|
-
const
|
|
27780
|
-
const
|
|
27781
|
-
const cell = this.env.model.getters.getCell(this.props.cellPosition);
|
|
27782
|
-
const evaluatedCell = this.env.model.getters.getEvaluatedCell(this.props.cellPosition);
|
|
27835
|
+
getIconHorizontalPosition(rect, cellPosition) {
|
|
27836
|
+
const start = rect.x;
|
|
27837
|
+
const end = rect.x + rect.width;
|
|
27838
|
+
const cell = this.env.model.getters.getCell(cellPosition);
|
|
27839
|
+
const evaluatedCell = this.env.model.getters.getEvaluatedCell(cellPosition);
|
|
27783
27840
|
const align = this.props.horizontalAlign || cell?.style?.align || evaluatedCell.defaultAlign;
|
|
27784
27841
|
switch (align) {
|
|
27785
27842
|
case "right":
|
|
@@ -27863,6 +27920,8 @@ css /* scss */ `
|
|
|
27863
27920
|
height: ${CHECKBOX_WIDTH}px;
|
|
27864
27921
|
accent-color: #808080;
|
|
27865
27922
|
margin: ${MARGIN}px;
|
|
27923
|
+
/** required to prevent the checkbox position to be sensible to the font-size (affects Firefox) */
|
|
27924
|
+
position: absolute;
|
|
27866
27925
|
}
|
|
27867
27926
|
`;
|
|
27868
27927
|
class DataValidationCheckbox extends owl.Component {
|
|
@@ -27881,7 +27940,7 @@ class DataValidationCheckbox extends owl.Component {
|
|
|
27881
27940
|
}
|
|
27882
27941
|
get isDisabled() {
|
|
27883
27942
|
const cell = this.env.model.getters.getCell(this.props.cellPosition);
|
|
27884
|
-
return !!cell?.isFormula;
|
|
27943
|
+
return this.env.model.getters.isReadonly() || !!cell?.isFormula;
|
|
27885
27944
|
}
|
|
27886
27945
|
}
|
|
27887
27946
|
|
|
@@ -27921,12 +27980,17 @@ class DataValidationOverlay extends owl.Component {
|
|
|
27921
27980
|
static props = {};
|
|
27922
27981
|
static components = { GridCellIcon, DataValidationCheckbox, DataValidationListIcon };
|
|
27923
27982
|
get checkBoxCellPositions() {
|
|
27924
|
-
return this.env.model.getters
|
|
27983
|
+
return this.env.model.getters
|
|
27984
|
+
.getVisibleCellPositions()
|
|
27985
|
+
.filter(this.env.model.getters.isCellValidCheckbox);
|
|
27925
27986
|
}
|
|
27926
27987
|
get listIconsCellPositions() {
|
|
27927
|
-
|
|
27928
|
-
|
|
27929
|
-
|
|
27988
|
+
if (this.env.model.getters.isReadonly()) {
|
|
27989
|
+
return [];
|
|
27990
|
+
}
|
|
27991
|
+
return this.env.model.getters
|
|
27992
|
+
.getVisibleCellPositions()
|
|
27993
|
+
.filter(this.env.model.getters.cellHasListDataValidationIcon);
|
|
27930
27994
|
}
|
|
27931
27995
|
}
|
|
27932
27996
|
|
|
@@ -34288,29 +34352,12 @@ const MIGRATIONS = [
|
|
|
34288
34352
|
from: 12,
|
|
34289
34353
|
to: 12.5,
|
|
34290
34354
|
applyMigration(data) {
|
|
34291
|
-
|
|
34292
|
-
let knownDataFilterZones = [];
|
|
34293
|
-
for (let filterTable of sheet.filterTables || []) {
|
|
34294
|
-
const zone = toZone(filterTable.range);
|
|
34295
|
-
// See commit message for the details
|
|
34296
|
-
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
34297
|
-
if (intersectZoneIndex !== -1) {
|
|
34298
|
-
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
34299
|
-
}
|
|
34300
|
-
else {
|
|
34301
|
-
knownDataFilterZones.push(zone);
|
|
34302
|
-
}
|
|
34303
|
-
}
|
|
34304
|
-
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
34305
|
-
range: zoneToXc(zone),
|
|
34306
|
-
}));
|
|
34307
|
-
}
|
|
34308
|
-
return data;
|
|
34355
|
+
return fixOverlappingFilters(data);
|
|
34309
34356
|
},
|
|
34310
34357
|
},
|
|
34311
34358
|
{
|
|
34312
34359
|
description: "Change Border description structure",
|
|
34313
|
-
from: 12,
|
|
34360
|
+
from: 12.5,
|
|
34314
34361
|
to: 13,
|
|
34315
34362
|
applyMigration(data) {
|
|
34316
34363
|
for (const borderId in data.borders) {
|
|
@@ -34341,6 +34388,14 @@ const MIGRATIONS = [
|
|
|
34341
34388
|
return data;
|
|
34342
34389
|
},
|
|
34343
34390
|
},
|
|
34391
|
+
{
|
|
34392
|
+
description: "Fix datafilter duplication (post saas-16.4)",
|
|
34393
|
+
from: 14,
|
|
34394
|
+
to: 14.5,
|
|
34395
|
+
applyMigration(data) {
|
|
34396
|
+
return fixOverlappingFilters(data);
|
|
34397
|
+
},
|
|
34398
|
+
},
|
|
34344
34399
|
];
|
|
34345
34400
|
/**
|
|
34346
34401
|
* This function is used to repair faulty data independently of the migration.
|
|
@@ -34498,6 +34553,26 @@ function fixChartDefinitions(data, initialMessages) {
|
|
|
34498
34553
|
}
|
|
34499
34554
|
return messages;
|
|
34500
34555
|
}
|
|
34556
|
+
function fixOverlappingFilters(data) {
|
|
34557
|
+
for (let sheet of data.sheets || []) {
|
|
34558
|
+
let knownDataFilterZones = [];
|
|
34559
|
+
for (let filterTable of sheet.filterTables || []) {
|
|
34560
|
+
const zone = toZone(filterTable.range);
|
|
34561
|
+
// See commit message of https://github.com/odoo/o-spreadsheet/pull/3632 of more details
|
|
34562
|
+
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
34563
|
+
if (intersectZoneIndex !== -1) {
|
|
34564
|
+
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
34565
|
+
}
|
|
34566
|
+
else {
|
|
34567
|
+
knownDataFilterZones.push(zone);
|
|
34568
|
+
}
|
|
34569
|
+
}
|
|
34570
|
+
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
34571
|
+
range: zoneToXc(zone),
|
|
34572
|
+
}));
|
|
34573
|
+
}
|
|
34574
|
+
return data;
|
|
34575
|
+
}
|
|
34501
34576
|
// -----------------------------------------------------------------------------
|
|
34502
34577
|
// Helpers
|
|
34503
34578
|
// -----------------------------------------------------------------------------
|
|
@@ -35147,22 +35222,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
35147
35222
|
}
|
|
35148
35223
|
}
|
|
35149
35224
|
export(data) {
|
|
35150
|
-
// Borders
|
|
35151
|
-
let borderId = 0;
|
|
35152
35225
|
const borders = {};
|
|
35153
|
-
/**
|
|
35154
|
-
* Get the id of the given border. If the border does not exist, it creates
|
|
35155
|
-
* one.
|
|
35156
|
-
*/
|
|
35157
|
-
function getBorderId(border) {
|
|
35158
|
-
for (let [key, value] of Object.entries(borders)) {
|
|
35159
|
-
if (deepEquals(value, border)) {
|
|
35160
|
-
return parseInt(key, 10);
|
|
35161
|
-
}
|
|
35162
|
-
}
|
|
35163
|
-
borders[++borderId] = border;
|
|
35164
|
-
return borderId;
|
|
35165
|
-
}
|
|
35166
35226
|
for (let sheet of data.sheets) {
|
|
35167
35227
|
for (let col = 0; col < sheet.colNumber; col++) {
|
|
35168
35228
|
for (let row = 0; row < sheet.rowNumber; row++) {
|
|
@@ -35170,7 +35230,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
35170
35230
|
if (border) {
|
|
35171
35231
|
const xc = toXC(col, row);
|
|
35172
35232
|
const cell = sheet.cells[xc];
|
|
35173
|
-
const borderId =
|
|
35233
|
+
const borderId = getItemId(border, borders);
|
|
35174
35234
|
if (cell) {
|
|
35175
35235
|
cell.border = borderId;
|
|
35176
35236
|
}
|
|
@@ -35959,9 +36019,9 @@ class CellPlugin extends CorePlugin {
|
|
|
35959
36019
|
allowDispatch(cmd) {
|
|
35960
36020
|
switch (cmd.type) {
|
|
35961
36021
|
case "UPDATE_CELL":
|
|
35962
|
-
return this.
|
|
36022
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
|
|
35963
36023
|
case "CLEAR_CELL":
|
|
35964
|
-
return this.checkValidations(cmd, this.
|
|
36024
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
|
|
35965
36025
|
default:
|
|
35966
36026
|
return "Success" /* CommandResult.Success */;
|
|
35967
36027
|
}
|
|
@@ -36111,8 +36171,8 @@ class CellPlugin extends CorePlugin {
|
|
|
36111
36171
|
}
|
|
36112
36172
|
removeDefaultStyleValues(style) {
|
|
36113
36173
|
const cleanedStyle = { ...style };
|
|
36114
|
-
for (const
|
|
36115
|
-
if (cleanedStyle[property] ===
|
|
36174
|
+
for (const property in DEFAULT_STYLE) {
|
|
36175
|
+
if (cleanedStyle[property] === DEFAULT_STYLE[property]) {
|
|
36116
36176
|
delete cleanedStyle[property];
|
|
36117
36177
|
}
|
|
36118
36178
|
}
|
|
@@ -36268,10 +36328,7 @@ class CellPlugin extends CorePlugin {
|
|
|
36268
36328
|
else {
|
|
36269
36329
|
style = before ? before.style : undefined;
|
|
36270
36330
|
}
|
|
36271
|
-
const
|
|
36272
|
-
let format = ("format" in after ? after.format : before && before.format) ||
|
|
36273
|
-
detectDateFormat(afterContent, locale) ||
|
|
36274
|
-
detectNumberFormat(afterContent);
|
|
36331
|
+
const format = "format" in after ? after.format : before && before.format;
|
|
36275
36332
|
/* Read the following IF as:
|
|
36276
36333
|
* we need to remove the cell if it is completely empty, but we can know if it completely empty if:
|
|
36277
36334
|
* - the command says the new content is empty and has no border/format/style
|
|
@@ -36312,6 +36369,7 @@ class CellPlugin extends CorePlugin {
|
|
|
36312
36369
|
}
|
|
36313
36370
|
createLiteralCell(id, content, format, style) {
|
|
36314
36371
|
const locale = this.getters.getLocale();
|
|
36372
|
+
format = format || detectDateFormat(content, locale) || detectNumberFormat(content);
|
|
36315
36373
|
if (format !== PLAIN_TEXT_FORMAT && !isEvaluationError(content)) {
|
|
36316
36374
|
content = toString(parseLiteral(content, locale));
|
|
36317
36375
|
}
|
|
@@ -36384,6 +36442,18 @@ class CellPlugin extends CorePlugin {
|
|
|
36384
36442
|
}
|
|
36385
36443
|
return "Success" /* CommandResult.Success */;
|
|
36386
36444
|
}
|
|
36445
|
+
checkUselessUpdateCell(cmd) {
|
|
36446
|
+
const cell = this.getters.getCell(cmd);
|
|
36447
|
+
const hasContent = "content" in cmd || "formula" in cmd;
|
|
36448
|
+
const hasStyle = "style" in cmd;
|
|
36449
|
+
const hasFormat = "format" in cmd;
|
|
36450
|
+
if ((!hasContent || cell?.content === cmd.content) &&
|
|
36451
|
+
(!hasStyle || deepEquals(cell?.style, cmd.style)) &&
|
|
36452
|
+
(!hasFormat || cell?.format === cmd.format)) {
|
|
36453
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
36454
|
+
}
|
|
36455
|
+
return "Success" /* CommandResult.Success */;
|
|
36456
|
+
}
|
|
36387
36457
|
}
|
|
36388
36458
|
class FormulaCellWithDependencies {
|
|
36389
36459
|
id;
|
|
@@ -39024,7 +39094,6 @@ class SheetPlugin extends CorePlugin {
|
|
|
39024
39094
|
"getNumberHeaders",
|
|
39025
39095
|
"getGridLinesVisibility",
|
|
39026
39096
|
"getNextSheetName",
|
|
39027
|
-
"isEmpty",
|
|
39028
39097
|
"getSheetSize",
|
|
39029
39098
|
"getSheetZone",
|
|
39030
39099
|
"getPaneDivisions",
|
|
@@ -39399,14 +39468,6 @@ class SheetPlugin extends CorePlugin {
|
|
|
39399
39468
|
// ---------------------------------------------------------------------------
|
|
39400
39469
|
// Row/Col manipulation
|
|
39401
39470
|
// ---------------------------------------------------------------------------
|
|
39402
|
-
/**
|
|
39403
|
-
* Check if a zone only contains empty cells
|
|
39404
|
-
*/
|
|
39405
|
-
isEmpty(sheetId, zone) {
|
|
39406
|
-
return positions(zone)
|
|
39407
|
-
.map(({ col, row }) => this.getCell({ sheetId, col, row }))
|
|
39408
|
-
.every((cell) => !cell || cell.content === "");
|
|
39409
|
-
}
|
|
39410
39471
|
getCommandZones(cmd) {
|
|
39411
39472
|
const zones = [];
|
|
39412
39473
|
if ("zone" in cmd) {
|
|
@@ -41168,7 +41229,15 @@ class SpreadsheetRTree {
|
|
|
41168
41229
|
if (!this.rTrees[sheetId]) {
|
|
41169
41230
|
return;
|
|
41170
41231
|
}
|
|
41171
|
-
this.rTrees[sheetId].remove(item,
|
|
41232
|
+
this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
|
|
41233
|
+
}
|
|
41234
|
+
rtreeItemComparer(left, right) {
|
|
41235
|
+
return (left.data == right.data &&
|
|
41236
|
+
left.boundingBox.sheetId === right.boundingBox.sheetId &&
|
|
41237
|
+
left.boundingBox?.zone.left === right.boundingBox.zone.left &&
|
|
41238
|
+
left.boundingBox?.zone.top === right.boundingBox.zone.top &&
|
|
41239
|
+
left.boundingBox?.zone.right === right.boundingBox.zone.right &&
|
|
41240
|
+
left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
|
|
41172
41241
|
}
|
|
41173
41242
|
}
|
|
41174
41243
|
/**
|
|
@@ -41246,7 +41315,7 @@ class FormulaDependencyGraph {
|
|
|
41246
41315
|
const queue = Array.from(ranges).reverse();
|
|
41247
41316
|
while (queue.length > 0) {
|
|
41248
41317
|
const range = queue.pop();
|
|
41249
|
-
visited.
|
|
41318
|
+
visited.addMany(this.encoder.encodeBoundingBox(range));
|
|
41250
41319
|
const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
|
|
41251
41320
|
for (const positionId of impactedPositionIds) {
|
|
41252
41321
|
if (!visited.has(positionId)) {
|
|
@@ -41254,7 +41323,7 @@ class FormulaDependencyGraph {
|
|
|
41254
41323
|
}
|
|
41255
41324
|
}
|
|
41256
41325
|
}
|
|
41257
|
-
visited.
|
|
41326
|
+
visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
|
|
41258
41327
|
return visited;
|
|
41259
41328
|
}
|
|
41260
41329
|
}
|
|
@@ -41394,9 +41463,9 @@ class Evaluator {
|
|
|
41394
41463
|
const cells = positions.map((p) => this.encoder.encode(p));
|
|
41395
41464
|
const cellsToCompute = new JetSet(cells);
|
|
41396
41465
|
const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
|
|
41397
|
-
cellsToCompute.
|
|
41398
|
-
cellsToCompute.
|
|
41399
|
-
cellsToCompute.
|
|
41466
|
+
cellsToCompute.addMany(this.getCellsDependingOn(cells));
|
|
41467
|
+
cellsToCompute.addMany(arrayFormulasPositionIds);
|
|
41468
|
+
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
|
|
41400
41469
|
this.evaluate(cellsToCompute);
|
|
41401
41470
|
}
|
|
41402
41471
|
getArrayFormulasImpactedByChangesOf(positionIds) {
|
|
@@ -41410,7 +41479,7 @@ class Evaluator {
|
|
|
41410
41479
|
}
|
|
41411
41480
|
if (!content) {
|
|
41412
41481
|
// The previous content could have blocked some array formulas
|
|
41413
|
-
impactedPositionIds.
|
|
41482
|
+
impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
|
|
41414
41483
|
}
|
|
41415
41484
|
}
|
|
41416
41485
|
return impactedPositionIds;
|
|
@@ -41462,7 +41531,7 @@ class Evaluator {
|
|
|
41462
41531
|
}
|
|
41463
41532
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
|
|
41464
41533
|
const cells = new JetSet(arrayFormulas);
|
|
41465
|
-
cells.
|
|
41534
|
+
cells.addMany(this.getCellsDependingOn(arrayFormulas));
|
|
41466
41535
|
return cells;
|
|
41467
41536
|
}
|
|
41468
41537
|
nextPositionsToUpdate = new JetSet();
|
|
@@ -41513,7 +41582,7 @@ class Evaluator {
|
|
|
41513
41582
|
: evaluateLiteral(cell.content, localeFormat);
|
|
41514
41583
|
}
|
|
41515
41584
|
catch (e) {
|
|
41516
|
-
return createEvaluatedCell(e.
|
|
41585
|
+
return createEvaluatedCell(e?.value || CellErrorType.GenericError, localeFormat, e?.message || implementationErrorMessage);
|
|
41517
41586
|
}
|
|
41518
41587
|
finally {
|
|
41519
41588
|
this.cellsBeingComputed.delete(cellId);
|
|
@@ -41600,7 +41669,7 @@ class Evaluator {
|
|
|
41600
41669
|
this.setEvaluatedCell(positionId, evaluatedCell);
|
|
41601
41670
|
// check if formula dependencies present in the spread zone
|
|
41602
41671
|
// if so, they need to be recomputed
|
|
41603
|
-
this.nextPositionsToUpdate.
|
|
41672
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
|
|
41604
41673
|
};
|
|
41605
41674
|
}
|
|
41606
41675
|
invalidateSpreading(positionId) {
|
|
@@ -41615,8 +41684,8 @@ class Evaluator {
|
|
|
41615
41684
|
continue;
|
|
41616
41685
|
}
|
|
41617
41686
|
this.evaluatedCells.delete(child);
|
|
41618
|
-
this.nextPositionsToUpdate.
|
|
41619
|
-
this.nextPositionsToUpdate.
|
|
41687
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
41688
|
+
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
41620
41689
|
}
|
|
41621
41690
|
this.spreadingRelations.removeNode(positionId);
|
|
41622
41691
|
}
|
|
@@ -41847,6 +41916,7 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
41847
41916
|
"getEvaluatedCellsInZone",
|
|
41848
41917
|
"getSpreadPositionsOf",
|
|
41849
41918
|
"getArrayFormulaSpreadingOn",
|
|
41919
|
+
"isEmpty",
|
|
41850
41920
|
];
|
|
41851
41921
|
shouldRebuildDependenciesGraph = true;
|
|
41852
41922
|
evaluator;
|
|
@@ -41952,6 +42022,14 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
41952
42022
|
getArrayFormulaSpreadingOn(position) {
|
|
41953
42023
|
return this.evaluator.getArrayFormulaSpreadingOn(position);
|
|
41954
42024
|
}
|
|
42025
|
+
/**
|
|
42026
|
+
* Check if a zone only contains empty cells
|
|
42027
|
+
*/
|
|
42028
|
+
isEmpty(sheetId, zone) {
|
|
42029
|
+
return positions(zone)
|
|
42030
|
+
.map(({ col, row }) => this.getEvaluatedCell({ sheetId, col, row }))
|
|
42031
|
+
.every((cell) => cell.type === CellValueType.empty);
|
|
42032
|
+
}
|
|
41955
42033
|
// ---------------------------------------------------------------------------
|
|
41956
42034
|
// Export
|
|
41957
42035
|
// ---------------------------------------------------------------------------
|
|
@@ -42599,8 +42677,6 @@ const VALID_RESULT = { isValid: true };
|
|
|
42599
42677
|
class EvaluationDataValidationPlugin extends UIPlugin {
|
|
42600
42678
|
static getters = [
|
|
42601
42679
|
"getDataValidationInvalidCriterionValueMessage",
|
|
42602
|
-
"getDataValidationCheckBoxCellPositions",
|
|
42603
|
-
"getDataValidationListCellsPositions",
|
|
42604
42680
|
"getInvalidDataValidationMessage",
|
|
42605
42681
|
"getValidationResultForCellValue",
|
|
42606
42682
|
"isCellValidCheckbox",
|
|
@@ -42664,19 +42740,6 @@ class EvaluationDataValidationPlugin extends UIPlugin {
|
|
|
42664
42740
|
const error = this.getRuleErrorForCellValue(cellValue, cellPosition, rule);
|
|
42665
42741
|
return error ? { error, rule, isValid: false } : VALID_RESULT;
|
|
42666
42742
|
}
|
|
42667
|
-
getDataValidationCheckBoxCellPositions() {
|
|
42668
|
-
const rules = this.getters
|
|
42669
|
-
.getDataValidationRules(this.getters.getActiveSheetId())
|
|
42670
|
-
.filter((rule) => rule.criterion.type === "isBoolean");
|
|
42671
|
-
return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat()).filter((position) => this.isCellValidCheckbox(position));
|
|
42672
|
-
}
|
|
42673
|
-
getDataValidationListCellsPositions() {
|
|
42674
|
-
const rules = this.getters
|
|
42675
|
-
.getDataValidationRules(this.getters.getActiveSheetId())
|
|
42676
|
-
.filter((rule) => (rule.criterion.type === "isValueInList" || rule.criterion.type === "isValueInRange") &&
|
|
42677
|
-
rule.criterion.displayStyle === "arrow");
|
|
42678
|
-
return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat());
|
|
42679
|
-
}
|
|
42680
42743
|
getValidationResultForCell(cellPosition) {
|
|
42681
42744
|
const { col, row, sheetId } = cellPosition;
|
|
42682
42745
|
if (!this.validationResults[sheetId]) {
|
|
@@ -45485,7 +45548,7 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45485
45548
|
}
|
|
45486
45549
|
finalize() {
|
|
45487
45550
|
if (this.isSearchDirty) {
|
|
45488
|
-
this.refreshSearch();
|
|
45551
|
+
this.refreshSearch(false);
|
|
45489
45552
|
this.isSearchDirty = false;
|
|
45490
45553
|
}
|
|
45491
45554
|
}
|
|
@@ -45529,10 +45592,10 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45529
45592
|
/**
|
|
45530
45593
|
* refresh the matches according to the current search options
|
|
45531
45594
|
*/
|
|
45532
|
-
refreshSearch() {
|
|
45595
|
+
refreshSearch(jumpToMatchSheet = true) {
|
|
45533
45596
|
this.selectedMatchIndex = null;
|
|
45534
45597
|
this.findMatches();
|
|
45535
|
-
this.selectNextCell(Direction.current);
|
|
45598
|
+
this.selectNextCell(Direction.current, jumpToMatchSheet);
|
|
45536
45599
|
}
|
|
45537
45600
|
/**
|
|
45538
45601
|
* Updates the regex based on the current searchOptions and
|
|
@@ -45614,7 +45677,7 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45614
45677
|
* It is also used to keep coherence between the selected searchMatch
|
|
45615
45678
|
* and selectedMatchIndex.
|
|
45616
45679
|
*/
|
|
45617
|
-
selectNextCell(indexChange) {
|
|
45680
|
+
selectNextCell(indexChange, jumpToMatchSheet = true) {
|
|
45618
45681
|
const matches = this.searchMatches;
|
|
45619
45682
|
if (!matches.length) {
|
|
45620
45683
|
this.selectedMatchIndex = null;
|
|
@@ -45640,11 +45703,13 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45640
45703
|
this.selectedMatchIndex = nextIndex;
|
|
45641
45704
|
const selectedMatch = matches[nextIndex];
|
|
45642
45705
|
// Switch to the sheet where the match is located
|
|
45643
|
-
if (this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
45706
|
+
if (jumpToMatchSheet && this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
45644
45707
|
this.dispatch("ACTIVATE_SHEET", {
|
|
45645
45708
|
sheetIdFrom: this.getters.getActiveSheetId(),
|
|
45646
45709
|
sheetIdTo: selectedMatch.sheetId,
|
|
45647
45710
|
});
|
|
45711
|
+
// We do not want to reset the selection at finalize in this case
|
|
45712
|
+
this.isSearchDirty = false;
|
|
45648
45713
|
}
|
|
45649
45714
|
// we want grid selection to capture the selection stream
|
|
45650
45715
|
this.selection.getBackToDefault();
|
|
@@ -46946,19 +47011,17 @@ class SelectionInputsManagerPlugin extends UIPlugin {
|
|
|
46946
47011
|
break;
|
|
46947
47012
|
case "FOCUS_RANGE":
|
|
46948
47013
|
case "CHANGE_RANGE":
|
|
46949
|
-
|
|
46950
|
-
|
|
46951
|
-
|
|
46952
|
-
|
|
46953
|
-
|
|
46954
|
-
|
|
46955
|
-
|
|
46956
|
-
|
|
46957
|
-
|
|
46958
|
-
});
|
|
46959
|
-
}
|
|
46960
|
-
this.focusedInputId = cmd.id;
|
|
47014
|
+
const input = this.inputs[cmd.id];
|
|
47015
|
+
const range = input.ranges.find((range) => range.id === cmd.rangeId);
|
|
47016
|
+
if (range) {
|
|
47017
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
47018
|
+
const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
|
|
47019
|
+
this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, {
|
|
47020
|
+
handleEvent: input.handleEvent.bind(input),
|
|
47021
|
+
release: () => (this.focusedInputId = null),
|
|
47022
|
+
});
|
|
46961
47023
|
}
|
|
47024
|
+
this.focusedInputId = cmd.id;
|
|
46962
47025
|
break;
|
|
46963
47026
|
}
|
|
46964
47027
|
this.currentInput?.handle(cmd);
|
|
@@ -47212,7 +47275,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
47212
47275
|
"getCellText",
|
|
47213
47276
|
"getCellMultiLineText",
|
|
47214
47277
|
"getContiguousZone",
|
|
47215
|
-
"
|
|
47278
|
+
"isEvaluatedCellEmpty",
|
|
47216
47279
|
];
|
|
47217
47280
|
ctx = document.createElement("canvas").getContext("2d");
|
|
47218
47281
|
// ---------------------------------------------------------------------------
|
|
@@ -47340,14 +47403,23 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
47340
47403
|
return zone;
|
|
47341
47404
|
}
|
|
47342
47405
|
/**
|
|
47343
|
-
*
|
|
47344
|
-
* check
|
|
47406
|
+
* Checks if a cell evaluated value is empty. If the cell is part of a merge,
|
|
47407
|
+
* the check applies to the main cell of the merge.
|
|
47345
47408
|
*/
|
|
47346
|
-
|
|
47409
|
+
isEvaluatedCellEmpty(position) {
|
|
47347
47410
|
const mainPosition = this.getters.getMainCellPosition(position);
|
|
47348
47411
|
const cell = this.getters.getEvaluatedCell(mainPosition);
|
|
47349
47412
|
return cell.type === CellValueType.empty;
|
|
47350
47413
|
}
|
|
47414
|
+
/**
|
|
47415
|
+
* Checks if a cell is empty (i.e. does not have a content or a formula does not spread over it).
|
|
47416
|
+
* If the cell is part of a merge, the check applies to the main cell of the merge.
|
|
47417
|
+
*/
|
|
47418
|
+
isCellEmpty(position) {
|
|
47419
|
+
const mainPosition = this.getters.getMainCellPosition(position);
|
|
47420
|
+
return !(this.getters.getCorrespondingFormulaCell(mainPosition) ||
|
|
47421
|
+
this.getters.getCell(mainPosition)?.content);
|
|
47422
|
+
}
|
|
47351
47423
|
getColMaxWidth(sheetId, index) {
|
|
47352
47424
|
const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
|
|
47353
47425
|
const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
|
|
@@ -50368,6 +50440,8 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
50368
50440
|
"getEdgeScrollRow",
|
|
50369
50441
|
"getVisibleFigures",
|
|
50370
50442
|
"getVisibleRect",
|
|
50443
|
+
"getVisibleRectWithoutHeaders",
|
|
50444
|
+
"getVisibleCellPositions",
|
|
50371
50445
|
"getColRowOffsetInViewport",
|
|
50372
50446
|
"getMainViewportCoordinates",
|
|
50373
50447
|
"getActiveSheetScrollInfo",
|
|
@@ -50611,6 +50685,26 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
50611
50685
|
const viewports = this.getSubViewports(sheetId);
|
|
50612
50686
|
return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
|
|
50613
50687
|
}
|
|
50688
|
+
/**
|
|
50689
|
+
* Get the positions of all the cells that are visible in the viewport, taking merges into account.
|
|
50690
|
+
*/
|
|
50691
|
+
getVisibleCellPositions() {
|
|
50692
|
+
const visibleCols = this.getSheetViewVisibleCols();
|
|
50693
|
+
const visibleRows = this.getSheetViewVisibleRows();
|
|
50694
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
50695
|
+
const positions = [];
|
|
50696
|
+
for (const col of visibleCols) {
|
|
50697
|
+
for (const row of visibleRows) {
|
|
50698
|
+
const position = { sheetId, col, row };
|
|
50699
|
+
const mainPosition = this.getters.getMainCellPosition(position);
|
|
50700
|
+
if (mainPosition.row !== row || mainPosition.col !== col) {
|
|
50701
|
+
continue;
|
|
50702
|
+
}
|
|
50703
|
+
positions.push(position);
|
|
50704
|
+
}
|
|
50705
|
+
}
|
|
50706
|
+
return positions;
|
|
50707
|
+
}
|
|
50614
50708
|
/**
|
|
50615
50709
|
* Return the main viewport maximum size relative to the client size.
|
|
50616
50710
|
*/
|
|
@@ -50730,6 +50824,13 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
50730
50824
|
* Computes the coordinates and size to draw the zone on the canvas
|
|
50731
50825
|
*/
|
|
50732
50826
|
getVisibleRect(zone) {
|
|
50827
|
+
const rect = this.getVisibleRectWithoutHeaders(zone);
|
|
50828
|
+
return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
|
|
50829
|
+
}
|
|
50830
|
+
/**
|
|
50831
|
+
* Computes the coordinates and size to draw the zone without taking the grid offset into account
|
|
50832
|
+
*/
|
|
50833
|
+
getVisibleRectWithoutHeaders(zone) {
|
|
50733
50834
|
const sheetId = this.getters.getActiveSheetId();
|
|
50734
50835
|
const viewportRects = this.getSubViewports(sheetId)
|
|
50735
50836
|
.map((viewport) => viewport.getRect(zone))
|
|
@@ -50741,12 +50842,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
50741
50842
|
const y = Math.min(...viewportRects.map((rect) => rect.y));
|
|
50742
50843
|
const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
|
|
50743
50844
|
const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
|
|
50744
|
-
return {
|
|
50745
|
-
x: x + this.gridOffsetX,
|
|
50746
|
-
y: y + this.gridOffsetY,
|
|
50747
|
-
width,
|
|
50748
|
-
height,
|
|
50749
|
-
};
|
|
50845
|
+
return { x, y, width, height };
|
|
50750
50846
|
}
|
|
50751
50847
|
/**
|
|
50752
50848
|
* Returns the position of the MainViewport relatively to the start of the grid (without headers)
|
|
@@ -50970,13 +51066,8 @@ class HeaderPositionsUIPlugin extends UIPlugin {
|
|
|
50970
51066
|
}
|
|
50971
51067
|
break;
|
|
50972
51068
|
case "UPDATE_CELL":
|
|
50973
|
-
|
|
50974
|
-
|
|
50975
|
-
this.isDirty = true;
|
|
50976
|
-
}
|
|
50977
|
-
else {
|
|
50978
|
-
this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
|
|
50979
|
-
}
|
|
51069
|
+
this.headerPositions = {};
|
|
51070
|
+
this.isDirty = true;
|
|
50980
51071
|
break;
|
|
50981
51072
|
case "UPDATE_FILTER":
|
|
50982
51073
|
case "REMOVE_FILTER_TABLE":
|
|
@@ -54889,8 +54980,8 @@ class SelectionStreamProcessorImpl {
|
|
|
54889
54980
|
let currentPosition = startPosition;
|
|
54890
54981
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
54891
54982
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
54892
|
-
let mode = !this.getters.
|
|
54893
|
-
!this.getters.
|
|
54983
|
+
let mode = !this.getters.isEvaluatedCellEmpty({ ...currentPosition, sheetId }) &&
|
|
54984
|
+
!this.getters.isEvaluatedCellEmpty({ ...nextCellPosition, sheetId })
|
|
54894
54985
|
? "endOfCluster"
|
|
54895
54986
|
: "nextCluster";
|
|
54896
54987
|
while (true) {
|
|
@@ -54900,7 +54991,7 @@ class SelectionStreamProcessorImpl {
|
|
|
54900
54991
|
currentPosition.row === nextCellPosition.row) {
|
|
54901
54992
|
break;
|
|
54902
54993
|
}
|
|
54903
|
-
const isNextCellEmpty = this.getters.
|
|
54994
|
+
const isNextCellEmpty = this.getters.isEvaluatedCellEmpty({ ...nextCellPosition, sheetId });
|
|
54904
54995
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
54905
54996
|
break;
|
|
54906
54997
|
}
|
|
@@ -57185,6 +57276,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
57185
57276
|
exports.tokenize = tokenize;
|
|
57186
57277
|
|
|
57187
57278
|
|
|
57188
|
-
__info__.version = "17.1.
|
|
57189
|
-
__info__.date = "2024-
|
|
57190
|
-
__info__.hash = "
|
|
57279
|
+
__info__.version = "17.1.7";
|
|
57280
|
+
__info__.date = "2024-03-12T07:56:10.783Z";
|
|
57281
|
+
__info__.hash = "3a9f334";
|