@odoo/o-spreadsheet 17.2.4 → 17.2.5
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 +380 -20
- package/dist/o-spreadsheet.esm.js +380 -20
- package/dist/o-spreadsheet.iife.js +380 -20
- package/dist/o-spreadsheet.iife.min.js +98 -98
- package/dist/o_spreadsheet.xml +3 -3
- package/package.json +1 -1
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
5
5
|
* @see https://github.com/odoo/o-spreadsheet
|
|
6
|
-
* @version 17.2.
|
|
7
|
-
* @date 2024-04-
|
|
8
|
-
* @hash
|
|
6
|
+
* @version 17.2.5
|
|
7
|
+
* @date 2024-04-26T07:41:13.193Z
|
|
8
|
+
* @hash a730f5c
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
@@ -32073,17 +32073,13 @@ class Composer extends owl.Component {
|
|
|
32073
32073
|
this.DOMFocusableElementStore.setFocusableElement(el);
|
|
32074
32074
|
}
|
|
32075
32075
|
this.contentHelper.updateEl(el);
|
|
32076
|
-
this.processTokenAtCursor();
|
|
32077
32076
|
});
|
|
32078
32077
|
owl.useEffect(() => {
|
|
32079
32078
|
this.processContent();
|
|
32080
32079
|
});
|
|
32081
|
-
owl.
|
|
32082
|
-
|
|
32083
|
-
|
|
32084
|
-
this.processTokenAtCursor();
|
|
32085
|
-
}
|
|
32086
|
-
});
|
|
32080
|
+
owl.useEffect(() => {
|
|
32081
|
+
this.processTokenAtCursor();
|
|
32082
|
+
}, () => [this.composerStore.editionMode !== "inactive"]);
|
|
32087
32083
|
}
|
|
32088
32084
|
// ---------------------------------------------------------------------------
|
|
32089
32085
|
// Handlers
|
|
@@ -40380,7 +40376,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
40380
40376
|
this.clearBorders(cmd.sheetId, cmd.target);
|
|
40381
40377
|
break;
|
|
40382
40378
|
case "REMOVE_COLUMNS_ROWS":
|
|
40383
|
-
for (let el of cmd.elements) {
|
|
40379
|
+
for (let el of [...cmd.elements].sort((a, b) => b - a)) {
|
|
40384
40380
|
if (cmd.dimension === "COL") {
|
|
40385
40381
|
this.shiftBordersHorizontally(cmd.sheetId, el + 1, -1);
|
|
40386
40382
|
}
|
|
@@ -45919,6 +45915,353 @@ class CompilationParametersBuilder {
|
|
|
45919
45915
|
}
|
|
45920
45916
|
}
|
|
45921
45917
|
|
|
45918
|
+
/**
|
|
45919
|
+
* ####################################################
|
|
45920
|
+
* # INTRODUCTION
|
|
45921
|
+
* ####################################################
|
|
45922
|
+
*
|
|
45923
|
+
* This file contain the function recomputeZones.
|
|
45924
|
+
* This function try to recompute in a performant way
|
|
45925
|
+
* an ensemble of zones possibly overlapping to avoid
|
|
45926
|
+
* overlapping and to reduce the number of zones.
|
|
45927
|
+
*
|
|
45928
|
+
* It also allows to remove some zones from the ensemble.
|
|
45929
|
+
*
|
|
45930
|
+
* In the following example, 2 zones are overlapping.
|
|
45931
|
+
* Applying recomputeZones will return zones without
|
|
45932
|
+
* overlapping:
|
|
45933
|
+
*
|
|
45934
|
+
* ["B3:D4", "D2:E3"] ["B3:C4", "D2:D4", "E2:E3"]
|
|
45935
|
+
*
|
|
45936
|
+
* A B C D E A B C D E
|
|
45937
|
+
* 1 ___ 1 ___
|
|
45938
|
+
* 2 ___|_ | 2 ___| | |
|
|
45939
|
+
* 3 | |_|_| ---> 3 | | |_|
|
|
45940
|
+
* 4 |_____| 4 |___|_|
|
|
45941
|
+
* 6 6
|
|
45942
|
+
* 7 7
|
|
45943
|
+
*
|
|
45944
|
+
*
|
|
45945
|
+
* In the following example, 2 zones are contiguous.
|
|
45946
|
+
* Applying recomputeZones will return only one zone:
|
|
45947
|
+
*
|
|
45948
|
+
* ["B2:B3", "C2:D3"] ["B2:D3"]
|
|
45949
|
+
*
|
|
45950
|
+
* A B C D E A B C D E
|
|
45951
|
+
* 1 _ ___ 1 _____
|
|
45952
|
+
* 2 | | | ---> 2 | |
|
|
45953
|
+
* 3 |_|___| 3 |_____|
|
|
45954
|
+
* 4 4
|
|
45955
|
+
*
|
|
45956
|
+
*
|
|
45957
|
+
* In the following example, we want to remove a zone
|
|
45958
|
+
* from the ensemble. Applying recomputeZones will
|
|
45959
|
+
* return the ensemble without the zone to remove:
|
|
45960
|
+
*
|
|
45961
|
+
* remove ["C3:D3"] ["B2:B4", "C2:D2",
|
|
45962
|
+
* "C4:D4", "E2:E4"]
|
|
45963
|
+
*
|
|
45964
|
+
* A B C D E F A B C D E F
|
|
45965
|
+
* 1 _______ 1 _______
|
|
45966
|
+
* 2 | | ---> 2 | |___| |
|
|
45967
|
+
* 3 | xxx | 3 | |___| |
|
|
45968
|
+
* 4 |_______| 4 |_|___|_|
|
|
45969
|
+
* 5 5
|
|
45970
|
+
*
|
|
45971
|
+
*
|
|
45972
|
+
* The exercise seems simple when we have only 2 zones.
|
|
45973
|
+
* But with n zones and in a performant way, we want to
|
|
45974
|
+
* avoid comparing each zone with all the others.
|
|
45975
|
+
*
|
|
45976
|
+
*
|
|
45977
|
+
* ####################################################
|
|
45978
|
+
* # Methodological approach
|
|
45979
|
+
* ####################################################
|
|
45980
|
+
*
|
|
45981
|
+
* The methodological approach to avoid comparing each
|
|
45982
|
+
* zone with all the others is to use a data structure
|
|
45983
|
+
* that allow to quickly find which zones are
|
|
45984
|
+
* overlapping with any other given zone.
|
|
45985
|
+
*
|
|
45986
|
+
* Here the idea is to profile the zones at the columns level.
|
|
45987
|
+
*
|
|
45988
|
+
* To do that, we propose to use a data structure
|
|
45989
|
+
* composed of 2 parts:
|
|
45990
|
+
* - profilesStartingPosition: a sorted number array
|
|
45991
|
+
* indicating on which columns a new profile begins.
|
|
45992
|
+
* - profiles: a map where the key is a column
|
|
45993
|
+
* position (from profilesStartingPosition) and the
|
|
45994
|
+
* value is a sorted number array representing a
|
|
45995
|
+
* profile.
|
|
45996
|
+
*
|
|
45997
|
+
*
|
|
45998
|
+
* See the following example: here profileStartingPosition
|
|
45999
|
+
* corresponds to [A,C,E,G,K]
|
|
46000
|
+
* A B C D E F G H I J K so with number [0,2,4,6,10]
|
|
46001
|
+
* 1 ' ' ' '
|
|
46002
|
+
* 2 ' ' '_______' here profile correspond
|
|
46003
|
+
* 3 '___' |_______| for A to []
|
|
46004
|
+
* 4 | | for C to [3, 5]
|
|
46005
|
+
* 5 |___| for E to []
|
|
46006
|
+
* 6 for G to [2, 3]
|
|
46007
|
+
* 7 for K to []
|
|
46008
|
+
*
|
|
46009
|
+
*
|
|
46010
|
+
* Now we can easily find which zones are overlapping
|
|
46011
|
+
* with a given zone. Suppose we want to add a new zone
|
|
46012
|
+
* D5:H6 to the ensemble:
|
|
46013
|
+
*
|
|
46014
|
+
* With a binary search of left and right
|
|
46015
|
+
* A B C D E F G H I J K on profilesStartingPosition, we can
|
|
46016
|
+
* 1 ' ' ' ' find the indexes of the profiles on which
|
|
46017
|
+
* 2 ' ' '_______' to apply a modification.
|
|
46018
|
+
* 3 '___' |_______|
|
|
46019
|
+
* 4 | _|_______ Here we will:
|
|
46020
|
+
* 5 |_|_| | - add a new profile in D --> become [3, 6]
|
|
46021
|
+
* 6 |_________| - modify the profile in E --> become [4, 6]
|
|
46022
|
+
* 7 - modify the profile in G --> become [2, 3, 4, 6]
|
|
46023
|
+
* - add a new profile in I --> become [8, 10]
|
|
46024
|
+
*
|
|
46025
|
+
* See below the result:
|
|
46026
|
+
*
|
|
46027
|
+
* Note the particularity of the profile
|
|
46028
|
+
* A B C D E F G H I J K for G: it will correspond to [2, 3, 4, 6]
|
|
46029
|
+
* 1 ' ' ' ' ' '
|
|
46030
|
+
* 2 ' ' ' '___'___' To know how to modify the profile (add a
|
|
46031
|
+
* 3 '_'_' |___|___| zone or remove it) we do a binary
|
|
46032
|
+
* 4 | | |___ ___ search of the top and bottom value on the
|
|
46033
|
+
* 5 |_| | | | profile array. Depending on the result index
|
|
46034
|
+
* 6 |_|___|___| parity (odd or even), because zone boundaries
|
|
46035
|
+
* 7 go by pairs, we know if we are in a zone or
|
|
46036
|
+
* not and how operate.
|
|
46037
|
+
*/
|
|
46038
|
+
/**
|
|
46039
|
+
* Recompute the zone without the cells in toRemoveZones and avoid overlapping.
|
|
46040
|
+
* This compute is particularly useful because after this function:
|
|
46041
|
+
* - you will find coordinate of a cell only once among all the zones
|
|
46042
|
+
* - the number of zones will be reduced to the minimum
|
|
46043
|
+
*/
|
|
46044
|
+
function futureRecomputeZones(zones, zonesToRemove = []) {
|
|
46045
|
+
const profilesStartingPosition = [0];
|
|
46046
|
+
const profiles = new Map([[0, []]]);
|
|
46047
|
+
modifyProfiles(profilesStartingPosition, profiles, zones, false);
|
|
46048
|
+
modifyProfiles(profilesStartingPosition, profiles, zonesToRemove, true);
|
|
46049
|
+
return constructZonesFromProfiles(profilesStartingPosition, profiles);
|
|
46050
|
+
}
|
|
46051
|
+
function modifyProfiles(// export for testing only
|
|
46052
|
+
profilesStartingPosition, profiles, zones, toRemove = false) {
|
|
46053
|
+
for (const zone of zones) {
|
|
46054
|
+
const leftValue = zone.left;
|
|
46055
|
+
const rightValue = zone.right === undefined ? undefined : zone.right + 1;
|
|
46056
|
+
const leftIndex = findIndexAndCreateProfile(profilesStartingPosition, profiles, leftValue, true, 0);
|
|
46057
|
+
const rightIndex = findIndexAndCreateProfile(profilesStartingPosition, profiles, rightValue, false, leftIndex);
|
|
46058
|
+
for (let i = leftIndex; i <= rightIndex; i++) {
|
|
46059
|
+
const profile = profiles.get(profilesStartingPosition[i]);
|
|
46060
|
+
modifyProfile(profile, zone, toRemove);
|
|
46061
|
+
}
|
|
46062
|
+
// maybe this part cost in performance, and maybe it's not necessary (depending on the use case). To be checked
|
|
46063
|
+
removeContiguousProfiles(profilesStartingPosition, profiles, leftIndex, rightIndex);
|
|
46064
|
+
}
|
|
46065
|
+
}
|
|
46066
|
+
function findIndexAndCreateProfile(profilesStartingPosition, profiles, value, searchLeft, startIndex) {
|
|
46067
|
+
if (value === undefined) {
|
|
46068
|
+
// this is only the case when the value correspond to a bottom value that could be undefined
|
|
46069
|
+
return profilesStartingPosition.length - 1;
|
|
46070
|
+
}
|
|
46071
|
+
const predecessorIndex = binaryPredecessorSearch(profilesStartingPosition, value, startIndex);
|
|
46072
|
+
if (value != profilesStartingPosition[predecessorIndex]) {
|
|
46073
|
+
// mean that the value is not ending/starting at the same position as the previous/next profile
|
|
46074
|
+
// --> it's a new profile
|
|
46075
|
+
// --> we need to add it
|
|
46076
|
+
profilesStartingPosition.splice(predecessorIndex + 1, 0, value);
|
|
46077
|
+
// suppose the we want to add the for the left value
|
|
46078
|
+
// following profile following zone: 'C', the predecessor index
|
|
46079
|
+
// for B: [1, 3] "C3:D4" correspond to 'B'.
|
|
46080
|
+
// The next line code will
|
|
46081
|
+
// A B C D A B C D copy the profile of 'B'
|
|
46082
|
+
// 1 '___' 1 '___' to 'C'. In the rest of the
|
|
46083
|
+
// 2 | | ---> 2 | _|_ process the 'modifyProfile'
|
|
46084
|
+
// 3 |___| 3 |_|_| | function will adapt the waiting
|
|
46085
|
+
// 4 4 |___| 'C' profile [1, 3] to the
|
|
46086
|
+
// correct 'C' profile [1, 4]
|
|
46087
|
+
profiles.set(value, [...profiles.get(profilesStartingPosition[predecessorIndex])]);
|
|
46088
|
+
return searchLeft ? predecessorIndex + 1 : predecessorIndex;
|
|
46089
|
+
}
|
|
46090
|
+
return searchLeft ? predecessorIndex : predecessorIndex - 1;
|
|
46091
|
+
}
|
|
46092
|
+
/**
|
|
46093
|
+
* Suppose the following Suppose we want to add We want to have the
|
|
46094
|
+
* profile: the following zone: following profile:
|
|
46095
|
+
*
|
|
46096
|
+
* A B C D E F A B C D E F A B C D E F
|
|
46097
|
+
* 1 '___' 1 ' ' 1 '___'
|
|
46098
|
+
* 2 |___| 2 '___' 2 | |
|
|
46099
|
+
* 3 ' ' 3 | | 3 | |
|
|
46100
|
+
* 4 '___' --> 4 | | --> 4 | |
|
|
46101
|
+
* 6 | | 6 |___| 6 | |
|
|
46102
|
+
* 7 |___| 7 7 |___|
|
|
46103
|
+
* 8 8 8
|
|
46104
|
+
*
|
|
46105
|
+
* the profile for 'C' the top zone correspond Here [2, 3, 5, 8] with [3, 7]
|
|
46106
|
+
* corresponds to: to 3 and the bottom zone would be merged into [2, 8]
|
|
46107
|
+
* ____ ____ correspond to 6
|
|
46108
|
+
* [2, 3, 5, 8] would be the profile: The difficulty of modify profile
|
|
46109
|
+
* ____ is to know what must be deleted
|
|
46110
|
+
* Note that the 'filled [3, 7] and what must be added to the
|
|
46111
|
+
* zone' are always between existing profile.
|
|
46112
|
+
* an even index and its
|
|
46113
|
+
* next index
|
|
46114
|
+
*
|
|
46115
|
+
*/
|
|
46116
|
+
function modifyProfile(profile, zone, toRemove = false) {
|
|
46117
|
+
const topValue = zone.top;
|
|
46118
|
+
const bottomValue = zone.bottom === undefined ? undefined : zone.bottom + 1;
|
|
46119
|
+
const newPoints = [];
|
|
46120
|
+
// Case we want to add a zone to the profile:
|
|
46121
|
+
// - If the top predecessor index `topPredIndex` is even, it means the top of the zone is already positioned on a filled zone
|
|
46122
|
+
// so we don't need to add it to the profile. we can keep in reference the index of the predecessor.
|
|
46123
|
+
// - If it is odd, it means the top of the zone must be the beginning of a filled zone.
|
|
46124
|
+
// so we can keep the index of the top position
|
|
46125
|
+
// Case we want to remove a zone from the profile: it's the opposite of the previous case
|
|
46126
|
+
const topPredIndex = binaryPredecessorSearch(profile, topValue, 0, false);
|
|
46127
|
+
if ((topPredIndex % 2 !== 0 && !toRemove) || (topPredIndex % 2 === 0 && toRemove)) {
|
|
46128
|
+
newPoints.push(topValue);
|
|
46129
|
+
}
|
|
46130
|
+
if (bottomValue === undefined) {
|
|
46131
|
+
// The following two code lines will not impact the final result,
|
|
46132
|
+
// but they will impact the intermediate profile.
|
|
46133
|
+
// We keep them for performance reason
|
|
46134
|
+
profile.splice(topPredIndex + 1);
|
|
46135
|
+
profile.push(...newPoints);
|
|
46136
|
+
return;
|
|
46137
|
+
}
|
|
46138
|
+
// Case we want to add a zone to the profile:
|
|
46139
|
+
// - If the bottom successor index `bottomSuccIndex` is even, it means the bottom of the zone must be the ending of a filled zone
|
|
46140
|
+
// so we can keep the index of the bottom position.
|
|
46141
|
+
// - If it is odd, it means the bottom of the zone is already positioned on a filled zone
|
|
46142
|
+
// so we don't need to add it to the profile. we can keep in reference the index of the successor
|
|
46143
|
+
// Case we want to remove a zone from the profile: it's the opposite of the previous case
|
|
46144
|
+
const bottomSuccIndex = binarySuccessorSearch(profile, bottomValue, 0, false);
|
|
46145
|
+
if ((bottomSuccIndex % 2 === 0 && !toRemove) || (bottomSuccIndex % 2 !== 0 && toRemove)) {
|
|
46146
|
+
newPoints.push(bottomValue);
|
|
46147
|
+
}
|
|
46148
|
+
// add the top and bottom value to the profile and
|
|
46149
|
+
// remove all information between the top and bottom index
|
|
46150
|
+
profile.splice(topPredIndex + 1, bottomSuccIndex - topPredIndex - 1, ...newPoints);
|
|
46151
|
+
}
|
|
46152
|
+
function removeContiguousProfiles(profilesStartingPosition, profiles, leftIndex, rightIndex) {
|
|
46153
|
+
const start = leftIndex - 1 === -1 ? 0 : leftIndex - 1;
|
|
46154
|
+
const end = rightIndex === profilesStartingPosition.length - 1 ? rightIndex : rightIndex + 1;
|
|
46155
|
+
for (let i = end; i > start; i--) {
|
|
46156
|
+
if (deepEqualsArray(profiles.get(profilesStartingPosition[i]), profiles.get(profilesStartingPosition[i - 1]))) {
|
|
46157
|
+
profiles.delete(profilesStartingPosition[i]);
|
|
46158
|
+
profilesStartingPosition.splice(i, 1);
|
|
46159
|
+
}
|
|
46160
|
+
}
|
|
46161
|
+
}
|
|
46162
|
+
function constructZonesFromProfiles(profilesStartingPosition, profiles) {
|
|
46163
|
+
const mergedZone = [];
|
|
46164
|
+
let pendingZones = [];
|
|
46165
|
+
for (let colIndex = 0; colIndex < profilesStartingPosition.length; colIndex++) {
|
|
46166
|
+
const left = profilesStartingPosition[colIndex];
|
|
46167
|
+
const profile = profiles.get(left);
|
|
46168
|
+
if (!profile || profile.length === 0) {
|
|
46169
|
+
mergedZone.push(...pendingZones);
|
|
46170
|
+
pendingZones = [];
|
|
46171
|
+
continue;
|
|
46172
|
+
}
|
|
46173
|
+
let right = profilesStartingPosition[colIndex + 1];
|
|
46174
|
+
if (right !== undefined) {
|
|
46175
|
+
right--;
|
|
46176
|
+
}
|
|
46177
|
+
const nextPendingZones = [];
|
|
46178
|
+
for (let i = 0; i < profile.length; i += 2) {
|
|
46179
|
+
const top = profile[i];
|
|
46180
|
+
let bottom = profile[i + 1];
|
|
46181
|
+
if (bottom !== undefined) {
|
|
46182
|
+
bottom--;
|
|
46183
|
+
}
|
|
46184
|
+
const profileZone = {
|
|
46185
|
+
top,
|
|
46186
|
+
left,
|
|
46187
|
+
bottom,
|
|
46188
|
+
right,
|
|
46189
|
+
hasHeader: (bottom === undefined && top !== 0) || (right === undefined && left !== 0),
|
|
46190
|
+
};
|
|
46191
|
+
let findCorrespondingZone = false;
|
|
46192
|
+
for (let j = pendingZones.length - 1; j >= 0; j--) {
|
|
46193
|
+
const pendingZone = pendingZones[j];
|
|
46194
|
+
if (pendingZone.top === profileZone.top && pendingZone.bottom === profileZone.bottom) {
|
|
46195
|
+
pendingZone.right = profileZone.right;
|
|
46196
|
+
pendingZones.splice(j, 1);
|
|
46197
|
+
nextPendingZones.push(pendingZone);
|
|
46198
|
+
findCorrespondingZone = true;
|
|
46199
|
+
break;
|
|
46200
|
+
}
|
|
46201
|
+
}
|
|
46202
|
+
if (!findCorrespondingZone) {
|
|
46203
|
+
nextPendingZones.push(profileZone);
|
|
46204
|
+
}
|
|
46205
|
+
}
|
|
46206
|
+
mergedZone.push(...pendingZones);
|
|
46207
|
+
pendingZones = nextPendingZones;
|
|
46208
|
+
}
|
|
46209
|
+
mergedZone.push(...pendingZones);
|
|
46210
|
+
return mergedZone;
|
|
46211
|
+
}
|
|
46212
|
+
function binaryPredecessorSearch(arr, val, start = 0, matchEqual = true) {
|
|
46213
|
+
let end = arr.length - 1;
|
|
46214
|
+
let result = -1;
|
|
46215
|
+
while (start <= end) {
|
|
46216
|
+
const mid = Math.floor((start + end) / 2);
|
|
46217
|
+
if (arr[mid] === val && matchEqual) {
|
|
46218
|
+
return mid;
|
|
46219
|
+
}
|
|
46220
|
+
else if (arr[mid] < val) {
|
|
46221
|
+
result = mid;
|
|
46222
|
+
start = mid + 1;
|
|
46223
|
+
}
|
|
46224
|
+
else {
|
|
46225
|
+
end = mid - 1;
|
|
46226
|
+
}
|
|
46227
|
+
}
|
|
46228
|
+
return result;
|
|
46229
|
+
}
|
|
46230
|
+
function binarySuccessorSearch(arr, val, start = 0, matchEqual = true) {
|
|
46231
|
+
let end = arr.length - 1;
|
|
46232
|
+
let result = arr.length;
|
|
46233
|
+
while (start <= end) {
|
|
46234
|
+
const mid = Math.floor((start + end) / 2);
|
|
46235
|
+
if (arr[mid] === val && matchEqual) {
|
|
46236
|
+
return mid;
|
|
46237
|
+
}
|
|
46238
|
+
else if (arr[mid] > val) {
|
|
46239
|
+
result = mid;
|
|
46240
|
+
end = mid - 1;
|
|
46241
|
+
}
|
|
46242
|
+
else {
|
|
46243
|
+
start = mid + 1;
|
|
46244
|
+
}
|
|
46245
|
+
}
|
|
46246
|
+
return result;
|
|
46247
|
+
}
|
|
46248
|
+
/**
|
|
46249
|
+
* Compares two arrays.
|
|
46250
|
+
* For performance reasons, this function is to be preferred
|
|
46251
|
+
* to 'deepEquals' in the case we know that the inputs are arrays.
|
|
46252
|
+
*/
|
|
46253
|
+
function deepEqualsArray(arr1, arr2) {
|
|
46254
|
+
if (arr1.length !== arr2.length) {
|
|
46255
|
+
return false;
|
|
46256
|
+
}
|
|
46257
|
+
for (let i = 0; i < arr1.length; i++) {
|
|
46258
|
+
if (!deepEquals(arr1[i], arr2[i])) {
|
|
46259
|
+
return false;
|
|
46260
|
+
}
|
|
46261
|
+
}
|
|
46262
|
+
return true;
|
|
46263
|
+
}
|
|
46264
|
+
|
|
45922
46265
|
class PositionMap {
|
|
45923
46266
|
map = {};
|
|
45924
46267
|
set({ sheetId, col, row }, value) {
|
|
@@ -46717,7 +47060,7 @@ class FormulaDependencyGraph {
|
|
|
46717
47060
|
}
|
|
46718
47061
|
}
|
|
46719
47062
|
/**
|
|
46720
|
-
* Return the
|
|
47063
|
+
* Return all the cells that depend on the provided ranges,
|
|
46721
47064
|
* in the correct order they should be evaluated.
|
|
46722
47065
|
* This is called a topological ordering (excluding cycles)
|
|
46723
47066
|
*/
|
|
@@ -46728,11 +47071,19 @@ class FormulaDependencyGraph {
|
|
|
46728
47071
|
const range = queue.pop();
|
|
46729
47072
|
visited.addMany(positions(range.zone).map((position) => ({ sheetId: range.sheetId, ...position })));
|
|
46730
47073
|
const impactedPositions = this.rTree.search(range).map((dep) => dep.data);
|
|
47074
|
+
const nextInQueue = {};
|
|
46731
47075
|
for (const position of impactedPositions) {
|
|
46732
47076
|
if (!visited.has(position)) {
|
|
46733
|
-
|
|
47077
|
+
if (!nextInQueue[position.sheetId]) {
|
|
47078
|
+
nextInQueue[position.sheetId] = [];
|
|
47079
|
+
}
|
|
47080
|
+
nextInQueue[position.sheetId].push(positionToZone(position));
|
|
46734
47081
|
}
|
|
46735
47082
|
}
|
|
47083
|
+
for (const sheetId in nextInQueue) {
|
|
47084
|
+
const zones = futureRecomputeZones(nextInQueue[sheetId]);
|
|
47085
|
+
queue.push(...zones.map((zone) => ({ sheetId, zone })));
|
|
47086
|
+
}
|
|
46736
47087
|
}
|
|
46737
47088
|
visited.deleteMany(ranges.flatMap((r) => positions(r.zone).map((position) => ({ sheetId: r.sheetId, ...position }))));
|
|
46738
47089
|
return visited;
|
|
@@ -47071,7 +47422,7 @@ class Evaluator {
|
|
|
47071
47422
|
}
|
|
47072
47423
|
if (!content) {
|
|
47073
47424
|
// The previous content could have blocked some array formulas
|
|
47074
|
-
impactedPositions.addMany(this.
|
|
47425
|
+
impactedPositions.addMany(this.getArrayFormulasBlockedBy(position));
|
|
47075
47426
|
}
|
|
47076
47427
|
}
|
|
47077
47428
|
return impactedPositions;
|
|
@@ -47114,14 +47465,23 @@ class Evaluator {
|
|
|
47114
47465
|
positions.fillAllPositions();
|
|
47115
47466
|
return positions;
|
|
47116
47467
|
}
|
|
47117
|
-
|
|
47468
|
+
/**
|
|
47469
|
+
* Return the position of formulas blocked by the given position
|
|
47470
|
+
* as well as all their dependencies.
|
|
47471
|
+
*/
|
|
47472
|
+
getArrayFormulasBlockedBy(position) {
|
|
47118
47473
|
if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
|
|
47119
47474
|
return [];
|
|
47120
47475
|
}
|
|
47121
47476
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
|
|
47122
47477
|
const positions = this.createEmptyPositionSet();
|
|
47123
47478
|
positions.addMany(arrayFormulas);
|
|
47124
|
-
|
|
47479
|
+
const arrayFormulaPosition = this.getArrayFormulaSpreadingOn(position);
|
|
47480
|
+
if (arrayFormulaPosition) {
|
|
47481
|
+
// ignore the formula spreading on the position. Keep only the blocked ones
|
|
47482
|
+
positions.delete(arrayFormulaPosition);
|
|
47483
|
+
}
|
|
47484
|
+
positions.addMany(this.getCellsDependingOn(positions));
|
|
47125
47485
|
return positions;
|
|
47126
47486
|
}
|
|
47127
47487
|
nextPositionsToUpdate = new PositionSet({});
|
|
@@ -47261,7 +47621,7 @@ class Evaluator {
|
|
|
47261
47621
|
}
|
|
47262
47622
|
this.evaluatedCells.delete(child);
|
|
47263
47623
|
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
47264
|
-
this.nextPositionsToUpdate.addMany(this.
|
|
47624
|
+
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedBy(child));
|
|
47265
47625
|
}
|
|
47266
47626
|
this.spreadingRelations.removeNode(position);
|
|
47267
47627
|
}
|
|
@@ -60240,6 +60600,6 @@ exports.tokenColors = tokenColors;
|
|
|
60240
60600
|
exports.tokenize = tokenize;
|
|
60241
60601
|
|
|
60242
60602
|
|
|
60243
|
-
__info__.version = "17.2.
|
|
60244
|
-
__info__.date = "2024-04-
|
|
60245
|
-
__info__.hash = "
|
|
60603
|
+
__info__.version = "17.2.5";
|
|
60604
|
+
__info__.date = "2024-04-26T07:41:13.193Z";
|
|
60605
|
+
__info__.hash = "a730f5c";
|