@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
|
import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
|
|
@@ -451,8 +451,8 @@ function isObjectEmptyRecursive(argument) {
|
|
|
451
451
|
* If the given item does not exist in the dictionary, it creates one with a new id.
|
|
452
452
|
*/
|
|
453
453
|
function getItemId(item, itemsDic) {
|
|
454
|
-
for (
|
|
455
|
-
if (deepEquals(
|
|
454
|
+
for (const key in itemsDic) {
|
|
455
|
+
if (deepEquals(itemsDic[key], item)) {
|
|
456
456
|
return parseInt(key, 10);
|
|
457
457
|
}
|
|
458
458
|
}
|
|
@@ -551,11 +551,13 @@ function deepEquals(o1, o2) {
|
|
|
551
551
|
if (typeof o1 !== "object")
|
|
552
552
|
return o1 === o2;
|
|
553
553
|
// Objects can have different keys if the values are undefined
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
554
|
+
for (const key in o2) {
|
|
555
|
+
if (!(key in o1) && o2[key] !== undefined) {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
for (const key in o1) {
|
|
560
|
+
if (typeof o1[key] !== typeof o2[key])
|
|
559
561
|
return false;
|
|
560
562
|
if (typeof o1[key] === "object") {
|
|
561
563
|
if (!deepEquals(o1[key], o2[key]))
|
|
@@ -625,18 +627,18 @@ function isConsecutive(iterable) {
|
|
|
625
627
|
return true;
|
|
626
628
|
}
|
|
627
629
|
class JetSet extends Set {
|
|
628
|
-
|
|
630
|
+
addMany(iterable) {
|
|
629
631
|
for (const element of iterable) {
|
|
630
632
|
super.add(element);
|
|
631
633
|
}
|
|
632
634
|
return this;
|
|
633
635
|
}
|
|
634
|
-
|
|
635
|
-
let
|
|
636
|
+
deleteMany(iterable) {
|
|
637
|
+
let wasDeleted = false;
|
|
636
638
|
for (const element of iterable) {
|
|
637
|
-
|
|
639
|
+
wasDeleted ||= super.delete(element);
|
|
638
640
|
}
|
|
639
|
-
return
|
|
641
|
+
return wasDeleted;
|
|
640
642
|
}
|
|
641
643
|
}
|
|
642
644
|
/**
|
|
@@ -1934,7 +1936,7 @@ class DispatchResult {
|
|
|
1934
1936
|
* Static helper which returns a successful DispatchResult
|
|
1935
1937
|
*/
|
|
1936
1938
|
static get Success() {
|
|
1937
|
-
return
|
|
1939
|
+
return SUCCESS;
|
|
1938
1940
|
}
|
|
1939
1941
|
get isSuccessful() {
|
|
1940
1942
|
return this.reasons.length === 0;
|
|
@@ -1947,6 +1949,7 @@ class DispatchResult {
|
|
|
1947
1949
|
return this.reasons.includes(reason);
|
|
1948
1950
|
}
|
|
1949
1951
|
}
|
|
1952
|
+
const SUCCESS = new DispatchResult();
|
|
1950
1953
|
var CommandResult;
|
|
1951
1954
|
(function (CommandResult) {
|
|
1952
1955
|
CommandResult["Success"] = "Success";
|
|
@@ -6095,8 +6098,10 @@ function getGroup(cell, cells, filter) {
|
|
|
6095
6098
|
if (x === cell) {
|
|
6096
6099
|
found = true;
|
|
6097
6100
|
}
|
|
6098
|
-
const cellValue =
|
|
6099
|
-
|
|
6101
|
+
const cellValue = x?.isFormula
|
|
6102
|
+
? undefined
|
|
6103
|
+
: evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
|
|
6104
|
+
if (cellValue && filter(cellValue)) {
|
|
6100
6105
|
group.push(cellValue);
|
|
6101
6106
|
}
|
|
6102
6107
|
else {
|
|
@@ -6320,11 +6325,14 @@ function cellTextStyleToCss(style) {
|
|
|
6320
6325
|
* Transform CSS properties into a CSS string.
|
|
6321
6326
|
*/
|
|
6322
6327
|
function cssPropertiesToCss(attributes) {
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
+
let styleStr = "";
|
|
6329
|
+
for (const attName in attributes) {
|
|
6330
|
+
if (!attributes[attName]) {
|
|
6331
|
+
continue;
|
|
6332
|
+
}
|
|
6333
|
+
styleStr += `${attName}:${attributes[attName]}; `;
|
|
6334
|
+
}
|
|
6335
|
+
return styleStr;
|
|
6328
6336
|
}
|
|
6329
6337
|
function getElementMargins(el) {
|
|
6330
6338
|
const style = window.getComputedStyle(el);
|
|
@@ -7653,6 +7661,9 @@ function isValidLocale(locale) {
|
|
|
7653
7661
|
if (locale.formulaArgSeparator === locale.decimalSeparator) {
|
|
7654
7662
|
return false;
|
|
7655
7663
|
}
|
|
7664
|
+
if (locale.thousandsSeparator === locale.decimalSeparator) {
|
|
7665
|
+
return false;
|
|
7666
|
+
}
|
|
7656
7667
|
try {
|
|
7657
7668
|
formatValue(1, { locale, format: "#,##0.00" });
|
|
7658
7669
|
formatValue(1, { locale, format: locale.dateFormat });
|
|
@@ -7743,7 +7754,7 @@ function canonicalizeNumberLiteral(content, locale) {
|
|
|
7743
7754
|
if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
|
|
7744
7755
|
return content;
|
|
7745
7756
|
}
|
|
7746
|
-
return content.replace(locale.decimalSeparator, ".");
|
|
7757
|
+
return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
|
|
7747
7758
|
}
|
|
7748
7759
|
/**
|
|
7749
7760
|
* Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
|
|
@@ -10838,6 +10849,12 @@ const INSERT_LINK = (env) => {
|
|
|
10838
10849
|
let { col, row } = env.model.getters.getActivePosition();
|
|
10839
10850
|
env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
|
|
10840
10851
|
};
|
|
10852
|
+
const INSERT_LINK_NAME = (env) => {
|
|
10853
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
10854
|
+
const { col, row } = env.model.getters.getActivePosition();
|
|
10855
|
+
const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
|
|
10856
|
+
return cell && cell.link ? _t("Edit link") : _t("Insert link");
|
|
10857
|
+
};
|
|
10841
10858
|
//------------------------------------------------------------------------------
|
|
10842
10859
|
// Filters action
|
|
10843
10860
|
//------------------------------------------------------------------------------
|
|
@@ -13039,6 +13056,18 @@ const TRUNC = {
|
|
|
13039
13056
|
},
|
|
13040
13057
|
isExported: true,
|
|
13041
13058
|
};
|
|
13059
|
+
// -----------------------------------------------------------------------------
|
|
13060
|
+
// INT
|
|
13061
|
+
// -----------------------------------------------------------------------------
|
|
13062
|
+
const INT = {
|
|
13063
|
+
description: _t("Rounds a number down to the nearest integer that is less than or equal to it."),
|
|
13064
|
+
args: [arg("value (number)", _t("The number to round down to the nearest integer."))],
|
|
13065
|
+
returns: ["NUMBER"],
|
|
13066
|
+
compute: function (value) {
|
|
13067
|
+
return Math.floor(toNumber(value, this.locale));
|
|
13068
|
+
},
|
|
13069
|
+
isExported: true,
|
|
13070
|
+
};
|
|
13042
13071
|
|
|
13043
13072
|
var math = /*#__PURE__*/Object.freeze({
|
|
13044
13073
|
__proto__: null,
|
|
@@ -13072,6 +13101,7 @@ var math = /*#__PURE__*/Object.freeze({
|
|
|
13072
13101
|
FLOOR: FLOOR,
|
|
13073
13102
|
FLOOR_MATH: FLOOR_MATH,
|
|
13074
13103
|
FLOOR_PRECISE: FLOOR_PRECISE,
|
|
13104
|
+
INT: INT,
|
|
13075
13105
|
ISEVEN: ISEVEN,
|
|
13076
13106
|
ISODD: ISODD,
|
|
13077
13107
|
ISO_CEILING: ISO_CEILING,
|
|
@@ -18598,10 +18628,11 @@ const DEFAULT_IS_SORTED = true;
|
|
|
18598
18628
|
const DEFAULT_MATCH_MODE = 0;
|
|
18599
18629
|
const DEFAULT_SEARCH_MODE = 1;
|
|
18600
18630
|
const DEFAULT_ABSOLUTE_RELATIVE_MODE = 1;
|
|
18601
|
-
function
|
|
18602
|
-
|
|
18603
|
-
|
|
18604
|
-
|
|
18631
|
+
function valueNotAvailable(searchKey) {
|
|
18632
|
+
return {
|
|
18633
|
+
value: CellErrorType.NotAvailable,
|
|
18634
|
+
message: _t("Did not find value '%s' in [[FUNCTION_NAME]] evaluation.", toString(searchKey)),
|
|
18635
|
+
};
|
|
18605
18636
|
}
|
|
18606
18637
|
// -----------------------------------------------------------------------------
|
|
18607
18638
|
// ADDRESS
|
|
@@ -18698,7 +18729,9 @@ const HLOOKUP = {
|
|
|
18698
18729
|
? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range.length, getValueFromRange)
|
|
18699
18730
|
: linearSearch(range, searchKey, "strict", range.length, getValueFromRange);
|
|
18700
18731
|
const col = range[colIndex];
|
|
18701
|
-
|
|
18732
|
+
if (col === undefined) {
|
|
18733
|
+
return valueNotAvailable(searchKey);
|
|
18734
|
+
}
|
|
18702
18735
|
return col[_index - 1];
|
|
18703
18736
|
},
|
|
18704
18737
|
isExported: true,
|
|
@@ -18755,11 +18788,11 @@ const LOOKUP = {
|
|
|
18755
18788
|
: (range, index) => range[index][0].value;
|
|
18756
18789
|
const rangeLength = verticalSearch ? nbRow : nbCol;
|
|
18757
18790
|
const index = dichotomicSearch(searchArray, searchKey, "nextSmaller", "asc", rangeLength, getElement);
|
|
18758
|
-
if (index === -1
|
|
18759
|
-
|
|
18760
|
-
|
|
18761
|
-
|
|
18762
|
-
|
|
18791
|
+
if (index === -1 ||
|
|
18792
|
+
(verticalSearch && searchArray[0][index] === undefined) ||
|
|
18793
|
+
(!verticalSearch && searchArray[index][nbRow - 1] === undefined)) {
|
|
18794
|
+
return valueNotAvailable(searchKey);
|
|
18795
|
+
}
|
|
18763
18796
|
if (resultRange === undefined) {
|
|
18764
18797
|
return verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1];
|
|
18765
18798
|
}
|
|
@@ -18809,7 +18842,10 @@ const MATCH = {
|
|
|
18809
18842
|
index = dichotomicSearch(range, searchKey, "nextGreater", "desc", rangeLen, getElement);
|
|
18810
18843
|
break;
|
|
18811
18844
|
}
|
|
18812
|
-
|
|
18845
|
+
if ((nbCol === 1 && range[0][index] === undefined) ||
|
|
18846
|
+
(nbCol !== 1 && range[index] === undefined)) {
|
|
18847
|
+
return valueNotAvailable(searchKey);
|
|
18848
|
+
}
|
|
18813
18849
|
return index + 1;
|
|
18814
18850
|
},
|
|
18815
18851
|
isExported: true,
|
|
@@ -18868,7 +18904,9 @@ const VLOOKUP = {
|
|
|
18868
18904
|
? dichotomicSearch(range, searchKey, "nextSmaller", "asc", range[0].length, getValueFromRange)
|
|
18869
18905
|
: linearSearch(range, searchKey, "strict", range[0].length, getValueFromRange);
|
|
18870
18906
|
const value = range[_index - 1][rowIndex];
|
|
18871
|
-
|
|
18907
|
+
if (value === undefined) {
|
|
18908
|
+
return valueNotAvailable(searchKey);
|
|
18909
|
+
}
|
|
18872
18910
|
return value;
|
|
18873
18911
|
},
|
|
18874
18912
|
isExported: true,
|
|
@@ -18918,7 +18956,9 @@ const XLOOKUP = {
|
|
|
18918
18956
|
? returnRange.map((col) => [col[index]])
|
|
18919
18957
|
: [returnRange[index]];
|
|
18920
18958
|
}
|
|
18921
|
-
|
|
18959
|
+
if (defaultValue === undefined) {
|
|
18960
|
+
return valueNotAvailable(searchKey);
|
|
18961
|
+
}
|
|
18922
18962
|
return [[defaultValue]];
|
|
18923
18963
|
},
|
|
18924
18964
|
isExported: true,
|
|
@@ -19690,8 +19730,7 @@ class FunctionRegistry extends Registry {
|
|
|
19690
19730
|
function addErrorHandling(compute, functionName) {
|
|
19691
19731
|
return function (...args) {
|
|
19692
19732
|
try {
|
|
19693
|
-
|
|
19694
|
-
return computeFormula(...args);
|
|
19733
|
+
return compute.apply(this, args);
|
|
19695
19734
|
}
|
|
19696
19735
|
catch (e) {
|
|
19697
19736
|
return handleError(e, functionName);
|
|
@@ -19725,8 +19764,7 @@ function hasStringMessage(obj) {
|
|
|
19725
19764
|
}
|
|
19726
19765
|
function addResultHandling(compute) {
|
|
19727
19766
|
return function (...args) {
|
|
19728
|
-
const
|
|
19729
|
-
const result = computeResult(...args);
|
|
19767
|
+
const result = compute.apply(this, args);
|
|
19730
19768
|
if (!isMatrix(result)) {
|
|
19731
19769
|
if (typeof result === "object" && result !== null && "value" in result) {
|
|
19732
19770
|
return result;
|
|
@@ -20082,7 +20120,7 @@ cellMenuRegistry
|
|
|
20082
20120
|
})
|
|
20083
20121
|
.add("insert_link", {
|
|
20084
20122
|
...insertLink,
|
|
20085
|
-
name:
|
|
20123
|
+
name: INSERT_LINK_NAME,
|
|
20086
20124
|
sequence: 150,
|
|
20087
20125
|
separator: true,
|
|
20088
20126
|
});
|
|
@@ -21693,7 +21731,7 @@ class SelectionInput extends Component {
|
|
|
21693
21731
|
? existingSelectionRanges
|
|
21694
21732
|
: this.props.ranges().map((xc, id) => ({
|
|
21695
21733
|
xc,
|
|
21696
|
-
id,
|
|
21734
|
+
id: id + 1,
|
|
21697
21735
|
isFocused: false,
|
|
21698
21736
|
}));
|
|
21699
21737
|
return ranges.map((range) => ({
|
|
@@ -26525,6 +26563,17 @@ class TextValueProvider extends Component {
|
|
|
26525
26563
|
onValueSelected: Function,
|
|
26526
26564
|
onValueHovered: Function,
|
|
26527
26565
|
};
|
|
26566
|
+
autoCompleteListRef = useRef("autoCompleteList");
|
|
26567
|
+
setup() {
|
|
26568
|
+
useEffect(() => {
|
|
26569
|
+
const selectedIndex = this.props.selectedIndex;
|
|
26570
|
+
if (selectedIndex === undefined) {
|
|
26571
|
+
return;
|
|
26572
|
+
}
|
|
26573
|
+
const selectedElement = this.autoCompleteListRef.el?.children[selectedIndex];
|
|
26574
|
+
selectedElement?.scrollIntoView?.({ block: "nearest" });
|
|
26575
|
+
}, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
|
|
26576
|
+
}
|
|
26528
26577
|
}
|
|
26529
26578
|
|
|
26530
26579
|
class ContentEditableHelper {
|
|
@@ -26969,6 +27018,7 @@ css /* scss */ `
|
|
|
26969
27018
|
position: absolute;
|
|
26970
27019
|
margin: 1px 4px;
|
|
26971
27020
|
pointer-events: none;
|
|
27021
|
+
overflow: auto;
|
|
26972
27022
|
|
|
26973
27023
|
.o-semi-bold {
|
|
26974
27024
|
/** FIXME: to remove in favor of Bootstrap
|
|
@@ -27026,7 +27076,10 @@ class Composer extends Component {
|
|
|
27026
27076
|
if (this.props.delimitation && this.props.rect) {
|
|
27027
27077
|
const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
|
|
27028
27078
|
const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
|
|
27079
|
+
assistantStyle["max-height"] = `${remainingHeight}px`;
|
|
27029
27080
|
if (cellY > remainingHeight) {
|
|
27081
|
+
const availableSpaceAbove = cellY;
|
|
27082
|
+
assistantStyle["max-height"] = `${availableSpaceAbove}px`;
|
|
27030
27083
|
// render top
|
|
27031
27084
|
// We compensate 2 px of margin on the assistant style + 1px for design reasons
|
|
27032
27085
|
assistantStyle.top = `-3px`;
|
|
@@ -27718,7 +27771,11 @@ class GridComposer extends Component {
|
|
|
27718
27771
|
}
|
|
27719
27772
|
}
|
|
27720
27773
|
updateCellReferenceVisibility() {
|
|
27721
|
-
if (this.
|
|
27774
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
27775
|
+
this.isCellReferenceVisible = false;
|
|
27776
|
+
return;
|
|
27777
|
+
}
|
|
27778
|
+
if (this.isCellReferenceVisible) {
|
|
27722
27779
|
return;
|
|
27723
27780
|
}
|
|
27724
27781
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
@@ -27747,19 +27804,21 @@ class GridCellIcon extends Component {
|
|
|
27747
27804
|
slots: Object,
|
|
27748
27805
|
};
|
|
27749
27806
|
get iconStyle() {
|
|
27750
|
-
const
|
|
27751
|
-
const
|
|
27807
|
+
const cellPosition = this.props.cellPosition;
|
|
27808
|
+
const merge = this.env.model.getters.getMerge(cellPosition);
|
|
27809
|
+
const zone = merge || positionToZone(cellPosition);
|
|
27810
|
+
const rect = this.env.model.getters.getVisibleRectWithoutHeaders(zone);
|
|
27811
|
+
const x = this.getIconHorizontalPosition(rect, cellPosition);
|
|
27812
|
+
const y = this.getIconVerticalPosition(rect, cellPosition);
|
|
27752
27813
|
return cssPropertiesToCss({
|
|
27753
27814
|
top: `${y + (this.props.offset?.y || 0)}px`,
|
|
27754
27815
|
left: `${x + (this.props.offset?.x || 0)}px`,
|
|
27755
27816
|
});
|
|
27756
27817
|
}
|
|
27757
|
-
getIconVerticalPosition() {
|
|
27758
|
-
const
|
|
27759
|
-
const
|
|
27760
|
-
const
|
|
27761
|
-
const end = this.env.model.getters.getRowDimensionsInViewport(sheetId, merge ? merge.bottom : row).end;
|
|
27762
|
-
const cell = this.env.model.getters.getCell(this.props.cellPosition);
|
|
27818
|
+
getIconVerticalPosition(rect, cellPosition) {
|
|
27819
|
+
const start = rect.y;
|
|
27820
|
+
const end = rect.y + rect.height;
|
|
27821
|
+
const cell = this.env.model.getters.getCell(cellPosition);
|
|
27763
27822
|
const align = this.props.verticalAlign || cell?.style?.verticalAlign || DEFAULT_VERTICAL_ALIGN;
|
|
27764
27823
|
switch (align) {
|
|
27765
27824
|
case "bottom":
|
|
@@ -27771,13 +27830,11 @@ class GridCellIcon extends Component {
|
|
|
27771
27830
|
return end - GRID_ICON_EDGE_LENGTH - centeringOffset;
|
|
27772
27831
|
}
|
|
27773
27832
|
}
|
|
27774
|
-
getIconHorizontalPosition() {
|
|
27775
|
-
const
|
|
27776
|
-
const
|
|
27777
|
-
const
|
|
27778
|
-
const
|
|
27779
|
-
const cell = this.env.model.getters.getCell(this.props.cellPosition);
|
|
27780
|
-
const evaluatedCell = this.env.model.getters.getEvaluatedCell(this.props.cellPosition);
|
|
27833
|
+
getIconHorizontalPosition(rect, cellPosition) {
|
|
27834
|
+
const start = rect.x;
|
|
27835
|
+
const end = rect.x + rect.width;
|
|
27836
|
+
const cell = this.env.model.getters.getCell(cellPosition);
|
|
27837
|
+
const evaluatedCell = this.env.model.getters.getEvaluatedCell(cellPosition);
|
|
27781
27838
|
const align = this.props.horizontalAlign || cell?.style?.align || evaluatedCell.defaultAlign;
|
|
27782
27839
|
switch (align) {
|
|
27783
27840
|
case "right":
|
|
@@ -27861,6 +27918,8 @@ css /* scss */ `
|
|
|
27861
27918
|
height: ${CHECKBOX_WIDTH}px;
|
|
27862
27919
|
accent-color: #808080;
|
|
27863
27920
|
margin: ${MARGIN}px;
|
|
27921
|
+
/** required to prevent the checkbox position to be sensible to the font-size (affects Firefox) */
|
|
27922
|
+
position: absolute;
|
|
27864
27923
|
}
|
|
27865
27924
|
`;
|
|
27866
27925
|
class DataValidationCheckbox extends Component {
|
|
@@ -27879,7 +27938,7 @@ class DataValidationCheckbox extends Component {
|
|
|
27879
27938
|
}
|
|
27880
27939
|
get isDisabled() {
|
|
27881
27940
|
const cell = this.env.model.getters.getCell(this.props.cellPosition);
|
|
27882
|
-
return !!cell?.isFormula;
|
|
27941
|
+
return this.env.model.getters.isReadonly() || !!cell?.isFormula;
|
|
27883
27942
|
}
|
|
27884
27943
|
}
|
|
27885
27944
|
|
|
@@ -27919,12 +27978,17 @@ class DataValidationOverlay extends Component {
|
|
|
27919
27978
|
static props = {};
|
|
27920
27979
|
static components = { GridCellIcon, DataValidationCheckbox, DataValidationListIcon };
|
|
27921
27980
|
get checkBoxCellPositions() {
|
|
27922
|
-
return this.env.model.getters
|
|
27981
|
+
return this.env.model.getters
|
|
27982
|
+
.getVisibleCellPositions()
|
|
27983
|
+
.filter(this.env.model.getters.isCellValidCheckbox);
|
|
27923
27984
|
}
|
|
27924
27985
|
get listIconsCellPositions() {
|
|
27925
|
-
|
|
27926
|
-
|
|
27927
|
-
|
|
27986
|
+
if (this.env.model.getters.isReadonly()) {
|
|
27987
|
+
return [];
|
|
27988
|
+
}
|
|
27989
|
+
return this.env.model.getters
|
|
27990
|
+
.getVisibleCellPositions()
|
|
27991
|
+
.filter(this.env.model.getters.cellHasListDataValidationIcon);
|
|
27928
27992
|
}
|
|
27929
27993
|
}
|
|
27930
27994
|
|
|
@@ -34286,29 +34350,12 @@ const MIGRATIONS = [
|
|
|
34286
34350
|
from: 12,
|
|
34287
34351
|
to: 12.5,
|
|
34288
34352
|
applyMigration(data) {
|
|
34289
|
-
|
|
34290
|
-
let knownDataFilterZones = [];
|
|
34291
|
-
for (let filterTable of sheet.filterTables || []) {
|
|
34292
|
-
const zone = toZone(filterTable.range);
|
|
34293
|
-
// See commit message for the details
|
|
34294
|
-
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
34295
|
-
if (intersectZoneIndex !== -1) {
|
|
34296
|
-
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
34297
|
-
}
|
|
34298
|
-
else {
|
|
34299
|
-
knownDataFilterZones.push(zone);
|
|
34300
|
-
}
|
|
34301
|
-
}
|
|
34302
|
-
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
34303
|
-
range: zoneToXc(zone),
|
|
34304
|
-
}));
|
|
34305
|
-
}
|
|
34306
|
-
return data;
|
|
34353
|
+
return fixOverlappingFilters(data);
|
|
34307
34354
|
},
|
|
34308
34355
|
},
|
|
34309
34356
|
{
|
|
34310
34357
|
description: "Change Border description structure",
|
|
34311
|
-
from: 12,
|
|
34358
|
+
from: 12.5,
|
|
34312
34359
|
to: 13,
|
|
34313
34360
|
applyMigration(data) {
|
|
34314
34361
|
for (const borderId in data.borders) {
|
|
@@ -34339,6 +34386,14 @@ const MIGRATIONS = [
|
|
|
34339
34386
|
return data;
|
|
34340
34387
|
},
|
|
34341
34388
|
},
|
|
34389
|
+
{
|
|
34390
|
+
description: "Fix datafilter duplication (post saas-16.4)",
|
|
34391
|
+
from: 14,
|
|
34392
|
+
to: 14.5,
|
|
34393
|
+
applyMigration(data) {
|
|
34394
|
+
return fixOverlappingFilters(data);
|
|
34395
|
+
},
|
|
34396
|
+
},
|
|
34342
34397
|
];
|
|
34343
34398
|
/**
|
|
34344
34399
|
* This function is used to repair faulty data independently of the migration.
|
|
@@ -34496,6 +34551,26 @@ function fixChartDefinitions(data, initialMessages) {
|
|
|
34496
34551
|
}
|
|
34497
34552
|
return messages;
|
|
34498
34553
|
}
|
|
34554
|
+
function fixOverlappingFilters(data) {
|
|
34555
|
+
for (let sheet of data.sheets || []) {
|
|
34556
|
+
let knownDataFilterZones = [];
|
|
34557
|
+
for (let filterTable of sheet.filterTables || []) {
|
|
34558
|
+
const zone = toZone(filterTable.range);
|
|
34559
|
+
// See commit message of https://github.com/odoo/o-spreadsheet/pull/3632 of more details
|
|
34560
|
+
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
34561
|
+
if (intersectZoneIndex !== -1) {
|
|
34562
|
+
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
34563
|
+
}
|
|
34564
|
+
else {
|
|
34565
|
+
knownDataFilterZones.push(zone);
|
|
34566
|
+
}
|
|
34567
|
+
}
|
|
34568
|
+
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
34569
|
+
range: zoneToXc(zone),
|
|
34570
|
+
}));
|
|
34571
|
+
}
|
|
34572
|
+
return data;
|
|
34573
|
+
}
|
|
34499
34574
|
// -----------------------------------------------------------------------------
|
|
34500
34575
|
// Helpers
|
|
34501
34576
|
// -----------------------------------------------------------------------------
|
|
@@ -35145,22 +35220,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
35145
35220
|
}
|
|
35146
35221
|
}
|
|
35147
35222
|
export(data) {
|
|
35148
|
-
// Borders
|
|
35149
|
-
let borderId = 0;
|
|
35150
35223
|
const borders = {};
|
|
35151
|
-
/**
|
|
35152
|
-
* Get the id of the given border. If the border does not exist, it creates
|
|
35153
|
-
* one.
|
|
35154
|
-
*/
|
|
35155
|
-
function getBorderId(border) {
|
|
35156
|
-
for (let [key, value] of Object.entries(borders)) {
|
|
35157
|
-
if (deepEquals(value, border)) {
|
|
35158
|
-
return parseInt(key, 10);
|
|
35159
|
-
}
|
|
35160
|
-
}
|
|
35161
|
-
borders[++borderId] = border;
|
|
35162
|
-
return borderId;
|
|
35163
|
-
}
|
|
35164
35224
|
for (let sheet of data.sheets) {
|
|
35165
35225
|
for (let col = 0; col < sheet.colNumber; col++) {
|
|
35166
35226
|
for (let row = 0; row < sheet.rowNumber; row++) {
|
|
@@ -35168,7 +35228,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
35168
35228
|
if (border) {
|
|
35169
35229
|
const xc = toXC(col, row);
|
|
35170
35230
|
const cell = sheet.cells[xc];
|
|
35171
|
-
const borderId =
|
|
35231
|
+
const borderId = getItemId(border, borders);
|
|
35172
35232
|
if (cell) {
|
|
35173
35233
|
cell.border = borderId;
|
|
35174
35234
|
}
|
|
@@ -35957,9 +36017,9 @@ class CellPlugin extends CorePlugin {
|
|
|
35957
36017
|
allowDispatch(cmd) {
|
|
35958
36018
|
switch (cmd.type) {
|
|
35959
36019
|
case "UPDATE_CELL":
|
|
35960
|
-
return this.
|
|
36020
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
|
|
35961
36021
|
case "CLEAR_CELL":
|
|
35962
|
-
return this.checkValidations(cmd, this.
|
|
36022
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
|
|
35963
36023
|
default:
|
|
35964
36024
|
return "Success" /* CommandResult.Success */;
|
|
35965
36025
|
}
|
|
@@ -36109,8 +36169,8 @@ class CellPlugin extends CorePlugin {
|
|
|
36109
36169
|
}
|
|
36110
36170
|
removeDefaultStyleValues(style) {
|
|
36111
36171
|
const cleanedStyle = { ...style };
|
|
36112
|
-
for (const
|
|
36113
|
-
if (cleanedStyle[property] ===
|
|
36172
|
+
for (const property in DEFAULT_STYLE) {
|
|
36173
|
+
if (cleanedStyle[property] === DEFAULT_STYLE[property]) {
|
|
36114
36174
|
delete cleanedStyle[property];
|
|
36115
36175
|
}
|
|
36116
36176
|
}
|
|
@@ -36266,10 +36326,7 @@ class CellPlugin extends CorePlugin {
|
|
|
36266
36326
|
else {
|
|
36267
36327
|
style = before ? before.style : undefined;
|
|
36268
36328
|
}
|
|
36269
|
-
const
|
|
36270
|
-
let format = ("format" in after ? after.format : before && before.format) ||
|
|
36271
|
-
detectDateFormat(afterContent, locale) ||
|
|
36272
|
-
detectNumberFormat(afterContent);
|
|
36329
|
+
const format = "format" in after ? after.format : before && before.format;
|
|
36273
36330
|
/* Read the following IF as:
|
|
36274
36331
|
* we need to remove the cell if it is completely empty, but we can know if it completely empty if:
|
|
36275
36332
|
* - the command says the new content is empty and has no border/format/style
|
|
@@ -36310,6 +36367,7 @@ class CellPlugin extends CorePlugin {
|
|
|
36310
36367
|
}
|
|
36311
36368
|
createLiteralCell(id, content, format, style) {
|
|
36312
36369
|
const locale = this.getters.getLocale();
|
|
36370
|
+
format = format || detectDateFormat(content, locale) || detectNumberFormat(content);
|
|
36313
36371
|
if (format !== PLAIN_TEXT_FORMAT && !isEvaluationError(content)) {
|
|
36314
36372
|
content = toString(parseLiteral(content, locale));
|
|
36315
36373
|
}
|
|
@@ -36382,6 +36440,18 @@ class CellPlugin extends CorePlugin {
|
|
|
36382
36440
|
}
|
|
36383
36441
|
return "Success" /* CommandResult.Success */;
|
|
36384
36442
|
}
|
|
36443
|
+
checkUselessUpdateCell(cmd) {
|
|
36444
|
+
const cell = this.getters.getCell(cmd);
|
|
36445
|
+
const hasContent = "content" in cmd || "formula" in cmd;
|
|
36446
|
+
const hasStyle = "style" in cmd;
|
|
36447
|
+
const hasFormat = "format" in cmd;
|
|
36448
|
+
if ((!hasContent || cell?.content === cmd.content) &&
|
|
36449
|
+
(!hasStyle || deepEquals(cell?.style, cmd.style)) &&
|
|
36450
|
+
(!hasFormat || cell?.format === cmd.format)) {
|
|
36451
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
36452
|
+
}
|
|
36453
|
+
return "Success" /* CommandResult.Success */;
|
|
36454
|
+
}
|
|
36385
36455
|
}
|
|
36386
36456
|
class FormulaCellWithDependencies {
|
|
36387
36457
|
id;
|
|
@@ -39022,7 +39092,6 @@ class SheetPlugin extends CorePlugin {
|
|
|
39022
39092
|
"getNumberHeaders",
|
|
39023
39093
|
"getGridLinesVisibility",
|
|
39024
39094
|
"getNextSheetName",
|
|
39025
|
-
"isEmpty",
|
|
39026
39095
|
"getSheetSize",
|
|
39027
39096
|
"getSheetZone",
|
|
39028
39097
|
"getPaneDivisions",
|
|
@@ -39397,14 +39466,6 @@ class SheetPlugin extends CorePlugin {
|
|
|
39397
39466
|
// ---------------------------------------------------------------------------
|
|
39398
39467
|
// Row/Col manipulation
|
|
39399
39468
|
// ---------------------------------------------------------------------------
|
|
39400
|
-
/**
|
|
39401
|
-
* Check if a zone only contains empty cells
|
|
39402
|
-
*/
|
|
39403
|
-
isEmpty(sheetId, zone) {
|
|
39404
|
-
return positions(zone)
|
|
39405
|
-
.map(({ col, row }) => this.getCell({ sheetId, col, row }))
|
|
39406
|
-
.every((cell) => !cell || cell.content === "");
|
|
39407
|
-
}
|
|
39408
39469
|
getCommandZones(cmd) {
|
|
39409
39470
|
const zones = [];
|
|
39410
39471
|
if ("zone" in cmd) {
|
|
@@ -41166,7 +41227,15 @@ class SpreadsheetRTree {
|
|
|
41166
41227
|
if (!this.rTrees[sheetId]) {
|
|
41167
41228
|
return;
|
|
41168
41229
|
}
|
|
41169
|
-
this.rTrees[sheetId].remove(item,
|
|
41230
|
+
this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
|
|
41231
|
+
}
|
|
41232
|
+
rtreeItemComparer(left, right) {
|
|
41233
|
+
return (left.data == right.data &&
|
|
41234
|
+
left.boundingBox.sheetId === right.boundingBox.sheetId &&
|
|
41235
|
+
left.boundingBox?.zone.left === right.boundingBox.zone.left &&
|
|
41236
|
+
left.boundingBox?.zone.top === right.boundingBox.zone.top &&
|
|
41237
|
+
left.boundingBox?.zone.right === right.boundingBox.zone.right &&
|
|
41238
|
+
left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
|
|
41170
41239
|
}
|
|
41171
41240
|
}
|
|
41172
41241
|
/**
|
|
@@ -41244,7 +41313,7 @@ class FormulaDependencyGraph {
|
|
|
41244
41313
|
const queue = Array.from(ranges).reverse();
|
|
41245
41314
|
while (queue.length > 0) {
|
|
41246
41315
|
const range = queue.pop();
|
|
41247
|
-
visited.
|
|
41316
|
+
visited.addMany(this.encoder.encodeBoundingBox(range));
|
|
41248
41317
|
const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
|
|
41249
41318
|
for (const positionId of impactedPositionIds) {
|
|
41250
41319
|
if (!visited.has(positionId)) {
|
|
@@ -41252,7 +41321,7 @@ class FormulaDependencyGraph {
|
|
|
41252
41321
|
}
|
|
41253
41322
|
}
|
|
41254
41323
|
}
|
|
41255
|
-
visited.
|
|
41324
|
+
visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
|
|
41256
41325
|
return visited;
|
|
41257
41326
|
}
|
|
41258
41327
|
}
|
|
@@ -41392,9 +41461,9 @@ class Evaluator {
|
|
|
41392
41461
|
const cells = positions.map((p) => this.encoder.encode(p));
|
|
41393
41462
|
const cellsToCompute = new JetSet(cells);
|
|
41394
41463
|
const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
|
|
41395
|
-
cellsToCompute.
|
|
41396
|
-
cellsToCompute.
|
|
41397
|
-
cellsToCompute.
|
|
41464
|
+
cellsToCompute.addMany(this.getCellsDependingOn(cells));
|
|
41465
|
+
cellsToCompute.addMany(arrayFormulasPositionIds);
|
|
41466
|
+
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
|
|
41398
41467
|
this.evaluate(cellsToCompute);
|
|
41399
41468
|
}
|
|
41400
41469
|
getArrayFormulasImpactedByChangesOf(positionIds) {
|
|
@@ -41408,7 +41477,7 @@ class Evaluator {
|
|
|
41408
41477
|
}
|
|
41409
41478
|
if (!content) {
|
|
41410
41479
|
// The previous content could have blocked some array formulas
|
|
41411
|
-
impactedPositionIds.
|
|
41480
|
+
impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
|
|
41412
41481
|
}
|
|
41413
41482
|
}
|
|
41414
41483
|
return impactedPositionIds;
|
|
@@ -41460,7 +41529,7 @@ class Evaluator {
|
|
|
41460
41529
|
}
|
|
41461
41530
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
|
|
41462
41531
|
const cells = new JetSet(arrayFormulas);
|
|
41463
|
-
cells.
|
|
41532
|
+
cells.addMany(this.getCellsDependingOn(arrayFormulas));
|
|
41464
41533
|
return cells;
|
|
41465
41534
|
}
|
|
41466
41535
|
nextPositionsToUpdate = new JetSet();
|
|
@@ -41511,7 +41580,7 @@ class Evaluator {
|
|
|
41511
41580
|
: evaluateLiteral(cell.content, localeFormat);
|
|
41512
41581
|
}
|
|
41513
41582
|
catch (e) {
|
|
41514
|
-
return createEvaluatedCell(e.
|
|
41583
|
+
return createEvaluatedCell(e?.value || CellErrorType.GenericError, localeFormat, e?.message || implementationErrorMessage);
|
|
41515
41584
|
}
|
|
41516
41585
|
finally {
|
|
41517
41586
|
this.cellsBeingComputed.delete(cellId);
|
|
@@ -41598,7 +41667,7 @@ class Evaluator {
|
|
|
41598
41667
|
this.setEvaluatedCell(positionId, evaluatedCell);
|
|
41599
41668
|
// check if formula dependencies present in the spread zone
|
|
41600
41669
|
// if so, they need to be recomputed
|
|
41601
|
-
this.nextPositionsToUpdate.
|
|
41670
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
|
|
41602
41671
|
};
|
|
41603
41672
|
}
|
|
41604
41673
|
invalidateSpreading(positionId) {
|
|
@@ -41613,8 +41682,8 @@ class Evaluator {
|
|
|
41613
41682
|
continue;
|
|
41614
41683
|
}
|
|
41615
41684
|
this.evaluatedCells.delete(child);
|
|
41616
|
-
this.nextPositionsToUpdate.
|
|
41617
|
-
this.nextPositionsToUpdate.
|
|
41685
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
41686
|
+
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
41618
41687
|
}
|
|
41619
41688
|
this.spreadingRelations.removeNode(positionId);
|
|
41620
41689
|
}
|
|
@@ -41845,6 +41914,7 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
41845
41914
|
"getEvaluatedCellsInZone",
|
|
41846
41915
|
"getSpreadPositionsOf",
|
|
41847
41916
|
"getArrayFormulaSpreadingOn",
|
|
41917
|
+
"isEmpty",
|
|
41848
41918
|
];
|
|
41849
41919
|
shouldRebuildDependenciesGraph = true;
|
|
41850
41920
|
evaluator;
|
|
@@ -41950,6 +42020,14 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
41950
42020
|
getArrayFormulaSpreadingOn(position) {
|
|
41951
42021
|
return this.evaluator.getArrayFormulaSpreadingOn(position);
|
|
41952
42022
|
}
|
|
42023
|
+
/**
|
|
42024
|
+
* Check if a zone only contains empty cells
|
|
42025
|
+
*/
|
|
42026
|
+
isEmpty(sheetId, zone) {
|
|
42027
|
+
return positions(zone)
|
|
42028
|
+
.map(({ col, row }) => this.getEvaluatedCell({ sheetId, col, row }))
|
|
42029
|
+
.every((cell) => cell.type === CellValueType.empty);
|
|
42030
|
+
}
|
|
41953
42031
|
// ---------------------------------------------------------------------------
|
|
41954
42032
|
// Export
|
|
41955
42033
|
// ---------------------------------------------------------------------------
|
|
@@ -42597,8 +42675,6 @@ const VALID_RESULT = { isValid: true };
|
|
|
42597
42675
|
class EvaluationDataValidationPlugin extends UIPlugin {
|
|
42598
42676
|
static getters = [
|
|
42599
42677
|
"getDataValidationInvalidCriterionValueMessage",
|
|
42600
|
-
"getDataValidationCheckBoxCellPositions",
|
|
42601
|
-
"getDataValidationListCellsPositions",
|
|
42602
42678
|
"getInvalidDataValidationMessage",
|
|
42603
42679
|
"getValidationResultForCellValue",
|
|
42604
42680
|
"isCellValidCheckbox",
|
|
@@ -42662,19 +42738,6 @@ class EvaluationDataValidationPlugin extends UIPlugin {
|
|
|
42662
42738
|
const error = this.getRuleErrorForCellValue(cellValue, cellPosition, rule);
|
|
42663
42739
|
return error ? { error, rule, isValid: false } : VALID_RESULT;
|
|
42664
42740
|
}
|
|
42665
|
-
getDataValidationCheckBoxCellPositions() {
|
|
42666
|
-
const rules = this.getters
|
|
42667
|
-
.getDataValidationRules(this.getters.getActiveSheetId())
|
|
42668
|
-
.filter((rule) => rule.criterion.type === "isBoolean");
|
|
42669
|
-
return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat()).filter((position) => this.isCellValidCheckbox(position));
|
|
42670
|
-
}
|
|
42671
|
-
getDataValidationListCellsPositions() {
|
|
42672
|
-
const rules = this.getters
|
|
42673
|
-
.getDataValidationRules(this.getters.getActiveSheetId())
|
|
42674
|
-
.filter((rule) => (rule.criterion.type === "isValueInList" || rule.criterion.type === "isValueInRange") &&
|
|
42675
|
-
rule.criterion.displayStyle === "arrow");
|
|
42676
|
-
return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat());
|
|
42677
|
-
}
|
|
42678
42741
|
getValidationResultForCell(cellPosition) {
|
|
42679
42742
|
const { col, row, sheetId } = cellPosition;
|
|
42680
42743
|
if (!this.validationResults[sheetId]) {
|
|
@@ -45483,7 +45546,7 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45483
45546
|
}
|
|
45484
45547
|
finalize() {
|
|
45485
45548
|
if (this.isSearchDirty) {
|
|
45486
|
-
this.refreshSearch();
|
|
45549
|
+
this.refreshSearch(false);
|
|
45487
45550
|
this.isSearchDirty = false;
|
|
45488
45551
|
}
|
|
45489
45552
|
}
|
|
@@ -45527,10 +45590,10 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45527
45590
|
/**
|
|
45528
45591
|
* refresh the matches according to the current search options
|
|
45529
45592
|
*/
|
|
45530
|
-
refreshSearch() {
|
|
45593
|
+
refreshSearch(jumpToMatchSheet = true) {
|
|
45531
45594
|
this.selectedMatchIndex = null;
|
|
45532
45595
|
this.findMatches();
|
|
45533
|
-
this.selectNextCell(Direction.current);
|
|
45596
|
+
this.selectNextCell(Direction.current, jumpToMatchSheet);
|
|
45534
45597
|
}
|
|
45535
45598
|
/**
|
|
45536
45599
|
* Updates the regex based on the current searchOptions and
|
|
@@ -45612,7 +45675,7 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45612
45675
|
* It is also used to keep coherence between the selected searchMatch
|
|
45613
45676
|
* and selectedMatchIndex.
|
|
45614
45677
|
*/
|
|
45615
|
-
selectNextCell(indexChange) {
|
|
45678
|
+
selectNextCell(indexChange, jumpToMatchSheet = true) {
|
|
45616
45679
|
const matches = this.searchMatches;
|
|
45617
45680
|
if (!matches.length) {
|
|
45618
45681
|
this.selectedMatchIndex = null;
|
|
@@ -45638,11 +45701,13 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45638
45701
|
this.selectedMatchIndex = nextIndex;
|
|
45639
45702
|
const selectedMatch = matches[nextIndex];
|
|
45640
45703
|
// Switch to the sheet where the match is located
|
|
45641
|
-
if (this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
45704
|
+
if (jumpToMatchSheet && this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
45642
45705
|
this.dispatch("ACTIVATE_SHEET", {
|
|
45643
45706
|
sheetIdFrom: this.getters.getActiveSheetId(),
|
|
45644
45707
|
sheetIdTo: selectedMatch.sheetId,
|
|
45645
45708
|
});
|
|
45709
|
+
// We do not want to reset the selection at finalize in this case
|
|
45710
|
+
this.isSearchDirty = false;
|
|
45646
45711
|
}
|
|
45647
45712
|
// we want grid selection to capture the selection stream
|
|
45648
45713
|
this.selection.getBackToDefault();
|
|
@@ -46944,19 +47009,17 @@ class SelectionInputsManagerPlugin extends UIPlugin {
|
|
|
46944
47009
|
break;
|
|
46945
47010
|
case "FOCUS_RANGE":
|
|
46946
47011
|
case "CHANGE_RANGE":
|
|
46947
|
-
|
|
46948
|
-
|
|
46949
|
-
|
|
46950
|
-
|
|
46951
|
-
|
|
46952
|
-
|
|
46953
|
-
|
|
46954
|
-
|
|
46955
|
-
|
|
46956
|
-
});
|
|
46957
|
-
}
|
|
46958
|
-
this.focusedInputId = cmd.id;
|
|
47012
|
+
const input = this.inputs[cmd.id];
|
|
47013
|
+
const range = input.ranges.find((range) => range.id === cmd.rangeId);
|
|
47014
|
+
if (range) {
|
|
47015
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
47016
|
+
const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
|
|
47017
|
+
this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, {
|
|
47018
|
+
handleEvent: input.handleEvent.bind(input),
|
|
47019
|
+
release: () => (this.focusedInputId = null),
|
|
47020
|
+
});
|
|
46959
47021
|
}
|
|
47022
|
+
this.focusedInputId = cmd.id;
|
|
46960
47023
|
break;
|
|
46961
47024
|
}
|
|
46962
47025
|
this.currentInput?.handle(cmd);
|
|
@@ -47210,7 +47273,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
47210
47273
|
"getCellText",
|
|
47211
47274
|
"getCellMultiLineText",
|
|
47212
47275
|
"getContiguousZone",
|
|
47213
|
-
"
|
|
47276
|
+
"isEvaluatedCellEmpty",
|
|
47214
47277
|
];
|
|
47215
47278
|
ctx = document.createElement("canvas").getContext("2d");
|
|
47216
47279
|
// ---------------------------------------------------------------------------
|
|
@@ -47338,14 +47401,23 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
47338
47401
|
return zone;
|
|
47339
47402
|
}
|
|
47340
47403
|
/**
|
|
47341
|
-
*
|
|
47342
|
-
* check
|
|
47404
|
+
* Checks if a cell evaluated value is empty. If the cell is part of a merge,
|
|
47405
|
+
* the check applies to the main cell of the merge.
|
|
47343
47406
|
*/
|
|
47344
|
-
|
|
47407
|
+
isEvaluatedCellEmpty(position) {
|
|
47345
47408
|
const mainPosition = this.getters.getMainCellPosition(position);
|
|
47346
47409
|
const cell = this.getters.getEvaluatedCell(mainPosition);
|
|
47347
47410
|
return cell.type === CellValueType.empty;
|
|
47348
47411
|
}
|
|
47412
|
+
/**
|
|
47413
|
+
* Checks if a cell is empty (i.e. does not have a content or a formula does not spread over it).
|
|
47414
|
+
* If the cell is part of a merge, the check applies to the main cell of the merge.
|
|
47415
|
+
*/
|
|
47416
|
+
isCellEmpty(position) {
|
|
47417
|
+
const mainPosition = this.getters.getMainCellPosition(position);
|
|
47418
|
+
return !(this.getters.getCorrespondingFormulaCell(mainPosition) ||
|
|
47419
|
+
this.getters.getCell(mainPosition)?.content);
|
|
47420
|
+
}
|
|
47349
47421
|
getColMaxWidth(sheetId, index) {
|
|
47350
47422
|
const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
|
|
47351
47423
|
const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
|
|
@@ -50366,6 +50438,8 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
50366
50438
|
"getEdgeScrollRow",
|
|
50367
50439
|
"getVisibleFigures",
|
|
50368
50440
|
"getVisibleRect",
|
|
50441
|
+
"getVisibleRectWithoutHeaders",
|
|
50442
|
+
"getVisibleCellPositions",
|
|
50369
50443
|
"getColRowOffsetInViewport",
|
|
50370
50444
|
"getMainViewportCoordinates",
|
|
50371
50445
|
"getActiveSheetScrollInfo",
|
|
@@ -50609,6 +50683,26 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
50609
50683
|
const viewports = this.getSubViewports(sheetId);
|
|
50610
50684
|
return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
|
|
50611
50685
|
}
|
|
50686
|
+
/**
|
|
50687
|
+
* Get the positions of all the cells that are visible in the viewport, taking merges into account.
|
|
50688
|
+
*/
|
|
50689
|
+
getVisibleCellPositions() {
|
|
50690
|
+
const visibleCols = this.getSheetViewVisibleCols();
|
|
50691
|
+
const visibleRows = this.getSheetViewVisibleRows();
|
|
50692
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
50693
|
+
const positions = [];
|
|
50694
|
+
for (const col of visibleCols) {
|
|
50695
|
+
for (const row of visibleRows) {
|
|
50696
|
+
const position = { sheetId, col, row };
|
|
50697
|
+
const mainPosition = this.getters.getMainCellPosition(position);
|
|
50698
|
+
if (mainPosition.row !== row || mainPosition.col !== col) {
|
|
50699
|
+
continue;
|
|
50700
|
+
}
|
|
50701
|
+
positions.push(position);
|
|
50702
|
+
}
|
|
50703
|
+
}
|
|
50704
|
+
return positions;
|
|
50705
|
+
}
|
|
50612
50706
|
/**
|
|
50613
50707
|
* Return the main viewport maximum size relative to the client size.
|
|
50614
50708
|
*/
|
|
@@ -50728,6 +50822,13 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
50728
50822
|
* Computes the coordinates and size to draw the zone on the canvas
|
|
50729
50823
|
*/
|
|
50730
50824
|
getVisibleRect(zone) {
|
|
50825
|
+
const rect = this.getVisibleRectWithoutHeaders(zone);
|
|
50826
|
+
return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
|
|
50827
|
+
}
|
|
50828
|
+
/**
|
|
50829
|
+
* Computes the coordinates and size to draw the zone without taking the grid offset into account
|
|
50830
|
+
*/
|
|
50831
|
+
getVisibleRectWithoutHeaders(zone) {
|
|
50731
50832
|
const sheetId = this.getters.getActiveSheetId();
|
|
50732
50833
|
const viewportRects = this.getSubViewports(sheetId)
|
|
50733
50834
|
.map((viewport) => viewport.getRect(zone))
|
|
@@ -50739,12 +50840,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
50739
50840
|
const y = Math.min(...viewportRects.map((rect) => rect.y));
|
|
50740
50841
|
const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
|
|
50741
50842
|
const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
|
|
50742
|
-
return {
|
|
50743
|
-
x: x + this.gridOffsetX,
|
|
50744
|
-
y: y + this.gridOffsetY,
|
|
50745
|
-
width,
|
|
50746
|
-
height,
|
|
50747
|
-
};
|
|
50843
|
+
return { x, y, width, height };
|
|
50748
50844
|
}
|
|
50749
50845
|
/**
|
|
50750
50846
|
* Returns the position of the MainViewport relatively to the start of the grid (without headers)
|
|
@@ -50968,13 +51064,8 @@ class HeaderPositionsUIPlugin extends UIPlugin {
|
|
|
50968
51064
|
}
|
|
50969
51065
|
break;
|
|
50970
51066
|
case "UPDATE_CELL":
|
|
50971
|
-
|
|
50972
|
-
|
|
50973
|
-
this.isDirty = true;
|
|
50974
|
-
}
|
|
50975
|
-
else {
|
|
50976
|
-
this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
|
|
50977
|
-
}
|
|
51067
|
+
this.headerPositions = {};
|
|
51068
|
+
this.isDirty = true;
|
|
50978
51069
|
break;
|
|
50979
51070
|
case "UPDATE_FILTER":
|
|
50980
51071
|
case "REMOVE_FILTER_TABLE":
|
|
@@ -54887,8 +54978,8 @@ class SelectionStreamProcessorImpl {
|
|
|
54887
54978
|
let currentPosition = startPosition;
|
|
54888
54979
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
54889
54980
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
54890
|
-
let mode = !this.getters.
|
|
54891
|
-
!this.getters.
|
|
54981
|
+
let mode = !this.getters.isEvaluatedCellEmpty({ ...currentPosition, sheetId }) &&
|
|
54982
|
+
!this.getters.isEvaluatedCellEmpty({ ...nextCellPosition, sheetId })
|
|
54892
54983
|
? "endOfCluster"
|
|
54893
54984
|
: "nextCluster";
|
|
54894
54985
|
while (true) {
|
|
@@ -54898,7 +54989,7 @@ class SelectionStreamProcessorImpl {
|
|
|
54898
54989
|
currentPosition.row === nextCellPosition.row) {
|
|
54899
54990
|
break;
|
|
54900
54991
|
}
|
|
54901
|
-
const isNextCellEmpty = this.getters.
|
|
54992
|
+
const isNextCellEmpty = this.getters.isEvaluatedCellEmpty({ ...nextCellPosition, sheetId });
|
|
54902
54993
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
54903
54994
|
break;
|
|
54904
54995
|
}
|
|
@@ -57147,6 +57238,6 @@ const constants = {
|
|
|
57147
57238
|
export { AbstractChart, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
|
|
57148
57239
|
|
|
57149
57240
|
|
|
57150
|
-
__info__.version = "17.1.
|
|
57151
|
-
__info__.date = "2024-
|
|
57152
|
-
__info__.hash = "
|
|
57241
|
+
__info__.version = "17.1.7";
|
|
57242
|
+
__info__.date = "2024-03-12T07:56:10.783Z";
|
|
57243
|
+
__info__.hash = "3a9f334";
|