@odoo/o-spreadsheet 18.0.18 → 18.0.20
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 +178 -51
- package/dist/o-spreadsheet.d.ts +3 -1
- package/dist/o-spreadsheet.esm.js +178 -51
- package/dist/o-spreadsheet.iife.js +178 -51
- package/dist/o-spreadsheet.iife.min.js +385 -385
- package/dist/o_spreadsheet.xml +14 -7
- package/package.json +1 -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 18.0.
|
|
6
|
-
* @date 2025-03-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.0.20
|
|
6
|
+
* @date 2025-03-19T08:21:32.426Z
|
|
7
|
+
* @hash 3f48d8b
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -420,7 +420,6 @@
|
|
|
420
420
|
* Sparse arrays remain sparse.
|
|
421
421
|
*/
|
|
422
422
|
function deepCopy(obj) {
|
|
423
|
-
const result = Array.isArray(obj) ? [] : {};
|
|
424
423
|
switch (typeof obj) {
|
|
425
424
|
case "object": {
|
|
426
425
|
if (obj === null) {
|
|
@@ -432,8 +431,18 @@
|
|
|
432
431
|
else if (!(isPlainObject(obj) || obj instanceof Array)) {
|
|
433
432
|
throw new Error("Unsupported type: only objects and arrays are supported");
|
|
434
433
|
}
|
|
435
|
-
|
|
436
|
-
|
|
434
|
+
const result = Array.isArray(obj) ? new Array(obj.length) : {};
|
|
435
|
+
if (Array.isArray(obj)) {
|
|
436
|
+
for (let i = 0, len = obj.length; i < len; i++) {
|
|
437
|
+
if (i in obj) {
|
|
438
|
+
result[i] = deepCopy(obj[i]);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
for (const key in obj) {
|
|
444
|
+
result[key] = deepCopy(obj[key]);
|
|
445
|
+
}
|
|
437
446
|
}
|
|
438
447
|
return result;
|
|
439
448
|
}
|
|
@@ -2535,21 +2544,30 @@
|
|
|
2535
2544
|
return mergedZones;
|
|
2536
2545
|
}
|
|
2537
2546
|
|
|
2547
|
+
const globalReverseLookup$1 = new WeakMap();
|
|
2548
|
+
const globalIdCounter = new WeakMap();
|
|
2538
2549
|
/**
|
|
2539
2550
|
* Get the id of the given item (its key in the given dictionary).
|
|
2540
2551
|
* If the given item does not exist in the dictionary, it creates one with a new id.
|
|
2541
2552
|
*/
|
|
2542
2553
|
function getItemId(item, itemsDic) {
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2554
|
+
if (!globalReverseLookup$1.has(itemsDic)) {
|
|
2555
|
+
globalReverseLookup$1.set(itemsDic, new Map());
|
|
2556
|
+
globalIdCounter.set(itemsDic, 0);
|
|
2557
|
+
}
|
|
2558
|
+
const reverseLookup = globalReverseLookup$1.get(itemsDic);
|
|
2559
|
+
const canonical = getCanonicalRepresentation(item);
|
|
2560
|
+
if (reverseLookup.has(canonical)) {
|
|
2561
|
+
const id = reverseLookup.get(canonical);
|
|
2562
|
+
itemsDic[id] = item;
|
|
2563
|
+
return id;
|
|
2547
2564
|
}
|
|
2548
2565
|
// Generate new Id if the item didn't exist in the dictionary
|
|
2549
|
-
const
|
|
2550
|
-
|
|
2551
|
-
itemsDic
|
|
2552
|
-
|
|
2566
|
+
const newId = globalIdCounter.get(itemsDic) + 1;
|
|
2567
|
+
reverseLookup.set(canonical, newId);
|
|
2568
|
+
globalIdCounter.set(itemsDic, newId);
|
|
2569
|
+
itemsDic[newId] = item;
|
|
2570
|
+
return newId;
|
|
2553
2571
|
}
|
|
2554
2572
|
function groupItemIdsByZones(positionsByItemId) {
|
|
2555
2573
|
const result = {};
|
|
@@ -2561,6 +2579,33 @@
|
|
|
2561
2579
|
}
|
|
2562
2580
|
return result;
|
|
2563
2581
|
}
|
|
2582
|
+
function getCanonicalRepresentation(item) {
|
|
2583
|
+
if (item === null)
|
|
2584
|
+
return "null";
|
|
2585
|
+
if (item === undefined)
|
|
2586
|
+
return "undefined";
|
|
2587
|
+
if (typeof item !== "object")
|
|
2588
|
+
return String(item);
|
|
2589
|
+
if (Array.isArray(item)) {
|
|
2590
|
+
const len = item.length;
|
|
2591
|
+
let result = "[";
|
|
2592
|
+
for (let i = 0; i < len; i++) {
|
|
2593
|
+
if (i > 0)
|
|
2594
|
+
result += ",";
|
|
2595
|
+
result += getCanonicalRepresentation(item[i]);
|
|
2596
|
+
}
|
|
2597
|
+
return result + "]";
|
|
2598
|
+
}
|
|
2599
|
+
const keys = Object.keys(item).sort();
|
|
2600
|
+
let repr = "{";
|
|
2601
|
+
for (const key of keys) {
|
|
2602
|
+
if (item[key] !== undefined) {
|
|
2603
|
+
repr += `"${key}":${getCanonicalRepresentation(item[key])},`;
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
repr += "}";
|
|
2607
|
+
return repr;
|
|
2608
|
+
}
|
|
2564
2609
|
|
|
2565
2610
|
// -----------------------------------------------------------------------------
|
|
2566
2611
|
// Date Type
|
|
@@ -6063,11 +6108,13 @@
|
|
|
6063
6108
|
if (!cell || (!cell.isFormula && !cell.content)) {
|
|
6064
6109
|
return DEFAULT_CELL_HEIGHT;
|
|
6065
6110
|
}
|
|
6066
|
-
const
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
const
|
|
6111
|
+
const content = cell.isFormula ? "" : cell.content;
|
|
6112
|
+
return getCellContentHeight(ctx, content, cell.style, colSize);
|
|
6113
|
+
}
|
|
6114
|
+
function getCellContentHeight(ctx, content, style, colSize) {
|
|
6115
|
+
const maxWidth = style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
|
|
6116
|
+
const numberOfLines = splitTextToWidth(ctx, content, style, maxWidth).length;
|
|
6117
|
+
const fontSize = computeTextFontSizeInPixels(style);
|
|
6071
6118
|
return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
6072
6119
|
}
|
|
6073
6120
|
function getDefaultContextFont(fontSize, bold = false, italic = false) {
|
|
@@ -8230,13 +8277,6 @@
|
|
|
8230
8277
|
this.clearClippedZones(content);
|
|
8231
8278
|
const selection = target[0];
|
|
8232
8279
|
this.pasteZone(sheetId, selection.left, selection.top, content.cells, options);
|
|
8233
|
-
this.dispatch("MOVE_RANGES", {
|
|
8234
|
-
target: content.zones,
|
|
8235
|
-
sheetId: content.sheetId,
|
|
8236
|
-
targetSheetId: sheetId,
|
|
8237
|
-
col: selection.left,
|
|
8238
|
-
row: selection.top,
|
|
8239
|
-
});
|
|
8240
8280
|
}
|
|
8241
8281
|
/**
|
|
8242
8282
|
* Clear the clipped zones: remove the cells and clear the formatting
|
|
@@ -8745,14 +8785,15 @@
|
|
|
8745
8785
|
}
|
|
8746
8786
|
merges.push(mergesInRow);
|
|
8747
8787
|
}
|
|
8748
|
-
return { merges };
|
|
8788
|
+
return { merges, sheetId };
|
|
8749
8789
|
}
|
|
8750
8790
|
/**
|
|
8751
8791
|
* Paste the clipboard content in the given target
|
|
8752
8792
|
*/
|
|
8753
8793
|
paste(target, content, options) {
|
|
8754
8794
|
if (options.isCutOperation) {
|
|
8755
|
-
|
|
8795
|
+
const copiedMerges = content.merges.flat().filter(isDefined);
|
|
8796
|
+
this.dispatch("REMOVE_MERGE", { sheetId: content.sheetId, target: copiedMerges });
|
|
8756
8797
|
}
|
|
8757
8798
|
this.pasteFromCopy(target.sheetId, target.zones, content.merges, options);
|
|
8758
8799
|
}
|
|
@@ -8787,6 +8828,27 @@
|
|
|
8787
8828
|
}
|
|
8788
8829
|
}
|
|
8789
8830
|
|
|
8831
|
+
class ReferenceClipboardHandler extends AbstractCellClipboardHandler {
|
|
8832
|
+
copy(data) {
|
|
8833
|
+
return {
|
|
8834
|
+
zones: data.clippedZones,
|
|
8835
|
+
sheetId: data.sheetId,
|
|
8836
|
+
};
|
|
8837
|
+
}
|
|
8838
|
+
paste(target, content, options) {
|
|
8839
|
+
if (options.isCutOperation) {
|
|
8840
|
+
const selection = target.zones[0];
|
|
8841
|
+
this.dispatch("MOVE_RANGES", {
|
|
8842
|
+
target: content.zones,
|
|
8843
|
+
sheetId: content.sheetId,
|
|
8844
|
+
targetSheetId: target.sheetId,
|
|
8845
|
+
col: selection.left,
|
|
8846
|
+
row: selection.top,
|
|
8847
|
+
});
|
|
8848
|
+
}
|
|
8849
|
+
}
|
|
8850
|
+
}
|
|
8851
|
+
|
|
8790
8852
|
class SheetClipboardHandler extends AbstractCellClipboardHandler {
|
|
8791
8853
|
isPasteAllowed(sheetId, target, content, options) {
|
|
8792
8854
|
if (!("cells" in content)) {
|
|
@@ -8954,7 +9016,8 @@
|
|
|
8954
9016
|
.add("merge", MergeClipboardHandler)
|
|
8955
9017
|
.add("border", BorderClipboardHandler)
|
|
8956
9018
|
.add("table", TableClipboardHandler)
|
|
8957
|
-
.add("conditionalFormat", ConditionalFormatClipboardHandler)
|
|
9019
|
+
.add("conditionalFormat", ConditionalFormatClipboardHandler)
|
|
9020
|
+
.add("references", ReferenceClipboardHandler);
|
|
8958
9021
|
|
|
8959
9022
|
function transformZone(zone, executed) {
|
|
8960
9023
|
if (executed.type === "REMOVE_COLUMNS_ROWS") {
|
|
@@ -11563,16 +11626,25 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
11563
11626
|
}
|
|
11564
11627
|
return id;
|
|
11565
11628
|
}
|
|
11629
|
+
const globalReverseLookup = new WeakMap();
|
|
11566
11630
|
function pushElement(property, propertyList) {
|
|
11567
|
-
let
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11631
|
+
let reverseLookup = globalReverseLookup.get(propertyList);
|
|
11632
|
+
if (!reverseLookup) {
|
|
11633
|
+
reverseLookup = new Map();
|
|
11634
|
+
for (let i = 0; i < propertyList.length; i++) {
|
|
11635
|
+
const canonical = getCanonicalRepresentation(propertyList[i]);
|
|
11636
|
+
reverseLookup.set(canonical, i);
|
|
11572
11637
|
}
|
|
11638
|
+
globalReverseLookup.set(propertyList, reverseLookup);
|
|
11639
|
+
}
|
|
11640
|
+
const canonical = getCanonicalRepresentation(property);
|
|
11641
|
+
if (reverseLookup.has(canonical)) {
|
|
11642
|
+
return reverseLookup.get(canonical);
|
|
11573
11643
|
}
|
|
11574
|
-
propertyList
|
|
11575
|
-
|
|
11644
|
+
const maxId = propertyList.length;
|
|
11645
|
+
propertyList.push(property);
|
|
11646
|
+
reverseLookup.set(canonical, maxId);
|
|
11647
|
+
return maxId;
|
|
11576
11648
|
}
|
|
11577
11649
|
const chartIds = [];
|
|
11578
11650
|
/**
|
|
@@ -13425,7 +13497,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
13425
13497
|
title: { text: chartTitle },
|
|
13426
13498
|
type: CHART_TYPE_CONVERSION_MAP[chartType],
|
|
13427
13499
|
dataSets: this.extractChartDatasets(this.querySelectorAll(rootChartElement, `c:${chartType}`), chartType),
|
|
13428
|
-
labelRange: this.
|
|
13500
|
+
labelRange: this.extractLabelRange(chartType, rootChartElement),
|
|
13429
13501
|
backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
13430
13502
|
default: "ffffff",
|
|
13431
13503
|
}).asString(),
|
|
@@ -13437,6 +13509,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
13437
13509
|
};
|
|
13438
13510
|
})[0];
|
|
13439
13511
|
}
|
|
13512
|
+
extractLabelRange(chartType, rootChartElement) {
|
|
13513
|
+
if (chartType === "scatterChart") {
|
|
13514
|
+
return (this.extractChildTextContent(rootChartElement, `c:ser c:strRef c:f`) ||
|
|
13515
|
+
this.extractChildTextContent(rootChartElement, `c:ser c:numRef c:f`));
|
|
13516
|
+
}
|
|
13517
|
+
return this.extractChildTextContent(rootChartElement, `c:ser c:cat c:f`);
|
|
13518
|
+
}
|
|
13440
13519
|
extractComboChart(chartElement) {
|
|
13441
13520
|
// Title can be separated into multiple xml elements (for styling and such), we only import the text
|
|
13442
13521
|
const chartTitle = this.mapOnElements({ parent: chartElement, query: "c:title a:t" }, (textElement) => {
|
|
@@ -16898,6 +16977,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
16898
16977
|
const autoCompleteProviders = new Registry();
|
|
16899
16978
|
|
|
16900
16979
|
autoCompleteProviders.add("dataValidation", {
|
|
16980
|
+
displayAllOnInitialContent: true,
|
|
16901
16981
|
getProposals(tokenAtCursor, content) {
|
|
16902
16982
|
if (content.startsWith("=")) {
|
|
16903
16983
|
return [];
|
|
@@ -28374,7 +28454,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28374
28454
|
text,
|
|
28375
28455
|
description: usedLabel,
|
|
28376
28456
|
htmlContent: [{ value: text, color }],
|
|
28377
|
-
fuzzySearchKey:
|
|
28457
|
+
fuzzySearchKey: text + usedLabel,
|
|
28378
28458
|
};
|
|
28379
28459
|
});
|
|
28380
28460
|
},
|
|
@@ -38777,8 +38857,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38777
38857
|
this.updateRangeColor();
|
|
38778
38858
|
}
|
|
38779
38859
|
cancelEdition() {
|
|
38780
|
-
this.cancelEditionAndActivateSheet();
|
|
38781
38860
|
this.resetContent();
|
|
38861
|
+
this.cancelEditionAndActivateSheet();
|
|
38782
38862
|
}
|
|
38783
38863
|
setCurrentContent(content, selection) {
|
|
38784
38864
|
if (selection && !this.isSelectionValid(content.length, selection.start, selection.end)) {
|
|
@@ -38794,8 +38874,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
38794
38874
|
switch (cmd.type) {
|
|
38795
38875
|
case "SELECT_FIGURE":
|
|
38796
38876
|
if (cmd.id) {
|
|
38797
|
-
this.cancelEditionAndActivateSheet();
|
|
38798
38877
|
this.resetContent();
|
|
38878
|
+
this.cancelEditionAndActivateSheet();
|
|
38799
38879
|
}
|
|
38800
38880
|
break;
|
|
38801
38881
|
case "START_CHANGE_HIGHLIGHT":
|
|
@@ -39146,6 +39226,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
39146
39226
|
const exactMatch = proposals?.find((p) => p.text === tokenAtCursor.value);
|
|
39147
39227
|
// remove tokens that are likely to be other parts of the formula that slipped in the token if it's a string
|
|
39148
39228
|
const searchTerm = tokenAtCursor.value.replace(/[ ,\(\)]/g, "");
|
|
39229
|
+
if (this._currentContent === this.initialContent &&
|
|
39230
|
+
provider.displayAllOnInitialContent &&
|
|
39231
|
+
proposals?.length) {
|
|
39232
|
+
return {
|
|
39233
|
+
proposals,
|
|
39234
|
+
selectProposal: provider.selectProposal,
|
|
39235
|
+
autoSelectFirstProposal: provider.autoSelectFirstProposal ?? false,
|
|
39236
|
+
};
|
|
39237
|
+
}
|
|
39149
39238
|
if (exactMatch && this._currentContent !== this.initialContent) {
|
|
39150
39239
|
// this means the user has chosen a proposal
|
|
39151
39240
|
return;
|
|
@@ -44681,6 +44770,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44681
44770
|
columns: {},
|
|
44682
44771
|
});
|
|
44683
44772
|
setup() {
|
|
44773
|
+
this.updateColumns();
|
|
44684
44774
|
owl.onWillUpdateProps(() => this.updateColumns());
|
|
44685
44775
|
}
|
|
44686
44776
|
toggleHasHeader() {
|
|
@@ -46469,8 +46559,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46469
46559
|
const sheetIdExists = !!this.getters.tryGetSheet(this.sheetId);
|
|
46470
46560
|
if (!sheetIdExists && this.editionMode !== "inactive") {
|
|
46471
46561
|
this.sheetId = this.getters.getActiveSheetId();
|
|
46472
|
-
this.cancelEditionAndActivateSheet();
|
|
46473
46562
|
this.resetContent();
|
|
46563
|
+
this.cancelEditionAndActivateSheet();
|
|
46474
46564
|
this.notificationStore.raiseError(CELL_DELETED_MESSAGE);
|
|
46475
46565
|
}
|
|
46476
46566
|
break;
|
|
@@ -62826,12 +62916,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62826
62916
|
}
|
|
62827
62917
|
break;
|
|
62828
62918
|
case "AUTORESIZE_ROWS":
|
|
62829
|
-
this.
|
|
62830
|
-
elements: cmd.rows,
|
|
62831
|
-
dimension: "ROW",
|
|
62832
|
-
size: null,
|
|
62833
|
-
sheetId: cmd.sheetId,
|
|
62834
|
-
});
|
|
62919
|
+
this.autoResizeRows(cmd.sheetId, cmd.rows);
|
|
62835
62920
|
break;
|
|
62836
62921
|
}
|
|
62837
62922
|
}
|
|
@@ -62996,6 +63081,48 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62996
63081
|
}
|
|
62997
63082
|
return "Success" /* CommandResult.Success */;
|
|
62998
63083
|
}
|
|
63084
|
+
autoResizeRows(sheetId, rows) {
|
|
63085
|
+
const rowSizes = [];
|
|
63086
|
+
for (const row of rows) {
|
|
63087
|
+
let evaluatedRowSize = 0;
|
|
63088
|
+
for (const cellId of this.getters.getRowCells(sheetId, row)) {
|
|
63089
|
+
const cell = this.getters.getCellById(cellId);
|
|
63090
|
+
if (!cell) {
|
|
63091
|
+
continue;
|
|
63092
|
+
}
|
|
63093
|
+
const position = this.getters.getCellPosition(cell.id);
|
|
63094
|
+
const colSize = this.getters.getColSize(sheetId, position.col);
|
|
63095
|
+
if (cell.isFormula) {
|
|
63096
|
+
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
63097
|
+
const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
|
|
63098
|
+
if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
|
|
63099
|
+
evaluatedRowSize = evaluatedSize;
|
|
63100
|
+
}
|
|
63101
|
+
}
|
|
63102
|
+
else {
|
|
63103
|
+
const content = cell.content;
|
|
63104
|
+
const dynamicRowSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
|
|
63105
|
+
// Only keep the size of evaluated cells if it's bigger than the dynamic row size
|
|
63106
|
+
if (dynamicRowSize >= evaluatedRowSize && dynamicRowSize > DEFAULT_CELL_HEIGHT) {
|
|
63107
|
+
evaluatedRowSize = 0;
|
|
63108
|
+
}
|
|
63109
|
+
}
|
|
63110
|
+
}
|
|
63111
|
+
rowSizes.push(evaluatedRowSize || null);
|
|
63112
|
+
}
|
|
63113
|
+
const groupedSizes = new Map(rowSizes.map((size) => [size, []]));
|
|
63114
|
+
for (let i = 0; i < rowSizes.length; i++) {
|
|
63115
|
+
groupedSizes.get(rowSizes[i])?.push(rows[i]);
|
|
63116
|
+
}
|
|
63117
|
+
for (const [size, rows] of groupedSizes) {
|
|
63118
|
+
this.dispatch("RESIZE_COLUMNS_ROWS", {
|
|
63119
|
+
elements: rows,
|
|
63120
|
+
dimension: "ROW",
|
|
63121
|
+
size,
|
|
63122
|
+
sheetId,
|
|
63123
|
+
});
|
|
63124
|
+
}
|
|
63125
|
+
}
|
|
62999
63126
|
}
|
|
63000
63127
|
|
|
63001
63128
|
class TableComputedStylePlugin extends UIPlugin {
|
|
@@ -72015,7 +72142,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
72015
72142
|
}
|
|
72016
72143
|
if (alignAttrs.length > 0) {
|
|
72017
72144
|
attributes.push(["applyAlignment", "1"]); // for Libre Office
|
|
72018
|
-
styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}
|
|
72145
|
+
styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}><alignment ${formatAttributes(alignAttrs)} /></xf> `);
|
|
72019
72146
|
}
|
|
72020
72147
|
else {
|
|
72021
72148
|
styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)} />`);
|
|
@@ -73479,9 +73606,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73479
73606
|
exports.tokenize = tokenize;
|
|
73480
73607
|
|
|
73481
73608
|
|
|
73482
|
-
__info__.version = "18.0.
|
|
73483
|
-
__info__.date = "2025-03-
|
|
73484
|
-
__info__.hash = "
|
|
73609
|
+
__info__.version = "18.0.20";
|
|
73610
|
+
__info__.date = "2025-03-19T08:21:32.426Z";
|
|
73611
|
+
__info__.hash = "3f48d8b";
|
|
73485
73612
|
|
|
73486
73613
|
|
|
73487
73614
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|