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