@odoo/o-spreadsheet 17.0.56 → 17.0.57
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 +594 -466
- package/dist/o-spreadsheet.d.ts +19 -10
- package/dist/o-spreadsheet.esm.js +594 -466
- package/dist/o-spreadsheet.iife.js +594 -466
- package/dist/o-spreadsheet.iife.min.js +16 -16
- package/dist/o_spreadsheet.xml +3 -3
- 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.0.
|
|
6
|
-
* @date 2025-04-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.0.57
|
|
6
|
+
* @date 2025-04-14T17:13:56.677Z
|
|
7
|
+
* @hash 6ac8bb7
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -2002,6 +2002,7 @@
|
|
|
2002
2002
|
"CLEAR_FORMATTING",
|
|
2003
2003
|
"SET_BORDER",
|
|
2004
2004
|
"SET_ZONE_BORDERS",
|
|
2005
|
+
"SET_BORDERS_ON_TARGET",
|
|
2005
2006
|
/** CHART */
|
|
2006
2007
|
"CREATE_CHART",
|
|
2007
2008
|
"UPDATE_CHART",
|
|
@@ -34684,6 +34685,15 @@
|
|
|
34684
34685
|
case "SET_BORDER":
|
|
34685
34686
|
this.setBorder(cmd.sheetId, cmd.col, cmd.row, cmd.border);
|
|
34686
34687
|
break;
|
|
34688
|
+
case "SET_BORDERS_ON_TARGET":
|
|
34689
|
+
for (const zone of cmd.target) {
|
|
34690
|
+
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
34691
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
34692
|
+
this.setBorder(cmd.sheetId, col, row, cmd.border);
|
|
34693
|
+
}
|
|
34694
|
+
}
|
|
34695
|
+
}
|
|
34696
|
+
break;
|
|
34687
34697
|
case "SET_ZONE_BORDERS":
|
|
34688
34698
|
if (cmd.border) {
|
|
34689
34699
|
const target = cmd.target.map((zone) => this.getters.expandZone(cmd.sheetId, zone));
|
|
@@ -36690,6 +36700,353 @@
|
|
|
36690
36700
|
}
|
|
36691
36701
|
}
|
|
36692
36702
|
|
|
36703
|
+
/**
|
|
36704
|
+
* ####################################################
|
|
36705
|
+
* # INTRODUCTION
|
|
36706
|
+
* ####################################################
|
|
36707
|
+
*
|
|
36708
|
+
* This file contain the function recomputeZones.
|
|
36709
|
+
* This function try to recompute in a performant way
|
|
36710
|
+
* an ensemble of zones possibly overlapping to avoid
|
|
36711
|
+
* overlapping and to reduce the number of zones.
|
|
36712
|
+
*
|
|
36713
|
+
* It also allows to remove some zones from the ensemble.
|
|
36714
|
+
*
|
|
36715
|
+
* In the following example, 2 zones are overlapping.
|
|
36716
|
+
* Applying recomputeZones will return zones without
|
|
36717
|
+
* overlapping:
|
|
36718
|
+
*
|
|
36719
|
+
* ["B3:D4", "D2:E3"] ["B3:C4", "D2:D4", "E2:E3"]
|
|
36720
|
+
*
|
|
36721
|
+
* A B C D E A B C D E
|
|
36722
|
+
* 1 ___ 1 ___
|
|
36723
|
+
* 2 ___|_ | 2 ___| | |
|
|
36724
|
+
* 3 | |_|_| ---> 3 | | |_|
|
|
36725
|
+
* 4 |_____| 4 |___|_|
|
|
36726
|
+
* 6 6
|
|
36727
|
+
* 7 7
|
|
36728
|
+
*
|
|
36729
|
+
*
|
|
36730
|
+
* In the following example, 2 zones are contiguous.
|
|
36731
|
+
* Applying recomputeZones will return only one zone:
|
|
36732
|
+
*
|
|
36733
|
+
* ["B2:B3", "C2:D3"] ["B2:D3"]
|
|
36734
|
+
*
|
|
36735
|
+
* A B C D E A B C D E
|
|
36736
|
+
* 1 _ ___ 1 _____
|
|
36737
|
+
* 2 | | | ---> 2 | |
|
|
36738
|
+
* 3 |_|___| 3 |_____|
|
|
36739
|
+
* 4 4
|
|
36740
|
+
*
|
|
36741
|
+
*
|
|
36742
|
+
* In the following example, we want to remove a zone
|
|
36743
|
+
* from the ensemble. Applying recomputeZones will
|
|
36744
|
+
* return the ensemble without the zone to remove:
|
|
36745
|
+
*
|
|
36746
|
+
* remove ["C3:D3"] ["B2:B4", "C2:D2",
|
|
36747
|
+
* "C4:D4", "E2:E4"]
|
|
36748
|
+
*
|
|
36749
|
+
* A B C D E F A B C D E F
|
|
36750
|
+
* 1 _______ 1 _______
|
|
36751
|
+
* 2 | | ---> 2 | |___| |
|
|
36752
|
+
* 3 | xxx | 3 | |___| |
|
|
36753
|
+
* 4 |_______| 4 |_|___|_|
|
|
36754
|
+
* 5 5
|
|
36755
|
+
*
|
|
36756
|
+
*
|
|
36757
|
+
* The exercise seems simple when we have only 2 zones.
|
|
36758
|
+
* But with n zones and in a performant way, we want to
|
|
36759
|
+
* avoid comparing each zone with all the others.
|
|
36760
|
+
*
|
|
36761
|
+
*
|
|
36762
|
+
* ####################################################
|
|
36763
|
+
* # Methodological approach
|
|
36764
|
+
* ####################################################
|
|
36765
|
+
*
|
|
36766
|
+
* The methodological approach to avoid comparing each
|
|
36767
|
+
* zone with all the others is to use a data structure
|
|
36768
|
+
* that allow to quickly find which zones are
|
|
36769
|
+
* overlapping with any other given zone.
|
|
36770
|
+
*
|
|
36771
|
+
* Here the idea is to profile the zones at the columns level.
|
|
36772
|
+
*
|
|
36773
|
+
* To do that, we propose to use a data structure
|
|
36774
|
+
* composed of 2 parts:
|
|
36775
|
+
* - profilesStartingPosition: a sorted number array
|
|
36776
|
+
* indicating on which columns a new profile begins.
|
|
36777
|
+
* - profiles: a map where the key is a column
|
|
36778
|
+
* position (from profilesStartingPosition) and the
|
|
36779
|
+
* value is a sorted number array representing a
|
|
36780
|
+
* profile.
|
|
36781
|
+
*
|
|
36782
|
+
*
|
|
36783
|
+
* See the following example: here profileStartingPosition
|
|
36784
|
+
* corresponds to [A,C,E,G,K]
|
|
36785
|
+
* A B C D E F G H I J K so with number [0,2,4,6,10]
|
|
36786
|
+
* 1 ' ' ' '
|
|
36787
|
+
* 2 ' ' '_______' here profile correspond
|
|
36788
|
+
* 3 '___' |_______| for A to []
|
|
36789
|
+
* 4 | | for C to [3, 5]
|
|
36790
|
+
* 5 |___| for E to []
|
|
36791
|
+
* 6 for G to [2, 3]
|
|
36792
|
+
* 7 for K to []
|
|
36793
|
+
*
|
|
36794
|
+
*
|
|
36795
|
+
* Now we can easily find which zones are overlapping
|
|
36796
|
+
* with a given zone. Suppose we want to add a new zone
|
|
36797
|
+
* D5:H6 to the ensemble:
|
|
36798
|
+
*
|
|
36799
|
+
* With a binary search of left and right
|
|
36800
|
+
* A B C D E F G H I J K on profilesStartingPosition, we can
|
|
36801
|
+
* 1 ' ' ' ' find the indexes of the profiles on which
|
|
36802
|
+
* 2 ' ' '_______' to apply a modification.
|
|
36803
|
+
* 3 '___' |_______|
|
|
36804
|
+
* 4 | _|_______ Here we will:
|
|
36805
|
+
* 5 |_|_| | - add a new profile in D --> become [3, 6]
|
|
36806
|
+
* 6 |_________| - modify the profile in E --> become [4, 6]
|
|
36807
|
+
* 7 - modify the profile in G --> become [2, 3, 4, 6]
|
|
36808
|
+
* - add a new profile in I --> become [8, 10]
|
|
36809
|
+
*
|
|
36810
|
+
* See below the result:
|
|
36811
|
+
*
|
|
36812
|
+
* Note the particularity of the profile
|
|
36813
|
+
* A B C D E F G H I J K for G: it will correspond to [2, 3, 4, 6]
|
|
36814
|
+
* 1 ' ' ' ' ' '
|
|
36815
|
+
* 2 ' ' ' '___'___' To know how to modify the profile (add a
|
|
36816
|
+
* 3 '_'_' |___|___| zone or remove it) we do a binary
|
|
36817
|
+
* 4 | | |___ ___ search of the top and bottom value on the
|
|
36818
|
+
* 5 |_| | | | profile array. Depending on the result index
|
|
36819
|
+
* 6 |_|___|___| parity (odd or even), because zone boundaries
|
|
36820
|
+
* 7 go by pairs, we know if we are in a zone or
|
|
36821
|
+
* not and how operate.
|
|
36822
|
+
*/
|
|
36823
|
+
/**
|
|
36824
|
+
* Recompute the zone without the cells in toRemoveZones and avoid overlapping.
|
|
36825
|
+
* This compute is particularly useful because after this function:
|
|
36826
|
+
* - you will find coordinate of a cell only once among all the zones
|
|
36827
|
+
* - the number of zones will be reduced to the minimum
|
|
36828
|
+
*/
|
|
36829
|
+
function futureRecomputeZones(zones, zonesToRemove = []) {
|
|
36830
|
+
const profilesStartingPosition = [0];
|
|
36831
|
+
const profiles = new Map([[0, []]]);
|
|
36832
|
+
modifyProfiles(profilesStartingPosition, profiles, zones, false);
|
|
36833
|
+
modifyProfiles(profilesStartingPosition, profiles, zonesToRemove, true);
|
|
36834
|
+
return constructZonesFromProfiles(profilesStartingPosition, profiles);
|
|
36835
|
+
}
|
|
36836
|
+
function modifyProfiles(// export for testing only
|
|
36837
|
+
profilesStartingPosition, profiles, zones, toRemove = false) {
|
|
36838
|
+
for (const zone of zones) {
|
|
36839
|
+
const leftValue = zone.left;
|
|
36840
|
+
const rightValue = zone.right === undefined ? undefined : zone.right + 1;
|
|
36841
|
+
const leftIndex = findIndexAndCreateProfile(profilesStartingPosition, profiles, leftValue, true, 0);
|
|
36842
|
+
const rightIndex = findIndexAndCreateProfile(profilesStartingPosition, profiles, rightValue, false, leftIndex);
|
|
36843
|
+
for (let i = leftIndex; i <= rightIndex; i++) {
|
|
36844
|
+
const profile = profiles.get(profilesStartingPosition[i]);
|
|
36845
|
+
modifyProfile(profile, zone, toRemove);
|
|
36846
|
+
}
|
|
36847
|
+
// maybe this part cost in performance, and maybe it's not necessary (depending on the use case). To be checked
|
|
36848
|
+
removeContiguousProfiles(profilesStartingPosition, profiles, leftIndex, rightIndex);
|
|
36849
|
+
}
|
|
36850
|
+
}
|
|
36851
|
+
function findIndexAndCreateProfile(profilesStartingPosition, profiles, value, searchLeft, startIndex) {
|
|
36852
|
+
if (value === undefined) {
|
|
36853
|
+
// this is only the case when the value correspond to a bottom value that could be undefined
|
|
36854
|
+
return profilesStartingPosition.length - 1;
|
|
36855
|
+
}
|
|
36856
|
+
const predecessorIndex = binaryPredecessorSearch(profilesStartingPosition, value, startIndex);
|
|
36857
|
+
if (value != profilesStartingPosition[predecessorIndex]) {
|
|
36858
|
+
// mean that the value is not ending/starting at the same position as the previous/next profile
|
|
36859
|
+
// --> it's a new profile
|
|
36860
|
+
// --> we need to add it
|
|
36861
|
+
profilesStartingPosition.splice(predecessorIndex + 1, 0, value);
|
|
36862
|
+
// suppose the we want to add the for the left value
|
|
36863
|
+
// following profile following zone: 'C', the predecessor index
|
|
36864
|
+
// for B: [1, 3] "C3:D4" correspond to 'B'.
|
|
36865
|
+
// The next line code will
|
|
36866
|
+
// A B C D A B C D copy the profile of 'B'
|
|
36867
|
+
// 1 '___' 1 '___' to 'C'. In the rest of the
|
|
36868
|
+
// 2 | | ---> 2 | _|_ process the 'modifyProfile'
|
|
36869
|
+
// 3 |___| 3 |_|_| | function will adapt the waiting
|
|
36870
|
+
// 4 4 |___| 'C' profile [1, 3] to the
|
|
36871
|
+
// correct 'C' profile [1, 4]
|
|
36872
|
+
profiles.set(value, [...profiles.get(profilesStartingPosition[predecessorIndex])]);
|
|
36873
|
+
return searchLeft ? predecessorIndex + 1 : predecessorIndex;
|
|
36874
|
+
}
|
|
36875
|
+
return searchLeft ? predecessorIndex : predecessorIndex - 1;
|
|
36876
|
+
}
|
|
36877
|
+
/**
|
|
36878
|
+
* Suppose the following Suppose we want to add We want to have the
|
|
36879
|
+
* profile: the following zone: following profile:
|
|
36880
|
+
*
|
|
36881
|
+
* A B C D E F A B C D E F A B C D E F
|
|
36882
|
+
* 1 '___' 1 ' ' 1 '___'
|
|
36883
|
+
* 2 |___| 2 '___' 2 | |
|
|
36884
|
+
* 3 ' ' 3 | | 3 | |
|
|
36885
|
+
* 4 '___' --> 4 | | --> 4 | |
|
|
36886
|
+
* 6 | | 6 |___| 6 | |
|
|
36887
|
+
* 7 |___| 7 7 |___|
|
|
36888
|
+
* 8 8 8
|
|
36889
|
+
*
|
|
36890
|
+
* the profile for 'C' the top zone correspond Here [2, 3, 5, 8] with [3, 7]
|
|
36891
|
+
* corresponds to: to 3 and the bottom zone would be merged into [2, 8]
|
|
36892
|
+
* ____ ____ correspond to 6
|
|
36893
|
+
* [2, 3, 5, 8] would be the profile: The difficulty of modify profile
|
|
36894
|
+
* ____ is to know what must be deleted
|
|
36895
|
+
* Note that the 'filled [3, 7] and what must be added to the
|
|
36896
|
+
* zone' are always between existing profile.
|
|
36897
|
+
* an even index and its
|
|
36898
|
+
* next index
|
|
36899
|
+
*
|
|
36900
|
+
*/
|
|
36901
|
+
function modifyProfile(profile, zone, toRemove = false) {
|
|
36902
|
+
const topValue = zone.top;
|
|
36903
|
+
const bottomValue = zone.bottom === undefined ? undefined : zone.bottom + 1;
|
|
36904
|
+
const newPoints = [];
|
|
36905
|
+
// Case we want to add a zone to the profile:
|
|
36906
|
+
// - If the top predecessor index `topPredIndex` is even, it means the top of the zone is already positioned on a filled zone
|
|
36907
|
+
// so we don't need to add it to the profile. we can keep in reference the index of the predecessor.
|
|
36908
|
+
// - If it is odd, it means the top of the zone must be the beginning of a filled zone.
|
|
36909
|
+
// so we can keep the index of the top position
|
|
36910
|
+
// Case we want to remove a zone from the profile: it's the opposite of the previous case
|
|
36911
|
+
const topPredIndex = binaryPredecessorSearch(profile, topValue, 0, false);
|
|
36912
|
+
if ((topPredIndex % 2 !== 0 && !toRemove) || (topPredIndex % 2 === 0 && toRemove)) {
|
|
36913
|
+
newPoints.push(topValue);
|
|
36914
|
+
}
|
|
36915
|
+
if (bottomValue === undefined) {
|
|
36916
|
+
// The following two code lines will not impact the final result,
|
|
36917
|
+
// but they will impact the intermediate profile.
|
|
36918
|
+
// We keep them for performance reason
|
|
36919
|
+
profile.splice(topPredIndex + 1);
|
|
36920
|
+
profile.push(...newPoints);
|
|
36921
|
+
return;
|
|
36922
|
+
}
|
|
36923
|
+
// Case we want to add a zone to the profile:
|
|
36924
|
+
// - If the bottom successor index `bottomSuccIndex` is even, it means the bottom of the zone must be the ending of a filled zone
|
|
36925
|
+
// so we can keep the index of the bottom position.
|
|
36926
|
+
// - If it is odd, it means the bottom of the zone is already positioned on a filled zone
|
|
36927
|
+
// so we don't need to add it to the profile. we can keep in reference the index of the successor
|
|
36928
|
+
// Case we want to remove a zone from the profile: it's the opposite of the previous case
|
|
36929
|
+
const bottomSuccIndex = binarySuccessorSearch(profile, bottomValue, 0, false);
|
|
36930
|
+
if ((bottomSuccIndex % 2 === 0 && !toRemove) || (bottomSuccIndex % 2 !== 0 && toRemove)) {
|
|
36931
|
+
newPoints.push(bottomValue);
|
|
36932
|
+
}
|
|
36933
|
+
// add the top and bottom value to the profile and
|
|
36934
|
+
// remove all information between the top and bottom index
|
|
36935
|
+
profile.splice(topPredIndex + 1, bottomSuccIndex - topPredIndex - 1, ...newPoints);
|
|
36936
|
+
}
|
|
36937
|
+
function removeContiguousProfiles(profilesStartingPosition, profiles, leftIndex, rightIndex) {
|
|
36938
|
+
const start = leftIndex - 1 === -1 ? 0 : leftIndex - 1;
|
|
36939
|
+
const end = rightIndex === profilesStartingPosition.length - 1 ? rightIndex : rightIndex + 1;
|
|
36940
|
+
for (let i = end; i > start; i--) {
|
|
36941
|
+
if (deepEqualsArray(profiles.get(profilesStartingPosition[i]), profiles.get(profilesStartingPosition[i - 1]))) {
|
|
36942
|
+
profiles.delete(profilesStartingPosition[i]);
|
|
36943
|
+
profilesStartingPosition.splice(i, 1);
|
|
36944
|
+
}
|
|
36945
|
+
}
|
|
36946
|
+
}
|
|
36947
|
+
function constructZonesFromProfiles(profilesStartingPosition, profiles) {
|
|
36948
|
+
const mergedZone = [];
|
|
36949
|
+
let pendingZones = [];
|
|
36950
|
+
for (let colIndex = 0; colIndex < profilesStartingPosition.length; colIndex++) {
|
|
36951
|
+
const left = profilesStartingPosition[colIndex];
|
|
36952
|
+
const profile = profiles.get(left);
|
|
36953
|
+
if (!profile || profile.length === 0) {
|
|
36954
|
+
mergedZone.push(...pendingZones);
|
|
36955
|
+
pendingZones = [];
|
|
36956
|
+
continue;
|
|
36957
|
+
}
|
|
36958
|
+
let right = profilesStartingPosition[colIndex + 1];
|
|
36959
|
+
if (right !== undefined) {
|
|
36960
|
+
right--;
|
|
36961
|
+
}
|
|
36962
|
+
const nextPendingZones = [];
|
|
36963
|
+
for (let i = 0; i < profile.length; i += 2) {
|
|
36964
|
+
const top = profile[i];
|
|
36965
|
+
let bottom = profile[i + 1];
|
|
36966
|
+
if (bottom !== undefined) {
|
|
36967
|
+
bottom--;
|
|
36968
|
+
}
|
|
36969
|
+
const profileZone = {
|
|
36970
|
+
top,
|
|
36971
|
+
left,
|
|
36972
|
+
bottom,
|
|
36973
|
+
right,
|
|
36974
|
+
hasHeader: (bottom === undefined && top !== 0) || (right === undefined && left !== 0),
|
|
36975
|
+
};
|
|
36976
|
+
let findCorrespondingZone = false;
|
|
36977
|
+
for (let j = pendingZones.length - 1; j >= 0; j--) {
|
|
36978
|
+
const pendingZone = pendingZones[j];
|
|
36979
|
+
if (pendingZone.top === profileZone.top && pendingZone.bottom === profileZone.bottom) {
|
|
36980
|
+
pendingZone.right = profileZone.right;
|
|
36981
|
+
pendingZones.splice(j, 1);
|
|
36982
|
+
nextPendingZones.push(pendingZone);
|
|
36983
|
+
findCorrespondingZone = true;
|
|
36984
|
+
break;
|
|
36985
|
+
}
|
|
36986
|
+
}
|
|
36987
|
+
if (!findCorrespondingZone) {
|
|
36988
|
+
nextPendingZones.push(profileZone);
|
|
36989
|
+
}
|
|
36990
|
+
}
|
|
36991
|
+
mergedZone.push(...pendingZones);
|
|
36992
|
+
pendingZones = nextPendingZones;
|
|
36993
|
+
}
|
|
36994
|
+
mergedZone.push(...pendingZones);
|
|
36995
|
+
return mergedZone;
|
|
36996
|
+
}
|
|
36997
|
+
function binaryPredecessorSearch(arr, val, start = 0, matchEqual = true) {
|
|
36998
|
+
let end = arr.length - 1;
|
|
36999
|
+
let result = -1;
|
|
37000
|
+
while (start <= end) {
|
|
37001
|
+
const mid = Math.floor((start + end) / 2);
|
|
37002
|
+
if (arr[mid] === val && matchEqual) {
|
|
37003
|
+
return mid;
|
|
37004
|
+
}
|
|
37005
|
+
else if (arr[mid] < val) {
|
|
37006
|
+
result = mid;
|
|
37007
|
+
start = mid + 1;
|
|
37008
|
+
}
|
|
37009
|
+
else {
|
|
37010
|
+
end = mid - 1;
|
|
37011
|
+
}
|
|
37012
|
+
}
|
|
37013
|
+
return result;
|
|
37014
|
+
}
|
|
37015
|
+
function binarySuccessorSearch(arr, val, start = 0, matchEqual = true) {
|
|
37016
|
+
let end = arr.length - 1;
|
|
37017
|
+
let result = arr.length;
|
|
37018
|
+
while (start <= end) {
|
|
37019
|
+
const mid = Math.floor((start + end) / 2);
|
|
37020
|
+
if (arr[mid] === val && matchEqual) {
|
|
37021
|
+
return mid;
|
|
37022
|
+
}
|
|
37023
|
+
else if (arr[mid] > val) {
|
|
37024
|
+
result = mid;
|
|
37025
|
+
end = mid - 1;
|
|
37026
|
+
}
|
|
37027
|
+
else {
|
|
37028
|
+
start = mid + 1;
|
|
37029
|
+
}
|
|
37030
|
+
}
|
|
37031
|
+
return result;
|
|
37032
|
+
}
|
|
37033
|
+
/**
|
|
37034
|
+
* Compares two arrays.
|
|
37035
|
+
* For performance reasons, this function is to be preferred
|
|
37036
|
+
* to 'deepEquals' in the case we know that the inputs are arrays.
|
|
37037
|
+
*/
|
|
37038
|
+
function deepEqualsArray(arr1, arr2) {
|
|
37039
|
+
if (arr1.length !== arr2.length) {
|
|
37040
|
+
return false;
|
|
37041
|
+
}
|
|
37042
|
+
for (let i = 0; i < arr1.length; i++) {
|
|
37043
|
+
if (!deepEquals(arr1[i], arr2[i])) {
|
|
37044
|
+
return false;
|
|
37045
|
+
}
|
|
37046
|
+
}
|
|
37047
|
+
return true;
|
|
37048
|
+
}
|
|
37049
|
+
|
|
36693
37050
|
// -----------------------------------------------------------------------------
|
|
36694
37051
|
// Constants
|
|
36695
37052
|
// -----------------------------------------------------------------------------
|
|
@@ -36859,10 +37216,12 @@
|
|
|
36859
37216
|
const replaceIndex = rules.findIndex((c) => c.id === cf.id);
|
|
36860
37217
|
let currentRanges = [];
|
|
36861
37218
|
if (replaceIndex > -1) {
|
|
36862
|
-
currentRanges = rules[replaceIndex].ranges;
|
|
37219
|
+
currentRanges = rules[replaceIndex].ranges.map(toUnboundedZone);
|
|
36863
37220
|
}
|
|
36864
37221
|
currentRanges = currentRanges.concat(toAdd);
|
|
36865
|
-
|
|
37222
|
+
// Remove the zones first in case the same position is in toAdd and toRemove
|
|
37223
|
+
const withRemovedZones = futureRecomputeZones(currentRanges, toRemove);
|
|
37224
|
+
return futureRecomputeZones([...toAdd, ...withRemovedZones], []);
|
|
36866
37225
|
}
|
|
36867
37226
|
// ---------------------------------------------------------------------------
|
|
36868
37227
|
// Private
|
|
@@ -40597,353 +40956,6 @@
|
|
|
40597
40956
|
}
|
|
40598
40957
|
}
|
|
40599
40958
|
|
|
40600
|
-
/**
|
|
40601
|
-
* ####################################################
|
|
40602
|
-
* # INTRODUCTION
|
|
40603
|
-
* ####################################################
|
|
40604
|
-
*
|
|
40605
|
-
* This file contain the function recomputeZones.
|
|
40606
|
-
* This function try to recompute in a performant way
|
|
40607
|
-
* an ensemble of zones possibly overlapping to avoid
|
|
40608
|
-
* overlapping and to reduce the number of zones.
|
|
40609
|
-
*
|
|
40610
|
-
* It also allows to remove some zones from the ensemble.
|
|
40611
|
-
*
|
|
40612
|
-
* In the following example, 2 zones are overlapping.
|
|
40613
|
-
* Applying recomputeZones will return zones without
|
|
40614
|
-
* overlapping:
|
|
40615
|
-
*
|
|
40616
|
-
* ["B3:D4", "D2:E3"] ["B3:C4", "D2:D4", "E2:E3"]
|
|
40617
|
-
*
|
|
40618
|
-
* A B C D E A B C D E
|
|
40619
|
-
* 1 ___ 1 ___
|
|
40620
|
-
* 2 ___|_ | 2 ___| | |
|
|
40621
|
-
* 3 | |_|_| ---> 3 | | |_|
|
|
40622
|
-
* 4 |_____| 4 |___|_|
|
|
40623
|
-
* 6 6
|
|
40624
|
-
* 7 7
|
|
40625
|
-
*
|
|
40626
|
-
*
|
|
40627
|
-
* In the following example, 2 zones are contiguous.
|
|
40628
|
-
* Applying recomputeZones will return only one zone:
|
|
40629
|
-
*
|
|
40630
|
-
* ["B2:B3", "C2:D3"] ["B2:D3"]
|
|
40631
|
-
*
|
|
40632
|
-
* A B C D E A B C D E
|
|
40633
|
-
* 1 _ ___ 1 _____
|
|
40634
|
-
* 2 | | | ---> 2 | |
|
|
40635
|
-
* 3 |_|___| 3 |_____|
|
|
40636
|
-
* 4 4
|
|
40637
|
-
*
|
|
40638
|
-
*
|
|
40639
|
-
* In the following example, we want to remove a zone
|
|
40640
|
-
* from the ensemble. Applying recomputeZones will
|
|
40641
|
-
* return the ensemble without the zone to remove:
|
|
40642
|
-
*
|
|
40643
|
-
* remove ["C3:D3"] ["B2:B4", "C2:D2",
|
|
40644
|
-
* "C4:D4", "E2:E4"]
|
|
40645
|
-
*
|
|
40646
|
-
* A B C D E F A B C D E F
|
|
40647
|
-
* 1 _______ 1 _______
|
|
40648
|
-
* 2 | | ---> 2 | |___| |
|
|
40649
|
-
* 3 | xxx | 3 | |___| |
|
|
40650
|
-
* 4 |_______| 4 |_|___|_|
|
|
40651
|
-
* 5 5
|
|
40652
|
-
*
|
|
40653
|
-
*
|
|
40654
|
-
* The exercise seems simple when we have only 2 zones.
|
|
40655
|
-
* But with n zones and in a performant way, we want to
|
|
40656
|
-
* avoid comparing each zone with all the others.
|
|
40657
|
-
*
|
|
40658
|
-
*
|
|
40659
|
-
* ####################################################
|
|
40660
|
-
* # Methodological approach
|
|
40661
|
-
* ####################################################
|
|
40662
|
-
*
|
|
40663
|
-
* The methodological approach to avoid comparing each
|
|
40664
|
-
* zone with all the others is to use a data structure
|
|
40665
|
-
* that allow to quickly find which zones are
|
|
40666
|
-
* overlapping with any other given zone.
|
|
40667
|
-
*
|
|
40668
|
-
* Here the idea is to profile the zones at the columns level.
|
|
40669
|
-
*
|
|
40670
|
-
* To do that, we propose to use a data structure
|
|
40671
|
-
* composed of 2 parts:
|
|
40672
|
-
* - profilesStartingPosition: a sorted number array
|
|
40673
|
-
* indicating on which columns a new profile begins.
|
|
40674
|
-
* - profiles: a map where the key is a column
|
|
40675
|
-
* position (from profilesStartingPosition) and the
|
|
40676
|
-
* value is a sorted number array representing a
|
|
40677
|
-
* profile.
|
|
40678
|
-
*
|
|
40679
|
-
*
|
|
40680
|
-
* See the following example: here profileStartingPosition
|
|
40681
|
-
* corresponds to [A,C,E,G,K]
|
|
40682
|
-
* A B C D E F G H I J K so with number [0,2,4,6,10]
|
|
40683
|
-
* 1 ' ' ' '
|
|
40684
|
-
* 2 ' ' '_______' here profile correspond
|
|
40685
|
-
* 3 '___' |_______| for A to []
|
|
40686
|
-
* 4 | | for C to [3, 5]
|
|
40687
|
-
* 5 |___| for E to []
|
|
40688
|
-
* 6 for G to [2, 3]
|
|
40689
|
-
* 7 for K to []
|
|
40690
|
-
*
|
|
40691
|
-
*
|
|
40692
|
-
* Now we can easily find which zones are overlapping
|
|
40693
|
-
* with a given zone. Suppose we want to add a new zone
|
|
40694
|
-
* D5:H6 to the ensemble:
|
|
40695
|
-
*
|
|
40696
|
-
* With a binary search of left and right
|
|
40697
|
-
* A B C D E F G H I J K on profilesStartingPosition, we can
|
|
40698
|
-
* 1 ' ' ' ' find the indexes of the profiles on which
|
|
40699
|
-
* 2 ' ' '_______' to apply a modification.
|
|
40700
|
-
* 3 '___' |_______|
|
|
40701
|
-
* 4 | _|_______ Here we will:
|
|
40702
|
-
* 5 |_|_| | - add a new profile in D --> become [3, 6]
|
|
40703
|
-
* 6 |_________| - modify the profile in E --> become [4, 6]
|
|
40704
|
-
* 7 - modify the profile in G --> become [2, 3, 4, 6]
|
|
40705
|
-
* - add a new profile in I --> become [8, 10]
|
|
40706
|
-
*
|
|
40707
|
-
* See below the result:
|
|
40708
|
-
*
|
|
40709
|
-
* Note the particularity of the profile
|
|
40710
|
-
* A B C D E F G H I J K for G: it will correspond to [2, 3, 4, 6]
|
|
40711
|
-
* 1 ' ' ' ' ' '
|
|
40712
|
-
* 2 ' ' ' '___'___' To know how to modify the profile (add a
|
|
40713
|
-
* 3 '_'_' |___|___| zone or remove it) we do a binary
|
|
40714
|
-
* 4 | | |___ ___ search of the top and bottom value on the
|
|
40715
|
-
* 5 |_| | | | profile array. Depending on the result index
|
|
40716
|
-
* 6 |_|___|___| parity (odd or even), because zone boundaries
|
|
40717
|
-
* 7 go by pairs, we know if we are in a zone or
|
|
40718
|
-
* not and how operate.
|
|
40719
|
-
*/
|
|
40720
|
-
/**
|
|
40721
|
-
* Recompute the zone without the cells in toRemoveZones and avoid overlapping.
|
|
40722
|
-
* This compute is particularly useful because after this function:
|
|
40723
|
-
* - you will find coordinate of a cell only once among all the zones
|
|
40724
|
-
* - the number of zones will be reduced to the minimum
|
|
40725
|
-
*/
|
|
40726
|
-
function futureRecomputeZones(zones, zonesToRemove = []) {
|
|
40727
|
-
const profilesStartingPosition = [0];
|
|
40728
|
-
const profiles = new Map([[0, []]]);
|
|
40729
|
-
modifyProfiles(profilesStartingPosition, profiles, zones, false);
|
|
40730
|
-
modifyProfiles(profilesStartingPosition, profiles, zonesToRemove, true);
|
|
40731
|
-
return constructZonesFromProfiles(profilesStartingPosition, profiles);
|
|
40732
|
-
}
|
|
40733
|
-
function modifyProfiles(// export for testing only
|
|
40734
|
-
profilesStartingPosition, profiles, zones, toRemove = false) {
|
|
40735
|
-
for (const zone of zones) {
|
|
40736
|
-
const leftValue = zone.left;
|
|
40737
|
-
const rightValue = zone.right === undefined ? undefined : zone.right + 1;
|
|
40738
|
-
const leftIndex = findIndexAndCreateProfile(profilesStartingPosition, profiles, leftValue, true, 0);
|
|
40739
|
-
const rightIndex = findIndexAndCreateProfile(profilesStartingPosition, profiles, rightValue, false, leftIndex);
|
|
40740
|
-
for (let i = leftIndex; i <= rightIndex; i++) {
|
|
40741
|
-
const profile = profiles.get(profilesStartingPosition[i]);
|
|
40742
|
-
modifyProfile(profile, zone, toRemove);
|
|
40743
|
-
}
|
|
40744
|
-
// maybe this part cost in performance, and maybe it's not necessary (depending on the use case). To be checked
|
|
40745
|
-
removeContiguousProfiles(profilesStartingPosition, profiles, leftIndex, rightIndex);
|
|
40746
|
-
}
|
|
40747
|
-
}
|
|
40748
|
-
function findIndexAndCreateProfile(profilesStartingPosition, profiles, value, searchLeft, startIndex) {
|
|
40749
|
-
if (value === undefined) {
|
|
40750
|
-
// this is only the case when the value correspond to a bottom value that could be undefined
|
|
40751
|
-
return profilesStartingPosition.length - 1;
|
|
40752
|
-
}
|
|
40753
|
-
const predecessorIndex = binaryPredecessorSearch(profilesStartingPosition, value, startIndex);
|
|
40754
|
-
if (value != profilesStartingPosition[predecessorIndex]) {
|
|
40755
|
-
// mean that the value is not ending/starting at the same position as the previous/next profile
|
|
40756
|
-
// --> it's a new profile
|
|
40757
|
-
// --> we need to add it
|
|
40758
|
-
profilesStartingPosition.splice(predecessorIndex + 1, 0, value);
|
|
40759
|
-
// suppose the we want to add the for the left value
|
|
40760
|
-
// following profile following zone: 'C', the predecessor index
|
|
40761
|
-
// for B: [1, 3] "C3:D4" correspond to 'B'.
|
|
40762
|
-
// The next line code will
|
|
40763
|
-
// A B C D A B C D copy the profile of 'B'
|
|
40764
|
-
// 1 '___' 1 '___' to 'C'. In the rest of the
|
|
40765
|
-
// 2 | | ---> 2 | _|_ process the 'modifyProfile'
|
|
40766
|
-
// 3 |___| 3 |_|_| | function will adapt the waiting
|
|
40767
|
-
// 4 4 |___| 'C' profile [1, 3] to the
|
|
40768
|
-
// correct 'C' profile [1, 4]
|
|
40769
|
-
profiles.set(value, [...profiles.get(profilesStartingPosition[predecessorIndex])]);
|
|
40770
|
-
return searchLeft ? predecessorIndex + 1 : predecessorIndex;
|
|
40771
|
-
}
|
|
40772
|
-
return searchLeft ? predecessorIndex : predecessorIndex - 1;
|
|
40773
|
-
}
|
|
40774
|
-
/**
|
|
40775
|
-
* Suppose the following Suppose we want to add We want to have the
|
|
40776
|
-
* profile: the following zone: following profile:
|
|
40777
|
-
*
|
|
40778
|
-
* A B C D E F A B C D E F A B C D E F
|
|
40779
|
-
* 1 '___' 1 ' ' 1 '___'
|
|
40780
|
-
* 2 |___| 2 '___' 2 | |
|
|
40781
|
-
* 3 ' ' 3 | | 3 | |
|
|
40782
|
-
* 4 '___' --> 4 | | --> 4 | |
|
|
40783
|
-
* 6 | | 6 |___| 6 | |
|
|
40784
|
-
* 7 |___| 7 7 |___|
|
|
40785
|
-
* 8 8 8
|
|
40786
|
-
*
|
|
40787
|
-
* the profile for 'C' the top zone correspond Here [2, 3, 5, 8] with [3, 7]
|
|
40788
|
-
* corresponds to: to 3 and the bottom zone would be merged into [2, 8]
|
|
40789
|
-
* ____ ____ correspond to 6
|
|
40790
|
-
* [2, 3, 5, 8] would be the profile: The difficulty of modify profile
|
|
40791
|
-
* ____ is to know what must be deleted
|
|
40792
|
-
* Note that the 'filled [3, 7] and what must be added to the
|
|
40793
|
-
* zone' are always between existing profile.
|
|
40794
|
-
* an even index and its
|
|
40795
|
-
* next index
|
|
40796
|
-
*
|
|
40797
|
-
*/
|
|
40798
|
-
function modifyProfile(profile, zone, toRemove = false) {
|
|
40799
|
-
const topValue = zone.top;
|
|
40800
|
-
const bottomValue = zone.bottom === undefined ? undefined : zone.bottom + 1;
|
|
40801
|
-
const newPoints = [];
|
|
40802
|
-
// Case we want to add a zone to the profile:
|
|
40803
|
-
// - If the top predecessor index `topPredIndex` is even, it means the top of the zone is already positioned on a filled zone
|
|
40804
|
-
// so we don't need to add it to the profile. we can keep in reference the index of the predecessor.
|
|
40805
|
-
// - If it is odd, it means the top of the zone must be the beginning of a filled zone.
|
|
40806
|
-
// so we can keep the index of the top position
|
|
40807
|
-
// Case we want to remove a zone from the profile: it's the opposite of the previous case
|
|
40808
|
-
const topPredIndex = binaryPredecessorSearch(profile, topValue, 0, false);
|
|
40809
|
-
if ((topPredIndex % 2 !== 0 && !toRemove) || (topPredIndex % 2 === 0 && toRemove)) {
|
|
40810
|
-
newPoints.push(topValue);
|
|
40811
|
-
}
|
|
40812
|
-
if (bottomValue === undefined) {
|
|
40813
|
-
// The following two code lines will not impact the final result,
|
|
40814
|
-
// but they will impact the intermediate profile.
|
|
40815
|
-
// We keep them for performance reason
|
|
40816
|
-
profile.splice(topPredIndex + 1);
|
|
40817
|
-
profile.push(...newPoints);
|
|
40818
|
-
return;
|
|
40819
|
-
}
|
|
40820
|
-
// Case we want to add a zone to the profile:
|
|
40821
|
-
// - If the bottom successor index `bottomSuccIndex` is even, it means the bottom of the zone must be the ending of a filled zone
|
|
40822
|
-
// so we can keep the index of the bottom position.
|
|
40823
|
-
// - If it is odd, it means the bottom of the zone is already positioned on a filled zone
|
|
40824
|
-
// so we don't need to add it to the profile. we can keep in reference the index of the successor
|
|
40825
|
-
// Case we want to remove a zone from the profile: it's the opposite of the previous case
|
|
40826
|
-
const bottomSuccIndex = binarySuccessorSearch(profile, bottomValue, 0, false);
|
|
40827
|
-
if ((bottomSuccIndex % 2 === 0 && !toRemove) || (bottomSuccIndex % 2 !== 0 && toRemove)) {
|
|
40828
|
-
newPoints.push(bottomValue);
|
|
40829
|
-
}
|
|
40830
|
-
// add the top and bottom value to the profile and
|
|
40831
|
-
// remove all information between the top and bottom index
|
|
40832
|
-
profile.splice(topPredIndex + 1, bottomSuccIndex - topPredIndex - 1, ...newPoints);
|
|
40833
|
-
}
|
|
40834
|
-
function removeContiguousProfiles(profilesStartingPosition, profiles, leftIndex, rightIndex) {
|
|
40835
|
-
const start = leftIndex - 1 === -1 ? 0 : leftIndex - 1;
|
|
40836
|
-
const end = rightIndex === profilesStartingPosition.length - 1 ? rightIndex : rightIndex + 1;
|
|
40837
|
-
for (let i = end; i > start; i--) {
|
|
40838
|
-
if (deepEqualsArray(profiles.get(profilesStartingPosition[i]), profiles.get(profilesStartingPosition[i - 1]))) {
|
|
40839
|
-
profiles.delete(profilesStartingPosition[i]);
|
|
40840
|
-
profilesStartingPosition.splice(i, 1);
|
|
40841
|
-
}
|
|
40842
|
-
}
|
|
40843
|
-
}
|
|
40844
|
-
function constructZonesFromProfiles(profilesStartingPosition, profiles) {
|
|
40845
|
-
const mergedZone = [];
|
|
40846
|
-
let pendingZones = [];
|
|
40847
|
-
for (let colIndex = 0; colIndex < profilesStartingPosition.length; colIndex++) {
|
|
40848
|
-
const left = profilesStartingPosition[colIndex];
|
|
40849
|
-
const profile = profiles.get(left);
|
|
40850
|
-
if (!profile || profile.length === 0) {
|
|
40851
|
-
mergedZone.push(...pendingZones);
|
|
40852
|
-
pendingZones = [];
|
|
40853
|
-
continue;
|
|
40854
|
-
}
|
|
40855
|
-
let right = profilesStartingPosition[colIndex + 1];
|
|
40856
|
-
if (right !== undefined) {
|
|
40857
|
-
right--;
|
|
40858
|
-
}
|
|
40859
|
-
const nextPendingZones = [];
|
|
40860
|
-
for (let i = 0; i < profile.length; i += 2) {
|
|
40861
|
-
const top = profile[i];
|
|
40862
|
-
let bottom = profile[i + 1];
|
|
40863
|
-
if (bottom !== undefined) {
|
|
40864
|
-
bottom--;
|
|
40865
|
-
}
|
|
40866
|
-
const profileZone = {
|
|
40867
|
-
top,
|
|
40868
|
-
left,
|
|
40869
|
-
bottom,
|
|
40870
|
-
right,
|
|
40871
|
-
hasHeader: (bottom === undefined && top !== 0) || (right === undefined && left !== 0),
|
|
40872
|
-
};
|
|
40873
|
-
let findCorrespondingZone = false;
|
|
40874
|
-
for (let j = pendingZones.length - 1; j >= 0; j--) {
|
|
40875
|
-
const pendingZone = pendingZones[j];
|
|
40876
|
-
if (pendingZone.top === profileZone.top && pendingZone.bottom === profileZone.bottom) {
|
|
40877
|
-
pendingZone.right = profileZone.right;
|
|
40878
|
-
pendingZones.splice(j, 1);
|
|
40879
|
-
nextPendingZones.push(pendingZone);
|
|
40880
|
-
findCorrespondingZone = true;
|
|
40881
|
-
break;
|
|
40882
|
-
}
|
|
40883
|
-
}
|
|
40884
|
-
if (!findCorrespondingZone) {
|
|
40885
|
-
nextPendingZones.push(profileZone);
|
|
40886
|
-
}
|
|
40887
|
-
}
|
|
40888
|
-
mergedZone.push(...pendingZones);
|
|
40889
|
-
pendingZones = nextPendingZones;
|
|
40890
|
-
}
|
|
40891
|
-
mergedZone.push(...pendingZones);
|
|
40892
|
-
return mergedZone;
|
|
40893
|
-
}
|
|
40894
|
-
function binaryPredecessorSearch(arr, val, start = 0, matchEqual = true) {
|
|
40895
|
-
let end = arr.length - 1;
|
|
40896
|
-
let result = -1;
|
|
40897
|
-
while (start <= end) {
|
|
40898
|
-
const mid = Math.floor((start + end) / 2);
|
|
40899
|
-
if (arr[mid] === val && matchEqual) {
|
|
40900
|
-
return mid;
|
|
40901
|
-
}
|
|
40902
|
-
else if (arr[mid] < val) {
|
|
40903
|
-
result = mid;
|
|
40904
|
-
start = mid + 1;
|
|
40905
|
-
}
|
|
40906
|
-
else {
|
|
40907
|
-
end = mid - 1;
|
|
40908
|
-
}
|
|
40909
|
-
}
|
|
40910
|
-
return result;
|
|
40911
|
-
}
|
|
40912
|
-
function binarySuccessorSearch(arr, val, start = 0, matchEqual = true) {
|
|
40913
|
-
let end = arr.length - 1;
|
|
40914
|
-
let result = arr.length;
|
|
40915
|
-
while (start <= end) {
|
|
40916
|
-
const mid = Math.floor((start + end) / 2);
|
|
40917
|
-
if (arr[mid] === val && matchEqual) {
|
|
40918
|
-
return mid;
|
|
40919
|
-
}
|
|
40920
|
-
else if (arr[mid] > val) {
|
|
40921
|
-
result = mid;
|
|
40922
|
-
end = mid - 1;
|
|
40923
|
-
}
|
|
40924
|
-
else {
|
|
40925
|
-
start = mid + 1;
|
|
40926
|
-
}
|
|
40927
|
-
}
|
|
40928
|
-
return result;
|
|
40929
|
-
}
|
|
40930
|
-
/**
|
|
40931
|
-
* Compares two arrays.
|
|
40932
|
-
* For performance reasons, this function is to be preferred
|
|
40933
|
-
* to 'deepEquals' in the case we know that the inputs are arrays.
|
|
40934
|
-
*/
|
|
40935
|
-
function deepEqualsArray(arr1, arr2) {
|
|
40936
|
-
if (arr1.length !== arr2.length) {
|
|
40937
|
-
return false;
|
|
40938
|
-
}
|
|
40939
|
-
for (let i = 0; i < arr1.length; i++) {
|
|
40940
|
-
if (!deepEquals(arr1[i], arr2[i])) {
|
|
40941
|
-
return false;
|
|
40942
|
-
}
|
|
40943
|
-
}
|
|
40944
|
-
return true;
|
|
40945
|
-
}
|
|
40946
|
-
|
|
40947
40959
|
function quickselect(arr, k, left, right, compare) {
|
|
40948
40960
|
quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare);
|
|
40949
40961
|
}
|
|
@@ -43540,25 +43552,6 @@
|
|
|
43540
43552
|
case "AUTOFILL_AUTO":
|
|
43541
43553
|
this.autofillAuto();
|
|
43542
43554
|
break;
|
|
43543
|
-
case "AUTOFILL_CELL":
|
|
43544
|
-
this.autoFillMerge(cmd.originCol, cmd.originRow, cmd.col, cmd.row);
|
|
43545
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
43546
|
-
this.dispatch("UPDATE_CELL", {
|
|
43547
|
-
sheetId,
|
|
43548
|
-
col: cmd.col,
|
|
43549
|
-
row: cmd.row,
|
|
43550
|
-
style: cmd.style || null,
|
|
43551
|
-
content: cmd.content || "",
|
|
43552
|
-
format: cmd.format || "",
|
|
43553
|
-
});
|
|
43554
|
-
this.dispatch("SET_BORDER", {
|
|
43555
|
-
sheetId,
|
|
43556
|
-
col: cmd.col,
|
|
43557
|
-
row: cmd.row,
|
|
43558
|
-
border: cmd.border,
|
|
43559
|
-
});
|
|
43560
|
-
this.autofillCF(cmd.originCol, cmd.originRow, cmd.col, cmd.row);
|
|
43561
|
-
this.autofillDV(cmd.originCol, cmd.originRow, cmd.col, cmd.row);
|
|
43562
43555
|
}
|
|
43563
43556
|
}
|
|
43564
43557
|
// ---------------------------------------------------------------------------
|
|
@@ -43582,6 +43575,7 @@
|
|
|
43582
43575
|
}
|
|
43583
43576
|
const source = this.getters.getSelectedZone();
|
|
43584
43577
|
const target = this.autofillZone;
|
|
43578
|
+
const autofillCellsData = [];
|
|
43585
43579
|
switch (this.direction) {
|
|
43586
43580
|
case "down" /* DIRECTION.DOWN */:
|
|
43587
43581
|
for (let col = source.left; col <= source.right; col++) {
|
|
@@ -43591,7 +43585,7 @@
|
|
|
43591
43585
|
}
|
|
43592
43586
|
const generator = this.createGenerator(xcs);
|
|
43593
43587
|
for (let row = target.top; row <= target.bottom; row++) {
|
|
43594
|
-
this.computeNewCell(generator, col, row
|
|
43588
|
+
autofillCellsData.push(this.computeNewCell(generator, col, row));
|
|
43595
43589
|
}
|
|
43596
43590
|
}
|
|
43597
43591
|
break;
|
|
@@ -43603,7 +43597,7 @@
|
|
|
43603
43597
|
}
|
|
43604
43598
|
const generator = this.createGenerator(xcs);
|
|
43605
43599
|
for (let row = target.bottom; row >= target.top; row--) {
|
|
43606
|
-
this.computeNewCell(generator, col, row
|
|
43600
|
+
autofillCellsData.push(this.computeNewCell(generator, col, row));
|
|
43607
43601
|
}
|
|
43608
43602
|
}
|
|
43609
43603
|
break;
|
|
@@ -43615,7 +43609,7 @@
|
|
|
43615
43609
|
}
|
|
43616
43610
|
const generator = this.createGenerator(xcs);
|
|
43617
43611
|
for (let col = target.right; col >= target.left; col--) {
|
|
43618
|
-
this.computeNewCell(generator, col, row
|
|
43612
|
+
autofillCellsData.push(this.computeNewCell(generator, col, row));
|
|
43619
43613
|
}
|
|
43620
43614
|
}
|
|
43621
43615
|
break;
|
|
@@ -43627,12 +43621,26 @@
|
|
|
43627
43621
|
}
|
|
43628
43622
|
const generator = this.createGenerator(xcs);
|
|
43629
43623
|
for (let col = target.left; col <= target.right; col++) {
|
|
43630
|
-
this.computeNewCell(generator, col, row
|
|
43624
|
+
autofillCellsData.push(this.computeNewCell(generator, col, row));
|
|
43631
43625
|
}
|
|
43632
43626
|
}
|
|
43633
43627
|
break;
|
|
43634
43628
|
}
|
|
43635
43629
|
if (apply) {
|
|
43630
|
+
const bordersZones = {};
|
|
43631
|
+
const cfNewRanges = {};
|
|
43632
|
+
const dvNewZones = {};
|
|
43633
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
43634
|
+
for (const data of autofillCellsData) {
|
|
43635
|
+
this.collectBordersData(data, bordersZones);
|
|
43636
|
+
this.autofillMerge(sheetId, data);
|
|
43637
|
+
this.autofillCell(sheetId, data);
|
|
43638
|
+
this.collectConditionalFormatsData(sheetId, data, cfNewRanges);
|
|
43639
|
+
this.collectDataValidationsData(sheetId, data, dvNewZones);
|
|
43640
|
+
}
|
|
43641
|
+
this.autofillBorders(sheetId, bordersZones);
|
|
43642
|
+
this.autofillConditionalFormats(sheetId, cfNewRanges);
|
|
43643
|
+
this.autofillDataValidations(sheetId, dvNewZones);
|
|
43636
43644
|
this.autofillZone = undefined;
|
|
43637
43645
|
this.selection.resizeAnchorZone(this.direction, this.steps);
|
|
43638
43646
|
this.lastCellSelected = {};
|
|
@@ -43641,6 +43649,95 @@
|
|
|
43641
43649
|
this.tooltip = undefined;
|
|
43642
43650
|
}
|
|
43643
43651
|
}
|
|
43652
|
+
collectBordersData(data, bordersPositions) {
|
|
43653
|
+
const key = JSON.stringify(data.border);
|
|
43654
|
+
if (!(key in bordersPositions)) {
|
|
43655
|
+
bordersPositions[key] = [];
|
|
43656
|
+
}
|
|
43657
|
+
bordersPositions[key].push(positionToZone({ col: data.col, row: data.row }));
|
|
43658
|
+
}
|
|
43659
|
+
collectConditionalFormatsData(sheetId, data, cfNewRanges) {
|
|
43660
|
+
const { originCol, originRow, col, row } = data;
|
|
43661
|
+
const cfsAtOrigin = this.getters.getRulesByCell(sheetId, originCol, originRow);
|
|
43662
|
+
const xc = toXC(col, row);
|
|
43663
|
+
for (const cf of cfsAtOrigin) {
|
|
43664
|
+
if (!(cf.id in cfNewRanges)) {
|
|
43665
|
+
cfNewRanges[cf.id] = [];
|
|
43666
|
+
}
|
|
43667
|
+
cfNewRanges[cf.id].push(xc);
|
|
43668
|
+
}
|
|
43669
|
+
}
|
|
43670
|
+
collectDataValidationsData(sheetId, data, dvNewZones) {
|
|
43671
|
+
const { originCol, originRow, col, row } = data;
|
|
43672
|
+
const cellPosition = { sheetId, col: originCol, row: originRow };
|
|
43673
|
+
const dvsAtOrigin = this.getters.getValidationRuleForCell(cellPosition);
|
|
43674
|
+
if (!dvsAtOrigin) {
|
|
43675
|
+
return;
|
|
43676
|
+
}
|
|
43677
|
+
if (!(dvsAtOrigin.id in dvNewZones)) {
|
|
43678
|
+
dvNewZones[dvsAtOrigin.id] = [];
|
|
43679
|
+
}
|
|
43680
|
+
dvNewZones[dvsAtOrigin.id].push(positionToZone({ col, row }));
|
|
43681
|
+
}
|
|
43682
|
+
autofillCell(sheetId, data) {
|
|
43683
|
+
this.dispatch("UPDATE_CELL", {
|
|
43684
|
+
sheetId,
|
|
43685
|
+
col: data.col,
|
|
43686
|
+
row: data.row,
|
|
43687
|
+
content: data.content || "",
|
|
43688
|
+
style: data.style || null,
|
|
43689
|
+
format: data.format || "",
|
|
43690
|
+
});
|
|
43691
|
+
// Still usefull in odoo ATM to autofill field sync
|
|
43692
|
+
this.dispatch("AUTOFILL_CELL", data);
|
|
43693
|
+
}
|
|
43694
|
+
autofillBorders(sheetId, bordersPositions) {
|
|
43695
|
+
for (const stringifiedBorder in bordersPositions) {
|
|
43696
|
+
const border = stringifiedBorder === "undefined" ? undefined : JSON.parse(stringifiedBorder);
|
|
43697
|
+
this.dispatch("SET_BORDERS_ON_TARGET", {
|
|
43698
|
+
sheetId,
|
|
43699
|
+
border,
|
|
43700
|
+
target: futureRecomputeZones(bordersPositions[stringifiedBorder]),
|
|
43701
|
+
});
|
|
43702
|
+
}
|
|
43703
|
+
}
|
|
43704
|
+
autofillConditionalFormats(sheetId, cfNewRanges) {
|
|
43705
|
+
for (const cfId in cfNewRanges) {
|
|
43706
|
+
const changes = cfNewRanges[cfId];
|
|
43707
|
+
const cf = this.getters.getConditionalFormats(sheetId).find((cf) => cf.id === cfId);
|
|
43708
|
+
if (!cf) {
|
|
43709
|
+
continue;
|
|
43710
|
+
}
|
|
43711
|
+
const newCfZones = this.getters.getAdaptedCfRanges(sheetId, cf, changes.map(toZone), []);
|
|
43712
|
+
if (newCfZones) {
|
|
43713
|
+
this.dispatch("ADD_CONDITIONAL_FORMAT", {
|
|
43714
|
+
cf: {
|
|
43715
|
+
id: cf.id,
|
|
43716
|
+
rule: cf.rule,
|
|
43717
|
+
stopIfTrue: cf.stopIfTrue,
|
|
43718
|
+
},
|
|
43719
|
+
ranges: newCfZones.map((xc) => this.getters.getRangeDataFromZone(sheetId, xc)),
|
|
43720
|
+
sheetId,
|
|
43721
|
+
});
|
|
43722
|
+
}
|
|
43723
|
+
}
|
|
43724
|
+
}
|
|
43725
|
+
autofillDataValidations(sheetId, dvNewZones) {
|
|
43726
|
+
for (const dvId in dvNewZones) {
|
|
43727
|
+
const changes = dvNewZones[dvId];
|
|
43728
|
+
const dvOrigin = this.getters.getDataValidationRule(sheetId, dvId);
|
|
43729
|
+
if (!dvOrigin) {
|
|
43730
|
+
continue;
|
|
43731
|
+
}
|
|
43732
|
+
const dvRangesXcs = dvOrigin.ranges.map((range) => range.zone);
|
|
43733
|
+
const newDvRanges = futureRecomputeZones(dvRangesXcs.concat(changes), []);
|
|
43734
|
+
this.dispatch("ADD_DATA_VALIDATION_RULE", {
|
|
43735
|
+
rule: dvOrigin,
|
|
43736
|
+
ranges: newDvRanges.map((zone) => this.getters.getRangeDataFromZone(sheetId, zone)),
|
|
43737
|
+
sheetId,
|
|
43738
|
+
});
|
|
43739
|
+
}
|
|
43740
|
+
}
|
|
43644
43741
|
/**
|
|
43645
43742
|
* Select a cell which becomes the last cell of the autofillZone
|
|
43646
43743
|
*/
|
|
@@ -43707,22 +43804,20 @@
|
|
|
43707
43804
|
/**
|
|
43708
43805
|
* Generate the next cell
|
|
43709
43806
|
*/
|
|
43710
|
-
computeNewCell(generator, col, row
|
|
43807
|
+
computeNewCell(generator, col, row) {
|
|
43711
43808
|
const { cellData, tooltip, origin } = generator.next();
|
|
43712
43809
|
const { content, style, border, format } = cellData;
|
|
43713
43810
|
this.tooltip = tooltip;
|
|
43714
|
-
|
|
43715
|
-
|
|
43716
|
-
|
|
43717
|
-
|
|
43718
|
-
|
|
43719
|
-
|
|
43720
|
-
|
|
43721
|
-
|
|
43722
|
-
|
|
43723
|
-
|
|
43724
|
-
});
|
|
43725
|
-
}
|
|
43811
|
+
return {
|
|
43812
|
+
originCol: origin.col,
|
|
43813
|
+
originRow: origin.row,
|
|
43814
|
+
col,
|
|
43815
|
+
row,
|
|
43816
|
+
content,
|
|
43817
|
+
style,
|
|
43818
|
+
border,
|
|
43819
|
+
format,
|
|
43820
|
+
};
|
|
43726
43821
|
}
|
|
43727
43822
|
/**
|
|
43728
43823
|
* Get the rule associated to the current cell
|
|
@@ -43790,8 +43885,8 @@
|
|
|
43790
43885
|
? position[first].value
|
|
43791
43886
|
: position[second].value;
|
|
43792
43887
|
}
|
|
43793
|
-
|
|
43794
|
-
const
|
|
43888
|
+
autofillMerge(sheetId, data) {
|
|
43889
|
+
const { originCol, originRow, col, row } = data;
|
|
43795
43890
|
const position = { sheetId, col, row };
|
|
43796
43891
|
const originPosition = { sheetId, col: originCol, row: originRow };
|
|
43797
43892
|
if (this.getters.isInMerge(position) && !this.getters.isInMerge(originPosition)) {
|
|
@@ -43818,35 +43913,6 @@
|
|
|
43818
43913
|
});
|
|
43819
43914
|
}
|
|
43820
43915
|
}
|
|
43821
|
-
autofillCF(originCol, originRow, col, row) {
|
|
43822
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
43823
|
-
const cfOrigin = this.getters.getRulesByCell(sheetId, originCol, originRow);
|
|
43824
|
-
for (const cf of cfOrigin) {
|
|
43825
|
-
const newCfRanges = this.getters.getAdaptedCfRanges(sheetId, cf, [toXC(col, row)], []);
|
|
43826
|
-
if (newCfRanges) {
|
|
43827
|
-
this.dispatch("ADD_CONDITIONAL_FORMAT", {
|
|
43828
|
-
cf: deepCopy(cf),
|
|
43829
|
-
ranges: newCfRanges.map((xc) => this.getters.getRangeDataFromXc(sheetId, xc)),
|
|
43830
|
-
sheetId,
|
|
43831
|
-
});
|
|
43832
|
-
}
|
|
43833
|
-
}
|
|
43834
|
-
}
|
|
43835
|
-
autofillDV(originCol, originRow, col, row) {
|
|
43836
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
43837
|
-
const cellPosition = { sheetId, col: originCol, row: originRow };
|
|
43838
|
-
const dvOrigin = this.getters.getValidationRuleForCell(cellPosition);
|
|
43839
|
-
if (!dvOrigin) {
|
|
43840
|
-
return;
|
|
43841
|
-
}
|
|
43842
|
-
const dvRangesXcs = dvOrigin.ranges.map((range) => this.getters.getRangeString(range, sheetId));
|
|
43843
|
-
const newDvRanges = recomputeZones(dvRangesXcs.concat(toXC(col, row)), []);
|
|
43844
|
-
this.dispatch("ADD_DATA_VALIDATION_RULE", {
|
|
43845
|
-
rule: dvOrigin,
|
|
43846
|
-
ranges: newDvRanges.map((xc) => this.getters.getRangeDataFromXc(sheetId, xc)),
|
|
43847
|
-
sheetId,
|
|
43848
|
-
});
|
|
43849
|
-
}
|
|
43850
43916
|
// ---------------------------------------------------------------------------
|
|
43851
43917
|
// Grid rendering
|
|
43852
43918
|
// ---------------------------------------------------------------------------
|
|
@@ -45233,6 +45299,9 @@
|
|
|
45233
45299
|
copiedTables;
|
|
45234
45300
|
zones;
|
|
45235
45301
|
uuidGenerator = new UuidGenerator();
|
|
45302
|
+
queuedBordersToAdd = {};
|
|
45303
|
+
queuedCFChanges = {};
|
|
45304
|
+
queuedDVChanges = {};
|
|
45236
45305
|
constructor(zones, operation, getters, dispatch, selection) {
|
|
45237
45306
|
super(operation, getters, dispatch, selection);
|
|
45238
45307
|
if (!zones.length) {
|
|
@@ -45342,6 +45411,8 @@
|
|
|
45342
45411
|
* Paste the clipboard content in the given target
|
|
45343
45412
|
*/
|
|
45344
45413
|
paste(target, options) {
|
|
45414
|
+
this.queuedCFChanges = {};
|
|
45415
|
+
this.queuedDVChanges = {};
|
|
45345
45416
|
if (this.operation === "COPY") {
|
|
45346
45417
|
this.pasteFromCopy(target, options);
|
|
45347
45418
|
}
|
|
@@ -45354,6 +45425,7 @@
|
|
|
45354
45425
|
if (options?.selectTarget) {
|
|
45355
45426
|
this.selectPastedZone(width, height, isCutOperation, target);
|
|
45356
45427
|
}
|
|
45428
|
+
this.executeQueuedChanges(this.getters.getActiveSheetId());
|
|
45357
45429
|
}
|
|
45358
45430
|
pasteFromCopy(target, options) {
|
|
45359
45431
|
if (target.length === 1) {
|
|
@@ -45528,7 +45600,11 @@
|
|
|
45528
45600
|
left: targetBorders?.left || originBorders?.left,
|
|
45529
45601
|
right: targetBorders?.right || originBorders?.right,
|
|
45530
45602
|
};
|
|
45531
|
-
|
|
45603
|
+
const borderKey = JSON.stringify(border);
|
|
45604
|
+
if (!this.queuedBordersToAdd[borderKey]) {
|
|
45605
|
+
this.queuedBordersToAdd[borderKey] = [];
|
|
45606
|
+
}
|
|
45607
|
+
this.queuedBordersToAdd[borderKey].push(positionToZone(target));
|
|
45532
45608
|
if (clipboardOption?.pasteOption === "onlyFormat") {
|
|
45533
45609
|
this.dispatch("UPDATE_CELL", {
|
|
45534
45610
|
...target,
|
|
@@ -45674,7 +45750,8 @@
|
|
|
45674
45750
|
}
|
|
45675
45751
|
}
|
|
45676
45752
|
pasteCf(origin, target) {
|
|
45677
|
-
const
|
|
45753
|
+
const zone = positionToZone(target);
|
|
45754
|
+
const originZone = positionToZone(origin);
|
|
45678
45755
|
for (let rule of this.getters.getConditionalFormats(origin.sheetId)) {
|
|
45679
45756
|
for (let range of rule.ranges) {
|
|
45680
45757
|
if (isInside(origin.col, origin.row, this.getters.getRangeFromSheetXC(origin.sheetId, range).zone)) {
|
|
@@ -45682,15 +45759,15 @@
|
|
|
45682
45759
|
const toRemoveRange = [];
|
|
45683
45760
|
if (this.operation === "CUT") {
|
|
45684
45761
|
//remove from current rule
|
|
45685
|
-
toRemoveRange.push(
|
|
45762
|
+
toRemoveRange.push(originZone);
|
|
45686
45763
|
}
|
|
45687
45764
|
if (origin.sheetId === target.sheetId) {
|
|
45688
|
-
this.adaptCFRules(origin.sheetId, cf, [
|
|
45765
|
+
this.adaptCFRules(origin.sheetId, cf, [zone], toRemoveRange);
|
|
45689
45766
|
}
|
|
45690
45767
|
else {
|
|
45691
45768
|
this.adaptCFRules(origin.sheetId, cf, [], toRemoveRange);
|
|
45692
45769
|
const cfToCopyTo = this.getCFToCopyTo(target.sheetId, cf);
|
|
45693
|
-
this.adaptCFRules(target.sheetId, cfToCopyTo, [
|
|
45770
|
+
this.adaptCFRules(target.sheetId, cfToCopyTo, [zone], []);
|
|
45694
45771
|
}
|
|
45695
45772
|
}
|
|
45696
45773
|
}
|
|
@@ -45700,79 +45777,130 @@
|
|
|
45700
45777
|
* Add or remove cells to a given conditional formatting rule.
|
|
45701
45778
|
*/
|
|
45702
45779
|
adaptCFRules(sheetId, cf, toAdd, toRemove) {
|
|
45703
|
-
|
|
45704
|
-
|
|
45705
|
-
return;
|
|
45780
|
+
if (!this.queuedCFChanges[sheetId]) {
|
|
45781
|
+
this.queuedCFChanges[sheetId] = [];
|
|
45706
45782
|
}
|
|
45707
|
-
|
|
45708
|
-
|
|
45709
|
-
|
|
45783
|
+
const queuedChange = this.queuedCFChanges[sheetId].find((queued) => queued.cf.id === cf.id);
|
|
45784
|
+
if (!queuedChange) {
|
|
45785
|
+
this.queuedCFChanges[sheetId].push({ toAdd, toRemove, cf });
|
|
45786
|
+
}
|
|
45787
|
+
else {
|
|
45788
|
+
queuedChange.toAdd.push(...toAdd);
|
|
45789
|
+
queuedChange.toRemove.push(...toRemove);
|
|
45710
45790
|
}
|
|
45711
|
-
this.dispatch("ADD_CONDITIONAL_FORMAT", {
|
|
45712
|
-
cf: {
|
|
45713
|
-
id: cf.id,
|
|
45714
|
-
rule: cf.rule,
|
|
45715
|
-
stopIfTrue: cf.stopIfTrue,
|
|
45716
|
-
},
|
|
45717
|
-
ranges: newRangesXC.map((xc) => this.getters.getRangeDataFromXc(sheetId, xc)),
|
|
45718
|
-
sheetId,
|
|
45719
|
-
});
|
|
45720
45791
|
}
|
|
45721
45792
|
getCFToCopyTo(targetSheetId, originCF) {
|
|
45722
|
-
|
|
45793
|
+
let targetCF = this.getters
|
|
45723
45794
|
.getConditionalFormats(targetSheetId)
|
|
45724
45795
|
.find((cf) => cf.stopIfTrue === originCF.stopIfTrue && deepEquals(cf.rule, originCF.rule));
|
|
45725
|
-
|
|
45726
|
-
|
|
45727
|
-
|
|
45796
|
+
const queuedCfs = this.queuedCFChanges[targetSheetId];
|
|
45797
|
+
if (!targetCF && queuedCfs) {
|
|
45798
|
+
targetCF = queuedCfs.find((queued) => queued.cf.stopIfTrue === originCF.stopIfTrue && deepEquals(queued.cf.rule, originCF.rule))?.cf;
|
|
45799
|
+
}
|
|
45800
|
+
return targetCF ? targetCF : { ...originCF, id: this.uuidGenerator.smallUuid(), ranges: [] };
|
|
45728
45801
|
}
|
|
45729
45802
|
pasteDataValidation(origin, target) {
|
|
45730
45803
|
const rule = this.getters.getValidationRuleForCell(origin);
|
|
45804
|
+
const originZone = positionToZone(origin);
|
|
45731
45805
|
if (!rule) {
|
|
45732
45806
|
return;
|
|
45733
45807
|
}
|
|
45734
|
-
const
|
|
45808
|
+
const zone = positionToZone(target);
|
|
45735
45809
|
for (const range of rule.ranges) {
|
|
45736
45810
|
if (isInside(origin.col, origin.row, range.zone)) {
|
|
45737
45811
|
const toRemoveRange = [];
|
|
45738
45812
|
if (this.operation === "CUT") {
|
|
45739
|
-
toRemoveRange.push(
|
|
45813
|
+
toRemoveRange.push(originZone);
|
|
45740
45814
|
}
|
|
45741
45815
|
if (origin.sheetId === target.sheetId) {
|
|
45742
|
-
this.
|
|
45816
|
+
const copyToRule = this.getDataValidationRuleToCopyTo(target.sheetId, rule);
|
|
45817
|
+
this.adaptDataValidationRule(origin.sheetId, copyToRule, [zone], toRemoveRange);
|
|
45743
45818
|
}
|
|
45744
45819
|
else {
|
|
45745
|
-
this.
|
|
45746
|
-
|
|
45747
|
-
|
|
45820
|
+
const originRule = this.getters.getValidationRuleForCell(origin);
|
|
45821
|
+
if (originRule) {
|
|
45822
|
+
this.adaptDataValidationRule(origin.sheetId, originRule, [], toRemoveRange);
|
|
45823
|
+
}
|
|
45824
|
+
const copyToRule = this.getDataValidationRuleToCopyTo(target.sheetId, rule);
|
|
45825
|
+
this.adaptDataValidationRule(target.sheetId, copyToRule, [zone], []);
|
|
45748
45826
|
}
|
|
45749
45827
|
}
|
|
45750
45828
|
}
|
|
45751
45829
|
}
|
|
45752
45830
|
getDataValidationRuleToCopyTo(targetSheetId, originRule) {
|
|
45753
|
-
|
|
45831
|
+
let targetRule = this.getters
|
|
45754
45832
|
.getDataValidationRules(targetSheetId)
|
|
45755
45833
|
.find((rule) => deepEquals(originRule.criterion, rule.criterion) &&
|
|
45756
45834
|
originRule.isBlocking === rule.isBlocking);
|
|
45757
|
-
|
|
45758
|
-
|
|
45759
|
-
|
|
45835
|
+
const queuedRules = this.queuedDVChanges[targetSheetId];
|
|
45836
|
+
if (!targetRule && queuedRules) {
|
|
45837
|
+
targetRule = queuedRules.find((queued) => deepEquals(originRule.criterion, queued.rule.criterion) &&
|
|
45838
|
+
originRule.isBlocking === queued.rule.isBlocking)?.rule;
|
|
45839
|
+
}
|
|
45840
|
+
return targetRule || { ...originRule, id: this.uuidGenerator.smallUuid(), ranges: [] };
|
|
45760
45841
|
}
|
|
45761
45842
|
/**
|
|
45762
45843
|
* Add or remove XCs to a given data validation rule.
|
|
45763
45844
|
*/
|
|
45764
45845
|
adaptDataValidationRule(sheetId, rule, toAdd, toRemove) {
|
|
45765
|
-
|
|
45766
|
-
|
|
45767
|
-
if (newRangesXC.length === 0) {
|
|
45768
|
-
this.dispatch("REMOVE_DATA_VALIDATION_RULE", { sheetId, id: rule.id });
|
|
45769
|
-
return;
|
|
45846
|
+
if (!this.queuedDVChanges[sheetId]) {
|
|
45847
|
+
this.queuedDVChanges[sheetId] = [];
|
|
45770
45848
|
}
|
|
45771
|
-
this.
|
|
45772
|
-
|
|
45773
|
-
|
|
45774
|
-
|
|
45775
|
-
|
|
45849
|
+
const queuedChange = this.queuedDVChanges[sheetId].find((queued) => queued.rule.id === rule.id);
|
|
45850
|
+
if (!queuedChange) {
|
|
45851
|
+
this.queuedDVChanges[sheetId].push({ toAdd, toRemove, rule: deepCopy(rule) });
|
|
45852
|
+
}
|
|
45853
|
+
else {
|
|
45854
|
+
queuedChange.toAdd.push(...toAdd);
|
|
45855
|
+
queuedChange.toRemove.push(...toRemove);
|
|
45856
|
+
}
|
|
45857
|
+
}
|
|
45858
|
+
executeQueuedChanges(pasteSheetTarget) {
|
|
45859
|
+
for (const sheetId in this.queuedCFChanges) {
|
|
45860
|
+
for (const { toAdd, toRemove, cf } of this.queuedCFChanges[sheetId]) {
|
|
45861
|
+
const newRangesXc = this.getters.getAdaptedCfRanges(sheetId, cf, toAdd, toRemove);
|
|
45862
|
+
if (!newRangesXc) {
|
|
45863
|
+
continue;
|
|
45864
|
+
}
|
|
45865
|
+
if (newRangesXc.length === 0) {
|
|
45866
|
+
this.dispatch("REMOVE_CONDITIONAL_FORMAT", { id: cf.id, sheetId });
|
|
45867
|
+
continue;
|
|
45868
|
+
}
|
|
45869
|
+
this.dispatch("ADD_CONDITIONAL_FORMAT", {
|
|
45870
|
+
cf: {
|
|
45871
|
+
id: cf.id,
|
|
45872
|
+
rule: cf.rule,
|
|
45873
|
+
stopIfTrue: cf.stopIfTrue,
|
|
45874
|
+
},
|
|
45875
|
+
ranges: newRangesXc.map((zone) => this.getters.getRangeDataFromZone(sheetId, zone)),
|
|
45876
|
+
sheetId,
|
|
45877
|
+
});
|
|
45878
|
+
}
|
|
45879
|
+
}
|
|
45880
|
+
for (const sheetId in this.queuedDVChanges) {
|
|
45881
|
+
for (const { toAdd, toRemove, rule: dv } of this.queuedDVChanges[sheetId]) {
|
|
45882
|
+
// Remove the zones first in case the same position is in toAdd and toRemove
|
|
45883
|
+
const dvZones = dv.ranges.map((range) => range.zone);
|
|
45884
|
+
const withRemovedZones = futureRecomputeZones(dvZones, toRemove);
|
|
45885
|
+
const newDvZones = futureRecomputeZones([...withRemovedZones, ...toAdd], []);
|
|
45886
|
+
if (newDvZones.length === 0) {
|
|
45887
|
+
this.dispatch("REMOVE_DATA_VALIDATION_RULE", { sheetId, id: dv.id });
|
|
45888
|
+
continue;
|
|
45889
|
+
}
|
|
45890
|
+
this.dispatch("ADD_DATA_VALIDATION_RULE", {
|
|
45891
|
+
rule: { id: dv.id, criterion: dv.criterion, isBlocking: dv.isBlocking },
|
|
45892
|
+
ranges: newDvZones.map((zone) => this.getters.getRangeDataFromZone(sheetId, zone)),
|
|
45893
|
+
sheetId,
|
|
45894
|
+
});
|
|
45895
|
+
}
|
|
45896
|
+
}
|
|
45897
|
+
for (const borderKey in this.queuedBordersToAdd) {
|
|
45898
|
+
const zones = this.queuedBordersToAdd[borderKey];
|
|
45899
|
+
const border = JSON.parse(borderKey);
|
|
45900
|
+
const target = futureRecomputeZones(zones, []);
|
|
45901
|
+
this.dispatch("SET_BORDERS_ON_TARGET", { sheetId: pasteSheetTarget, target, border });
|
|
45902
|
+
}
|
|
45903
|
+
this.queuedBordersToAdd = {};
|
|
45776
45904
|
}
|
|
45777
45905
|
}
|
|
45778
45906
|
|
|
@@ -58120,9 +58248,9 @@
|
|
|
58120
58248
|
exports.tokenize = tokenize;
|
|
58121
58249
|
|
|
58122
58250
|
|
|
58123
|
-
__info__.version = "17.0.
|
|
58124
|
-
__info__.date = "2025-04-
|
|
58125
|
-
__info__.hash = "
|
|
58251
|
+
__info__.version = "17.0.57";
|
|
58252
|
+
__info__.date = "2025-04-14T17:13:56.677Z";
|
|
58253
|
+
__info__.hash = "6ac8bb7";
|
|
58126
58254
|
|
|
58127
58255
|
|
|
58128
58256
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|