@odoo/o-spreadsheet 17.2.0-alpha.8 → 17.2.1
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 +415 -286
- package/dist/o-spreadsheet.d.ts +5 -3
- package/dist/o-spreadsheet.esm.js +415 -286
- package/dist/o-spreadsheet.iife.js +415 -286
- package/dist/o-spreadsheet.iife.min.js +333 -328
- package/dist/o_spreadsheet.xml +29 -20
- package/package.json +2 -2
|
@@ -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-03-
|
|
8
|
-
* @hash
|
|
6
|
+
* @version 17.2.1
|
|
7
|
+
* @date 2024-03-25T09:41:58.737Z
|
|
8
|
+
* @hash f97284c
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
(function (exports, owl) {
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
const LINK_COLOR = "#017E84";
|
|
31
31
|
const FILTERS_COLOR = "#188038";
|
|
32
32
|
const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
|
|
33
|
-
const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
|
|
34
33
|
const SEPARATOR_COLOR = "#E0E2E4";
|
|
35
34
|
const ICONS_COLOR = "#4A4F59";
|
|
36
35
|
const HEADER_GROUPING_BACKGROUND_COLOR = "#F5F5F5";
|
|
@@ -641,21 +640,6 @@
|
|
|
641
640
|
}
|
|
642
641
|
return true;
|
|
643
642
|
}
|
|
644
|
-
class JetSet extends Set {
|
|
645
|
-
addMany(iterable) {
|
|
646
|
-
for (const element of iterable) {
|
|
647
|
-
super.add(element);
|
|
648
|
-
}
|
|
649
|
-
return this;
|
|
650
|
-
}
|
|
651
|
-
deleteMany(iterable) {
|
|
652
|
-
let wasDeleted = false;
|
|
653
|
-
for (const element of iterable) {
|
|
654
|
-
wasDeleted ||= super.delete(element);
|
|
655
|
-
}
|
|
656
|
-
return wasDeleted;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
643
|
/**
|
|
660
644
|
* Creates a version of the function that's memoized on the value of its first
|
|
661
645
|
* argument, if any.
|
|
@@ -4101,14 +4085,6 @@
|
|
|
4101
4085
|
}
|
|
4102
4086
|
return positions;
|
|
4103
4087
|
}
|
|
4104
|
-
function forEachPositionsInZone(zone, callback) {
|
|
4105
|
-
const { left, right, top, bottom } = zone;
|
|
4106
|
-
for (let col = left; col <= right; col++) {
|
|
4107
|
-
for (let row = top; row <= bottom; row++) {
|
|
4108
|
-
callback(col, row);
|
|
4109
|
-
}
|
|
4110
|
-
}
|
|
4111
|
-
}
|
|
4112
4088
|
/**
|
|
4113
4089
|
* This function returns a zone with coordinates modified according to the change
|
|
4114
4090
|
* applied to the zone. It may be possible to change the zone by resizing or moving
|
|
@@ -8027,6 +8003,9 @@
|
|
|
8027
8003
|
instantiate(Store, ...args) {
|
|
8028
8004
|
return this.factory.build(Store, ...args);
|
|
8029
8005
|
}
|
|
8006
|
+
resetStores() {
|
|
8007
|
+
this.dependencies.clear();
|
|
8008
|
+
}
|
|
8030
8009
|
}
|
|
8031
8010
|
class StoreFactory {
|
|
8032
8011
|
get;
|
|
@@ -10054,6 +10033,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
10054
10033
|
result.default = true;
|
|
10055
10034
|
result.defaultValue = defaultValue;
|
|
10056
10035
|
}
|
|
10036
|
+
if (types.some((t) => t.startsWith("RANGE"))) {
|
|
10037
|
+
result.acceptMatrix = true;
|
|
10038
|
+
}
|
|
10057
10039
|
return result;
|
|
10058
10040
|
}
|
|
10059
10041
|
/**
|
|
@@ -18624,11 +18606,27 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
18624
18606
|
}
|
|
18625
18607
|
const descr = addMetaInfoFromArg(addDescr);
|
|
18626
18608
|
validateArguments(descr.args);
|
|
18627
|
-
this.mapping[name] = addErrorHandling(addResultHandling(descr
|
|
18609
|
+
this.mapping[name] = addErrorHandling(addResultHandling(addInputHandling(descr)), name);
|
|
18628
18610
|
super.add(name, descr);
|
|
18629
18611
|
return this;
|
|
18630
18612
|
}
|
|
18631
18613
|
}
|
|
18614
|
+
function addInputHandling(descr) {
|
|
18615
|
+
function computeWithInputHandling(...args) {
|
|
18616
|
+
for (let i = 0; i < args.length; i++) {
|
|
18617
|
+
const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
|
|
18618
|
+
const arg = args[i];
|
|
18619
|
+
if (isMatrix(arg) && !argDefinition.acceptMatrix) {
|
|
18620
|
+
if (arg.length !== 1 || arg[0].length !== 1) {
|
|
18621
|
+
throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be a single value or a single cell reference, not a range.", argDefinition.name));
|
|
18622
|
+
}
|
|
18623
|
+
args[i] = arg[0][0];
|
|
18624
|
+
}
|
|
18625
|
+
}
|
|
18626
|
+
return descr.compute.apply(this, args);
|
|
18627
|
+
}
|
|
18628
|
+
return computeWithInputHandling;
|
|
18629
|
+
}
|
|
18632
18630
|
function addErrorHandling(compute, functionName) {
|
|
18633
18631
|
return function (...args) {
|
|
18634
18632
|
try {
|
|
@@ -24218,14 +24216,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24218
24216
|
children: [allFunctionListMenuBuilder],
|
|
24219
24217
|
};
|
|
24220
24218
|
function allFunctionListMenuBuilder() {
|
|
24221
|
-
const fnNames = functionRegistry.getKeys();
|
|
24219
|
+
const fnNames = functionRegistry.getKeys().filter((key) => !functionRegistry.get(key).hidden);
|
|
24222
24220
|
return createFormulaFunctions(fnNames);
|
|
24223
24221
|
}
|
|
24224
24222
|
const categoriesFunctionListMenuBuilder = () => {
|
|
24225
24223
|
const functions = functionRegistry.content;
|
|
24226
|
-
const categories = [
|
|
24224
|
+
const categories = [
|
|
24225
|
+
...new Set(functionRegistry
|
|
24226
|
+
.getAll()
|
|
24227
|
+
.filter((fn) => !fn.hidden)
|
|
24228
|
+
.map((fn) => fn.category)),
|
|
24229
|
+
].filter(isDefined$1);
|
|
24227
24230
|
return categories.sort().map((category, i) => {
|
|
24228
|
-
const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category);
|
|
24231
|
+
const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category && !functions[key].hidden);
|
|
24229
24232
|
return {
|
|
24230
24233
|
name: category,
|
|
24231
24234
|
children: createFormulaFunctions(functionsInCategory),
|
|
@@ -28383,11 +28386,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28383
28386
|
}
|
|
28384
28387
|
.o-cell-is-operator {
|
|
28385
28388
|
margin-bottom: 5px;
|
|
28386
|
-
width: 96%;
|
|
28387
28389
|
}
|
|
28388
28390
|
.o-cell-is-value {
|
|
28389
28391
|
margin-bottom: 5px;
|
|
28390
|
-
width: 96%;
|
|
28391
28392
|
}
|
|
28392
28393
|
.o-color-picker-widget .o-color-picker-button {
|
|
28393
28394
|
pointer-events: all;
|
|
@@ -31089,6 +31090,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31089
31090
|
el?.focus({ preventScroll: true });
|
|
31090
31091
|
}
|
|
31091
31092
|
}, () => [this.env.model.getters.getSelectedFigureId(), this.props.figure.id, this.figureRef.el]);
|
|
31093
|
+
owl.onWillUnmount(() => {
|
|
31094
|
+
this.props.onFigureDeleted();
|
|
31095
|
+
});
|
|
31092
31096
|
}
|
|
31093
31097
|
clickAnchor(dirX, dirY, ev) {
|
|
31094
31098
|
this.props.onClickAnchor(dirX, dirY, ev);
|
|
@@ -31107,6 +31111,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31107
31111
|
this.props.onFigureDeleted();
|
|
31108
31112
|
ev.stopPropagation();
|
|
31109
31113
|
ev.preventDefault();
|
|
31114
|
+
ev.stopPropagation();
|
|
31110
31115
|
break;
|
|
31111
31116
|
case "ArrowDown":
|
|
31112
31117
|
case "ArrowLeft":
|
|
@@ -31127,6 +31132,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31127
31132
|
});
|
|
31128
31133
|
ev.stopPropagation();
|
|
31129
31134
|
ev.preventDefault();
|
|
31135
|
+
ev.stopPropagation();
|
|
31130
31136
|
break;
|
|
31131
31137
|
}
|
|
31132
31138
|
}
|
|
@@ -31794,6 +31800,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31794
31800
|
// -----------------------------------------------------------------------------
|
|
31795
31801
|
css /* scss */ `
|
|
31796
31802
|
.o-formula-assistant {
|
|
31803
|
+
background: #ffffff;
|
|
31797
31804
|
.o-formula-assistant-head {
|
|
31798
31805
|
background-color: #f2f2f2;
|
|
31799
31806
|
padding: 10px;
|
|
@@ -31849,6 +31856,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31849
31856
|
this.assistantState.allowCellSelectionBehind = false;
|
|
31850
31857
|
}, 2000);
|
|
31851
31858
|
}
|
|
31859
|
+
get formulaArgSeparator() {
|
|
31860
|
+
return this.env.model.getters.getLocale().formulaArgSeparator + " ";
|
|
31861
|
+
}
|
|
31852
31862
|
}
|
|
31853
31863
|
|
|
31854
31864
|
const functions$2 = functionRegistry.content;
|
|
@@ -34618,19 +34628,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34618
34628
|
for (let col = left; col <= right; col++) {
|
|
34619
34629
|
const colZone = { left: col, right: col, top: 0, bottom: numberOfRows - 1 };
|
|
34620
34630
|
const { x, width } = this.getters.getVisibleRect(colZone);
|
|
34621
|
-
const colHasFilter = this.getters.doesZonesContainFilter(sheetId, [colZone]);
|
|
34622
34631
|
const isColActive = activeCols.has(col);
|
|
34623
34632
|
const isColSelected = selectedCols.has(col);
|
|
34624
34633
|
if (isColActive) {
|
|
34625
|
-
ctx.fillStyle =
|
|
34634
|
+
ctx.fillStyle = BACKGROUND_HEADER_ACTIVE_COLOR;
|
|
34626
34635
|
}
|
|
34627
34636
|
else if (isColSelected) {
|
|
34628
|
-
ctx.fillStyle =
|
|
34629
|
-
? BACKGROUND_HEADER_SELECTED_FILTER_COLOR
|
|
34630
|
-
: BACKGROUND_HEADER_SELECTED_COLOR;
|
|
34637
|
+
ctx.fillStyle = BACKGROUND_HEADER_SELECTED_COLOR;
|
|
34631
34638
|
}
|
|
34632
34639
|
else {
|
|
34633
|
-
ctx.fillStyle =
|
|
34640
|
+
ctx.fillStyle = BACKGROUND_HEADER_COLOR;
|
|
34634
34641
|
}
|
|
34635
34642
|
ctx.fillRect(x, 0, width, HEADER_HEIGHT);
|
|
34636
34643
|
}
|
|
@@ -34638,19 +34645,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34638
34645
|
for (let row = top; row <= bottom; row++) {
|
|
34639
34646
|
const rowZone = { top: row, bottom: row, left: 0, right: numberOfCols - 1 };
|
|
34640
34647
|
const { y, height } = this.getters.getVisibleRect(rowZone);
|
|
34641
|
-
const rowHasFilter = this.getters.doesZonesContainFilter(sheetId, [rowZone]);
|
|
34642
34648
|
const isRowActive = activeRows.has(row);
|
|
34643
34649
|
const isRowSelected = selectedRows.has(row);
|
|
34644
34650
|
if (isRowActive) {
|
|
34645
|
-
ctx.fillStyle =
|
|
34651
|
+
ctx.fillStyle = BACKGROUND_HEADER_ACTIVE_COLOR;
|
|
34646
34652
|
}
|
|
34647
34653
|
else if (isRowSelected) {
|
|
34648
|
-
ctx.fillStyle =
|
|
34649
|
-
? BACKGROUND_HEADER_SELECTED_FILTER_COLOR
|
|
34650
|
-
: BACKGROUND_HEADER_SELECTED_COLOR;
|
|
34654
|
+
ctx.fillStyle = BACKGROUND_HEADER_SELECTED_COLOR;
|
|
34651
34655
|
}
|
|
34652
34656
|
else {
|
|
34653
|
-
ctx.fillStyle =
|
|
34657
|
+
ctx.fillStyle = BACKGROUND_HEADER_COLOR;
|
|
34654
34658
|
}
|
|
34655
34659
|
ctx.fillRect(0, y, HEADER_WIDTH, height);
|
|
34656
34660
|
}
|
|
@@ -44823,7 +44827,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44823
44827
|
|
|
44824
44828
|
class TablePlugin extends CorePlugin {
|
|
44825
44829
|
static getters = [
|
|
44826
|
-
"doesZonesContainFilter",
|
|
44827
44830
|
"getFilter",
|
|
44828
44831
|
"getFilters",
|
|
44829
44832
|
"getTable",
|
|
@@ -44980,10 +44983,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44980
44983
|
getTablesOverlappingZones(sheetId, zones) {
|
|
44981
44984
|
return this.getTables(sheetId).filter((table) => zones.some((zone) => overlap(table.range.zone, zone)));
|
|
44982
44985
|
}
|
|
44983
|
-
doesZonesContainFilter(sheetId, zones) {
|
|
44984
|
-
return (this.getTablesOverlappingZones(sheetId, zones).filter((table) => table.config.hasFilters)
|
|
44985
|
-
.length > 0);
|
|
44986
|
-
}
|
|
44987
44986
|
getFilterHeaders(sheetId) {
|
|
44988
44987
|
const headers = [];
|
|
44989
44988
|
for (const table of this.getTables(sheetId)) {
|
|
@@ -45850,6 +45849,41 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45850
45849
|
}
|
|
45851
45850
|
}
|
|
45852
45851
|
|
|
45852
|
+
class PositionMap {
|
|
45853
|
+
map = {};
|
|
45854
|
+
set({ sheetId, col, row }, value) {
|
|
45855
|
+
const map = this.map;
|
|
45856
|
+
if (!map[sheetId]) {
|
|
45857
|
+
map[sheetId] = {};
|
|
45858
|
+
}
|
|
45859
|
+
if (!map[sheetId][col]) {
|
|
45860
|
+
map[sheetId][col] = {};
|
|
45861
|
+
}
|
|
45862
|
+
map[sheetId][col][row] = value;
|
|
45863
|
+
}
|
|
45864
|
+
get({ sheetId, col, row }) {
|
|
45865
|
+
return this.map[sheetId]?.[col]?.[row];
|
|
45866
|
+
}
|
|
45867
|
+
has({ sheetId, col, row }) {
|
|
45868
|
+
return this.map[sheetId]?.[col]?.[row] !== undefined;
|
|
45869
|
+
}
|
|
45870
|
+
delete({ sheetId, col, row }) {
|
|
45871
|
+
delete this.map[sheetId]?.[col]?.[row];
|
|
45872
|
+
}
|
|
45873
|
+
keys() {
|
|
45874
|
+
const map = this.map;
|
|
45875
|
+
const keys = [];
|
|
45876
|
+
for (const sheetId in map) {
|
|
45877
|
+
for (const col in map[sheetId]) {
|
|
45878
|
+
for (const row in map[sheetId][col]) {
|
|
45879
|
+
keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
|
|
45880
|
+
}
|
|
45881
|
+
}
|
|
45882
|
+
}
|
|
45883
|
+
return keys;
|
|
45884
|
+
}
|
|
45885
|
+
}
|
|
45886
|
+
|
|
45853
45887
|
function quickselect(arr, k, left, right, compare) {
|
|
45854
45888
|
quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare);
|
|
45855
45889
|
}
|
|
@@ -46576,26 +46610,26 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46576
46610
|
* It uses an R-Tree data structure to efficiently find dependent cells.
|
|
46577
46611
|
*/
|
|
46578
46612
|
class FormulaDependencyGraph {
|
|
46579
|
-
|
|
46580
|
-
dependencies = new
|
|
46613
|
+
createEmptyPositionSet;
|
|
46614
|
+
dependencies = new PositionMap();
|
|
46581
46615
|
rTree;
|
|
46582
|
-
constructor(
|
|
46583
|
-
this.
|
|
46616
|
+
constructor(createEmptyPositionSet, data = []) {
|
|
46617
|
+
this.createEmptyPositionSet = createEmptyPositionSet;
|
|
46584
46618
|
this.rTree = new SpreadsheetRTree(data);
|
|
46585
46619
|
}
|
|
46586
|
-
removeAllDependencies(
|
|
46587
|
-
const ranges = this.dependencies.get(
|
|
46620
|
+
removeAllDependencies(formulaPosition) {
|
|
46621
|
+
const ranges = this.dependencies.get(formulaPosition);
|
|
46588
46622
|
if (!ranges) {
|
|
46589
46623
|
return;
|
|
46590
46624
|
}
|
|
46591
46625
|
for (const range of ranges) {
|
|
46592
46626
|
this.rTree.remove(range);
|
|
46593
46627
|
}
|
|
46594
|
-
this.dependencies.delete(
|
|
46628
|
+
this.dependencies.delete(formulaPosition);
|
|
46595
46629
|
}
|
|
46596
|
-
addDependencies(
|
|
46630
|
+
addDependencies(formulaPosition, dependencies) {
|
|
46597
46631
|
const rTreeItems = dependencies.map(({ sheetId, zone }) => ({
|
|
46598
|
-
data:
|
|
46632
|
+
data: formulaPosition,
|
|
46599
46633
|
boundingBox: {
|
|
46600
46634
|
zone,
|
|
46601
46635
|
sheetId,
|
|
@@ -46604,12 +46638,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46604
46638
|
for (const item of rTreeItems) {
|
|
46605
46639
|
this.rTree.insert(item);
|
|
46606
46640
|
}
|
|
46607
|
-
const existingDependencies = this.dependencies.get(
|
|
46641
|
+
const existingDependencies = this.dependencies.get(formulaPosition);
|
|
46608
46642
|
if (existingDependencies) {
|
|
46609
46643
|
existingDependencies.push(...rTreeItems);
|
|
46610
46644
|
}
|
|
46611
46645
|
else {
|
|
46612
|
-
this.dependencies.set(
|
|
46646
|
+
this.dependencies.set(formulaPosition, rTreeItems);
|
|
46613
46647
|
}
|
|
46614
46648
|
}
|
|
46615
46649
|
/**
|
|
@@ -46618,23 +46652,194 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46618
46652
|
* This is called a topological ordering (excluding cycles)
|
|
46619
46653
|
*/
|
|
46620
46654
|
getCellsDependingOn(ranges) {
|
|
46621
|
-
const visited =
|
|
46655
|
+
const visited = this.createEmptyPositionSet();
|
|
46622
46656
|
const queue = Array.from(ranges).reverse();
|
|
46623
46657
|
while (queue.length > 0) {
|
|
46624
46658
|
const range = queue.pop();
|
|
46625
|
-
visited.addMany(
|
|
46626
|
-
const
|
|
46627
|
-
for (const
|
|
46628
|
-
if (!visited.has(
|
|
46629
|
-
queue.push(
|
|
46659
|
+
visited.addMany(positions(range.zone).map((position) => ({ sheetId: range.sheetId, ...position })));
|
|
46660
|
+
const impactedPositions = this.rTree.search(range).map((dep) => dep.data);
|
|
46661
|
+
for (const position of impactedPositions) {
|
|
46662
|
+
if (!visited.has(position)) {
|
|
46663
|
+
queue.push({ sheetId: position.sheetId, zone: positionToZone(position) });
|
|
46630
46664
|
}
|
|
46631
46665
|
}
|
|
46632
46666
|
}
|
|
46633
|
-
visited.deleteMany(ranges.flatMap((r) =>
|
|
46667
|
+
visited.deleteMany(ranges.flatMap((r) => positions(r.zone).map((position) => ({ sheetId: r.sheetId, ...position }))));
|
|
46634
46668
|
return visited;
|
|
46635
46669
|
}
|
|
46636
46670
|
}
|
|
46637
46671
|
|
|
46672
|
+
/**
|
|
46673
|
+
* Implements a fixed-sized grid or 2D matrix of bits.
|
|
46674
|
+
* based on https://github.com/zandaqo/structurae
|
|
46675
|
+
*
|
|
46676
|
+
* The grid is implemented as a 1D array of 32-bit integers, where each bit represents a cell in the grid.
|
|
46677
|
+
* It follows row-major order, with each row stored consecutively in 32-bit blocks.
|
|
46678
|
+
* Pads the number of columns to the next power of 2 to allow quick lookups with bitwise operations.
|
|
46679
|
+
*
|
|
46680
|
+
* Key terminology:
|
|
46681
|
+
* - bucket: Index of an item in the Uint32Array, a 32-bit integer.
|
|
46682
|
+
* - bitPosition: The position of a bit within the bucket 32-bit integer.
|
|
46683
|
+
*/
|
|
46684
|
+
class BinaryGrid extends Uint32Array {
|
|
46685
|
+
columnOffset = 0;
|
|
46686
|
+
cols = 0;
|
|
46687
|
+
rows = 0;
|
|
46688
|
+
/**
|
|
46689
|
+
* Creates a binary grid of specified dimensions.
|
|
46690
|
+
*/
|
|
46691
|
+
static create(rows, columns) {
|
|
46692
|
+
const columnOffset = log2Ceil(columns);
|
|
46693
|
+
const length = (rows << columnOffset) >> 5;
|
|
46694
|
+
const grid = new this(length + 1);
|
|
46695
|
+
grid.columnOffset = columnOffset;
|
|
46696
|
+
grid.cols = columns;
|
|
46697
|
+
grid.rows = rows;
|
|
46698
|
+
return grid;
|
|
46699
|
+
}
|
|
46700
|
+
/**
|
|
46701
|
+
* Returns the bit at given coordinates.
|
|
46702
|
+
*/
|
|
46703
|
+
getValue(position) {
|
|
46704
|
+
const [bucket, bitPosition] = this.getCoordinates(position);
|
|
46705
|
+
return ((this[bucket] >> bitPosition) & 1);
|
|
46706
|
+
}
|
|
46707
|
+
/**
|
|
46708
|
+
* Sets the bit at given coordinates.
|
|
46709
|
+
*/
|
|
46710
|
+
setValue(position, value) {
|
|
46711
|
+
const [bucket, bitPosition] = this.getCoordinates(position);
|
|
46712
|
+
const currentValue = (this[bucket] >> bitPosition) & 1;
|
|
46713
|
+
const hasBeenInserted = currentValue === 0 && value === 1;
|
|
46714
|
+
this[bucket] = (this[bucket] & ~(1 << bitPosition)) | (value << bitPosition);
|
|
46715
|
+
return hasBeenInserted;
|
|
46716
|
+
// Let's breakdown of the above line:
|
|
46717
|
+
// with an example with a 4-bit integer (instead of 32-bit).
|
|
46718
|
+
//
|
|
46719
|
+
// Let's say we want to set the bit at position 2 to 1 and the existing
|
|
46720
|
+
// bit sequence this[bucket] is 1001. The final bit sequence should be 1101.
|
|
46721
|
+
//
|
|
46722
|
+
// First, we clear the bit at position 2 by AND-ing this[bucket] with a
|
|
46723
|
+
// mask having all 1s except a 0 at the bit position (~ (1 << bitPosition)).
|
|
46724
|
+
// 1 << bitPosition is 0100 (shifting 0001 to the left by 2)
|
|
46725
|
+
// Inverting the bits with ~ gives the final mask ~(1 << bitPosition): 1011
|
|
46726
|
+
//
|
|
46727
|
+
// Then, we shift the value by the bit position (value << bitPosition: 0100)
|
|
46728
|
+
// and OR the result with the previous step's result:
|
|
46729
|
+
// (1001 & 1011) | 0100 = 1101
|
|
46730
|
+
}
|
|
46731
|
+
isEmpty() {
|
|
46732
|
+
return !this.some((bucket) => bucket !== 0);
|
|
46733
|
+
}
|
|
46734
|
+
fillAllPositions() {
|
|
46735
|
+
const thirtyTwoOnes = -1 >>> 0; // same as 2 ** 32 - 1, a 32-bit number with all bits set to 1
|
|
46736
|
+
this.fill(thirtyTwoOnes);
|
|
46737
|
+
}
|
|
46738
|
+
clear() {
|
|
46739
|
+
this.fill(0);
|
|
46740
|
+
}
|
|
46741
|
+
getCoordinates(position) {
|
|
46742
|
+
const { row, col } = position;
|
|
46743
|
+
const index = (row << this.columnOffset) + col;
|
|
46744
|
+
const bucket = index >> 5;
|
|
46745
|
+
return [bucket, index - (bucket << 5)];
|
|
46746
|
+
}
|
|
46747
|
+
}
|
|
46748
|
+
function log2Ceil(value) {
|
|
46749
|
+
// A faster version of Math.ceil(Math.log2(value)).
|
|
46750
|
+
if (value === 0) {
|
|
46751
|
+
return -Infinity;
|
|
46752
|
+
}
|
|
46753
|
+
else if (value < 0) {
|
|
46754
|
+
return NaN;
|
|
46755
|
+
}
|
|
46756
|
+
// --value handles the case where value is a power of 2
|
|
46757
|
+
return 32 - Math.clz32(--value);
|
|
46758
|
+
}
|
|
46759
|
+
|
|
46760
|
+
class PositionSet {
|
|
46761
|
+
sheets = {};
|
|
46762
|
+
/**
|
|
46763
|
+
* List of positions in the order they were inserted.
|
|
46764
|
+
*/
|
|
46765
|
+
insertions = [];
|
|
46766
|
+
maxSize = 0;
|
|
46767
|
+
constructor(sheetSizes) {
|
|
46768
|
+
for (const sheetId in sheetSizes) {
|
|
46769
|
+
const cols = sheetSizes[sheetId].cols;
|
|
46770
|
+
const rows = sheetSizes[sheetId].rows;
|
|
46771
|
+
this.maxSize += cols * rows;
|
|
46772
|
+
this.sheets[sheetId] = BinaryGrid.create(rows, cols);
|
|
46773
|
+
}
|
|
46774
|
+
}
|
|
46775
|
+
add(position) {
|
|
46776
|
+
const hasBeenInserted = this.sheets[position.sheetId].setValue(position, 1);
|
|
46777
|
+
if (hasBeenInserted) {
|
|
46778
|
+
this.insertions.push(position);
|
|
46779
|
+
}
|
|
46780
|
+
}
|
|
46781
|
+
addMany(positions) {
|
|
46782
|
+
for (const position of positions) {
|
|
46783
|
+
this.add(position);
|
|
46784
|
+
}
|
|
46785
|
+
}
|
|
46786
|
+
delete(position) {
|
|
46787
|
+
this.sheets[position.sheetId].setValue(position, 0);
|
|
46788
|
+
}
|
|
46789
|
+
deleteMany(positions) {
|
|
46790
|
+
for (const position of positions) {
|
|
46791
|
+
this.delete(position);
|
|
46792
|
+
}
|
|
46793
|
+
}
|
|
46794
|
+
has(position) {
|
|
46795
|
+
return this.sheets[position.sheetId].getValue(position) === 1;
|
|
46796
|
+
}
|
|
46797
|
+
clear() {
|
|
46798
|
+
const insertions = this.insertions;
|
|
46799
|
+
this.insertions = [];
|
|
46800
|
+
for (const sheetId in this.sheets) {
|
|
46801
|
+
this.sheets[sheetId].clear();
|
|
46802
|
+
}
|
|
46803
|
+
return insertions;
|
|
46804
|
+
}
|
|
46805
|
+
isEmpty() {
|
|
46806
|
+
if (this.insertions.length === 0) {
|
|
46807
|
+
return true;
|
|
46808
|
+
}
|
|
46809
|
+
for (const sheetId in this.sheets) {
|
|
46810
|
+
if (!this.sheets[sheetId].isEmpty()) {
|
|
46811
|
+
return false;
|
|
46812
|
+
}
|
|
46813
|
+
}
|
|
46814
|
+
return true;
|
|
46815
|
+
}
|
|
46816
|
+
fillAllPositions() {
|
|
46817
|
+
this.insertions = new Array(this.maxSize);
|
|
46818
|
+
let index = 0;
|
|
46819
|
+
for (const sheetId in this.sheets) {
|
|
46820
|
+
const grid = this.sheets[sheetId];
|
|
46821
|
+
grid.fillAllPositions();
|
|
46822
|
+
for (let i = 0; i < grid.rows; i++) {
|
|
46823
|
+
for (let j = 0; j < grid.cols; j++) {
|
|
46824
|
+
this.insertions[index++] = { sheetId, row: i, col: j };
|
|
46825
|
+
}
|
|
46826
|
+
}
|
|
46827
|
+
}
|
|
46828
|
+
}
|
|
46829
|
+
/**
|
|
46830
|
+
* Iterate over the positions in the order of insertion.
|
|
46831
|
+
* Note that the same position may be yielded multiple times if the value was added
|
|
46832
|
+
* to the set then removed and then added again.
|
|
46833
|
+
*/
|
|
46834
|
+
*[Symbol.iterator]() {
|
|
46835
|
+
for (const position of this.insertions) {
|
|
46836
|
+
if (this.sheets[position.sheetId].getValue(position) === 1) {
|
|
46837
|
+
yield position;
|
|
46838
|
+
}
|
|
46839
|
+
}
|
|
46840
|
+
}
|
|
46841
|
+
}
|
|
46842
|
+
|
|
46638
46843
|
/**
|
|
46639
46844
|
* Contains, for each cell, the array
|
|
46640
46845
|
* formulas that could potentially spread on it
|
|
@@ -46648,6 +46853,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46648
46853
|
*
|
|
46649
46854
|
*/
|
|
46650
46855
|
class SpreadingRelation {
|
|
46856
|
+
createEmptyPositionSet;
|
|
46651
46857
|
/**
|
|
46652
46858
|
* Internal structure:
|
|
46653
46859
|
* For something like
|
|
@@ -46676,39 +46882,42 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46676
46882
|
* - (B1) --> (B2, B3, B4) meaning B1 spreads on B2, B3 and B4
|
|
46677
46883
|
*
|
|
46678
46884
|
*/
|
|
46679
|
-
resultsToArrayFormulas = new
|
|
46680
|
-
arrayFormulasToResults = new
|
|
46681
|
-
|
|
46682
|
-
|
|
46885
|
+
resultsToArrayFormulas = new PositionMap();
|
|
46886
|
+
arrayFormulasToResults = new PositionMap();
|
|
46887
|
+
constructor(createEmptyPositionSet) {
|
|
46888
|
+
this.createEmptyPositionSet = createEmptyPositionSet;
|
|
46889
|
+
}
|
|
46890
|
+
getFormulaPositionsSpreadingOn(resultPosition) {
|
|
46891
|
+
return this.resultsToArrayFormulas.get(resultPosition) || EMPTY_ARRAY;
|
|
46683
46892
|
}
|
|
46684
|
-
|
|
46685
|
-
return this.arrayFormulasToResults.get(
|
|
46893
|
+
getArrayResultPositions(formulasPosition) {
|
|
46894
|
+
return this.arrayFormulasToResults.get(formulasPosition) || EMPTY_ARRAY;
|
|
46686
46895
|
}
|
|
46687
46896
|
/**
|
|
46688
46897
|
* Remove a node, also remove it from other nodes adjacency list
|
|
46689
46898
|
*/
|
|
46690
|
-
removeNode(
|
|
46691
|
-
this.resultsToArrayFormulas.delete(
|
|
46692
|
-
this.arrayFormulasToResults.delete(
|
|
46899
|
+
removeNode(position) {
|
|
46900
|
+
this.resultsToArrayFormulas.delete(position);
|
|
46901
|
+
this.arrayFormulasToResults.delete(position);
|
|
46693
46902
|
}
|
|
46694
46903
|
/**
|
|
46695
46904
|
* Create a spreading relation between two cells
|
|
46696
46905
|
*/
|
|
46697
|
-
addRelation({
|
|
46698
|
-
if (!this.resultsToArrayFormulas.has(
|
|
46699
|
-
this.resultsToArrayFormulas.set(
|
|
46906
|
+
addRelation({ arrayFormulaPosition, resultPosition, }) {
|
|
46907
|
+
if (!this.resultsToArrayFormulas.has(resultPosition)) {
|
|
46908
|
+
this.resultsToArrayFormulas.set(resultPosition, this.createEmptyPositionSet());
|
|
46700
46909
|
}
|
|
46701
|
-
this.resultsToArrayFormulas.get(
|
|
46702
|
-
if (!this.arrayFormulasToResults.has(
|
|
46703
|
-
this.arrayFormulasToResults.set(
|
|
46910
|
+
this.resultsToArrayFormulas.get(resultPosition)?.add(arrayFormulaPosition);
|
|
46911
|
+
if (!this.arrayFormulasToResults.has(arrayFormulaPosition)) {
|
|
46912
|
+
this.arrayFormulasToResults.set(arrayFormulaPosition, this.createEmptyPositionSet());
|
|
46704
46913
|
}
|
|
46705
|
-
this.arrayFormulasToResults.get(
|
|
46914
|
+
this.arrayFormulasToResults.get(arrayFormulaPosition)?.add(resultPosition);
|
|
46706
46915
|
}
|
|
46707
|
-
hasArrayFormulaResult(
|
|
46708
|
-
return this.resultsToArrayFormulas.has(
|
|
46916
|
+
hasArrayFormulaResult(position) {
|
|
46917
|
+
return this.resultsToArrayFormulas.has(position);
|
|
46709
46918
|
}
|
|
46710
|
-
isArrayFormula(
|
|
46711
|
-
return this.arrayFormulasToResults.has(
|
|
46919
|
+
isArrayFormula(position) {
|
|
46920
|
+
return this.arrayFormulasToResults.has(position);
|
|
46712
46921
|
}
|
|
46713
46922
|
}
|
|
46714
46923
|
const EMPTY_ARRAY = [];
|
|
@@ -46720,50 +46929,41 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46720
46929
|
context;
|
|
46721
46930
|
getters;
|
|
46722
46931
|
compilationParams;
|
|
46723
|
-
|
|
46724
|
-
|
|
46725
|
-
|
|
46726
|
-
|
|
46727
|
-
spreadingRelations = new SpreadingRelation();
|
|
46932
|
+
evaluatedCells = new PositionMap();
|
|
46933
|
+
formulaDependencies = lazy(new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this)));
|
|
46934
|
+
blockedArrayFormulas = new PositionSet({});
|
|
46935
|
+
spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
|
|
46728
46936
|
constructor(context, getters) {
|
|
46729
46937
|
this.context = context;
|
|
46730
46938
|
this.getters = getters;
|
|
46731
46939
|
this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
|
|
46732
46940
|
}
|
|
46733
46941
|
getEvaluatedCell(position) {
|
|
46734
|
-
return this.evaluatedCells.get(
|
|
46942
|
+
return this.evaluatedCells.get(position) || EMPTY_CELL;
|
|
46735
46943
|
}
|
|
46736
46944
|
getSpreadPositionsOf(position) {
|
|
46737
|
-
|
|
46738
|
-
if (!this.spreadingRelations.isArrayFormula(positionId)) {
|
|
46945
|
+
if (!this.spreadingRelations.isArrayFormula(position)) {
|
|
46739
46946
|
return [];
|
|
46740
46947
|
}
|
|
46741
|
-
return Array.from(this.spreadingRelations.
|
|
46742
|
-
}
|
|
46743
|
-
getArrayFormulaSpreadingOn(position) {
|
|
46744
|
-
const positionId = this.encoder.encode(position);
|
|
46745
|
-
const formulaPosition = this.getArrayFormulaSpreadingOnId(positionId);
|
|
46746
|
-
return formulaPosition !== undefined ? this.encoder.decode(formulaPosition) : undefined;
|
|
46948
|
+
return Array.from(this.spreadingRelations.getArrayResultPositions(position));
|
|
46747
46949
|
}
|
|
46748
46950
|
getEvaluatedPositions() {
|
|
46749
|
-
return
|
|
46951
|
+
return this.evaluatedCells.keys();
|
|
46750
46952
|
}
|
|
46751
|
-
|
|
46752
|
-
if (!this.spreadingRelations.hasArrayFormulaResult(
|
|
46953
|
+
getArrayFormulaSpreadingOn(position) {
|
|
46954
|
+
if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
|
|
46753
46955
|
return undefined;
|
|
46754
46956
|
}
|
|
46755
|
-
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(
|
|
46756
|
-
return Array.from(arrayFormulas).find((
|
|
46957
|
+
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
|
|
46958
|
+
return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
|
|
46757
46959
|
}
|
|
46758
46960
|
updateDependencies(position) {
|
|
46759
|
-
|
|
46760
|
-
this.
|
|
46761
|
-
|
|
46762
|
-
this.formulaDependencies().addDependencies(positionId, dependencies);
|
|
46961
|
+
this.formulaDependencies().removeAllDependencies(position);
|
|
46962
|
+
const dependencies = this.getDirectDependencies(position);
|
|
46963
|
+
this.formulaDependencies().addDependencies(position, dependencies);
|
|
46763
46964
|
}
|
|
46764
46965
|
addDependencies(position, dependencies) {
|
|
46765
|
-
|
|
46766
|
-
this.formulaDependencies().addDependencies(positionId, dependencies);
|
|
46966
|
+
this.formulaDependencies().addDependencies(position, dependencies);
|
|
46767
46967
|
}
|
|
46768
46968
|
updateCompilationParameters() {
|
|
46769
46969
|
// rebuild the compilation parameters (with a clean cache)
|
|
@@ -46771,47 +46971,57 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46771
46971
|
this.compilationParams.evalContext.updateDependencies = this.updateDependencies.bind(this);
|
|
46772
46972
|
this.compilationParams.evalContext.addDependencies = this.addDependencies.bind(this);
|
|
46773
46973
|
}
|
|
46974
|
+
createEmptyPositionSet() {
|
|
46975
|
+
const sheetSizes = {};
|
|
46976
|
+
for (const sheetId of this.getters.getSheetIds()) {
|
|
46977
|
+
sheetSizes[sheetId] = {
|
|
46978
|
+
rows: this.getters.getNumberRows(sheetId),
|
|
46979
|
+
cols: this.getters.getNumberCols(sheetId),
|
|
46980
|
+
};
|
|
46981
|
+
}
|
|
46982
|
+
return new PositionSet(sheetSizes);
|
|
46983
|
+
}
|
|
46774
46984
|
evaluateCells(positions) {
|
|
46775
|
-
const
|
|
46776
|
-
|
|
46777
|
-
const
|
|
46778
|
-
cellsToCompute.addMany(this.getCellsDependingOn(
|
|
46779
|
-
cellsToCompute.addMany(
|
|
46780
|
-
cellsToCompute.addMany(this.getCellsDependingOn(
|
|
46985
|
+
const cellsToCompute = this.createEmptyPositionSet();
|
|
46986
|
+
cellsToCompute.addMany(positions);
|
|
46987
|
+
const arrayFormulasPositions = this.getArrayFormulasImpactedByChangesOf(positions);
|
|
46988
|
+
cellsToCompute.addMany(this.getCellsDependingOn(positions));
|
|
46989
|
+
cellsToCompute.addMany(arrayFormulasPositions);
|
|
46990
|
+
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositions));
|
|
46781
46991
|
this.evaluate(cellsToCompute);
|
|
46782
46992
|
}
|
|
46783
|
-
getArrayFormulasImpactedByChangesOf(
|
|
46784
|
-
const
|
|
46785
|
-
for (const
|
|
46786
|
-
const content = this.getCell(
|
|
46787
|
-
const
|
|
46788
|
-
if (
|
|
46993
|
+
getArrayFormulasImpactedByChangesOf(positions) {
|
|
46994
|
+
const impactedPositions = this.createEmptyPositionSet();
|
|
46995
|
+
for (const position of positions) {
|
|
46996
|
+
const content = this.getters.getCell(position)?.content;
|
|
46997
|
+
const arrayFormulaPosition = this.getArrayFormulaSpreadingOn(position);
|
|
46998
|
+
if (arrayFormulaPosition !== undefined) {
|
|
46789
46999
|
// take into account new collisions.
|
|
46790
|
-
|
|
47000
|
+
impactedPositions.add(arrayFormulaPosition);
|
|
46791
47001
|
}
|
|
46792
47002
|
if (!content) {
|
|
46793
47003
|
// The previous content could have blocked some array formulas
|
|
46794
|
-
|
|
47004
|
+
impactedPositions.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(position));
|
|
46795
47005
|
}
|
|
46796
47006
|
}
|
|
46797
|
-
return
|
|
47007
|
+
return impactedPositions;
|
|
46798
47008
|
}
|
|
46799
47009
|
buildDependencyGraph() {
|
|
46800
|
-
this.blockedArrayFormulas =
|
|
46801
|
-
this.spreadingRelations = new SpreadingRelation();
|
|
47010
|
+
this.blockedArrayFormulas = this.createEmptyPositionSet();
|
|
47011
|
+
this.spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
|
|
46802
47012
|
this.formulaDependencies = lazy(() => {
|
|
46803
|
-
const dependencies = [...this.getAllCells()].flatMap((
|
|
46804
|
-
data:
|
|
47013
|
+
const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position).map((range) => ({
|
|
47014
|
+
data: position,
|
|
46805
47015
|
boundingBox: {
|
|
46806
47016
|
zone: range.zone,
|
|
46807
47017
|
sheetId: range.sheetId,
|
|
46808
47018
|
},
|
|
46809
47019
|
})));
|
|
46810
|
-
return new FormulaDependencyGraph(this.
|
|
47020
|
+
return new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this), dependencies);
|
|
46811
47021
|
});
|
|
46812
47022
|
}
|
|
46813
47023
|
evaluateAllCells() {
|
|
46814
|
-
this.evaluatedCells = new
|
|
47024
|
+
this.evaluatedCells = new PositionMap();
|
|
46815
47025
|
this.evaluate(this.getAllCells());
|
|
46816
47026
|
}
|
|
46817
47027
|
evaluateFormula(sheetId, formulaString) {
|
|
@@ -46828,57 +47038,50 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46828
47038
|
return result.value;
|
|
46829
47039
|
}
|
|
46830
47040
|
getAllCells() {
|
|
46831
|
-
const
|
|
46832
|
-
|
|
46833
|
-
|
|
46834
|
-
for (const cellId in cellIds) {
|
|
46835
|
-
positionIds.add(this.encoder.encode(this.getters.getCellPosition(cellId)));
|
|
46836
|
-
}
|
|
46837
|
-
}
|
|
46838
|
-
return positionIds;
|
|
47041
|
+
const positions = this.createEmptyPositionSet();
|
|
47042
|
+
positions.fillAllPositions();
|
|
47043
|
+
return positions;
|
|
46839
47044
|
}
|
|
46840
|
-
getArrayFormulasBlockedByOrSpreadingOn(
|
|
46841
|
-
if (!this.spreadingRelations.hasArrayFormulaResult(
|
|
47045
|
+
getArrayFormulasBlockedByOrSpreadingOn(position) {
|
|
47046
|
+
if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
|
|
46842
47047
|
return [];
|
|
46843
47048
|
}
|
|
46844
|
-
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(
|
|
46845
|
-
const
|
|
46846
|
-
|
|
46847
|
-
|
|
47049
|
+
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
|
|
47050
|
+
const positions = this.createEmptyPositionSet();
|
|
47051
|
+
positions.addMany(arrayFormulas);
|
|
47052
|
+
positions.addMany(this.getCellsDependingOn(arrayFormulas));
|
|
47053
|
+
return positions;
|
|
46848
47054
|
}
|
|
46849
|
-
nextPositionsToUpdate = new
|
|
47055
|
+
nextPositionsToUpdate = new PositionSet({});
|
|
46850
47056
|
cellsBeingComputed = new Set();
|
|
46851
|
-
evaluate(
|
|
47057
|
+
evaluate(positions) {
|
|
46852
47058
|
this.cellsBeingComputed = new Set();
|
|
46853
|
-
this.nextPositionsToUpdate =
|
|
47059
|
+
this.nextPositionsToUpdate = positions;
|
|
46854
47060
|
let currentIteration = 0;
|
|
46855
|
-
while (this.nextPositionsToUpdate.
|
|
47061
|
+
while (!this.nextPositionsToUpdate.isEmpty() && currentIteration++ < MAX_ITERATION) {
|
|
46856
47062
|
this.updateCompilationParameters();
|
|
46857
|
-
const
|
|
46858
|
-
|
|
46859
|
-
|
|
46860
|
-
const cell = positionIds[i];
|
|
46861
|
-
this.evaluatedCells.delete(cell);
|
|
47063
|
+
const positions = this.nextPositionsToUpdate.clear();
|
|
47064
|
+
for (let i = 0; i < positions.length; ++i) {
|
|
47065
|
+
this.evaluatedCells.delete(positions[i]);
|
|
46862
47066
|
}
|
|
46863
|
-
for (let i = 0; i <
|
|
46864
|
-
const
|
|
46865
|
-
|
|
47067
|
+
for (let i = 0; i < positions.length; ++i) {
|
|
47068
|
+
const position = positions[i];
|
|
47069
|
+
const evaluatedCell = this.computeCell(position);
|
|
47070
|
+
if (evaluatedCell !== EMPTY_CELL) {
|
|
47071
|
+
this.evaluatedCells.set(position, evaluatedCell);
|
|
47072
|
+
}
|
|
46866
47073
|
}
|
|
46867
47074
|
}
|
|
46868
47075
|
}
|
|
46869
|
-
|
|
46870
|
-
this.evaluatedCells.
|
|
46871
|
-
}
|
|
46872
|
-
computeCell(positionId) {
|
|
46873
|
-
const evaluation = this.evaluatedCells.get(positionId);
|
|
47076
|
+
computeCell(position) {
|
|
47077
|
+
const evaluation = this.evaluatedCells.get(position);
|
|
46874
47078
|
if (evaluation) {
|
|
46875
47079
|
return evaluation; // already computed
|
|
46876
47080
|
}
|
|
46877
|
-
if (!this.blockedArrayFormulas.has(
|
|
46878
|
-
this.invalidateSpreading(
|
|
47081
|
+
if (!this.blockedArrayFormulas.has(position)) {
|
|
47082
|
+
this.invalidateSpreading(position);
|
|
46879
47083
|
}
|
|
46880
|
-
const
|
|
46881
|
-
const cell = this.getters.getCell(cellPosition);
|
|
47084
|
+
const cell = this.getters.getCell(position);
|
|
46882
47085
|
if (cell === undefined) {
|
|
46883
47086
|
return EMPTY_CELL;
|
|
46884
47087
|
}
|
|
@@ -46890,7 +47093,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46890
47093
|
}
|
|
46891
47094
|
this.cellsBeingComputed.add(cellId);
|
|
46892
47095
|
return cell.isFormula
|
|
46893
|
-
? this.computeFormulaCell(
|
|
47096
|
+
? this.computeFormulaCell(position.sheetId, cell)
|
|
46894
47097
|
: evaluateLiteral(cell.content, localeFormat);
|
|
46895
47098
|
}
|
|
46896
47099
|
catch (e) {
|
|
@@ -46903,10 +47106,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46903
47106
|
}
|
|
46904
47107
|
}
|
|
46905
47108
|
computeAndSave(position) {
|
|
46906
|
-
const
|
|
46907
|
-
|
|
46908
|
-
|
|
46909
|
-
this.setEvaluatedCell(positionId, evaluatedCell);
|
|
47109
|
+
const evaluatedCell = this.computeCell(position);
|
|
47110
|
+
if (!this.evaluatedCells.has(position)) {
|
|
47111
|
+
this.evaluatedCells.set(position, evaluatedCell);
|
|
46910
47112
|
}
|
|
46911
47113
|
return evaluatedCell;
|
|
46912
47114
|
}
|
|
@@ -46944,24 +47146,23 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46944
47146
|
throw new EvaluationError(_t("Result couldn't be automatically expanded. Please insert more columns and rows."));
|
|
46945
47147
|
}
|
|
46946
47148
|
updateSpreadRelation({ sheetId, col, row, }) {
|
|
46947
|
-
const
|
|
47149
|
+
const arrayFormulaPosition = { sheetId, col, row };
|
|
46948
47150
|
return (i, j) => {
|
|
46949
47151
|
const position = { sheetId, col: i + col, row: j + row };
|
|
46950
|
-
|
|
46951
|
-
this.spreadingRelations.addRelation({ resultPositionId, arrayFormulaPositionId });
|
|
47152
|
+
this.spreadingRelations.addRelation({ resultPosition: position, arrayFormulaPosition });
|
|
46952
47153
|
};
|
|
46953
47154
|
}
|
|
46954
|
-
checkCollision(
|
|
46955
|
-
const
|
|
47155
|
+
checkCollision(formulaPosition) {
|
|
47156
|
+
const { sheetId, col, row } = formulaPosition;
|
|
46956
47157
|
return (i, j) => {
|
|
46957
47158
|
const position = { sheetId: sheetId, col: i + col, row: j + row };
|
|
46958
47159
|
const rawCell = this.getters.getCell(position);
|
|
46959
47160
|
if (rawCell?.content ||
|
|
46960
47161
|
this.getters.getEvaluatedCell(position).type !== CellValueType.empty) {
|
|
46961
|
-
this.blockedArrayFormulas.add(
|
|
47162
|
+
this.blockedArrayFormulas.add(formulaPosition);
|
|
46962
47163
|
throw new EvaluationError(_t("Array result was not expanded because it would overwrite data in %s.", toXC(position.col, position.row)));
|
|
46963
47164
|
}
|
|
46964
|
-
this.blockedArrayFormulas.delete(
|
|
47165
|
+
this.blockedArrayFormulas.delete(formulaPosition);
|
|
46965
47166
|
};
|
|
46966
47167
|
}
|
|
46967
47168
|
spreadValues({ sheetId, col, row }, matrixResult) {
|
|
@@ -46969,19 +47170,18 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46969
47170
|
const position = { sheetId, col: i + col, row: j + row };
|
|
46970
47171
|
const cell = this.getters.getCell(position);
|
|
46971
47172
|
const evaluatedCell = createEvaluatedCell(nullValueToZeroValue(matrixResult[i][j]), this.getters.getLocale(), cell);
|
|
46972
|
-
|
|
46973
|
-
this.setEvaluatedCell(positionId, evaluatedCell);
|
|
47173
|
+
this.evaluatedCells.set(position, evaluatedCell);
|
|
46974
47174
|
// check if formula dependencies present in the spread zone
|
|
46975
47175
|
// if so, they need to be recomputed
|
|
46976
|
-
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([
|
|
47176
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([position]));
|
|
46977
47177
|
};
|
|
46978
47178
|
}
|
|
46979
|
-
invalidateSpreading(
|
|
46980
|
-
if (!this.spreadingRelations.isArrayFormula(
|
|
47179
|
+
invalidateSpreading(position) {
|
|
47180
|
+
if (!this.spreadingRelations.isArrayFormula(position)) {
|
|
46981
47181
|
return;
|
|
46982
47182
|
}
|
|
46983
|
-
for (const child of this.spreadingRelations.
|
|
46984
|
-
const content = this.getCell(child)?.content;
|
|
47183
|
+
for (const child of this.spreadingRelations.getArrayResultPositions(position)) {
|
|
47184
|
+
const content = this.getters.getCell(child)?.content;
|
|
46985
47185
|
if (content) {
|
|
46986
47186
|
// there's no point at re-evaluating overlapping array formulas,
|
|
46987
47187
|
// there's still a collision
|
|
@@ -46991,28 +47191,25 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46991
47191
|
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
46992
47192
|
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
46993
47193
|
}
|
|
46994
|
-
this.spreadingRelations.removeNode(
|
|
47194
|
+
this.spreadingRelations.removeNode(position);
|
|
46995
47195
|
}
|
|
46996
47196
|
// ----------------------------------------------------------
|
|
46997
47197
|
// COMMON FUNCTIONALITY
|
|
46998
47198
|
// ----------------------------------------------------------
|
|
46999
|
-
getDirectDependencies(
|
|
47000
|
-
const cell = this.getCell(
|
|
47199
|
+
getDirectDependencies(position) {
|
|
47200
|
+
const cell = this.getters.getCell(position);
|
|
47001
47201
|
if (!cell?.isFormula) {
|
|
47002
47202
|
return [];
|
|
47003
47203
|
}
|
|
47004
47204
|
return cell.compiledFormula.dependencies;
|
|
47005
47205
|
}
|
|
47006
|
-
getCellsDependingOn(
|
|
47206
|
+
getCellsDependingOn(positions) {
|
|
47007
47207
|
const ranges = [];
|
|
47008
|
-
for (const
|
|
47009
|
-
ranges.push(
|
|
47208
|
+
for (const position of positions) {
|
|
47209
|
+
ranges.push({ sheetId: position.sheetId, zone: positionToZone(position) });
|
|
47010
47210
|
}
|
|
47011
47211
|
return this.formulaDependencies().getCellsDependingOn(ranges);
|
|
47012
47212
|
}
|
|
47013
|
-
getCell(positionId) {
|
|
47014
|
-
return this.getters.getCell(this.encoder.decode(positionId));
|
|
47015
|
-
}
|
|
47016
47213
|
}
|
|
47017
47214
|
function forEachSpreadPositionInMatrix(nbColumns, nbRows, callback) {
|
|
47018
47215
|
for (let i = 0; i < nbColumns; ++i) {
|
|
@@ -47038,85 +47235,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47038
47235
|
}
|
|
47039
47236
|
return fPayload;
|
|
47040
47237
|
}
|
|
47041
|
-
/**
|
|
47042
|
-
* Encode (and decode) cell positions { sheetId, col, row }
|
|
47043
|
-
* to a single integer.
|
|
47044
|
-
*
|
|
47045
|
-
* `col` and `row` values are encoded on 21 bits each (max 2^21 = 2_097_152),
|
|
47046
|
-
* An incremental integer id is assigned to each different sheet id, starting at 0.
|
|
47047
|
-
*
|
|
47048
|
-
* e.g.
|
|
47049
|
-
* Given { col: 10, row: 4, sheetId: "abcde" }
|
|
47050
|
-
* we have:
|
|
47051
|
-
* - row "4" encoded on 21 bits: 000000000000000000100
|
|
47052
|
-
* - col "10" encoded on 21 bits: 000000000000000001010
|
|
47053
|
-
* - sheetId: let's say it's the 4th sheetId met, encoded to: 11
|
|
47054
|
-
*
|
|
47055
|
-
* The final encoded value is found by concatenating the 3 bit sequences:
|
|
47056
|
-
*
|
|
47057
|
-
* sheetId: 11
|
|
47058
|
-
* col: 000000000000000001010
|
|
47059
|
-
* row: 000000000000000000100
|
|
47060
|
-
* => 11000000000000000001010000000000000000000100
|
|
47061
|
-
*
|
|
47062
|
-
* this binary sequence is the integer 13194160504836
|
|
47063
|
-
*/
|
|
47064
|
-
class PositionBitsEncoder {
|
|
47065
|
-
sheetMapping = {};
|
|
47066
|
-
inverseSheetMapping = new Map();
|
|
47067
|
-
constructor() {
|
|
47068
|
-
try {
|
|
47069
|
-
// @ts-ignore
|
|
47070
|
-
o_spreadsheet.__DEBUG__ = o_spreadsheet.__DEBUG__ || {};
|
|
47071
|
-
// @ts-ignore
|
|
47072
|
-
o_spreadsheet.__DEBUG__.decodePosition = this.decode.bind(this);
|
|
47073
|
-
// @ts-ignore
|
|
47074
|
-
o_spreadsheet.__DEBUG__.encodePosition = this.encode.bind(this);
|
|
47075
|
-
}
|
|
47076
|
-
catch (error) { }
|
|
47077
|
-
}
|
|
47078
|
-
/**
|
|
47079
|
-
* Encode a cell position to a single integer.
|
|
47080
|
-
*/
|
|
47081
|
-
encode({ sheetId, col, row }) {
|
|
47082
|
-
return (this.encodeSheet(sheetId) << 42n) | (BigInt(col) << 21n) | BigInt(row);
|
|
47083
|
-
}
|
|
47084
|
-
encodeBoundingBox({ sheetId, zone }) {
|
|
47085
|
-
const positions = [];
|
|
47086
|
-
forEachPositionsInZone(zone, (col, row) => {
|
|
47087
|
-
positions.push(this.encode({ sheetId, col, row }));
|
|
47088
|
-
});
|
|
47089
|
-
return positions;
|
|
47090
|
-
}
|
|
47091
|
-
decode(id) {
|
|
47092
|
-
// keep only the last 21 bits by AND-ing the bit sequence with 21 ones
|
|
47093
|
-
const row = Number(id & 2097151n);
|
|
47094
|
-
const col = Number((id >> 21n) & 2097151n);
|
|
47095
|
-
const sheetId = this.decodeSheet(id >> 42n);
|
|
47096
|
-
return { sheetId, col, row };
|
|
47097
|
-
}
|
|
47098
|
-
decodeToBoundingBox(id) {
|
|
47099
|
-
const { sheetId, col, row } = this.decode(id);
|
|
47100
|
-
return { sheetId, zone: { left: col, top: row, right: col, bottom: row } };
|
|
47101
|
-
}
|
|
47102
|
-
encodeSheet(sheetId) {
|
|
47103
|
-
const sheetKey = this.sheetMapping[sheetId];
|
|
47104
|
-
if (sheetKey === undefined) {
|
|
47105
|
-
const newSheetKey = BigInt(Object.keys(this.sheetMapping).length);
|
|
47106
|
-
this.sheetMapping[sheetId] = newSheetKey;
|
|
47107
|
-
this.inverseSheetMapping.set(newSheetKey, sheetId);
|
|
47108
|
-
return newSheetKey;
|
|
47109
|
-
}
|
|
47110
|
-
return sheetKey;
|
|
47111
|
-
}
|
|
47112
|
-
decodeSheet(sheetKey) {
|
|
47113
|
-
const sheetId = this.inverseSheetMapping.get(sheetKey);
|
|
47114
|
-
if (sheetId === undefined) {
|
|
47115
|
-
throw new Error("Sheet id not found");
|
|
47116
|
-
}
|
|
47117
|
-
return sheetId;
|
|
47118
|
-
}
|
|
47119
|
-
}
|
|
47120
47238
|
function updateEvalContextAndExecute(compiledFormula, compilationParams, sheetId, cellId) {
|
|
47121
47239
|
compilationParams.evalContext.__originCellXC = lazy(() => {
|
|
47122
47240
|
if (!cellId) {
|
|
@@ -47263,6 +47381,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47263
47381
|
this.evaluator.updateDependencies(cmd);
|
|
47264
47382
|
}
|
|
47265
47383
|
break;
|
|
47384
|
+
case "DUPLICATE_SHEET":
|
|
47385
|
+
case "CREATE_SHEET":
|
|
47386
|
+
this.shouldRebuildDependenciesGraph = true;
|
|
47387
|
+
break;
|
|
47266
47388
|
case "EVALUATE_CELLS":
|
|
47267
47389
|
this.evaluator.evaluateAllCells();
|
|
47268
47390
|
break;
|
|
@@ -52355,6 +52477,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52355
52477
|
this.gridSelection.zones = this.gridSelection.zones.map((z) => this.getters.expandZone(sheetId, z));
|
|
52356
52478
|
this.gridSelection.anchor.zone = this.getters.expandZone(sheetId, this.gridSelection.anchor.zone);
|
|
52357
52479
|
this.setSelectionMixin(this.gridSelection.anchor, this.gridSelection.zones);
|
|
52480
|
+
this.selectedFigureId = null;
|
|
52358
52481
|
break;
|
|
52359
52482
|
}
|
|
52360
52483
|
/** Any change to the selection has to be reflected in the selection processor. */
|
|
@@ -55973,9 +56096,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55973
56096
|
.text-muted {
|
|
55974
56097
|
color: grey !important;
|
|
55975
56098
|
}
|
|
55976
|
-
button {
|
|
55977
|
-
color: #333;
|
|
55978
|
-
}
|
|
55979
56099
|
.o-disabled {
|
|
55980
56100
|
opacity: 0.4;
|
|
55981
56101
|
pointer: default;
|
|
@@ -56096,17 +56216,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56096
56216
|
}
|
|
56097
56217
|
|
|
56098
56218
|
.o-button {
|
|
56099
|
-
border: 1px solid
|
|
56219
|
+
border: 1px solid;
|
|
56100
56220
|
padding: 0px 20px 0px 20px;
|
|
56101
56221
|
border-radius: 4px;
|
|
56102
56222
|
font-weight: 500;
|
|
56103
56223
|
font-size: 14px;
|
|
56104
56224
|
height: 30px;
|
|
56105
56225
|
line-height: 16px;
|
|
56106
|
-
background: white;
|
|
56107
56226
|
margin-right: 8px;
|
|
56108
|
-
|
|
56109
|
-
|
|
56227
|
+
|
|
56228
|
+
&:not(:hover) {
|
|
56229
|
+
background-color: transparent;
|
|
56110
56230
|
}
|
|
56111
56231
|
|
|
56112
56232
|
&:enabled {
|
|
@@ -56120,6 +56240,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56120
56240
|
&:last-child {
|
|
56121
56241
|
margin-right: 0px;
|
|
56122
56242
|
}
|
|
56243
|
+
|
|
56244
|
+
&.o-button-grey {
|
|
56245
|
+
border-color: lightgrey;
|
|
56246
|
+
background: #ffffff;
|
|
56247
|
+
color: #333;
|
|
56248
|
+
&:hover:enabled {
|
|
56249
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
56250
|
+
}
|
|
56251
|
+
}
|
|
56123
56252
|
}
|
|
56124
56253
|
|
|
56125
56254
|
.o-input {
|
|
@@ -60047,9 +60176,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60047
60176
|
exports.tokenize = tokenize;
|
|
60048
60177
|
|
|
60049
60178
|
|
|
60050
|
-
__info__.version = "17.2.
|
|
60051
|
-
__info__.date = "2024-03-
|
|
60052
|
-
__info__.hash = "
|
|
60179
|
+
__info__.version = "17.2.1";
|
|
60180
|
+
__info__.date = "2024-03-25T09:41:58.737Z";
|
|
60181
|
+
__info__.hash = "f97284c";
|
|
60053
60182
|
|
|
60054
60183
|
|
|
60055
60184
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|