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