@odoo/o-spreadsheet 17.0.50 → 17.0.52
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 +252 -157
- package/dist/o-spreadsheet.d.ts +8 -4
- package/dist/o-spreadsheet.esm.js +252 -157
- package/dist/o-spreadsheet.iife.js +252 -157
- package/dist/o-spreadsheet.iife.min.js +272 -254
- package/dist/o_spreadsheet.xml +48 -36
- package/package.json +2 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 17.0.
|
|
6
|
-
* @date 2025-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.0.52
|
|
6
|
+
* @date 2025-03-07T10:30:04.783Z
|
|
7
|
+
* @hash c19cd9a
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -4733,11 +4733,12 @@ class UuidGenerator {
|
|
|
4733
4733
|
if (this.isFastIdStrategy) {
|
|
4734
4734
|
this.fastIdStart++;
|
|
4735
4735
|
return String(this.fastIdStart);
|
|
4736
|
-
//@ts-ignore
|
|
4737
4736
|
}
|
|
4738
|
-
else if (window.crypto
|
|
4739
|
-
|
|
4740
|
-
|
|
4737
|
+
else if (window.crypto) {
|
|
4738
|
+
return "10000000-1000".replace(/[01]/g, (c) => {
|
|
4739
|
+
const n = Number(c);
|
|
4740
|
+
return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
|
|
4741
|
+
});
|
|
4741
4742
|
}
|
|
4742
4743
|
else {
|
|
4743
4744
|
// mainly for jest and other browsers that do not have the crypto functionality
|
|
@@ -4755,11 +4756,12 @@ class UuidGenerator {
|
|
|
4755
4756
|
if (this.isFastIdStrategy) {
|
|
4756
4757
|
this.fastIdStart++;
|
|
4757
4758
|
return String(this.fastIdStart);
|
|
4758
|
-
//@ts-ignore
|
|
4759
4759
|
}
|
|
4760
|
-
else if (window.crypto
|
|
4761
|
-
|
|
4762
|
-
|
|
4760
|
+
else if (window.crypto) {
|
|
4761
|
+
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => {
|
|
4762
|
+
const n = Number(c);
|
|
4763
|
+
return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
|
|
4764
|
+
});
|
|
4763
4765
|
}
|
|
4764
4766
|
else {
|
|
4765
4767
|
// mainly for jest and other browsers that do not have the crypto functionality
|
|
@@ -6212,7 +6214,7 @@ autofillRulesRegistry
|
|
|
6212
6214
|
condition: (cell) => !cell.isFormula &&
|
|
6213
6215
|
evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.text &&
|
|
6214
6216
|
alphaNumericValueRegExp.test(cell.content),
|
|
6215
|
-
generateRule: (cell, cells) => {
|
|
6217
|
+
generateRule: (cell, cells, direction) => {
|
|
6216
6218
|
const numberPostfix = parseInt(cell.content.match(numberPostfixRegExp)[0]);
|
|
6217
6219
|
const prefix = cell.content.match(stringPrefixRegExp)[0];
|
|
6218
6220
|
const numberPostfixLength = cell.content.length - prefix.length;
|
|
@@ -6220,7 +6222,10 @@ autofillRulesRegistry
|
|
|
6220
6222
|
alphaNumericValueRegExp.test(evaluatedCell.value)) // get consecutive alphanumeric cells, no matter what the prefix is
|
|
6221
6223
|
.filter((cell) => prefix === cell.value.toString().match(stringPrefixRegExp)[0])
|
|
6222
6224
|
.map((cell) => parseInt(cell.value.toString().match(numberPostfixRegExp)[0]));
|
|
6223
|
-
|
|
6225
|
+
let increment = calculateIncrementBasedOnGroup(group);
|
|
6226
|
+
if (["up", "left"].includes(direction) && group.length === 1) {
|
|
6227
|
+
increment = -increment;
|
|
6228
|
+
}
|
|
6224
6229
|
return {
|
|
6225
6230
|
type: "ALPHANUMERIC_INCREMENT_MODIFIER",
|
|
6226
6231
|
prefix,
|
|
@@ -6249,9 +6254,12 @@ autofillRulesRegistry
|
|
|
6249
6254
|
.add("increment_number", {
|
|
6250
6255
|
condition: (cell) => !cell.isFormula &&
|
|
6251
6256
|
evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.number,
|
|
6252
|
-
generateRule: (cell, cells) => {
|
|
6257
|
+
generateRule: (cell, cells, direction) => {
|
|
6253
6258
|
const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.number).map((cell) => Number(cell.value));
|
|
6254
|
-
|
|
6259
|
+
let increment = calculateIncrementBasedOnGroup(group);
|
|
6260
|
+
if (["up", "left"].includes(direction) && group.length === 1) {
|
|
6261
|
+
increment = -increment;
|
|
6262
|
+
}
|
|
6255
6263
|
const evaluation = evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE });
|
|
6256
6264
|
return {
|
|
6257
6265
|
type: "INCREMENT_MODIFIER",
|
|
@@ -6985,10 +6993,6 @@ class Popover extends owl.Component {
|
|
|
6985
6993
|
this.currentDisplayValue = newDisplay;
|
|
6986
6994
|
if (!anchor)
|
|
6987
6995
|
return;
|
|
6988
|
-
el.style.top = "";
|
|
6989
|
-
el.style.left = "";
|
|
6990
|
-
el.style["max-height"] = "";
|
|
6991
|
-
el.style["max-width"] = "";
|
|
6992
6996
|
const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
|
|
6993
6997
|
let elDims = {
|
|
6994
6998
|
width: el.getBoundingClientRect().width,
|
|
@@ -9730,7 +9734,7 @@ function createPieChartRuntime(chart, getters) {
|
|
|
9730
9734
|
const dataset = {
|
|
9731
9735
|
label,
|
|
9732
9736
|
data,
|
|
9733
|
-
borderColor: "#FFFFFF",
|
|
9737
|
+
borderColor: chart.background || "#FFFFFF",
|
|
9734
9738
|
backgroundColor,
|
|
9735
9739
|
};
|
|
9736
9740
|
config.data.datasets.push(dataset);
|
|
@@ -26762,25 +26766,21 @@ css /* scss */ `
|
|
|
26762
26766
|
}
|
|
26763
26767
|
}
|
|
26764
26768
|
}
|
|
26769
|
+
}
|
|
26770
|
+
.o-spreadsheet .o-composer-assistant {
|
|
26771
|
+
pointer-events: none;
|
|
26765
26772
|
|
|
26766
|
-
.o-
|
|
26767
|
-
|
|
26768
|
-
|
|
26769
|
-
|
|
26770
|
-
|
|
26771
|
-
|
|
26772
|
-
.o-semi-bold {
|
|
26773
|
-
/** FIXME: to remove in favor of Bootstrap
|
|
26774
|
-
* 'fw-semibold' when we upgrade to Bootstrap 5.2
|
|
26775
|
-
*/
|
|
26776
|
-
font-weight: 600 !important;
|
|
26777
|
-
}
|
|
26773
|
+
.o-semi-bold {
|
|
26774
|
+
/** FIXME: to remove in favor of Bootstrap
|
|
26775
|
+
* 'fw-semibold' when we upgrade to Bootstrap 5.2
|
|
26776
|
+
*/
|
|
26777
|
+
font-weight: 600 !important;
|
|
26778
26778
|
}
|
|
26779
26779
|
}
|
|
26780
26780
|
`;
|
|
26781
26781
|
class Composer extends owl.Component {
|
|
26782
26782
|
static template = "o-spreadsheet-Composer";
|
|
26783
|
-
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
26783
|
+
static components = { TextValueProvider, FunctionDescriptionProvider, Popover };
|
|
26784
26784
|
static defaultProps = {
|
|
26785
26785
|
inputStyle: "",
|
|
26786
26786
|
isDefaultFocus: false,
|
|
@@ -26805,35 +26805,13 @@ class Composer extends owl.Component {
|
|
|
26805
26805
|
argToFocus: 0,
|
|
26806
26806
|
});
|
|
26807
26807
|
compositionActive = false;
|
|
26808
|
-
spreadsheetRect = useSpreadsheetRect();
|
|
26809
26808
|
get assistantStyle() {
|
|
26810
|
-
const composerRect = this.composerRef.el.getBoundingClientRect();
|
|
26811
26809
|
const assistantStyle = {};
|
|
26812
|
-
|
|
26810
|
+
const minWidth = Math.min(getBoundingRectAsPOJO(this.composerRef.el).width || Infinity, ASSISTANT_WIDTH);
|
|
26811
|
+
assistantStyle["min-width"] = `${minWidth}px`;
|
|
26813
26812
|
if (this.autoCompleteState.type === "function") {
|
|
26814
26813
|
assistantStyle.width = `${ASSISTANT_WIDTH}px`;
|
|
26815
26814
|
}
|
|
26816
|
-
if (this.props.delimitation && this.props.rect) {
|
|
26817
|
-
const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
|
|
26818
|
-
const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
|
|
26819
|
-
assistantStyle["max-height"] = `${remainingHeight}px`;
|
|
26820
|
-
if (cellY > remainingHeight) {
|
|
26821
|
-
const availableSpaceAbove = cellY;
|
|
26822
|
-
assistantStyle["max-height"] = `${availableSpaceAbove}px`;
|
|
26823
|
-
// render top
|
|
26824
|
-
// We compensate 2 px of margin on the assistant style + 1px for design reasons
|
|
26825
|
-
assistantStyle.top = `-3px`;
|
|
26826
|
-
assistantStyle.transform = `translate(0, -100%)`;
|
|
26827
|
-
}
|
|
26828
|
-
if (cellX + ASSISTANT_WIDTH > this.props.delimitation.width) {
|
|
26829
|
-
// render left
|
|
26830
|
-
assistantStyle.right = `0px`;
|
|
26831
|
-
}
|
|
26832
|
-
}
|
|
26833
|
-
if (this.props.focus === "contentFocus" &&
|
|
26834
|
-
composerRect.left + ASSISTANT_WIDTH > this.spreadsheetRect.width) {
|
|
26835
|
-
assistantStyle.right = "0px";
|
|
26836
|
-
}
|
|
26837
26815
|
return cssPropertiesToCss(assistantStyle);
|
|
26838
26816
|
}
|
|
26839
26817
|
// we can't allow input events to be triggered while we remove and add back the content of the composer in processContent
|
|
@@ -27082,7 +27060,7 @@ class Composer extends owl.Component {
|
|
|
27082
27060
|
this.autoCompleteState.selectedIndex = 0;
|
|
27083
27061
|
}
|
|
27084
27062
|
updateAutoCompleteIndex(index) {
|
|
27085
|
-
this.autoCompleteState.selectedIndex =
|
|
27063
|
+
this.autoCompleteState.selectedIndex = index;
|
|
27086
27064
|
}
|
|
27087
27065
|
/**
|
|
27088
27066
|
* This is required to ensure the content helper selection is
|
|
@@ -27370,11 +27348,16 @@ class Composer extends owl.Component {
|
|
|
27370
27348
|
this.autoCompleteState.values = values.map((value) => ({ text: value, description: "" }));
|
|
27371
27349
|
this.autoCompleteState.getHtmlContent = (value) => [{ value }];
|
|
27372
27350
|
}
|
|
27351
|
+
get popoverProps() {
|
|
27352
|
+
return {
|
|
27353
|
+
anchorRect: getBoundingRectAsPOJO(this.composerRef.el),
|
|
27354
|
+
positioning: "BottomLeft",
|
|
27355
|
+
verticalOffset: 0,
|
|
27356
|
+
};
|
|
27357
|
+
}
|
|
27373
27358
|
}
|
|
27374
27359
|
Composer.props = {
|
|
27375
27360
|
inputStyle: { type: String, optional: true },
|
|
27376
|
-
rect: { type: Object, optional: true },
|
|
27377
|
-
delimitation: { type: Object, optional: true },
|
|
27378
27361
|
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27379
27362
|
onComposerCellFocused: { type: Function, optional: true },
|
|
27380
27363
|
onComposerContentFocused: Function,
|
|
@@ -27444,13 +27427,7 @@ class GridComposer extends owl.Component {
|
|
|
27444
27427
|
});
|
|
27445
27428
|
}
|
|
27446
27429
|
get composerProps() {
|
|
27447
|
-
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
27448
27430
|
return {
|
|
27449
|
-
rect: { ...this.rect },
|
|
27450
|
-
delimitation: {
|
|
27451
|
-
width,
|
|
27452
|
-
height,
|
|
27453
|
-
},
|
|
27454
27431
|
focus: this.props.focus,
|
|
27455
27432
|
isDefaultFocus: true,
|
|
27456
27433
|
onComposerContentFocused: this.props.onComposerContentFocused,
|
|
@@ -28992,6 +28969,9 @@ class ColResizer extends AbstractResizer {
|
|
|
28992
28969
|
this.MAX_SIZE_MARGIN = 90;
|
|
28993
28970
|
this.MIN_ELEMENT_SIZE = MIN_COL_WIDTH;
|
|
28994
28971
|
}
|
|
28972
|
+
get sheetId() {
|
|
28973
|
+
return this.env.model.getters.getActiveSheetId();
|
|
28974
|
+
}
|
|
28995
28975
|
_getEvOffset(ev) {
|
|
28996
28976
|
return ev.offsetX;
|
|
28997
28977
|
}
|
|
@@ -29014,10 +28994,10 @@ class ColResizer extends AbstractResizer {
|
|
|
29014
28994
|
return this.env.model.getters.getEdgeScrollCol(position, position, position);
|
|
29015
28995
|
}
|
|
29016
28996
|
_getDimensionsInViewport(index) {
|
|
29017
|
-
return this.env.model.getters.getColDimensionsInViewport(this.
|
|
28997
|
+
return this.env.model.getters.getColDimensionsInViewport(this.sheetId, index);
|
|
29018
28998
|
}
|
|
29019
28999
|
_getElementSize(index) {
|
|
29020
|
-
return this.env.model.getters.getColSize(this.
|
|
29000
|
+
return this.env.model.getters.getColSize(this.sheetId, index);
|
|
29021
29001
|
}
|
|
29022
29002
|
_getMaxSize() {
|
|
29023
29003
|
return this.colResizerRef.el.clientWidth;
|
|
@@ -29028,7 +29008,7 @@ class ColResizer extends AbstractResizer {
|
|
|
29028
29008
|
const cols = this.env.model.getters.getActiveCols();
|
|
29029
29009
|
this.env.model.dispatch("RESIZE_COLUMNS_ROWS", {
|
|
29030
29010
|
dimension: "COL",
|
|
29031
|
-
sheetId: this.
|
|
29011
|
+
sheetId: this.sheetId,
|
|
29032
29012
|
elements: cols.has(index) ? [...cols] : [index],
|
|
29033
29013
|
size,
|
|
29034
29014
|
});
|
|
@@ -29041,7 +29021,7 @@ class ColResizer extends AbstractResizer {
|
|
|
29041
29021
|
elements.push(colIndex);
|
|
29042
29022
|
}
|
|
29043
29023
|
const result = this.env.model.dispatch("MOVE_COLUMNS_ROWS", {
|
|
29044
|
-
sheetId: this.
|
|
29024
|
+
sheetId: this.sheetId,
|
|
29045
29025
|
dimension: "COL",
|
|
29046
29026
|
base: this.state.base,
|
|
29047
29027
|
elements,
|
|
@@ -29060,7 +29040,7 @@ class ColResizer extends AbstractResizer {
|
|
|
29060
29040
|
_fitElementSize(index) {
|
|
29061
29041
|
const cols = this.env.model.getters.getActiveCols();
|
|
29062
29042
|
this.env.model.dispatch("AUTORESIZE_COLUMNS", {
|
|
29063
|
-
sheetId: this.
|
|
29043
|
+
sheetId: this.sheetId,
|
|
29064
29044
|
cols: cols.has(index) ? [...cols] : [index],
|
|
29065
29045
|
});
|
|
29066
29046
|
}
|
|
@@ -29071,7 +29051,7 @@ class ColResizer extends AbstractResizer {
|
|
|
29071
29051
|
return this.env.model.getters.getActiveCols();
|
|
29072
29052
|
}
|
|
29073
29053
|
_getPreviousVisibleElement(index) {
|
|
29074
|
-
const sheetId = this.
|
|
29054
|
+
const sheetId = this.sheetId;
|
|
29075
29055
|
let row;
|
|
29076
29056
|
for (row = index - 1; row >= 0; row--) {
|
|
29077
29057
|
if (!this.env.model.getters.isColHidden(sheetId, row)) {
|
|
@@ -29082,7 +29062,7 @@ class ColResizer extends AbstractResizer {
|
|
|
29082
29062
|
}
|
|
29083
29063
|
unhide(hiddenElements) {
|
|
29084
29064
|
this.env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
|
|
29085
|
-
sheetId: this.
|
|
29065
|
+
sheetId: this.sheetId,
|
|
29086
29066
|
elements: hiddenElements,
|
|
29087
29067
|
dimension: "COL",
|
|
29088
29068
|
});
|
|
@@ -29098,7 +29078,7 @@ css /* scss */ `
|
|
|
29098
29078
|
left: 0;
|
|
29099
29079
|
right: 0;
|
|
29100
29080
|
width: ${HEADER_WIDTH}px;
|
|
29101
|
-
height: 100
|
|
29081
|
+
height: calc(100% - ${HEADER_HEIGHT + SCROLLBAR_WIDTH}px);
|
|
29102
29082
|
&.o-dragging {
|
|
29103
29083
|
cursor: grabbing;
|
|
29104
29084
|
}
|
|
@@ -29166,6 +29146,9 @@ class RowResizer extends AbstractResizer {
|
|
|
29166
29146
|
this.MIN_ELEMENT_SIZE = MIN_ROW_HEIGHT;
|
|
29167
29147
|
}
|
|
29168
29148
|
rowResizerRef;
|
|
29149
|
+
get sheetId() {
|
|
29150
|
+
return this.env.model.getters.getActiveSheetId();
|
|
29151
|
+
}
|
|
29169
29152
|
_getEvOffset(ev) {
|
|
29170
29153
|
return ev.offsetY;
|
|
29171
29154
|
}
|
|
@@ -29188,10 +29171,10 @@ class RowResizer extends AbstractResizer {
|
|
|
29188
29171
|
return this.env.model.getters.getEdgeScrollRow(position, position, position);
|
|
29189
29172
|
}
|
|
29190
29173
|
_getDimensionsInViewport(index) {
|
|
29191
|
-
return this.env.model.getters.getRowDimensionsInViewport(this.
|
|
29174
|
+
return this.env.model.getters.getRowDimensionsInViewport(this.sheetId, index);
|
|
29192
29175
|
}
|
|
29193
29176
|
_getElementSize(index) {
|
|
29194
|
-
return this.env.model.getters.getRowSize(this.
|
|
29177
|
+
return this.env.model.getters.getRowSize(this.sheetId, index);
|
|
29195
29178
|
}
|
|
29196
29179
|
_getMaxSize() {
|
|
29197
29180
|
return this.rowResizerRef.el.clientHeight;
|
|
@@ -29202,7 +29185,7 @@ class RowResizer extends AbstractResizer {
|
|
|
29202
29185
|
const rows = this.env.model.getters.getActiveRows();
|
|
29203
29186
|
this.env.model.dispatch("RESIZE_COLUMNS_ROWS", {
|
|
29204
29187
|
dimension: "ROW",
|
|
29205
|
-
sheetId: this.
|
|
29188
|
+
sheetId: this.sheetId,
|
|
29206
29189
|
elements: rows.has(index) ? [...rows] : [index],
|
|
29207
29190
|
size,
|
|
29208
29191
|
});
|
|
@@ -29215,7 +29198,7 @@ class RowResizer extends AbstractResizer {
|
|
|
29215
29198
|
elements.push(rowIndex);
|
|
29216
29199
|
}
|
|
29217
29200
|
const result = this.env.model.dispatch("MOVE_COLUMNS_ROWS", {
|
|
29218
|
-
sheetId: this.
|
|
29201
|
+
sheetId: this.sheetId,
|
|
29219
29202
|
dimension: "ROW",
|
|
29220
29203
|
base: this.state.base,
|
|
29221
29204
|
elements,
|
|
@@ -29234,7 +29217,7 @@ class RowResizer extends AbstractResizer {
|
|
|
29234
29217
|
_fitElementSize(index) {
|
|
29235
29218
|
const rows = this.env.model.getters.getActiveRows();
|
|
29236
29219
|
this.env.model.dispatch("AUTORESIZE_ROWS", {
|
|
29237
|
-
sheetId: this.
|
|
29220
|
+
sheetId: this.sheetId,
|
|
29238
29221
|
rows: rows.has(index) ? [...rows] : [index],
|
|
29239
29222
|
});
|
|
29240
29223
|
}
|
|
@@ -29245,7 +29228,7 @@ class RowResizer extends AbstractResizer {
|
|
|
29245
29228
|
return this.env.model.getters.getActiveRows();
|
|
29246
29229
|
}
|
|
29247
29230
|
_getPreviousVisibleElement(index) {
|
|
29248
|
-
const sheetId = this.
|
|
29231
|
+
const sheetId = this.sheetId;
|
|
29249
29232
|
let row;
|
|
29250
29233
|
for (row = index - 1; row >= 0; row--) {
|
|
29251
29234
|
if (!this.env.model.getters.isRowHidden(sheetId, row)) {
|
|
@@ -29256,7 +29239,7 @@ class RowResizer extends AbstractResizer {
|
|
|
29256
29239
|
}
|
|
29257
29240
|
unhide(hiddenElements) {
|
|
29258
29241
|
this.env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
|
|
29259
|
-
sheetId: this.
|
|
29242
|
+
sheetId: this.sheetId,
|
|
29260
29243
|
dimension: "ROW",
|
|
29261
29244
|
elements: hiddenElements,
|
|
29262
29245
|
});
|
|
@@ -30401,6 +30384,7 @@ const DRAWING_NS_C = "http://schemas.openxmlformats.org/drawingml/2006/chart";
|
|
|
30401
30384
|
const CONTENT_TYPES = {
|
|
30402
30385
|
workbook: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
|
|
30403
30386
|
sheet: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
|
|
30387
|
+
metadata: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
|
|
30404
30388
|
sharedStrings: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
|
|
30405
30389
|
styles: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
|
|
30406
30390
|
drawing: "application/vnd.openxmlformats-officedocument.drawing+xml",
|
|
@@ -30413,6 +30397,7 @@ const CONTENT_TYPES = {
|
|
|
30413
30397
|
const XLSX_RELATION_TYPE = {
|
|
30414
30398
|
document: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
|
|
30415
30399
|
sheet: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
|
|
30400
|
+
metadata: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata",
|
|
30416
30401
|
sharedStrings: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings",
|
|
30417
30402
|
styles: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
|
|
30418
30403
|
drawing: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",
|
|
@@ -30422,6 +30407,7 @@ const XLSX_RELATION_TYPE = {
|
|
|
30422
30407
|
hyperlink: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
|
30423
30408
|
image: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
30424
30409
|
};
|
|
30410
|
+
const ARRAY_FORMULA_URI = "bdbb8cdc-fa1e-496e-a857-3c3f30c029c3";
|
|
30425
30411
|
const RELATIONSHIP_NSR = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
30426
30412
|
const HEIGHT_FACTOR = 0.75; // 100px => 75 u
|
|
30427
30413
|
/**
|
|
@@ -32251,29 +32237,33 @@ function applyStyleToZone(appliedStyle, zone, cells, styles) {
|
|
|
32251
32237
|
* In all the sheets, replace the table-only references in the formula cells with standard references.
|
|
32252
32238
|
*/
|
|
32253
32239
|
function convertTableFormulaReferences(convertedSheets, xlsxSheets) {
|
|
32254
|
-
for (let
|
|
32255
|
-
const tables = xlsxSheets.find((s) => s.sheetName ===
|
|
32240
|
+
for (let tableSheet of convertedSheets) {
|
|
32241
|
+
const tables = xlsxSheets.find((s) => s.sheetName === tableSheet.name).tables;
|
|
32256
32242
|
for (let table of tables) {
|
|
32257
32243
|
const tabRef = table.name + "[";
|
|
32258
|
-
for (let
|
|
32259
|
-
|
|
32260
|
-
|
|
32261
|
-
|
|
32262
|
-
|
|
32263
|
-
|
|
32264
|
-
|
|
32265
|
-
|
|
32266
|
-
|
|
32267
|
-
|
|
32268
|
-
|
|
32269
|
-
|
|
32244
|
+
for (let sheet of convertedSheets) {
|
|
32245
|
+
for (let xc in sheet.cells) {
|
|
32246
|
+
const cell = sheet.cells[xc];
|
|
32247
|
+
if (cell && cell.content && cell.content.startsWith("=")) {
|
|
32248
|
+
let refIndex;
|
|
32249
|
+
while ((refIndex = cell.content.indexOf(tabRef)) !== -1) {
|
|
32250
|
+
let endIndex = refIndex + tabRef.length;
|
|
32251
|
+
let openBrackets = 1;
|
|
32252
|
+
while (openBrackets > 0 && endIndex < cell.content.length) {
|
|
32253
|
+
if (cell.content[endIndex] === "[") {
|
|
32254
|
+
openBrackets++;
|
|
32255
|
+
}
|
|
32256
|
+
else if (cell.content[endIndex] === "]") {
|
|
32257
|
+
openBrackets--;
|
|
32258
|
+
}
|
|
32259
|
+
endIndex++;
|
|
32260
|
+
}
|
|
32261
|
+
let reference = cell.content.slice(refIndex + tabRef.length, endIndex - 1);
|
|
32262
|
+
const sheetPrefix = tableSheet.id === sheet.id ? "" : tableSheet.name + "!";
|
|
32263
|
+
const convertedRef = convertTableReference(sheetPrefix, reference, table, xc);
|
|
32264
|
+
cell.content =
|
|
32265
|
+
cell.content.slice(0, refIndex) + convertedRef + cell.content.slice(endIndex);
|
|
32270
32266
|
}
|
|
32271
|
-
reference = reference.slice(0, endIndex);
|
|
32272
|
-
const convertedRef = convertTableReference(reference, table, xc);
|
|
32273
|
-
cell.content =
|
|
32274
|
-
cell.content.slice(0, refIndex) +
|
|
32275
|
-
convertedRef +
|
|
32276
|
-
cell.content.slice(tabRef.length + refIndex + endIndex + 1);
|
|
32277
32267
|
}
|
|
32278
32268
|
}
|
|
32279
32269
|
}
|
|
@@ -32281,11 +32271,17 @@ function convertTableFormulaReferences(convertedSheets, xlsxSheets) {
|
|
|
32281
32271
|
}
|
|
32282
32272
|
}
|
|
32283
32273
|
/**
|
|
32284
|
-
* Convert table-specific references in formulas into standard references.
|
|
32274
|
+
* Convert table-specific references in formulas into standard references. A table reference is composed of columns names,
|
|
32275
|
+
* and of keywords determining the rows of the table to reference.
|
|
32285
32276
|
*
|
|
32286
32277
|
* A reference in a table can have the form (only the part between brackets should be given to this function):
|
|
32287
32278
|
* - tableName[colName] : reference to the whole column "colName"
|
|
32279
|
+
* - tableName[#keyword] : reference to the whatever row the keyword refers to
|
|
32288
32280
|
* - tableName[[#keyword], [colName]] : reference to some of the element(s) of the column colName
|
|
32281
|
+
* - tableName[[#keyword], [colName]:[col2Name]] : reference to some of the element(s) of the columns colName to col2Name
|
|
32282
|
+
* - tableName[[#keyword1], [#keyword2], [colName]] : reference to all the rows referenced by the keywords in the column colName
|
|
32283
|
+
* - tableName[[#keyword1], [colName], [#keyword2]]: the keywords and colName can be in any order
|
|
32284
|
+
*
|
|
32289
32285
|
*
|
|
32290
32286
|
* The available keywords are :
|
|
32291
32287
|
* - #All : all the column (including totals)
|
|
@@ -32293,58 +32289,109 @@ function convertTableFormulaReferences(convertedSheets, xlsxSheets) {
|
|
|
32293
32289
|
* - #Headers : only the header of the column
|
|
32294
32290
|
* - #Totals : only the totals of the column
|
|
32295
32291
|
* - #This Row : only the element in the same row as the cell
|
|
32292
|
+
*
|
|
32293
|
+
* Note that the only valid combination of multiple keywords are #Data + #Totals and #Headers + #Data.
|
|
32296
32294
|
*/
|
|
32297
|
-
function convertTableReference(expr, table, cellXc) {
|
|
32298
|
-
|
|
32295
|
+
function convertTableReference(sheetPrefix, expr, table, cellXc) {
|
|
32296
|
+
// TODO: Ideally we'd want to make a real tokenizer, this simple approach won't work if for example the column name
|
|
32297
|
+
// contain # or , characters. But that's probably an edge case that we can ignore for now.
|
|
32298
|
+
const parts = expr.split(",").map((part) => part.trim());
|
|
32299
32299
|
const tableZone = toZone(table.ref);
|
|
32300
|
-
const
|
|
32301
|
-
|
|
32302
|
-
|
|
32303
|
-
|
|
32304
|
-
|
|
32305
|
-
|
|
32306
|
-
|
|
32307
|
-
|
|
32308
|
-
|
|
32309
|
-
|
|
32310
|
-
|
|
32300
|
+
const colIndexes = [];
|
|
32301
|
+
const rowIndexes = [];
|
|
32302
|
+
const foundKeywords = [];
|
|
32303
|
+
for (const part of parts) {
|
|
32304
|
+
if (removeBrackets(part).startsWith("#")) {
|
|
32305
|
+
const keyWord = removeBrackets(part);
|
|
32306
|
+
foundKeywords.push(keyWord);
|
|
32307
|
+
switch (keyWord) {
|
|
32308
|
+
case "#All":
|
|
32309
|
+
rowIndexes.push(tableZone.top, tableZone.bottom);
|
|
32310
|
+
break;
|
|
32311
|
+
case "#Data":
|
|
32312
|
+
const top = table.headerRowCount ? tableZone.top + table.headerRowCount : tableZone.top;
|
|
32313
|
+
const bottom = table.totalsRowCount
|
|
32314
|
+
? tableZone.bottom - table.totalsRowCount
|
|
32315
|
+
: tableZone.bottom;
|
|
32316
|
+
rowIndexes.push(top, bottom);
|
|
32317
|
+
break;
|
|
32318
|
+
case "#This Row":
|
|
32319
|
+
rowIndexes.push(toCartesian(cellXc).row);
|
|
32320
|
+
break;
|
|
32321
|
+
case "#Headers":
|
|
32322
|
+
if (!table.headerRowCount) {
|
|
32323
|
+
return INCORRECT_RANGE_STRING;
|
|
32324
|
+
}
|
|
32325
|
+
rowIndexes.push(tableZone.top);
|
|
32326
|
+
break;
|
|
32327
|
+
case "#Totals":
|
|
32328
|
+
if (!table.totalsRowCount) {
|
|
32329
|
+
return INCORRECT_RANGE_STRING;
|
|
32330
|
+
}
|
|
32331
|
+
rowIndexes.push(tableZone.bottom);
|
|
32332
|
+
break;
|
|
32333
|
+
}
|
|
32311
32334
|
}
|
|
32312
|
-
|
|
32313
|
-
|
|
32314
|
-
|
|
32315
|
-
|
|
32316
|
-
|
|
32317
|
-
|
|
32318
|
-
|
|
32319
|
-
|
|
32320
|
-
|
|
32321
|
-
|
|
32322
|
-
|
|
32323
|
-
|
|
32324
|
-
|
|
32325
|
-
|
|
32326
|
-
|
|
32327
|
-
|
|
32328
|
-
|
|
32329
|
-
if (!table.headerRowCount) {
|
|
32330
|
-
isReferencedZoneValid = false;
|
|
32331
|
-
}
|
|
32332
|
-
break;
|
|
32333
|
-
case "#Totals":
|
|
32334
|
-
refZone.top = refZone.bottom = tableZone.bottom;
|
|
32335
|
-
if (!table.totalsRowCount) {
|
|
32336
|
-
isReferencedZoneValid = false;
|
|
32335
|
+
else {
|
|
32336
|
+
const columns = part
|
|
32337
|
+
.split(":")
|
|
32338
|
+
.map((part) => part.trim())
|
|
32339
|
+
.map(removeBrackets);
|
|
32340
|
+
if (colIndexes.length) {
|
|
32341
|
+
return INCORRECT_RANGE_STRING;
|
|
32342
|
+
}
|
|
32343
|
+
const colRelativeIndex = table.cols.findIndex((col) => col.name === columns[0]);
|
|
32344
|
+
if (colRelativeIndex === -1) {
|
|
32345
|
+
return INCORRECT_RANGE_STRING;
|
|
32346
|
+
}
|
|
32347
|
+
colIndexes.push(colRelativeIndex + tableZone.left);
|
|
32348
|
+
if (columns[1]) {
|
|
32349
|
+
const colRelativeIndex2 = table.cols.findIndex((col) => col.name === columns[1]);
|
|
32350
|
+
if (colRelativeIndex2 === -1) {
|
|
32351
|
+
return INCORRECT_RANGE_STRING;
|
|
32337
32352
|
}
|
|
32338
|
-
|
|
32353
|
+
colIndexes.push(colRelativeIndex2 + tableZone.left);
|
|
32354
|
+
}
|
|
32339
32355
|
}
|
|
32340
|
-
const colRef = refElements[1].slice(1, refElements[1].length - 1);
|
|
32341
|
-
const colRelativeIndex = table.cols.findIndex((col) => col.name === colRef);
|
|
32342
|
-
refZone.left = refZone.right = colRelativeIndex + tableZone.left;
|
|
32343
32356
|
}
|
|
32344
|
-
if (!
|
|
32357
|
+
if (!areKeywordsCompatible(foundKeywords)) {
|
|
32345
32358
|
return INCORRECT_RANGE_STRING;
|
|
32346
32359
|
}
|
|
32347
|
-
|
|
32360
|
+
if (rowIndexes.length === 0) {
|
|
32361
|
+
const top = table.headerRowCount ? tableZone.top + table.headerRowCount : tableZone.top;
|
|
32362
|
+
const bottom = table.totalsRowCount
|
|
32363
|
+
? tableZone.bottom - table.totalsRowCount
|
|
32364
|
+
: tableZone.bottom;
|
|
32365
|
+
rowIndexes.push(top, bottom);
|
|
32366
|
+
}
|
|
32367
|
+
if (colIndexes.length === 0) {
|
|
32368
|
+
colIndexes.push(tableZone.left, tableZone.right);
|
|
32369
|
+
}
|
|
32370
|
+
const refZone = {
|
|
32371
|
+
top: Math.min(...rowIndexes),
|
|
32372
|
+
left: Math.min(...colIndexes),
|
|
32373
|
+
bottom: Math.max(...rowIndexes),
|
|
32374
|
+
right: Math.max(...colIndexes),
|
|
32375
|
+
};
|
|
32376
|
+
return sheetPrefix + zoneToXc(refZone);
|
|
32377
|
+
}
|
|
32378
|
+
function removeBrackets(str) {
|
|
32379
|
+
return str.startsWith("[") && str.endsWith("]") ? str.slice(1, str.length - 1) : str;
|
|
32380
|
+
}
|
|
32381
|
+
function areKeywordsCompatible(keywords) {
|
|
32382
|
+
if (keywords.length < 2) {
|
|
32383
|
+
return true;
|
|
32384
|
+
}
|
|
32385
|
+
else if (keywords.length > 2) {
|
|
32386
|
+
return false;
|
|
32387
|
+
}
|
|
32388
|
+
else if (keywords.includes("#Data") && keywords.includes("#Totals")) {
|
|
32389
|
+
return true;
|
|
32390
|
+
}
|
|
32391
|
+
else if (keywords.includes("#Headers") && keywords.includes("#Data")) {
|
|
32392
|
+
return true;
|
|
32393
|
+
}
|
|
32394
|
+
return false;
|
|
32348
32395
|
}
|
|
32349
32396
|
|
|
32350
32397
|
// -------------------------------------
|
|
@@ -33897,7 +33944,7 @@ function normalizeV9(formula) {
|
|
|
33897
33944
|
* a breaking change is made in the way the state is handled, and an upgrade
|
|
33898
33945
|
* function should be defined
|
|
33899
33946
|
*/
|
|
33900
|
-
const CURRENT_VERSION = 14;
|
|
33947
|
+
const CURRENT_VERSION = 14.5;
|
|
33901
33948
|
const INITIAL_SHEET_ID = "Sheet1";
|
|
33902
33949
|
/**
|
|
33903
33950
|
* This function tries to load anything that could look like a valid
|
|
@@ -42406,6 +42453,9 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
42406
42453
|
// Export
|
|
42407
42454
|
// ---------------------------------------------------------------------------
|
|
42408
42455
|
exportForExcel(data) {
|
|
42456
|
+
for (const sheet of data.sheets) {
|
|
42457
|
+
sheet.formulaSpillRanges = {};
|
|
42458
|
+
}
|
|
42409
42459
|
for (const position of this.evaluator.getEvaluatedPositions()) {
|
|
42410
42460
|
const evaluatedCell = this.evaluator.getEvaluatedCell(position);
|
|
42411
42461
|
const xc = toXC(position.col, position.row);
|
|
@@ -42417,8 +42467,9 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
42417
42467
|
const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
|
|
42418
42468
|
const formulaCell = this.getCorrespondingFormulaCell(position);
|
|
42419
42469
|
if (formulaCell) {
|
|
42470
|
+
const cell = this.getters.getCell(position);
|
|
42420
42471
|
isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
|
|
42421
|
-
isFormula = isExported;
|
|
42472
|
+
isFormula = isExported && cell?.content === formulaCell.content;
|
|
42422
42473
|
if (!isExported) {
|
|
42423
42474
|
// If the cell contains a non-exported formula and that is evaluates to
|
|
42424
42475
|
// nothing* ,we don't export it.
|
|
@@ -42442,6 +42493,14 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
42442
42493
|
content = !isExported ? newContent : exportedCellData.content;
|
|
42443
42494
|
}
|
|
42444
42495
|
exportedSheetData.cells[xc] = { ...exportedCellData, value, isFormula, content, format };
|
|
42496
|
+
const spillCells = this.getSpreadPositionsOf(position);
|
|
42497
|
+
spillCells.push(position);
|
|
42498
|
+
const spillZones = spillCells.map((cell) => positionToZone(cell));
|
|
42499
|
+
const spillZone = union(...spillZones);
|
|
42500
|
+
const spillZoneXc = this.getters.getRangeString(this.getters.getRangeFromZone(position.sheetId, spillZone), position.sheetId);
|
|
42501
|
+
if (spillZoneXc && spillZoneXc !== "#REF") {
|
|
42502
|
+
exportedSheetData.formulaSpillRanges[xc] = spillZoneXc;
|
|
42503
|
+
}
|
|
42445
42504
|
}
|
|
42446
42505
|
}
|
|
42447
42506
|
/**
|
|
@@ -43642,7 +43701,7 @@ class AutofillPlugin extends UIPlugin {
|
|
|
43642
43701
|
getRule(cell, cells) {
|
|
43643
43702
|
const rules = autofillRulesRegistry.getAll().sort((a, b) => a.sequence - b.sequence);
|
|
43644
43703
|
const rule = rules.find((rule) => rule.condition(cell, cells));
|
|
43645
|
-
return rule && rule.generateRule(cell, cells);
|
|
43704
|
+
return rule && this.direction && rule.generateRule(cell, cells, this.direction);
|
|
43646
43705
|
}
|
|
43647
43706
|
/**
|
|
43648
43707
|
* Create the generator to be able to autofill the next cells.
|
|
@@ -51312,7 +51371,8 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
51312
51371
|
? this.getters.getSheetViewVisibleCols()
|
|
51313
51372
|
: this.getters.getSheetViewVisibleRows();
|
|
51314
51373
|
const startIndex = visibleHeaders.findIndex((header) => referenceHeaderIndex >= header);
|
|
51315
|
-
|
|
51374
|
+
let endIndex = visibleHeaders.findIndex((header) => targetHeaderIndex <= header);
|
|
51375
|
+
endIndex = endIndex === -1 ? visibleHeaders.length : endIndex;
|
|
51316
51376
|
const relevantIndexes = visibleHeaders.slice(startIndex, endIndex);
|
|
51317
51377
|
let offset = 0;
|
|
51318
51378
|
for (const i of relevantIndexes) {
|
|
@@ -56111,7 +56171,7 @@ function numberRef(reference) {
|
|
|
56111
56171
|
`;
|
|
56112
56172
|
}
|
|
56113
56173
|
|
|
56114
|
-
function addFormula(cell) {
|
|
56174
|
+
function addFormula(cell, formulaSpillRange) {
|
|
56115
56175
|
const formula = cell.content;
|
|
56116
56176
|
if (!formula) {
|
|
56117
56177
|
return { attrs: [], node: escapeXml `` };
|
|
@@ -56120,10 +56180,17 @@ function addFormula(cell) {
|
|
|
56120
56180
|
if (type === undefined) {
|
|
56121
56181
|
return { attrs: [], node: escapeXml `` };
|
|
56122
56182
|
}
|
|
56123
|
-
const attrs = [
|
|
56183
|
+
const attrs = [
|
|
56184
|
+
["cm", "1"],
|
|
56185
|
+
["t", type],
|
|
56186
|
+
];
|
|
56124
56187
|
const XlsxFormula = adaptFormulaToExcel(formula);
|
|
56125
56188
|
const exportedValue = adaptFormulaValueToExcel(cell.value);
|
|
56126
|
-
|
|
56189
|
+
// We treat all formulas as array formulas (a simple formula
|
|
56190
|
+
// is an array formula that spills on only one cell) to avoid
|
|
56191
|
+
// trying to detect spilling sub-formulas which is not a trivial task.
|
|
56192
|
+
let node;
|
|
56193
|
+
node = escapeXml /*xml*/ `<f t="array" ref="${formulaSpillRange}">${XlsxFormula}</f><v>${exportedValue}</v>`;
|
|
56127
56194
|
return { attrs, node };
|
|
56128
56195
|
}
|
|
56129
56196
|
function addContent(content, sharedStrings, forceString = false) {
|
|
@@ -56935,7 +57002,7 @@ function addRows(construct, data, sheet) {
|
|
|
56935
57002
|
let cellNode = escapeXml ``;
|
|
56936
57003
|
// Either formula or static value inside the cell
|
|
56937
57004
|
if (cell.isFormula) {
|
|
56938
|
-
const res = addFormula(cell);
|
|
57005
|
+
const res = addFormula(cell, sheet.formulaSpillRanges[xc] ?? xc);
|
|
56939
57006
|
if (!res) {
|
|
56940
57007
|
continue;
|
|
56941
57008
|
}
|
|
@@ -57192,6 +57259,30 @@ function createWorksheets(data, construct) {
|
|
|
57192
57259
|
`;
|
|
57193
57260
|
files.push(createXMLFile(parseXML(sheetXml), `xl/worksheets/sheet${sheetIndex}.xml`, "sheet"));
|
|
57194
57261
|
}
|
|
57262
|
+
const sheetMetadataXml = escapeXml /*xml*/ `
|
|
57263
|
+
<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">
|
|
57264
|
+
<metadataTypes count="1">
|
|
57265
|
+
<metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1"
|
|
57266
|
+
pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1"
|
|
57267
|
+
clearComments="1" assign="1" coerce="1" cellMeta="1" />
|
|
57268
|
+
</metadataTypes>
|
|
57269
|
+
<futureMetadata name="XLDAPR" count="1">
|
|
57270
|
+
<bk>
|
|
57271
|
+
<extLst>
|
|
57272
|
+
<ext uri="{${ARRAY_FORMULA_URI}}">
|
|
57273
|
+
<xda:dynamicArrayProperties fDynamic="1" fCollapsed="0" />
|
|
57274
|
+
</ext>
|
|
57275
|
+
</extLst>
|
|
57276
|
+
</bk>
|
|
57277
|
+
</futureMetadata>
|
|
57278
|
+
<cellMetadata count="1">
|
|
57279
|
+
<bk>
|
|
57280
|
+
<rc t="1" v="0" />
|
|
57281
|
+
</bk>
|
|
57282
|
+
</cellMetadata>
|
|
57283
|
+
</metadata>
|
|
57284
|
+
`;
|
|
57285
|
+
files.push(createXMLFile(parseXML(sheetMetadataXml), "xl/metadata.xml", "metadata"));
|
|
57195
57286
|
addRelsToFile(construct.relsFiles, "xl/_rels/workbook.xml.rels", {
|
|
57196
57287
|
type: XLSX_RELATION_TYPE.sharedStrings,
|
|
57197
57288
|
target: "sharedStrings.xml",
|
|
@@ -57200,6 +57291,10 @@ function createWorksheets(data, construct) {
|
|
|
57200
57291
|
type: XLSX_RELATION_TYPE.styles,
|
|
57201
57292
|
target: "styles.xml",
|
|
57202
57293
|
});
|
|
57294
|
+
addRelsToFile(construct.relsFiles, "xl/_rels/workbook.xml.rels", {
|
|
57295
|
+
type: XLSX_RELATION_TYPE.metadata,
|
|
57296
|
+
target: "metadata.xml",
|
|
57297
|
+
});
|
|
57203
57298
|
return files;
|
|
57204
57299
|
}
|
|
57205
57300
|
/**
|
|
@@ -57974,6 +58069,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
57974
58069
|
exports.tokenize = tokenize;
|
|
57975
58070
|
|
|
57976
58071
|
|
|
57977
|
-
__info__.version = "17.0.
|
|
57978
|
-
__info__.date = "2025-
|
|
57979
|
-
__info__.hash = "
|
|
58072
|
+
__info__.version = "17.0.52";
|
|
58073
|
+
__info__.date = "2025-03-07T10:30:04.783Z";
|
|
58074
|
+
__info__.hash = "c19cd9a";
|