@odoo/o-spreadsheet 19.1.0-alpha.4 → 19.1.0-alpha.5
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 +388 -153
- package/dist/o-spreadsheet.d.ts +30 -5
- package/dist/o-spreadsheet.esm.js +388 -153
- package/dist/o-spreadsheet.iife.js +388 -153
- package/dist/o-spreadsheet.iife.min.js +321 -321
- package/dist/o_spreadsheet.xml +31 -6
- 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 19.1.0-alpha.
|
|
6
|
-
* @date 2025-10-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 19.1.0-alpha.5
|
|
6
|
+
* @date 2025-10-16T06:39:55.925Z
|
|
7
|
+
* @hash 1a0e3d5
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, useExternalListener, onWillUpdateProps, onWillStart, onWillPatch, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
|
|
@@ -4450,7 +4450,17 @@ function toNumberMatrix(data, argName) {
|
|
|
4450
4450
|
return toMatrix(data).map((row) => {
|
|
4451
4451
|
return row.map((cell) => {
|
|
4452
4452
|
if (typeof cell.value !== "number") {
|
|
4453
|
-
|
|
4453
|
+
let message = "";
|
|
4454
|
+
if (typeof cell === "object") {
|
|
4455
|
+
message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got an empty value.", argName);
|
|
4456
|
+
}
|
|
4457
|
+
else if (typeof cell === "string") {
|
|
4458
|
+
message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got a string.", argName);
|
|
4459
|
+
}
|
|
4460
|
+
else if (typeof cell === "boolean") {
|
|
4461
|
+
message = _t("Function [[FUNCTION_NAME]] expects number values for %s, but got a boolean.", argName);
|
|
4462
|
+
}
|
|
4463
|
+
throw new EvaluationError(message);
|
|
4454
4464
|
}
|
|
4455
4465
|
return cell.value;
|
|
4456
4466
|
});
|
|
@@ -6388,6 +6398,9 @@ function parseLiteral(content, locale) {
|
|
|
6388
6398
|
if (content.startsWith("=")) {
|
|
6389
6399
|
throw new Error(`Cannot parse "${content}" because it's not a literal value. It's a formula`);
|
|
6390
6400
|
}
|
|
6401
|
+
if (content.startsWith("'")) {
|
|
6402
|
+
return content.slice(1);
|
|
6403
|
+
}
|
|
6391
6404
|
if (content === "") {
|
|
6392
6405
|
return null;
|
|
6393
6406
|
}
|
|
@@ -9337,6 +9350,32 @@ function getCustomFieldWithParentField(definition, parentField, fields) {
|
|
|
9337
9350
|
groups: [],
|
|
9338
9351
|
});
|
|
9339
9352
|
}
|
|
9353
|
+
function togglePivotCollapse(position, env) {
|
|
9354
|
+
const pivotCell = env.model.getters.getPivotCellFromPosition(position);
|
|
9355
|
+
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
9356
|
+
if (!pivotId || pivotCell.type !== "HEADER") {
|
|
9357
|
+
return;
|
|
9358
|
+
}
|
|
9359
|
+
const definition = env.model.getters.getPivotCoreDefinition(pivotId);
|
|
9360
|
+
const collapsedDomains = definition.collapsedDomains?.[pivotCell.dimension]
|
|
9361
|
+
? [...definition.collapsedDomains[pivotCell.dimension]]
|
|
9362
|
+
: [];
|
|
9363
|
+
const index = collapsedDomains.findIndex((domain) => deepEquals(domain, pivotCell.domain));
|
|
9364
|
+
if (index !== -1) {
|
|
9365
|
+
collapsedDomains.splice(index, 1);
|
|
9366
|
+
}
|
|
9367
|
+
else {
|
|
9368
|
+
collapsedDomains.push(pivotCell.domain);
|
|
9369
|
+
}
|
|
9370
|
+
const newDomains = definition.collapsedDomains
|
|
9371
|
+
? { ...definition.collapsedDomains }
|
|
9372
|
+
: { COL: [], ROW: [] };
|
|
9373
|
+
newDomains[pivotCell.dimension] = collapsedDomains;
|
|
9374
|
+
env.model.dispatch("UPDATE_PIVOT", {
|
|
9375
|
+
pivotId,
|
|
9376
|
+
pivot: { ...definition, collapsedDomains: newDomains },
|
|
9377
|
+
});
|
|
9378
|
+
}
|
|
9340
9379
|
|
|
9341
9380
|
class CellClipboardHandler extends AbstractCellClipboardHandler {
|
|
9342
9381
|
isCutAllowed(data) {
|
|
@@ -9510,7 +9549,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
9510
9549
|
pasteCell(origin, target, clipboardOption) {
|
|
9511
9550
|
const { sheetId, col, row } = target;
|
|
9512
9551
|
const targetCell = this.getters.getEvaluatedCell(target);
|
|
9513
|
-
const originFormat = origin?.format
|
|
9552
|
+
const originFormat = origin?.format || origin.evaluatedCell.format;
|
|
9514
9553
|
if (clipboardOption?.pasteOption === "asValue") {
|
|
9515
9554
|
this.dispatch("UPDATE_CELL", {
|
|
9516
9555
|
...target,
|
|
@@ -13736,7 +13775,7 @@ const GROWTH = {
|
|
|
13736
13775
|
if (knownDataY.length === 0 || knownDataY[0].length === 0) {
|
|
13737
13776
|
return new EvaluationError(emptyDataErrorMessage("known_data_y"));
|
|
13738
13777
|
}
|
|
13739
|
-
return expM(predictLinearValues(logM(toNumberMatrix(knownDataY, "
|
|
13778
|
+
return expM(predictLinearValues(logM(toNumberMatrix(knownDataY, "known_data_y")), toNumberMatrix(knownDataX, "known_data_x"), toNumberMatrix(newDataX, "new_data_y"), toBoolean(b)));
|
|
13740
13779
|
},
|
|
13741
13780
|
};
|
|
13742
13781
|
// -----------------------------------------------------------------------------
|
|
@@ -13809,7 +13848,7 @@ const LINEST = {
|
|
|
13809
13848
|
if (dataY.length === 0 || dataY[0].length === 0) {
|
|
13810
13849
|
return new EvaluationError(emptyDataErrorMessage("data_y"));
|
|
13811
13850
|
}
|
|
13812
|
-
return fullLinearRegression(toNumberMatrix(dataX, "
|
|
13851
|
+
return fullLinearRegression(toNumberMatrix(dataX, "data_x"), toNumberMatrix(dataY, "data_y"), toBoolean(calculateB), toBoolean(verbose));
|
|
13813
13852
|
},
|
|
13814
13853
|
isExported: true,
|
|
13815
13854
|
};
|
|
@@ -13828,7 +13867,7 @@ const LOGEST = {
|
|
|
13828
13867
|
if (dataY.length === 0 || dataY[0].length === 0) {
|
|
13829
13868
|
return new EvaluationError(emptyDataErrorMessage("data_y"));
|
|
13830
13869
|
}
|
|
13831
|
-
const coeffs = fullLinearRegression(toNumberMatrix(dataX, "
|
|
13870
|
+
const coeffs = fullLinearRegression(toNumberMatrix(dataX, "data_x"), logM(toNumberMatrix(dataY, "data_y")), toBoolean(calculateB), toBoolean(verbose));
|
|
13832
13871
|
for (let i = 0; i < coeffs.length; i++) {
|
|
13833
13872
|
coeffs[i][0] = Math.exp(coeffs[i][0]);
|
|
13834
13873
|
}
|
|
@@ -14449,7 +14488,7 @@ const TREND = {
|
|
|
14449
14488
|
if (knownDataY.length === 0 || knownDataY[0].length === 0) {
|
|
14450
14489
|
return new EvaluationError(emptyDataErrorMessage("known_data_y"));
|
|
14451
14490
|
}
|
|
14452
|
-
return predictLinearValues(toNumberMatrix(knownDataY, "
|
|
14491
|
+
return predictLinearValues(toNumberMatrix(knownDataY, "known_data_y"), toNumberMatrix(knownDataX, "known_data_x"), toNumberMatrix(newDataX, "new_data_y"), toBoolean(b));
|
|
14453
14492
|
},
|
|
14454
14493
|
};
|
|
14455
14494
|
// -----------------------------------------------------------------------------
|
|
@@ -22970,6 +23009,10 @@ const chartShowValuesPlugin = {
|
|
|
22970
23009
|
}
|
|
22971
23010
|
const ctx = chart.ctx;
|
|
22972
23011
|
ctx.save();
|
|
23012
|
+
const { left, top, height, width } = chart.chartArea;
|
|
23013
|
+
ctx.beginPath();
|
|
23014
|
+
ctx.rect(left, top, width, height);
|
|
23015
|
+
ctx.clip();
|
|
22973
23016
|
ctx.textAlign = "center";
|
|
22974
23017
|
ctx.textBaseline = "middle";
|
|
22975
23018
|
ctx.miterLimit = 1; // Avoid sharp artifacts on strokeText
|
|
@@ -24004,7 +24047,7 @@ class ChartJsComponent extends Component {
|
|
|
24004
24047
|
this.chart.update();
|
|
24005
24048
|
}
|
|
24006
24049
|
hasChartDataChanged() {
|
|
24007
|
-
return !deepEquals(this.currentRuntime
|
|
24050
|
+
return !deepEquals(this.getChartDataInRuntime(this.currentRuntime), this.getChartDataInRuntime(this.chartRuntime));
|
|
24008
24051
|
}
|
|
24009
24052
|
enableAnimationInChartData(chartData) {
|
|
24010
24053
|
return {
|
|
@@ -24012,6 +24055,17 @@ class ChartJsComponent extends Component {
|
|
|
24012
24055
|
options: { ...chartData.options, animation: { animateRotate: true } },
|
|
24013
24056
|
};
|
|
24014
24057
|
}
|
|
24058
|
+
getChartDataInRuntime(runtime) {
|
|
24059
|
+
const data = runtime.chartJsConfig.data;
|
|
24060
|
+
return {
|
|
24061
|
+
labels: data.labels,
|
|
24062
|
+
dataset: data.datasets.map((dataset) => ({
|
|
24063
|
+
data: dataset.data,
|
|
24064
|
+
label: dataset.label,
|
|
24065
|
+
tree: dataset.tree,
|
|
24066
|
+
})),
|
|
24067
|
+
};
|
|
24068
|
+
}
|
|
24015
24069
|
get animationChartId() {
|
|
24016
24070
|
return this.props.isFullScreen ? this.props.chartId + "-fullscreen" : this.props.chartId;
|
|
24017
24071
|
}
|
|
@@ -25435,6 +25489,7 @@ function getChartTimeOptions(labels, labelFormat, locale) {
|
|
|
25435
25489
|
parser: luxonFormat,
|
|
25436
25490
|
displayFormats,
|
|
25437
25491
|
unit: timeUnit ?? false,
|
|
25492
|
+
tooltipFormat: luxonFormat,
|
|
25438
25493
|
};
|
|
25439
25494
|
}
|
|
25440
25495
|
/**
|
|
@@ -26503,6 +26558,7 @@ function getLineChartScales(definition, args) {
|
|
|
26503
26558
|
};
|
|
26504
26559
|
Object.assign(scales.x, axis);
|
|
26505
26560
|
scales.x.ticks.maxTicksLimit = 15;
|
|
26561
|
+
delete scales?.x?.ticks?.callback;
|
|
26506
26562
|
}
|
|
26507
26563
|
else if (axisType === "linear") {
|
|
26508
26564
|
scales.x.type = "linear";
|
|
@@ -31581,7 +31637,8 @@ class Menu extends Component {
|
|
|
31581
31637
|
const menuItemsAndSeparators = [];
|
|
31582
31638
|
for (let i = 0; i < this.props.menuItems.length; i++) {
|
|
31583
31639
|
const menuItem = this.props.menuItems[i];
|
|
31584
|
-
if (menuItem.isVisible(this.env)
|
|
31640
|
+
if (menuItem.isVisible(this.env) &&
|
|
31641
|
+
(!this.isRoot(menuItem) || this.hasVisibleChildren(menuItem))) {
|
|
31585
31642
|
menuItemsAndSeparators.push(menuItem);
|
|
31586
31643
|
}
|
|
31587
31644
|
if (menuItem.separator &&
|
|
@@ -31623,6 +31680,9 @@ class Menu extends Component {
|
|
|
31623
31680
|
isRoot(menu) {
|
|
31624
31681
|
return !menu.execute;
|
|
31625
31682
|
}
|
|
31683
|
+
hasVisibleChildren(menu) {
|
|
31684
|
+
return menu.children(this.env).some((child) => child.isVisible(this.env));
|
|
31685
|
+
}
|
|
31626
31686
|
isEnabled(menu) {
|
|
31627
31687
|
if (menu.isEnabled(this.env)) {
|
|
31628
31688
|
return this.env.model.getters.isReadonly() ? menu.isReadonlyAllowed : true;
|
|
@@ -32181,7 +32241,7 @@ class ChartDashboardMenu extends Component {
|
|
|
32181
32241
|
}
|
|
32182
32242
|
openContextMenu(ev) {
|
|
32183
32243
|
this.menuState.isOpen = true;
|
|
32184
|
-
this.menuState.anchorRect =
|
|
32244
|
+
this.menuState.anchorRect = getBoundingRectAsPOJO(ev.currentTarget);
|
|
32185
32245
|
const figureId = this.env.model.getters.getFigureIdFromChartId(this.props.chartId);
|
|
32186
32246
|
this.menuState.menuItems = getChartMenuActions(figureId, () => { }, this.env);
|
|
32187
32247
|
}
|
|
@@ -32213,6 +32273,7 @@ class CarouselFigure extends Component {
|
|
|
32213
32273
|
onFigureDeleted: Function,
|
|
32214
32274
|
editFigureStyle: { type: Function, optional: true },
|
|
32215
32275
|
isFullScreen: { type: Boolean, optional: true },
|
|
32276
|
+
openContextMenu: { type: Function, optional: true },
|
|
32216
32277
|
};
|
|
32217
32278
|
static components = { ChartDashboardMenu, MenuPopover };
|
|
32218
32279
|
carouselTabsRef = useRef("carouselTabs");
|
|
@@ -32346,6 +32407,12 @@ class CarouselFigure extends Component {
|
|
|
32346
32407
|
get visibleCarouselItems() {
|
|
32347
32408
|
return this.carousel.items.filter((item) => item.type === "carouselDataView" && this.props.isFullScreen ? false : true);
|
|
32348
32409
|
}
|
|
32410
|
+
openContextMenu(event) {
|
|
32411
|
+
const target = event.currentTarget;
|
|
32412
|
+
if (target) {
|
|
32413
|
+
this.props.openContextMenu?.(getBoundingRectAsPOJO(target));
|
|
32414
|
+
}
|
|
32415
|
+
}
|
|
32349
32416
|
}
|
|
32350
32417
|
|
|
32351
32418
|
class ChartFigure extends Component {
|
|
@@ -32355,6 +32422,7 @@ class ChartFigure extends Component {
|
|
|
32355
32422
|
onFigureDeleted: Function,
|
|
32356
32423
|
editFigureStyle: { type: Function, optional: true },
|
|
32357
32424
|
isFullScreen: { type: Boolean, optional: true },
|
|
32425
|
+
openContextMenu: { type: Function, optional: true },
|
|
32358
32426
|
};
|
|
32359
32427
|
static components = { ChartDashboardMenu };
|
|
32360
32428
|
onDoubleClick() {
|
|
@@ -32387,6 +32455,7 @@ class ImageFigure extends Component {
|
|
|
32387
32455
|
figureUI: Object,
|
|
32388
32456
|
onFigureDeleted: Function,
|
|
32389
32457
|
editFigureStyle: { type: Function, optional: true },
|
|
32458
|
+
openContextMenu: { type: Function, optional: true },
|
|
32390
32459
|
};
|
|
32391
32460
|
static components = {};
|
|
32392
32461
|
// ---------------------------------------------------------------------------
|
|
@@ -34189,8 +34258,11 @@ class Composer extends Component {
|
|
|
34189
34258
|
}
|
|
34190
34259
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
34191
34260
|
this.props.composerStore.stopComposerRangeSelection();
|
|
34192
|
-
this.props.
|
|
34193
|
-
this.props.
|
|
34261
|
+
const isCurrentlyInactive = this.props.composerStore.editionMode === "inactive";
|
|
34262
|
+
this.props.onComposerContentFocused(newSelection);
|
|
34263
|
+
if (!isCurrentlyInactive) {
|
|
34264
|
+
this.props.composerStore.changeComposerCursorSelection(newSelection.start, newSelection.end);
|
|
34265
|
+
}
|
|
34194
34266
|
this.processTokenAtCursor();
|
|
34195
34267
|
}
|
|
34196
34268
|
onDblClick() {
|
|
@@ -34685,13 +34757,6 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
34685
34757
|
}
|
|
34686
34758
|
}
|
|
34687
34759
|
startEdition(text, selection) {
|
|
34688
|
-
if (selection) {
|
|
34689
|
-
const content = text || this.getComposerContent(this.getters.getActivePosition());
|
|
34690
|
-
const validSelection = this.isSelectionValid(content.length, selection.start, selection.end);
|
|
34691
|
-
if (!validSelection) {
|
|
34692
|
-
return;
|
|
34693
|
-
}
|
|
34694
|
-
}
|
|
34695
34760
|
const { col, row } = this.getters.getActivePosition();
|
|
34696
34761
|
this.model.dispatch("SELECT_FIGURE", { figureId: null });
|
|
34697
34762
|
this.model.dispatch("SCROLL_TO_CELL", { col, row });
|
|
@@ -34748,7 +34813,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
34748
34813
|
// ---------------------------------------------------------------------------
|
|
34749
34814
|
get currentContent() {
|
|
34750
34815
|
if (this.editionMode === "inactive") {
|
|
34751
|
-
return this.getComposerContent(this.getters.getActivePosition());
|
|
34816
|
+
return this.getComposerContent(this.getters.getActivePosition()).text;
|
|
34752
34817
|
}
|
|
34753
34818
|
return this._currentContent;
|
|
34754
34819
|
}
|
|
@@ -34947,8 +35012,9 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
34947
35012
|
this.sheetId = sheetId;
|
|
34948
35013
|
this.row = row;
|
|
34949
35014
|
this.editionMode = "editing";
|
|
34950
|
-
|
|
34951
|
-
this.
|
|
35015
|
+
const { text, adjustedSelection } = this.getComposerContent({ sheetId, col, row }, selection);
|
|
35016
|
+
this.initialContent = text;
|
|
35017
|
+
this.setContent(str || this.initialContent, adjustedSelection ?? selection);
|
|
34952
35018
|
this.colorIndexByRange = {};
|
|
34953
35019
|
const zone = positionToZone({ col: this.col, row: this.row });
|
|
34954
35020
|
this.captureSelection(zone, col, row);
|
|
@@ -35425,7 +35491,7 @@ class StandaloneComposerStore extends AbstractComposerStore {
|
|
|
35425
35491
|
constructor(get, args) {
|
|
35426
35492
|
super(get);
|
|
35427
35493
|
this.args = args;
|
|
35428
|
-
this._currentContent = this.getComposerContent();
|
|
35494
|
+
this._currentContent = this.getComposerContent().text;
|
|
35429
35495
|
}
|
|
35430
35496
|
getAutoCompleteProviders() {
|
|
35431
35497
|
const providersDefinitions = super.getAutoCompleteProviders();
|
|
@@ -35462,7 +35528,7 @@ class StandaloneComposerStore extends AbstractComposerStore {
|
|
|
35462
35528
|
})
|
|
35463
35529
|
.join("");
|
|
35464
35530
|
}
|
|
35465
|
-
return localizeContent(content, this.getters.getLocale());
|
|
35531
|
+
return { text: localizeContent(content, this.getters.getLocale()) };
|
|
35466
35532
|
}
|
|
35467
35533
|
stopEdition() {
|
|
35468
35534
|
this._stopEdition();
|
|
@@ -38682,6 +38748,74 @@ function getPath2D(svgPath) {
|
|
|
38682
38748
|
return path2D;
|
|
38683
38749
|
}
|
|
38684
38750
|
|
|
38751
|
+
/**
|
|
38752
|
+
* Get the relative path between two files
|
|
38753
|
+
*
|
|
38754
|
+
* Eg.:
|
|
38755
|
+
* from "folder1/file1.txt" to "folder2/file2.txt" => "../folder2/file2.txt"
|
|
38756
|
+
*/
|
|
38757
|
+
function getRelativePath(from, to) {
|
|
38758
|
+
const fromPathParts = from.split("/");
|
|
38759
|
+
const toPathParts = to.split("/");
|
|
38760
|
+
let relPath = "";
|
|
38761
|
+
let startIndex = 0;
|
|
38762
|
+
for (let i = 0; i < fromPathParts.length - 1; i++) {
|
|
38763
|
+
if (fromPathParts[i] === toPathParts[i]) {
|
|
38764
|
+
startIndex++;
|
|
38765
|
+
}
|
|
38766
|
+
else {
|
|
38767
|
+
relPath += "../";
|
|
38768
|
+
}
|
|
38769
|
+
}
|
|
38770
|
+
relPath += toPathParts.slice(startIndex).join("/");
|
|
38771
|
+
return relPath;
|
|
38772
|
+
}
|
|
38773
|
+
/**
|
|
38774
|
+
* Convert an array of element into an object where the objects keys were the elements position in the array.
|
|
38775
|
+
* Can give an offset as argument, and all the array indexes will we shifted by this offset in the returned object.
|
|
38776
|
+
*
|
|
38777
|
+
* eg. : ["a", "b"] => {0:"a", 1:"b"}
|
|
38778
|
+
*/
|
|
38779
|
+
function arrayToObject(array, indexOffset = 0) {
|
|
38780
|
+
const obj = {};
|
|
38781
|
+
for (let i = 0; i < array.length; i++) {
|
|
38782
|
+
if (array[i]) {
|
|
38783
|
+
obj[i + indexOffset] = array[i];
|
|
38784
|
+
}
|
|
38785
|
+
}
|
|
38786
|
+
return obj;
|
|
38787
|
+
}
|
|
38788
|
+
/**
|
|
38789
|
+
* In xlsx we can have string with unicode characters with the format _x00fa_.
|
|
38790
|
+
* Replace with characters understandable by JS
|
|
38791
|
+
*/
|
|
38792
|
+
function fixXlsxUnicode(str) {
|
|
38793
|
+
return str.replace(/_x([0-9a-zA-Z]{4})_/g, (match, code) => {
|
|
38794
|
+
return String.fromCharCode(parseInt(code, 16));
|
|
38795
|
+
});
|
|
38796
|
+
}
|
|
38797
|
+
/** Get a header in the SheetData. Create the header if it doesn't exist in the SheetData */
|
|
38798
|
+
function getSheetDataHeader(sheetData, dimension, index) {
|
|
38799
|
+
if (dimension === "COL") {
|
|
38800
|
+
if (!sheetData.cols[index]) {
|
|
38801
|
+
sheetData.cols[index] = {};
|
|
38802
|
+
}
|
|
38803
|
+
return sheetData.cols[index];
|
|
38804
|
+
}
|
|
38805
|
+
if (!sheetData.rows[index]) {
|
|
38806
|
+
sheetData.rows[index] = {};
|
|
38807
|
+
}
|
|
38808
|
+
return sheetData.rows[index];
|
|
38809
|
+
}
|
|
38810
|
+
/** Prefix the string by "=" if the string looks like a formula */
|
|
38811
|
+
function prefixFormulaWithEqual(formula) {
|
|
38812
|
+
if (formula[0] === "=") {
|
|
38813
|
+
return formula;
|
|
38814
|
+
}
|
|
38815
|
+
const tokens = tokenize(formula);
|
|
38816
|
+
return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
|
|
38817
|
+
}
|
|
38818
|
+
|
|
38685
38819
|
/**
|
|
38686
38820
|
* Map of the different types of conversions warnings and their name in error messages
|
|
38687
38821
|
*/
|
|
@@ -39204,66 +39338,6 @@ function hexaToInt(hex) {
|
|
|
39204
39338
|
*/
|
|
39205
39339
|
const DEFAULT_SYSTEM_COLOR = "FF000000";
|
|
39206
39340
|
|
|
39207
|
-
/**
|
|
39208
|
-
* Get the relative path between two files
|
|
39209
|
-
*
|
|
39210
|
-
* Eg.:
|
|
39211
|
-
* from "folder1/file1.txt" to "folder2/file2.txt" => "../folder2/file2.txt"
|
|
39212
|
-
*/
|
|
39213
|
-
function getRelativePath(from, to) {
|
|
39214
|
-
const fromPathParts = from.split("/");
|
|
39215
|
-
const toPathParts = to.split("/");
|
|
39216
|
-
let relPath = "";
|
|
39217
|
-
let startIndex = 0;
|
|
39218
|
-
for (let i = 0; i < fromPathParts.length - 1; i++) {
|
|
39219
|
-
if (fromPathParts[i] === toPathParts[i]) {
|
|
39220
|
-
startIndex++;
|
|
39221
|
-
}
|
|
39222
|
-
else {
|
|
39223
|
-
relPath += "../";
|
|
39224
|
-
}
|
|
39225
|
-
}
|
|
39226
|
-
relPath += toPathParts.slice(startIndex).join("/");
|
|
39227
|
-
return relPath;
|
|
39228
|
-
}
|
|
39229
|
-
/**
|
|
39230
|
-
* Convert an array of element into an object where the objects keys were the elements position in the array.
|
|
39231
|
-
* Can give an offset as argument, and all the array indexes will we shifted by this offset in the returned object.
|
|
39232
|
-
*
|
|
39233
|
-
* eg. : ["a", "b"] => {0:"a", 1:"b"}
|
|
39234
|
-
*/
|
|
39235
|
-
function arrayToObject(array, indexOffset = 0) {
|
|
39236
|
-
const obj = {};
|
|
39237
|
-
for (let i = 0; i < array.length; i++) {
|
|
39238
|
-
if (array[i]) {
|
|
39239
|
-
obj[i + indexOffset] = array[i];
|
|
39240
|
-
}
|
|
39241
|
-
}
|
|
39242
|
-
return obj;
|
|
39243
|
-
}
|
|
39244
|
-
/**
|
|
39245
|
-
* In xlsx we can have string with unicode characters with the format _x00fa_.
|
|
39246
|
-
* Replace with characters understandable by JS
|
|
39247
|
-
*/
|
|
39248
|
-
function fixXlsxUnicode(str) {
|
|
39249
|
-
return str.replace(/_x([0-9a-zA-Z]{4})_/g, (match, code) => {
|
|
39250
|
-
return String.fromCharCode(parseInt(code, 16));
|
|
39251
|
-
});
|
|
39252
|
-
}
|
|
39253
|
-
/** Get a header in the SheetData. Create the header if it doesn't exist in the SheetData */
|
|
39254
|
-
function getSheetDataHeader(sheetData, dimension, index) {
|
|
39255
|
-
if (dimension === "COL") {
|
|
39256
|
-
if (!sheetData.cols[index]) {
|
|
39257
|
-
sheetData.cols[index] = {};
|
|
39258
|
-
}
|
|
39259
|
-
return sheetData.cols[index];
|
|
39260
|
-
}
|
|
39261
|
-
if (!sheetData.rows[index]) {
|
|
39262
|
-
sheetData.rows[index] = {};
|
|
39263
|
-
}
|
|
39264
|
-
return sheetData.rows[index];
|
|
39265
|
-
}
|
|
39266
|
-
|
|
39267
39341
|
const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/m|\s|-|\/|\.|:)+$/i;
|
|
39268
39342
|
/**
|
|
39269
39343
|
* Convert excel format to o_spreadsheet format
|
|
@@ -39478,9 +39552,9 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
|
|
|
39478
39552
|
if (!rule.operator || !rule.formula || rule.formula.length === 0)
|
|
39479
39553
|
continue;
|
|
39480
39554
|
operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.operator];
|
|
39481
|
-
values.push(
|
|
39555
|
+
values.push(prefixFormulaWithEqual(rule.formula[0]));
|
|
39482
39556
|
if (rule.formula.length === 2) {
|
|
39483
|
-
values.push(
|
|
39557
|
+
values.push(prefixFormulaWithEqual(rule.formula[1]));
|
|
39484
39558
|
}
|
|
39485
39559
|
break;
|
|
39486
39560
|
}
|
|
@@ -39638,11 +39712,6 @@ function convertIcons(xlsxIconSet, index) {
|
|
|
39638
39712
|
? ICON_SETS[iconSet].neutral
|
|
39639
39713
|
: ICON_SETS[iconSet].good;
|
|
39640
39714
|
}
|
|
39641
|
-
/** Prefix the string by "=" if the string looks like a formula */
|
|
39642
|
-
function prefixFormula(formula) {
|
|
39643
|
-
const tokens = tokenize(formula);
|
|
39644
|
-
return tokens.length === 1 && tokens[0].type !== "REFERENCE" ? formula : "=" + formula;
|
|
39645
|
-
}
|
|
39646
39715
|
// ---------------------------------------------------------------------------
|
|
39647
39716
|
// Warnings
|
|
39648
39717
|
// ---------------------------------------------------------------------------
|
|
@@ -40118,7 +40187,7 @@ function convertDataValidationRules(xlsxDataValidations, warningManager) {
|
|
|
40118
40187
|
dvRules.push(decimalRule);
|
|
40119
40188
|
break;
|
|
40120
40189
|
case "list":
|
|
40121
|
-
const listRule =
|
|
40190
|
+
const listRule = convertListRule(dvId++, dv);
|
|
40122
40191
|
dvRules.push(listRule);
|
|
40123
40192
|
break;
|
|
40124
40193
|
case "date":
|
|
@@ -40138,9 +40207,9 @@ function convertDataValidationRules(xlsxDataValidations, warningManager) {
|
|
|
40138
40207
|
return dvRules;
|
|
40139
40208
|
}
|
|
40140
40209
|
function convertDecimalRule(id, dv) {
|
|
40141
|
-
const values = [dv.formula1.toString()];
|
|
40210
|
+
const values = [prefixFormulaWithEqual(dv.formula1.toString())];
|
|
40142
40211
|
if (dv.formula2) {
|
|
40143
|
-
values.push(dv.formula2.toString());
|
|
40212
|
+
values.push(prefixFormulaWithEqual(dv.formula2.toString()));
|
|
40144
40213
|
}
|
|
40145
40214
|
return {
|
|
40146
40215
|
id: id.toString(),
|
|
@@ -40152,7 +40221,7 @@ function convertDecimalRule(id, dv) {
|
|
|
40152
40221
|
},
|
|
40153
40222
|
};
|
|
40154
40223
|
}
|
|
40155
|
-
function
|
|
40224
|
+
function convertListRule(id, dv) {
|
|
40156
40225
|
const formula1 = dv.formula1.toString();
|
|
40157
40226
|
const isRangeRule = rangeReference.test(formula1);
|
|
40158
40227
|
return {
|
|
@@ -40168,9 +40237,9 @@ function convertListrule(id, dv) {
|
|
|
40168
40237
|
}
|
|
40169
40238
|
function convertDateRule(id, dv) {
|
|
40170
40239
|
let criterion;
|
|
40171
|
-
const values = [dv.formula1.toString()];
|
|
40240
|
+
const values = [prefixFormulaWithEqual(dv.formula1.toString())];
|
|
40172
40241
|
if (dv.formula2) {
|
|
40173
|
-
values.push(dv.formula2.toString());
|
|
40242
|
+
values.push(prefixFormulaWithEqual(dv.formula2.toString()));
|
|
40174
40243
|
criterion = {
|
|
40175
40244
|
type: XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[dv.operator],
|
|
40176
40245
|
values: getDateCriterionFormattedValues(values, DEFAULT_LOCALE),
|
|
@@ -40197,7 +40266,7 @@ function convertCustomRule(id, dv) {
|
|
|
40197
40266
|
isBlocking: dv.errorStyle !== "warning",
|
|
40198
40267
|
criterion: {
|
|
40199
40268
|
type: "customFormula",
|
|
40200
|
-
values: [
|
|
40269
|
+
values: [prefixFormulaWithEqual(dv.formula1.toString())],
|
|
40201
40270
|
},
|
|
40202
40271
|
};
|
|
40203
40272
|
}
|
|
@@ -45971,6 +46040,18 @@ class SpreadsheetPivotTable {
|
|
|
45971
46040
|
get numberOfCells() {
|
|
45972
46041
|
return this.rows.length * this.getNumberOfDataColumns();
|
|
45973
46042
|
}
|
|
46043
|
+
getColumnDomainsAtDepth(depth) {
|
|
46044
|
+
if (depth < 0 || depth >= this.columns.length - 1) {
|
|
46045
|
+
return [];
|
|
46046
|
+
}
|
|
46047
|
+
return this.columns[depth].map((col) => this.getDomain(col)).filter((d) => d.length);
|
|
46048
|
+
}
|
|
46049
|
+
getRowDomainsAtDepth(depth) {
|
|
46050
|
+
if (depth < 0 || depth > this.maxIndent) {
|
|
46051
|
+
return [];
|
|
46052
|
+
}
|
|
46053
|
+
return this.rows.filter((row) => row.indent === depth + 1).map((row) => this.getDomain(row));
|
|
46054
|
+
}
|
|
45974
46055
|
}
|
|
45975
46056
|
const EMPTY_PIVOT_CELL = { type: "EMPTY" };
|
|
45976
46057
|
|
|
@@ -46963,6 +47044,109 @@ const ungroupPivotHeadersAction = {
|
|
|
46963
47044
|
return areFieldValuesInGroups(definition, values, field, pivot.getFields());
|
|
46964
47045
|
},
|
|
46965
47046
|
};
|
|
47047
|
+
const toggleCollapsePivotGroupAction = {
|
|
47048
|
+
name: (env) => {
|
|
47049
|
+
const position = env.model.getters.getActivePosition();
|
|
47050
|
+
const pivotCellState = getPivotCellCollapseState(env.model.getters, position);
|
|
47051
|
+
if (pivotCellState.isPivotGroup) {
|
|
47052
|
+
return pivotCellState.isCollapsed ? _t("Expand") : _t("Collapse");
|
|
47053
|
+
}
|
|
47054
|
+
return "";
|
|
47055
|
+
},
|
|
47056
|
+
execute(env) {
|
|
47057
|
+
const position = env.model.getters.getActivePosition();
|
|
47058
|
+
togglePivotCollapse(position, env);
|
|
47059
|
+
},
|
|
47060
|
+
isVisible: (env) => {
|
|
47061
|
+
const position = env.model.getters.getActivePosition();
|
|
47062
|
+
const pivotCellState = getPivotCellCollapseState(env.model.getters, position);
|
|
47063
|
+
return pivotCellState.isPivotGroup;
|
|
47064
|
+
},
|
|
47065
|
+
};
|
|
47066
|
+
const collapseAllPivotGroupAction = {
|
|
47067
|
+
name: _t("Collapse all"),
|
|
47068
|
+
execute(env) {
|
|
47069
|
+
const position = env.model.getters.getActivePosition();
|
|
47070
|
+
const pivotCellState = getPivotCellCollapseState(env.model.getters, position);
|
|
47071
|
+
if (!pivotCellState.isPivotGroup) {
|
|
47072
|
+
return;
|
|
47073
|
+
}
|
|
47074
|
+
const { pivotCell, pivotId, siblingDomains } = pivotCellState;
|
|
47075
|
+
const definition = deepCopy(env.model.getters.getPivotCoreDefinition(pivotId));
|
|
47076
|
+
definition.collapsedDomains = definition.collapsedDomains || { COL: [], ROW: [] };
|
|
47077
|
+
const newCollapsed = [
|
|
47078
|
+
...(definition.collapsedDomains[pivotCell.dimension] || []),
|
|
47079
|
+
...siblingDomains,
|
|
47080
|
+
];
|
|
47081
|
+
const filteredCollapsed = newCollapsed.filter((domain, index) => index === newCollapsed.findIndex((d) => deepEquals(d, domain)));
|
|
47082
|
+
definition.collapsedDomains[pivotCell.dimension] = filteredCollapsed;
|
|
47083
|
+
env.model.dispatch("UPDATE_PIVOT", { pivotId, pivot: definition });
|
|
47084
|
+
},
|
|
47085
|
+
isVisible: (env) => {
|
|
47086
|
+
const position = env.model.getters.getActivePosition();
|
|
47087
|
+
const pivotCellState = getPivotCellCollapseState(env.model.getters, position);
|
|
47088
|
+
if (!pivotCellState.isPivotGroup) {
|
|
47089
|
+
return false;
|
|
47090
|
+
}
|
|
47091
|
+
const { pivotCell, pivotId, siblingDomains } = pivotCellState;
|
|
47092
|
+
const definition = env.model.getters.getPivotCoreDefinition(pivotId);
|
|
47093
|
+
return !siblingDomains.every((domain) => (definition.collapsedDomains?.[pivotCell.dimension] || []).some((d) => deepEquals(d, domain)));
|
|
47094
|
+
},
|
|
47095
|
+
};
|
|
47096
|
+
const expandAllPivotGroupAction = {
|
|
47097
|
+
name: _t("Expand all"),
|
|
47098
|
+
execute(env) {
|
|
47099
|
+
const position = env.model.getters.getActivePosition();
|
|
47100
|
+
const pivotCellState = getPivotCellCollapseState(env.model.getters, position);
|
|
47101
|
+
if (!pivotCellState.isPivotGroup) {
|
|
47102
|
+
return;
|
|
47103
|
+
}
|
|
47104
|
+
const { pivotCell, pivotId, siblingDomains } = pivotCellState;
|
|
47105
|
+
const definition = deepCopy(env.model.getters.getPivotCoreDefinition(pivotId));
|
|
47106
|
+
definition.collapsedDomains = definition.collapsedDomains || { COL: [], ROW: [] };
|
|
47107
|
+
const domains = definition.collapsedDomains[pivotCell.dimension] || [];
|
|
47108
|
+
const filteredDomains = domains.filter((domain) => !siblingDomains.find((d) => deepEquals(d, domain)));
|
|
47109
|
+
definition.collapsedDomains[pivotCell.dimension] = filteredDomains;
|
|
47110
|
+
env.model.dispatch("UPDATE_PIVOT", { pivotId, pivot: definition });
|
|
47111
|
+
},
|
|
47112
|
+
isVisible: (env) => {
|
|
47113
|
+
const position = env.model.getters.getActivePosition();
|
|
47114
|
+
const pivotCellState = getPivotCellCollapseState(env.model.getters, position);
|
|
47115
|
+
if (!pivotCellState.isPivotGroup) {
|
|
47116
|
+
return false;
|
|
47117
|
+
}
|
|
47118
|
+
const { pivotCell, pivotId, siblingDomains } = pivotCellState;
|
|
47119
|
+
const definition = env.model.getters.getPivotCoreDefinition(pivotId);
|
|
47120
|
+
const collapsedDomains = definition.collapsedDomains?.[pivotCell.dimension] || [];
|
|
47121
|
+
return collapsedDomains.some((domain) => siblingDomains.some((d) => deepEquals(d, domain)));
|
|
47122
|
+
},
|
|
47123
|
+
};
|
|
47124
|
+
function getPivotCellCollapseState(getters, position) {
|
|
47125
|
+
if (!getters.isSpillPivotFormula(position)) {
|
|
47126
|
+
return { isPivotGroup: false };
|
|
47127
|
+
}
|
|
47128
|
+
const pivotCell = getters.getPivotCellFromPosition(position);
|
|
47129
|
+
const pivotId = getters.getPivotIdFromPosition(position);
|
|
47130
|
+
if (pivotCell.type !== "HEADER" || !pivotId || !pivotCell.domain.length) {
|
|
47131
|
+
return { isPivotGroup: false };
|
|
47132
|
+
}
|
|
47133
|
+
const definition = getters.getPivotCoreDefinition(pivotId);
|
|
47134
|
+
const isDashboard = getters.isDashboard();
|
|
47135
|
+
const fields = pivotCell.dimension === "COL" ? definition.columns : definition.rows;
|
|
47136
|
+
const hasIcon = !isDashboard && pivotCell.domain.length !== fields.length;
|
|
47137
|
+
if (!hasIcon) {
|
|
47138
|
+
return { isPivotGroup: false };
|
|
47139
|
+
}
|
|
47140
|
+
const domains = definition.collapsedDomains?.[pivotCell.dimension] ?? [];
|
|
47141
|
+
const isCollapsed = domains.some((domain) => deepEquals(domain, pivotCell.domain));
|
|
47142
|
+
const pivot = getters.getPivot(pivotId);
|
|
47143
|
+
const table = pivot.getExpandedTableStructure();
|
|
47144
|
+
const depth = pivotCell.domain.length - 1;
|
|
47145
|
+
const siblingDomains = pivotCell.dimension === "ROW"
|
|
47146
|
+
? table.getRowDomainsAtDepth(depth)
|
|
47147
|
+
: table.getColumnDomainsAtDepth(depth);
|
|
47148
|
+
return { isPivotGroup: true, isCollapsed, pivotCell, pivotId, siblingDomains };
|
|
47149
|
+
}
|
|
46966
47150
|
function canSortPivot(getters, position) {
|
|
46967
47151
|
const pivotId = getters.getPivotIdFromPosition(position);
|
|
46968
47152
|
if (!pivotId || !getters.isExistingPivot(pivotId) || !getters.isSpillPivotFormula(position)) {
|
|
@@ -47298,6 +47482,23 @@ cellMenuRegistry
|
|
|
47298
47482
|
sequence: 155,
|
|
47299
47483
|
icon: "o-spreadsheet-Icon.MINUS_IN_BOX",
|
|
47300
47484
|
...ungroupPivotHeadersAction,
|
|
47485
|
+
})
|
|
47486
|
+
.add("collapse_pivot", {
|
|
47487
|
+
sequence: 156,
|
|
47488
|
+
name: _t("Expand/Collapse"),
|
|
47489
|
+
icon: "o-spreadsheet-Icon.COLLAPSE",
|
|
47490
|
+
})
|
|
47491
|
+
.addChild("toggle_collapse_pivot_cell", ["collapse_pivot"], {
|
|
47492
|
+
sequence: 10,
|
|
47493
|
+
...toggleCollapsePivotGroupAction,
|
|
47494
|
+
})
|
|
47495
|
+
.addChild("collapse_all_pivot", ["collapse_pivot"], {
|
|
47496
|
+
sequence: 20,
|
|
47497
|
+
...collapseAllPivotGroupAction,
|
|
47498
|
+
})
|
|
47499
|
+
.addChild("expand_all_pivot", ["collapse_pivot"], {
|
|
47500
|
+
sequence: 30,
|
|
47501
|
+
...expandAllPivotGroupAction,
|
|
47301
47502
|
})
|
|
47302
47503
|
.add("pivot_sorting", {
|
|
47303
47504
|
name: _t("Sort pivot"),
|
|
@@ -47922,6 +48123,7 @@ function createHeaderGroupContainerContextMenu(sheetId, dimension) {
|
|
|
47922
48123
|
execute: (env) => {
|
|
47923
48124
|
env.model.dispatch("UNFOLD_ALL_HEADER_GROUPS", { sheetId, dimension });
|
|
47924
48125
|
},
|
|
48126
|
+
icon: "o-spreadsheet-Icon.EXPAND",
|
|
47925
48127
|
},
|
|
47926
48128
|
{
|
|
47927
48129
|
id: "fold_all",
|
|
@@ -47929,6 +48131,7 @@ function createHeaderGroupContainerContextMenu(sheetId, dimension) {
|
|
|
47929
48131
|
execute: (env) => {
|
|
47930
48132
|
env.model.dispatch("FOLD_ALL_HEADER_GROUPS", { sheetId, dimension });
|
|
47931
48133
|
},
|
|
48134
|
+
icon: "o-spreadsheet-Icon.COLLAPSE",
|
|
47932
48135
|
},
|
|
47933
48136
|
]);
|
|
47934
48137
|
}
|
|
@@ -47950,6 +48153,11 @@ function getHeaderGroupContextMenu(sheetId, dimension, start, end) {
|
|
|
47950
48153
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
47951
48154
|
interactiveToggleGroup(env, sheetId, dimension, start, end);
|
|
47952
48155
|
},
|
|
48156
|
+
icon: (env) => {
|
|
48157
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
48158
|
+
const groupIsFolded = env.model.getters.isGroupFolded(sheetId, dimension, start, end);
|
|
48159
|
+
return groupIsFolded ? "o-spreadsheet-Icon.EXPAND" : "o-spreadsheet-Icon.COLLAPSE";
|
|
48160
|
+
},
|
|
47953
48161
|
},
|
|
47954
48162
|
{
|
|
47955
48163
|
id: "remove_group",
|
|
@@ -47958,6 +48166,7 @@ function getHeaderGroupContextMenu(sheetId, dimension, start, end) {
|
|
|
47958
48166
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
47959
48167
|
env.model.dispatch("UNGROUP_HEADERS", { sheetId, dimension, start, end });
|
|
47960
48168
|
},
|
|
48169
|
+
icon: "o-spreadsheet-Icon.TRASH",
|
|
47961
48170
|
separator: true,
|
|
47962
48171
|
},
|
|
47963
48172
|
]);
|
|
@@ -48820,39 +49029,66 @@ class CellComposerStore extends AbstractComposerStore {
|
|
|
48820
49029
|
this.model.dispatch("AUTOFILL_TABLE_COLUMN", { ...this.currentEditedCell });
|
|
48821
49030
|
this.setContent("");
|
|
48822
49031
|
}
|
|
48823
|
-
getComposerContent(position) {
|
|
49032
|
+
getComposerContent(position, selection) {
|
|
48824
49033
|
const locale = this.getters.getLocale();
|
|
48825
49034
|
const cell = this.getters.getCell(position);
|
|
48826
49035
|
if (cell?.isFormula) {
|
|
48827
49036
|
const prettifiedContent = this.getPrettifiedFormula(cell);
|
|
48828
|
-
|
|
49037
|
+
// when a formula is prettified (multi lines, indented), adapt the cursor position
|
|
49038
|
+
// to take into account line breaks and tabs
|
|
49039
|
+
function adjustCursorIndex(targetIndex) {
|
|
49040
|
+
let adjustedIndex = 0;
|
|
49041
|
+
let originalIndex = 0;
|
|
49042
|
+
while (originalIndex < targetIndex) {
|
|
49043
|
+
adjustedIndex++;
|
|
49044
|
+
const char = prettifiedContent[adjustedIndex];
|
|
49045
|
+
if (char !== "\n" && char !== "\t") {
|
|
49046
|
+
originalIndex++;
|
|
49047
|
+
}
|
|
49048
|
+
}
|
|
49049
|
+
return adjustedIndex;
|
|
49050
|
+
}
|
|
49051
|
+
let adjustedSelection = selection;
|
|
49052
|
+
if (selection) {
|
|
49053
|
+
adjustedSelection = {
|
|
49054
|
+
start: adjustCursorIndex(selection.start),
|
|
49055
|
+
end: adjustCursorIndex(selection.end),
|
|
49056
|
+
};
|
|
49057
|
+
}
|
|
49058
|
+
return {
|
|
49059
|
+
text: localizeFormula(prettifiedContent, locale),
|
|
49060
|
+
adjustedSelection,
|
|
49061
|
+
};
|
|
48829
49062
|
}
|
|
48830
49063
|
const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
|
|
48831
49064
|
if (spreader) {
|
|
48832
|
-
return "";
|
|
49065
|
+
return { text: "" };
|
|
49066
|
+
}
|
|
49067
|
+
if (cell?.content.startsWith("'")) {
|
|
49068
|
+
return { text: cell.content };
|
|
48833
49069
|
}
|
|
48834
49070
|
const { format, value, type, formattedValue } = this.getters.getEvaluatedCell(position);
|
|
48835
49071
|
switch (type) {
|
|
48836
49072
|
case CellValueType.empty:
|
|
48837
|
-
return "";
|
|
49073
|
+
return { text: "" };
|
|
48838
49074
|
case CellValueType.text:
|
|
48839
49075
|
case CellValueType.error:
|
|
48840
|
-
return value;
|
|
49076
|
+
return { text: value };
|
|
48841
49077
|
case CellValueType.boolean:
|
|
48842
|
-
return formattedValue;
|
|
49078
|
+
return { text: formattedValue };
|
|
48843
49079
|
case CellValueType.number:
|
|
48844
49080
|
if (format && isDateTimeFormat(format)) {
|
|
48845
49081
|
if (parseDateTime(formattedValue, locale) !== null) {
|
|
48846
49082
|
// formatted string can be parsed again
|
|
48847
|
-
return formattedValue;
|
|
49083
|
+
return { text: formattedValue };
|
|
48848
49084
|
}
|
|
48849
49085
|
// display a simplified and parsable string otherwise
|
|
48850
49086
|
const timeFormat = Number.isInteger(value)
|
|
48851
49087
|
? locale.dateFormat
|
|
48852
49088
|
: getDateTimeFormat(locale);
|
|
48853
|
-
return formatValue(value, { locale, format: timeFormat });
|
|
49089
|
+
return { text: formatValue(value, { locale, format: timeFormat }) };
|
|
48854
49090
|
}
|
|
48855
|
-
return this.numberComposerContent(value, format, locale);
|
|
49091
|
+
return { text: this.numberComposerContent(value, format, locale) };
|
|
48856
49092
|
}
|
|
48857
49093
|
}
|
|
48858
49094
|
getPrettifiedFormula(cell) {
|
|
@@ -48999,8 +49235,9 @@ class GridComposer extends Component {
|
|
|
48999
49235
|
},
|
|
49000
49236
|
focus: this.focus,
|
|
49001
49237
|
isDefaultFocus: true,
|
|
49002
|
-
onComposerContentFocused: () => this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
49238
|
+
onComposerContentFocused: (selection) => this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
49003
49239
|
focusMode: "contentFocus",
|
|
49240
|
+
selection,
|
|
49004
49241
|
}),
|
|
49005
49242
|
onComposerCellFocused: (content) => this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
49006
49243
|
focusMode: "cellFocus",
|
|
@@ -55688,12 +55925,13 @@ class DataValidationEditor extends Component {
|
|
|
55688
55925
|
onCloseSidePanel: { type: Function, optional: true },
|
|
55689
55926
|
};
|
|
55690
55927
|
state = useState({ rule: this.defaultDataValidationRule, errors: [] });
|
|
55928
|
+
editingSheetId;
|
|
55691
55929
|
setup() {
|
|
55930
|
+
this.editingSheetId = this.env.model.getters.getActiveSheetId();
|
|
55692
55931
|
if (this.props.rule) {
|
|
55693
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
55694
55932
|
this.state.rule = {
|
|
55695
55933
|
...this.props.rule,
|
|
55696
|
-
ranges: this.props.rule.ranges.map((range) => this.env.model.getters.getRangeString(range,
|
|
55934
|
+
ranges: this.props.rule.ranges.map((range) => this.env.model.getters.getRangeString(range, this.editingSheetId)),
|
|
55697
55935
|
};
|
|
55698
55936
|
this.state.rule.criterion.type = this.props.rule.criterion.type;
|
|
55699
55937
|
}
|
|
@@ -55727,7 +55965,6 @@ class DataValidationEditor extends Component {
|
|
|
55727
55965
|
const locale = this.env.model.getters.getLocale();
|
|
55728
55966
|
const criterion = rule.criterion;
|
|
55729
55967
|
const criterionEvaluator = criterionEvaluatorRegistry.get(criterion.type);
|
|
55730
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
55731
55968
|
const values = criterion.values
|
|
55732
55969
|
.slice(0, criterionEvaluator.numberOfValues(criterion))
|
|
55733
55970
|
.map((value) => value?.trim())
|
|
@@ -55735,8 +55972,8 @@ class DataValidationEditor extends Component {
|
|
|
55735
55972
|
.map((value) => canonicalizeContent(value, locale));
|
|
55736
55973
|
rule.criterion = { ...criterion, values };
|
|
55737
55974
|
return {
|
|
55738
|
-
sheetId,
|
|
55739
|
-
ranges: this.state.rule.ranges.map((xc) => this.env.model.getters.getRangeDataFromXc(
|
|
55975
|
+
sheetId: this.editingSheetId,
|
|
55976
|
+
ranges: this.state.rule.ranges.map((xc) => this.env.model.getters.getRangeDataFromXc(this.editingSheetId, xc)),
|
|
55740
55977
|
rule,
|
|
55741
55978
|
};
|
|
55742
55979
|
}
|
|
@@ -60846,7 +61083,7 @@ class CellPlugin extends CorePlugin {
|
|
|
60846
61083
|
(typeof parsedValue === "number"
|
|
60847
61084
|
? detectDateFormat(content, locale) || detectNumberFormat(content)
|
|
60848
61085
|
: undefined);
|
|
60849
|
-
if (!isTextFormat(format) && !isEvaluationError(content)) {
|
|
61086
|
+
if (!isTextFormat(format) && !content.startsWith("'") && !isEvaluationError(content)) {
|
|
60850
61087
|
content = toString(parsedValue);
|
|
60851
61088
|
}
|
|
60852
61089
|
return {
|
|
@@ -66744,7 +66981,7 @@ class FormulaDependencyGraph {
|
|
|
66744
66981
|
* in the correct order they should be evaluated.
|
|
66745
66982
|
* This is called a topological ordering (excluding cycles)
|
|
66746
66983
|
*/
|
|
66747
|
-
getCellsDependingOn(ranges) {
|
|
66984
|
+
getCellsDependingOn(ranges, ignore) {
|
|
66748
66985
|
const visited = this.createEmptyPositionSet();
|
|
66749
66986
|
const queue = Array.from(ranges).reverse();
|
|
66750
66987
|
while (queue.length > 0) {
|
|
@@ -66759,7 +66996,7 @@ class FormulaDependencyGraph {
|
|
|
66759
66996
|
const impactedPositions = this.rTree.search(range).map((dep) => dep.data);
|
|
66760
66997
|
const nextInQueue = {};
|
|
66761
66998
|
for (const position of impactedPositions) {
|
|
66762
|
-
if (!visited.has(position)) {
|
|
66999
|
+
if (!visited.has(position) && !ignore.has(position)) {
|
|
66763
67000
|
if (!nextInQueue[position.sheetId]) {
|
|
66764
67001
|
nextInQueue[position.sheetId] = [];
|
|
66765
67002
|
}
|
|
@@ -67317,7 +67554,7 @@ class Evaluator {
|
|
|
67317
67554
|
}
|
|
67318
67555
|
invalidatePositionsDependingOnSpread(sheetId, resultZone) {
|
|
67319
67556
|
// the result matrix is split in 2 zones to exclude the array formula position
|
|
67320
|
-
const invalidatedPositions = this.formulaDependencies().getCellsDependingOn(excludeTopLeft(resultZone).map((zone) => ({ sheetId, zone })));
|
|
67557
|
+
const invalidatedPositions = this.formulaDependencies().getCellsDependingOn(excludeTopLeft(resultZone).map((zone) => ({ sheetId, zone })), this.nextPositionsToUpdate);
|
|
67321
67558
|
invalidatedPositions.delete({ sheetId, col: resultZone.left, row: resultZone.top });
|
|
67322
67559
|
this.nextPositionsToUpdate.addMany(invalidatedPositions);
|
|
67323
67560
|
}
|
|
@@ -67435,7 +67672,7 @@ class Evaluator {
|
|
|
67435
67672
|
for (const sheetId in zonesBySheetIds) {
|
|
67436
67673
|
ranges.push(...zonesBySheetIds[sheetId].map((zone) => ({ sheetId, zone })));
|
|
67437
67674
|
}
|
|
67438
|
-
return this.formulaDependencies().getCellsDependingOn(ranges);
|
|
67675
|
+
return this.formulaDependencies().getCellsDependingOn(ranges, this.nextPositionsToUpdate);
|
|
67439
67676
|
}
|
|
67440
67677
|
}
|
|
67441
67678
|
function forEachSpreadPositionInMatrix(nbColumns, nbRows, callback) {
|
|
@@ -68702,32 +68939,6 @@ iconsOnCellRegistry.add("pivot_collapse", (getters, position) => {
|
|
|
68702
68939
|
}
|
|
68703
68940
|
return undefined;
|
|
68704
68941
|
});
|
|
68705
|
-
function togglePivotCollapse(position, env) {
|
|
68706
|
-
const pivotCell = env.model.getters.getPivotCellFromPosition(position);
|
|
68707
|
-
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
68708
|
-
if (!pivotId || pivotCell.type !== "HEADER") {
|
|
68709
|
-
return;
|
|
68710
|
-
}
|
|
68711
|
-
const definition = env.model.getters.getPivotCoreDefinition(pivotId);
|
|
68712
|
-
const collapsedDomains = definition.collapsedDomains?.[pivotCell.dimension]
|
|
68713
|
-
? [...definition.collapsedDomains[pivotCell.dimension]]
|
|
68714
|
-
: [];
|
|
68715
|
-
const index = collapsedDomains.findIndex((domain) => deepEquals(domain, pivotCell.domain));
|
|
68716
|
-
if (index !== -1) {
|
|
68717
|
-
collapsedDomains.splice(index, 1);
|
|
68718
|
-
}
|
|
68719
|
-
else {
|
|
68720
|
-
collapsedDomains.push(pivotCell.domain);
|
|
68721
|
-
}
|
|
68722
|
-
const newDomains = definition.collapsedDomains
|
|
68723
|
-
? { ...definition.collapsedDomains }
|
|
68724
|
-
: { COL: [], ROW: [] };
|
|
68725
|
-
newDomains[pivotCell.dimension] = collapsedDomains;
|
|
68726
|
-
env.model.dispatch("UPDATE_PIVOT", {
|
|
68727
|
-
pivotId,
|
|
68728
|
-
pivot: { ...definition, collapsedDomains: newDomains },
|
|
68729
|
-
});
|
|
68730
|
-
}
|
|
68731
68942
|
iconsOnCellRegistry.add("pivot_dashboard_sorting", (getters, position) => {
|
|
68732
68943
|
if (!getters.isDashboard()) {
|
|
68733
68944
|
return undefined;
|
|
@@ -68946,7 +69157,8 @@ class DynamicTablesPlugin extends CoreViewPlugin {
|
|
|
68946
69157
|
const topLeft = { col: unionZone.left, row: unionZone.top, sheetId };
|
|
68947
69158
|
const parentSpreadingCell = this.getters.getArrayFormulaSpreadingOn(topLeft);
|
|
68948
69159
|
if (!parentSpreadingCell) {
|
|
68949
|
-
|
|
69160
|
+
const evaluatedCell = this.getters.getEvaluatedCell(topLeft);
|
|
69161
|
+
return (evaluatedCell.value === CellErrorType.SpilledBlocked && !evaluatedCell.errorOriginPosition);
|
|
68950
69162
|
}
|
|
68951
69163
|
else if (deepEquals(parentSpreadingCell, topLeft) && getZoneArea(unionZone) === 1) {
|
|
68952
69164
|
return true;
|
|
@@ -79812,6 +80024,7 @@ class RibbonMenu extends Component {
|
|
|
79812
80024
|
static components = { Menu };
|
|
79813
80025
|
rootItems = topbarMenuRegistry.getMenuItems();
|
|
79814
80026
|
menuRef = useRef("menu");
|
|
80027
|
+
containerRef = useRef("container");
|
|
79815
80028
|
state = useState({
|
|
79816
80029
|
menuItems: this.rootItems,
|
|
79817
80030
|
title: _t("Menu Bar"),
|
|
@@ -79819,6 +80032,7 @@ class RibbonMenu extends Component {
|
|
|
79819
80032
|
});
|
|
79820
80033
|
setup() {
|
|
79821
80034
|
useExternalListener(window, "click", this.onExternalClick, { capture: true });
|
|
80035
|
+
onMounted(this.updateShadows);
|
|
79822
80036
|
}
|
|
79823
80037
|
onExternalClick(ev) {
|
|
79824
80038
|
if (!this.menuRef.el?.contains(ev.target)) {
|
|
@@ -79831,6 +80045,7 @@ class RibbonMenu extends Component {
|
|
|
79831
80045
|
this.state.parentState = { ...this.state };
|
|
79832
80046
|
this.state.menuItems = children;
|
|
79833
80047
|
this.state.title = menu.name(this.env);
|
|
80048
|
+
this.containerRef.el?.scrollTo({ top: 0 });
|
|
79834
80049
|
}
|
|
79835
80050
|
else {
|
|
79836
80051
|
this.state.menuItems = this.rootItems;
|
|
@@ -79852,6 +80067,19 @@ class RibbonMenu extends Component {
|
|
|
79852
80067
|
height: `${this.props.height}px`,
|
|
79853
80068
|
});
|
|
79854
80069
|
}
|
|
80070
|
+
updateShadows() {
|
|
80071
|
+
if (!this.containerRef.el) {
|
|
80072
|
+
return;
|
|
80073
|
+
}
|
|
80074
|
+
this.containerRef.el.classList.remove("scroll-top", "scroll-bottom");
|
|
80075
|
+
const maxScroll = this.containerRef.el.scrollHeight - this.containerRef.el.clientHeight || 0;
|
|
80076
|
+
if (this.containerRef.el.scrollTop < maxScroll - 1) {
|
|
80077
|
+
this.containerRef.el.classList.add("scroll-bottom");
|
|
80078
|
+
}
|
|
80079
|
+
if (this.containerRef.el.scrollTop > 0) {
|
|
80080
|
+
this.containerRef.el.classList.add("scroll-top");
|
|
80081
|
+
}
|
|
80082
|
+
}
|
|
79855
80083
|
onClickBack() {
|
|
79856
80084
|
if (!this.state.parentState) {
|
|
79857
80085
|
this.props.onClose();
|
|
@@ -79860,6 +80088,7 @@ class RibbonMenu extends Component {
|
|
|
79860
80088
|
this.state.menuItems = this.state.parentState.menuItems;
|
|
79861
80089
|
this.state.title = this.state.parentState.title;
|
|
79862
80090
|
this.state.parentState = this.state.parentState.parentState;
|
|
80091
|
+
this.containerRef.el?.scrollTo({ top: 0 });
|
|
79863
80092
|
}
|
|
79864
80093
|
get backTitle() {
|
|
79865
80094
|
return this.state.parentState ? _t("Go to previous menu") : _t("Close menu bar");
|
|
@@ -79911,7 +80140,9 @@ class SmallBottomBar extends Component {
|
|
|
79911
80140
|
: "inactive";
|
|
79912
80141
|
}
|
|
79913
80142
|
get showFxIcon() {
|
|
79914
|
-
return this.focus === "inactive" &&
|
|
80143
|
+
return (this.focus === "inactive" &&
|
|
80144
|
+
!this.composerStore.currentContent &&
|
|
80145
|
+
!this.composerStore.placeholder);
|
|
79915
80146
|
}
|
|
79916
80147
|
get rect() {
|
|
79917
80148
|
return this.composerRef.el
|
|
@@ -79928,8 +80159,9 @@ class SmallBottomBar extends Component {
|
|
|
79928
80159
|
},
|
|
79929
80160
|
focus: this.focus,
|
|
79930
80161
|
composerStore: this.composerStore,
|
|
79931
|
-
onComposerContentFocused: () => this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
80162
|
+
onComposerContentFocused: (selection) => this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
79932
80163
|
focusMode: "contentFocus",
|
|
80164
|
+
selection,
|
|
79933
80165
|
}),
|
|
79934
80166
|
isDefaultFocus: false,
|
|
79935
80167
|
inputStyle: cssPropertiesToCss({
|
|
@@ -79937,6 +80169,7 @@ class SmallBottomBar extends Component {
|
|
|
79937
80169
|
"max-height": `130px`,
|
|
79938
80170
|
}),
|
|
79939
80171
|
showAssistant: !isIOS(), // Hide assistant on iOS as it breaks visually
|
|
80172
|
+
placeholder: this.composerStore.placeholder,
|
|
79940
80173
|
};
|
|
79941
80174
|
}
|
|
79942
80175
|
get symbols() {
|
|
@@ -79982,7 +80215,9 @@ class TopBarComposer extends Component {
|
|
|
79982
80215
|
: "inactive";
|
|
79983
80216
|
}
|
|
79984
80217
|
get showFxIcon() {
|
|
79985
|
-
return this.focus === "inactive" &&
|
|
80218
|
+
return (this.focus === "inactive" &&
|
|
80219
|
+
!this.composerStore.currentContent &&
|
|
80220
|
+
!this.composerStore.placeholder);
|
|
79986
80221
|
}
|
|
79987
80222
|
get composerStyle() {
|
|
79988
80223
|
const style = {
|
|
@@ -85734,6 +85969,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
|
|
|
85734
85969
|
export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, LocalTransportService, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, getCaretDownSvg, getCaretUpSvg, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
|
|
85735
85970
|
|
|
85736
85971
|
|
|
85737
|
-
__info__.version = "19.1.0-alpha.
|
|
85738
|
-
__info__.date = "2025-10-
|
|
85739
|
-
__info__.hash = "
|
|
85972
|
+
__info__.version = "19.1.0-alpha.5";
|
|
85973
|
+
__info__.date = "2025-10-16T06:39:55.925Z";
|
|
85974
|
+
__info__.hash = "1a0e3d5";
|