@odoo/o-spreadsheet 18.5.0-alpha.10 → 18.5.0-alpha.12
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 +461 -158
- package/dist/o-spreadsheet.d.ts +176 -151
- package/dist/o-spreadsheet.esm.js +461 -158
- package/dist/o-spreadsheet.iife.js +461 -158
- package/dist/o-spreadsheet.iife.min.js +421 -419
- package/dist/o_spreadsheet.xml +35 -18
- 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.5.0-alpha.
|
|
6
|
-
* @date 2025-08-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.5.0-alpha.12
|
|
6
|
+
* @date 2025-08-29T08:05:09.767Z
|
|
7
|
+
* @hash 8ee7677
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -724,7 +724,7 @@
|
|
|
724
724
|
/*
|
|
725
725
|
* Concatenate an array of strings.
|
|
726
726
|
*/
|
|
727
|
-
function concat(chars) {
|
|
727
|
+
function concat$1(chars) {
|
|
728
728
|
// ~40% faster than chars.join("")
|
|
729
729
|
let output = "";
|
|
730
730
|
for (let i = 0, len = chars.length; i < len; i++) {
|
|
@@ -1196,7 +1196,7 @@
|
|
|
1196
1196
|
if (alphaHex !== 255) {
|
|
1197
1197
|
vals.push(alphaHex);
|
|
1198
1198
|
}
|
|
1199
|
-
return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
|
|
1199
|
+
return "#" + concat$1(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
|
|
1200
1200
|
}
|
|
1201
1201
|
/**
|
|
1202
1202
|
* RGBA to HEX representation (#RRGGBBAA).
|
|
@@ -1346,6 +1346,18 @@
|
|
|
1346
1346
|
function hexToHSLA(hex) {
|
|
1347
1347
|
return rgbaToHSLA(colorToRGBA(hex));
|
|
1348
1348
|
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Blend color2 on top of color1, with alpha blending.
|
|
1351
|
+
*/
|
|
1352
|
+
function blendColors(color1, color2) {
|
|
1353
|
+
const rgba2 = colorToRGBA(color2);
|
|
1354
|
+
const rgba1 = colorToRGBA(color1);
|
|
1355
|
+
const a = rgba2.a + rgba1.a * (1 - rgba2.a);
|
|
1356
|
+
const r = Math.round((rgba2.r * rgba2.a + rgba1.r * rgba1.a * (1 - rgba2.a)) / a);
|
|
1357
|
+
const g = Math.round((rgba2.g * rgba2.a + rgba1.g * rgba1.a * (1 - rgba2.a)) / a);
|
|
1358
|
+
const b = Math.round((rgba2.b * rgba2.a + rgba1.b * rgba1.a * (1 - rgba2.a)) / a);
|
|
1359
|
+
return rgbaToHex({ r, g, b, a });
|
|
1360
|
+
}
|
|
1349
1361
|
function colorOrNumberToRGBA(color) {
|
|
1350
1362
|
if (typeof color === "number") {
|
|
1351
1363
|
return colorToRGBA(colorNumberToHex(color));
|
|
@@ -2660,6 +2672,7 @@
|
|
|
2660
2672
|
"AUTOFILL_CELL",
|
|
2661
2673
|
"SET_BORDER",
|
|
2662
2674
|
"SET_ZONE_BORDERS",
|
|
2675
|
+
"SET_BORDERS_ON_TARGET",
|
|
2663
2676
|
]);
|
|
2664
2677
|
const invalidSubtotalFormulasCommands = new Set([
|
|
2665
2678
|
"UNHIDE_COLUMNS_ROWS",
|
|
@@ -2687,6 +2700,7 @@
|
|
|
2687
2700
|
"UPDATE_FILTER",
|
|
2688
2701
|
"UPDATE_CHART",
|
|
2689
2702
|
"UPDATE_CAROUSEL_ACTIVE_ITEM",
|
|
2703
|
+
"UPDATE_PIVOT",
|
|
2690
2704
|
]);
|
|
2691
2705
|
const coreTypes = new Set([
|
|
2692
2706
|
/** CELLS */
|
|
@@ -5110,6 +5124,9 @@
|
|
|
5110
5124
|
if (content === "") {
|
|
5111
5125
|
return null;
|
|
5112
5126
|
}
|
|
5127
|
+
if (content.includes("\n")) {
|
|
5128
|
+
return content;
|
|
5129
|
+
}
|
|
5113
5130
|
if (isNumber(content, DEFAULT_LOCALE)) {
|
|
5114
5131
|
return parseNumber(content, DEFAULT_LOCALE);
|
|
5115
5132
|
}
|
|
@@ -7318,14 +7335,11 @@
|
|
|
7318
7335
|
const width = content[0].length, height = content.length;
|
|
7319
7336
|
return target.map((t) => splitZoneForPaste(t, width, height)).flat();
|
|
7320
7337
|
}
|
|
7321
|
-
function parseOSClipboardContent(content
|
|
7338
|
+
function parseOSClipboardContent(content) {
|
|
7322
7339
|
let spreadsheetContent = undefined;
|
|
7323
7340
|
if (content[ClipboardMIMEType.Html]) {
|
|
7324
7341
|
const htmlDocument = new DOMParser().parseFromString(content[ClipboardMIMEType.Html], "text/html");
|
|
7325
|
-
|
|
7326
|
-
.querySelector("div")
|
|
7327
|
-
?.getAttribute("data-osheet-clipboard");
|
|
7328
|
-
spreadsheetContent = oSheetClipboardData && JSON.parse(oSheetClipboardData);
|
|
7342
|
+
spreadsheetContent = getOSheetDataFromHTML(htmlDocument);
|
|
7329
7343
|
}
|
|
7330
7344
|
const textContent = content[ClipboardMIMEType.PlainText] || "";
|
|
7331
7345
|
let imageBlob = undefined;
|
|
@@ -7344,6 +7358,17 @@
|
|
|
7344
7358
|
};
|
|
7345
7359
|
return osClipboardContent;
|
|
7346
7360
|
}
|
|
7361
|
+
function getOSheetDataFromHTML(htmlDocument) {
|
|
7362
|
+
const attributes = [...htmlDocument.documentElement.attributes];
|
|
7363
|
+
// Check if it's a Microsoft Office clipboard data (it will have some namespaces defined in the root element)
|
|
7364
|
+
if (attributes.some((attr) => attr.value.includes("microsoft"))) {
|
|
7365
|
+
return undefined;
|
|
7366
|
+
}
|
|
7367
|
+
const oSheetClipboardData = htmlDocument
|
|
7368
|
+
.querySelector("div")
|
|
7369
|
+
?.getAttribute("data-osheet-clipboard");
|
|
7370
|
+
return oSheetClipboardData && JSON.parse(oSheetClipboardData);
|
|
7371
|
+
}
|
|
7347
7372
|
/**
|
|
7348
7373
|
* Applies each clipboard handler to paste its corresponding data into the target.
|
|
7349
7374
|
*/
|
|
@@ -18337,7 +18362,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
18337
18362
|
const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
|
|
18338
18363
|
const UNARY_OPERATORS_PREFIX = ["-", "+"];
|
|
18339
18364
|
const UNARY_OPERATORS_POSTFIX = ["%"];
|
|
18340
|
-
const ASSOCIATIVE_OPERATORS = ["*", "+", "&"];
|
|
18341
18365
|
class TokenList {
|
|
18342
18366
|
tokens;
|
|
18343
18367
|
currentIndex = 0;
|
|
@@ -18358,8 +18382,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
18358
18382
|
}
|
|
18359
18383
|
}
|
|
18360
18384
|
const OP_PRIORITY = {
|
|
18385
|
+
"%": 40,
|
|
18361
18386
|
"^": 30,
|
|
18362
|
-
"%": 30,
|
|
18363
18387
|
"*": 20,
|
|
18364
18388
|
"/": 20,
|
|
18365
18389
|
"+": 15,
|
|
@@ -18640,64 +18664,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
18640
18664
|
return ast;
|
|
18641
18665
|
}
|
|
18642
18666
|
}
|
|
18643
|
-
/**
|
|
18644
|
-
* Converts an ast formula to the corresponding string
|
|
18645
|
-
*/
|
|
18646
|
-
function astToFormula(ast) {
|
|
18647
|
-
switch (ast.type) {
|
|
18648
|
-
case "FUNCALL":
|
|
18649
|
-
const args = ast.args.map((arg) => astToFormula(arg));
|
|
18650
|
-
return `${ast.value}(${args.join(",")})`;
|
|
18651
|
-
case "NUMBER":
|
|
18652
|
-
return ast.value.toString();
|
|
18653
|
-
case "REFERENCE":
|
|
18654
|
-
return ast.value;
|
|
18655
|
-
case "STRING":
|
|
18656
|
-
return `"${ast.value}"`;
|
|
18657
|
-
case "BOOLEAN":
|
|
18658
|
-
return ast.value ? "TRUE" : "FALSE";
|
|
18659
|
-
case "UNARY_OPERATION":
|
|
18660
|
-
return ast.postfix
|
|
18661
|
-
? leftOperandToFormula(ast) + ast.value
|
|
18662
|
-
: ast.value + rightOperandToFormula(ast);
|
|
18663
|
-
case "BIN_OPERATION":
|
|
18664
|
-
return leftOperandToFormula(ast) + ast.value + rightOperandToFormula(ast);
|
|
18665
|
-
default:
|
|
18666
|
-
return ast.value;
|
|
18667
|
-
}
|
|
18668
|
-
}
|
|
18669
|
-
/**
|
|
18670
|
-
* Convert the left operand of a binary operation to the corresponding string
|
|
18671
|
-
* and enclose the result inside parenthesis if necessary.
|
|
18672
|
-
*/
|
|
18673
|
-
function leftOperandToFormula(operationAST) {
|
|
18674
|
-
const mainOperator = operationAST.value;
|
|
18675
|
-
const leftOperation = "left" in operationAST ? operationAST.left : operationAST.operand;
|
|
18676
|
-
const leftOperator = leftOperation.value;
|
|
18677
|
-
const needParenthesis = leftOperation.type === "BIN_OPERATION" && OP_PRIORITY[leftOperator] < OP_PRIORITY[mainOperator];
|
|
18678
|
-
return needParenthesis ? `(${astToFormula(leftOperation)})` : astToFormula(leftOperation);
|
|
18679
|
-
}
|
|
18680
|
-
/**
|
|
18681
|
-
* Convert the right operand of a binary or unary operation to the corresponding string
|
|
18682
|
-
* and enclose the result inside parenthesis if necessary.
|
|
18683
|
-
*/
|
|
18684
|
-
function rightOperandToFormula(operationAST) {
|
|
18685
|
-
const mainOperator = operationAST.value;
|
|
18686
|
-
const rightOperation = "right" in operationAST ? operationAST.right : operationAST.operand;
|
|
18687
|
-
const rightPriority = OP_PRIORITY[rightOperation.value];
|
|
18688
|
-
const mainPriority = OP_PRIORITY[mainOperator];
|
|
18689
|
-
let needParenthesis = false;
|
|
18690
|
-
if (rightOperation.type !== "BIN_OPERATION") {
|
|
18691
|
-
needParenthesis = false;
|
|
18692
|
-
}
|
|
18693
|
-
else if (rightPriority < mainPriority) {
|
|
18694
|
-
needParenthesis = true;
|
|
18695
|
-
}
|
|
18696
|
-
else if (rightPriority === mainPriority && !ASSOCIATIVE_OPERATORS.includes(mainOperator)) {
|
|
18697
|
-
needParenthesis = true;
|
|
18698
|
-
}
|
|
18699
|
-
return needParenthesis ? `(${astToFormula(rightOperation)})` : astToFormula(rightOperation);
|
|
18700
|
-
}
|
|
18701
18667
|
|
|
18702
18668
|
/**
|
|
18703
18669
|
* Add the following information on tokens:
|
|
@@ -22196,7 +22162,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
22196
22162
|
};
|
|
22197
22163
|
}
|
|
22198
22164
|
}
|
|
22199
|
-
return concat(tokens.map((token) => token.value));
|
|
22165
|
+
return concat$1(tokens.map((token) => token.value));
|
|
22200
22166
|
}
|
|
22201
22167
|
function adaptStringRange(defaultSheetId, sheetXC, applyChange) {
|
|
22202
22168
|
const sheetName = splitReference(sheetXC).sheetName;
|
|
@@ -28281,10 +28247,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28281
28247
|
};
|
|
28282
28248
|
}
|
|
28283
28249
|
getDefinitionForExcel() {
|
|
28284
|
-
// Excel does not support aggregating labels
|
|
28285
|
-
if (this.aggregated) {
|
|
28286
|
-
return undefined;
|
|
28287
|
-
}
|
|
28288
28250
|
const { dataSets, labelRange } = this.getCommonDataSetAttributesForExcel(this.labelRange, this.dataSets, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
28289
28251
|
const definition = this.getDefinition();
|
|
28290
28252
|
return {
|
|
@@ -29486,9 +29448,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29486
29448
|
};
|
|
29487
29449
|
}
|
|
29488
29450
|
getDefinitionForExcel() {
|
|
29489
|
-
if (this.aggregated) {
|
|
29490
|
-
return undefined;
|
|
29491
|
-
}
|
|
29492
29451
|
const { dataSets, labelRange } = this.getCommonDataSetAttributesForExcel(this.labelRange, this.dataSets, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
29493
29452
|
const definition = this.getDefinition();
|
|
29494
29453
|
return {
|
|
@@ -29636,10 +29595,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29636
29595
|
return new ScatterChart(definition, this.sheetId, this.getters);
|
|
29637
29596
|
}
|
|
29638
29597
|
getDefinitionForExcel() {
|
|
29639
|
-
// Excel does not support aggregating labels
|
|
29640
|
-
if (this.aggregated) {
|
|
29641
|
-
return undefined;
|
|
29642
|
-
}
|
|
29643
29598
|
const dataSets = this.dataSets
|
|
29644
29599
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
29645
29600
|
.filter((ds) => ds.range !== "");
|
|
@@ -30958,7 +30913,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30958
30913
|
const value = expressions[i] instanceof XMLString ? expressions[i] : xmlEscape(expressions[i]);
|
|
30959
30914
|
str.push(value + strings[i + 1]);
|
|
30960
30915
|
}
|
|
30961
|
-
return new XMLString(concat(str));
|
|
30916
|
+
return new XMLString(concat$1(str));
|
|
30962
30917
|
}
|
|
30963
30918
|
/**
|
|
30964
30919
|
* Removes the escaped namespace of all the xml tags in the string.
|
|
@@ -32044,10 +31999,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32044
31999
|
const item = chartSubtypeRegistry.get(type);
|
|
32045
32000
|
return {
|
|
32046
32001
|
id: item.chartType,
|
|
32047
|
-
label: item.displayName,
|
|
32002
|
+
label: _t("Show as %(chart_type)s chart", { chart_type: item.displayName.toLowerCase() }),
|
|
32048
32003
|
onClick: () => this.updateType(item.chartType),
|
|
32049
|
-
|
|
32050
|
-
|
|
32004
|
+
class: item.chartType === definition.type ? "active" : "",
|
|
32005
|
+
preview: item.preview,
|
|
32051
32006
|
};
|
|
32052
32007
|
});
|
|
32053
32008
|
}
|
|
@@ -32083,18 +32038,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32083
32038
|
sheetId: this.getters.getActiveSheetId(),
|
|
32084
32039
|
});
|
|
32085
32040
|
}
|
|
32086
|
-
getIconClasses(type) {
|
|
32087
|
-
if (type.includes("bar")) {
|
|
32088
|
-
return "fa fa-bar-chart";
|
|
32089
|
-
}
|
|
32090
|
-
if (type.includes("line")) {
|
|
32091
|
-
return "fa fa-line-chart";
|
|
32092
|
-
}
|
|
32093
|
-
if (type.includes("pie")) {
|
|
32094
|
-
return "fa fa-pie-chart";
|
|
32095
|
-
}
|
|
32096
|
-
return "";
|
|
32097
|
-
}
|
|
32098
32041
|
}
|
|
32099
32042
|
|
|
32100
32043
|
class ChartDashboardMenu extends owl.Component {
|
|
@@ -32133,20 +32076,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32133
32076
|
if (definition.type === "scorecard") {
|
|
32134
32077
|
return undefined;
|
|
32135
32078
|
}
|
|
32136
|
-
|
|
32137
|
-
return {
|
|
32138
|
-
id: "fullScreenChart",
|
|
32139
|
-
label: _t("Exit Full Screen"),
|
|
32140
|
-
iconClass: "fa fa-compress",
|
|
32141
|
-
onClick: () => {
|
|
32142
|
-
this.fullScreenFigureStore.toggleFullScreenChart(figureId);
|
|
32143
|
-
},
|
|
32144
|
-
};
|
|
32145
|
-
}
|
|
32079
|
+
const isFullScreen = this.props.chartId === this.fullScreenFigureStore.fullScreenFigure?.id;
|
|
32146
32080
|
return {
|
|
32147
32081
|
id: "fullScreenChart",
|
|
32148
|
-
label: _t("Full Screen"),
|
|
32149
|
-
|
|
32082
|
+
label: isFullScreen ? _t("Exit Full Screen") : _t("Full Screen"),
|
|
32083
|
+
class: `text-muted fa ${isFullScreen ? "fa-compress" : "fa-expand"}`,
|
|
32150
32084
|
onClick: () => {
|
|
32151
32085
|
this.fullScreenFigureStore.toggleFullScreenChart(figureId);
|
|
32152
32086
|
},
|
|
@@ -34328,7 +34262,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34328
34262
|
if (isFormula(content)) {
|
|
34329
34263
|
const missing = this.getNumberOfMissingParenthesis(this.currentTokens);
|
|
34330
34264
|
if (missing > 0) {
|
|
34331
|
-
content += concat(new Array(missing).fill(")"));
|
|
34265
|
+
content += concat$1(new Array(missing).fill(")"));
|
|
34332
34266
|
}
|
|
34333
34267
|
}
|
|
34334
34268
|
}
|
|
@@ -34380,9 +34314,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34380
34314
|
if (isNewCurrentContent || this.editionMode !== "inactive") {
|
|
34381
34315
|
const locale = this.getters.getLocale();
|
|
34382
34316
|
this.currentTokens = isFormula(text) ? composerTokenize(text, locale) : [];
|
|
34383
|
-
|
|
34317
|
+
const nonSpaceTokensCount = this.currentTokens.filter((token) => token.type !== "SPACE").length;
|
|
34318
|
+
if (nonSpaceTokensCount > 1000) {
|
|
34384
34319
|
if (raise) {
|
|
34385
|
-
this.notificationStore.raiseError(_t("This formula has over
|
|
34320
|
+
this.notificationStore.raiseError(_t("This formula has over 1000 parts. It can't be processed properly, consider splitting it into multiple cells"));
|
|
34386
34321
|
}
|
|
34387
34322
|
}
|
|
34388
34323
|
}
|
|
@@ -34803,6 +34738,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34803
34738
|
padding-right: 3px;
|
|
34804
34739
|
outline: none;
|
|
34805
34740
|
|
|
34741
|
+
tab-size: 4;
|
|
34742
|
+
|
|
34806
34743
|
p {
|
|
34807
34744
|
margin-bottom: 0px;
|
|
34808
34745
|
|
|
@@ -47002,18 +46939,18 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47002
46939
|
};
|
|
47003
46940
|
const pivotSortingAsc = {
|
|
47004
46941
|
name: _t("Ascending"),
|
|
47005
|
-
execute: (env) => sortPivot(env, "asc"),
|
|
47006
|
-
isActive: (env) =>
|
|
46942
|
+
execute: (env) => sortPivot(env, env.model.getters.getActivePosition(), "asc"),
|
|
46943
|
+
isActive: (env) => env.model.getters.getPivotCellSortDirection(env.model.getters.getActivePosition()) === "asc",
|
|
47007
46944
|
};
|
|
47008
46945
|
const pivotSortingDesc = {
|
|
47009
46946
|
name: _t("Descending"),
|
|
47010
|
-
execute: (env) => sortPivot(env, "desc"),
|
|
47011
|
-
isActive: (env) =>
|
|
46947
|
+
execute: (env) => sortPivot(env, env.model.getters.getActivePosition(), "desc"),
|
|
46948
|
+
isActive: (env) => env.model.getters.getPivotCellSortDirection(env.model.getters.getActivePosition()) === "desc",
|
|
47012
46949
|
};
|
|
47013
46950
|
const noPivotSorting = {
|
|
47014
46951
|
name: _t("No sorting"),
|
|
47015
|
-
execute: (env) => sortPivot(env, "none"),
|
|
47016
|
-
isActive: (env) =>
|
|
46952
|
+
execute: (env) => sortPivot(env, env.model.getters.getActivePosition(), "none"),
|
|
46953
|
+
isActive: (env) => env.model.getters.getPivotCellSortDirection(env.model.getters.getActivePosition()) === "none",
|
|
47017
46954
|
};
|
|
47018
46955
|
const FIX_FORMULAS = {
|
|
47019
46956
|
name: _t("Convert to individual formulas"),
|
|
@@ -47149,23 +47086,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47149
47086
|
return areFieldValuesInGroups(definition, values, field, pivot.getFields());
|
|
47150
47087
|
},
|
|
47151
47088
|
};
|
|
47152
|
-
function canSortPivot(
|
|
47153
|
-
const
|
|
47154
|
-
|
|
47155
|
-
if (!pivotId ||
|
|
47156
|
-
!env.model.getters.isExistingPivot(pivotId) ||
|
|
47157
|
-
!env.model.getters.isSpillPivotFormula(position)) {
|
|
47089
|
+
function canSortPivot(getters, position) {
|
|
47090
|
+
const pivotId = getters.getPivotIdFromPosition(position);
|
|
47091
|
+
if (!pivotId || !getters.isExistingPivot(pivotId) || !getters.isSpillPivotFormula(position)) {
|
|
47158
47092
|
return false;
|
|
47159
47093
|
}
|
|
47160
|
-
const pivot =
|
|
47094
|
+
const pivot = getters.getPivot(pivotId);
|
|
47161
47095
|
if (!pivot.isValid()) {
|
|
47162
47096
|
return false;
|
|
47163
47097
|
}
|
|
47164
|
-
const pivotCell =
|
|
47098
|
+
const pivotCell = getters.getPivotCellFromPosition(position);
|
|
47165
47099
|
return pivotCell.type === "VALUE" || pivotCell.type === "MEASURE_HEADER";
|
|
47166
47100
|
}
|
|
47167
|
-
function sortPivot(env, order) {
|
|
47168
|
-
const position = env.model.getters.getActivePosition();
|
|
47101
|
+
function sortPivot(env, position, order) {
|
|
47169
47102
|
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
47170
47103
|
const pivotCell = env.model.getters.getPivotCellFromPosition(position);
|
|
47171
47104
|
if (pivotCell.type === "EMPTY" || pivotCell.type === "HEADER" || !pivotId) {
|
|
@@ -47191,24 +47124,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47191
47124
|
},
|
|
47192
47125
|
});
|
|
47193
47126
|
}
|
|
47194
|
-
function isPivotSortMenuItemActive(env, order) {
|
|
47195
|
-
const position = env.model.getters.getActivePosition();
|
|
47196
|
-
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
47197
|
-
const pivotCell = env.model.getters.getPivotCellFromPosition(position);
|
|
47198
|
-
if (pivotCell.type === "EMPTY" || pivotCell.type === "HEADER" || !pivotId) {
|
|
47199
|
-
return false;
|
|
47200
|
-
}
|
|
47201
|
-
const pivot = env.model.getters.getPivot(pivotId);
|
|
47202
|
-
const colDomain = domainToColRowDomain(pivot, pivotCell.domain).colDomain;
|
|
47203
|
-
const sortedColumn = pivot.definition.sortedColumn;
|
|
47204
|
-
if (order === "none") {
|
|
47205
|
-
return !sortedColumn;
|
|
47206
|
-
}
|
|
47207
|
-
if (!sortedColumn || sortedColumn.order !== order) {
|
|
47208
|
-
return false;
|
|
47209
|
-
}
|
|
47210
|
-
return sortedColumn.measure === pivotCell.measure && deepEquals(sortedColumn.domain, colDomain);
|
|
47211
|
-
}
|
|
47212
47127
|
/*
|
|
47213
47128
|
* Get the values of the pivot headers in the current selection, if all the pivot headers on the selection belong
|
|
47214
47129
|
* to the same pivot, the same field and that the pivot formula is a dynamic pivot. Otherwise return undefined.
|
|
@@ -47511,7 +47426,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47511
47426
|
name: _t("Sort pivot"),
|
|
47512
47427
|
sequence: 155,
|
|
47513
47428
|
icon: "o-spreadsheet-Icon.SORT_RANGE",
|
|
47514
|
-
isVisible:
|
|
47429
|
+
isVisible: (env) => {
|
|
47430
|
+
const position = env.model.getters.getActivePosition();
|
|
47431
|
+
return canSortPivot(env.model.getters, position);
|
|
47432
|
+
},
|
|
47515
47433
|
})
|
|
47516
47434
|
.add("pivot_fix_formulas", {
|
|
47517
47435
|
...FIX_FORMULAS,
|
|
@@ -48653,6 +48571,280 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48653
48571
|
}
|
|
48654
48572
|
}
|
|
48655
48573
|
|
|
48574
|
+
const ASSOCIATIVE_OPERATORS = ["*", "+", "&"];
|
|
48575
|
+
/**
|
|
48576
|
+
* Pretty-prints formula ASTs into readable formulas.
|
|
48577
|
+
*
|
|
48578
|
+
* Implements a Wadler-inspired pretty printer:
|
|
48579
|
+
* it converts an AST into a `Doc` structure,
|
|
48580
|
+
* and then chooses between compact (flat) or expanded (with
|
|
48581
|
+
* line breaks and indentation) layouts depending on space.
|
|
48582
|
+
*
|
|
48583
|
+
* References:
|
|
48584
|
+
* - https://lik.ai/blog/how-a-pretty-printer-works/
|
|
48585
|
+
* - Wadler, "A prettier printer": https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf
|
|
48586
|
+
*/
|
|
48587
|
+
function prettify(ast, width = 60) {
|
|
48588
|
+
return "=" + print(astToDoc(ast), width - 1); // width-1 because of the leading '='
|
|
48589
|
+
}
|
|
48590
|
+
/**
|
|
48591
|
+
* A possible line break.
|
|
48592
|
+
* Printed as either space or newline.
|
|
48593
|
+
*/
|
|
48594
|
+
function line() {
|
|
48595
|
+
return { type: "insertLine" };
|
|
48596
|
+
}
|
|
48597
|
+
/**
|
|
48598
|
+
* Increase indentation for a nested block.
|
|
48599
|
+
*/
|
|
48600
|
+
function nest(indentLevel, doc) {
|
|
48601
|
+
return { type: "nest", indentLevel, doc };
|
|
48602
|
+
}
|
|
48603
|
+
/**
|
|
48604
|
+
* Combines multiple docs into a single doc, concatenating them side by side
|
|
48605
|
+
* without any line breaks or indentation.
|
|
48606
|
+
*/
|
|
48607
|
+
function concat(docs) {
|
|
48608
|
+
return { type: "concat", docs };
|
|
48609
|
+
}
|
|
48610
|
+
/**
|
|
48611
|
+
* Marks a document as a unit to be printed "flat" (all on one line)
|
|
48612
|
+
* if it fits within the width, otherwise with line breaks.
|
|
48613
|
+
*/
|
|
48614
|
+
function group(doc) {
|
|
48615
|
+
return chooseBetween(flatten(doc), doc);
|
|
48616
|
+
}
|
|
48617
|
+
/**
|
|
48618
|
+
* Creates a choice between two alternative layouts.
|
|
48619
|
+
* The formatter tries `doc1`; if it does not fit within
|
|
48620
|
+
* the line width, it falls back to `doc2`.
|
|
48621
|
+
*/
|
|
48622
|
+
function chooseBetween(doc1, doc2) {
|
|
48623
|
+
return { type: "chooseBetween", doc1, doc2 };
|
|
48624
|
+
}
|
|
48625
|
+
/**
|
|
48626
|
+
* Flattens a doc into its single-line form.
|
|
48627
|
+
*/
|
|
48628
|
+
function flatten(doc) {
|
|
48629
|
+
if (typeof doc === "string") {
|
|
48630
|
+
return doc;
|
|
48631
|
+
}
|
|
48632
|
+
if (doc.type === "chooseBetween") {
|
|
48633
|
+
// Normally should be "chooseBetween(flatten(doc.doc1), flatten(doc.doc2))",
|
|
48634
|
+
// but this is simplified for performance reasons.
|
|
48635
|
+
return flatten(doc.doc1);
|
|
48636
|
+
}
|
|
48637
|
+
if (doc.type === "concat") {
|
|
48638
|
+
return concat(doc.docs.map(flatten));
|
|
48639
|
+
}
|
|
48640
|
+
if (doc.type === "nest") {
|
|
48641
|
+
return {
|
|
48642
|
+
type: "nest",
|
|
48643
|
+
indentLevel: doc.indentLevel,
|
|
48644
|
+
doc: flatten(doc.doc),
|
|
48645
|
+
};
|
|
48646
|
+
}
|
|
48647
|
+
if (doc.type === "insertLine") {
|
|
48648
|
+
return "";
|
|
48649
|
+
}
|
|
48650
|
+
return doc;
|
|
48651
|
+
}
|
|
48652
|
+
const getIndentationString = memoize(function getIndentationString(indentLevel) {
|
|
48653
|
+
return "\n" + "\t".repeat(indentLevel);
|
|
48654
|
+
});
|
|
48655
|
+
/**
|
|
48656
|
+
* Converts a `Doc` into a string representation that fits within
|
|
48657
|
+
* the specified width.
|
|
48658
|
+
*/
|
|
48659
|
+
function print(doc, width) {
|
|
48660
|
+
return stringify(selectBestLayout(width, doc));
|
|
48661
|
+
}
|
|
48662
|
+
/**
|
|
48663
|
+
* Join all segments of a LinkedString into the final string.
|
|
48664
|
+
*/
|
|
48665
|
+
function stringify(linkedString) {
|
|
48666
|
+
let result = "";
|
|
48667
|
+
while (linkedString) {
|
|
48668
|
+
result += linkedString.subString;
|
|
48669
|
+
linkedString = linkedString.next;
|
|
48670
|
+
}
|
|
48671
|
+
return result;
|
|
48672
|
+
}
|
|
48673
|
+
/**
|
|
48674
|
+
* Layout selection for a `Doc` that fits within the given width.
|
|
48675
|
+
*/
|
|
48676
|
+
function selectBestLayout(width, doc) {
|
|
48677
|
+
const head = {
|
|
48678
|
+
indentLevel: 0,
|
|
48679
|
+
doc,
|
|
48680
|
+
next: null,
|
|
48681
|
+
};
|
|
48682
|
+
return _selectBestLayout(width, 0, head);
|
|
48683
|
+
}
|
|
48684
|
+
function _selectBestLayout(width, currentIndentLevel, head) {
|
|
48685
|
+
if (head === null) {
|
|
48686
|
+
return null;
|
|
48687
|
+
}
|
|
48688
|
+
const { indentLevel, doc, next } = head;
|
|
48689
|
+
if (typeof doc === "string") {
|
|
48690
|
+
return {
|
|
48691
|
+
subString: doc,
|
|
48692
|
+
next: _selectBestLayout(width, currentIndentLevel + doc.length, next),
|
|
48693
|
+
};
|
|
48694
|
+
}
|
|
48695
|
+
if (doc.type === "concat") {
|
|
48696
|
+
let newHead = next;
|
|
48697
|
+
for (let i = doc.docs.length - 1; i >= 0; i--) {
|
|
48698
|
+
newHead = { indentLevel, doc: doc.docs[i], next: newHead };
|
|
48699
|
+
}
|
|
48700
|
+
return _selectBestLayout(width, currentIndentLevel, newHead);
|
|
48701
|
+
}
|
|
48702
|
+
if (doc.type === "nest") {
|
|
48703
|
+
return _selectBestLayout(width, currentIndentLevel, {
|
|
48704
|
+
indentLevel: indentLevel + doc.indentLevel,
|
|
48705
|
+
doc: doc.doc,
|
|
48706
|
+
next,
|
|
48707
|
+
});
|
|
48708
|
+
}
|
|
48709
|
+
if (doc.type === "insertLine") {
|
|
48710
|
+
return {
|
|
48711
|
+
subString: getIndentationString(indentLevel),
|
|
48712
|
+
next: _selectBestLayout(width, indentLevel, next),
|
|
48713
|
+
};
|
|
48714
|
+
}
|
|
48715
|
+
if (doc.type === "chooseBetween") {
|
|
48716
|
+
const head1 = { indentLevel, doc: doc.doc1, next };
|
|
48717
|
+
const possibleLinkedString = _selectBestLayout(width, currentIndentLevel, head1);
|
|
48718
|
+
if (fits(width - currentIndentLevel, possibleLinkedString)) {
|
|
48719
|
+
return possibleLinkedString;
|
|
48720
|
+
}
|
|
48721
|
+
const head2 = { indentLevel, doc: doc.doc2, next };
|
|
48722
|
+
return _selectBestLayout(width, currentIndentLevel, head2);
|
|
48723
|
+
}
|
|
48724
|
+
return null;
|
|
48725
|
+
}
|
|
48726
|
+
/**
|
|
48727
|
+
* Check if a layout fits on a single line within width.
|
|
48728
|
+
*/
|
|
48729
|
+
function fits(width, linkedString) {
|
|
48730
|
+
while (linkedString) {
|
|
48731
|
+
if (linkedString.subString[0] === "\n") {
|
|
48732
|
+
return true;
|
|
48733
|
+
}
|
|
48734
|
+
width -= linkedString.subString.length;
|
|
48735
|
+
if (width < 0)
|
|
48736
|
+
return false;
|
|
48737
|
+
linkedString = linkedString.next;
|
|
48738
|
+
}
|
|
48739
|
+
return true;
|
|
48740
|
+
}
|
|
48741
|
+
function astToDoc(ast) {
|
|
48742
|
+
switch (ast.type) {
|
|
48743
|
+
case "NUMBER":
|
|
48744
|
+
return String(ast.value);
|
|
48745
|
+
case "STRING":
|
|
48746
|
+
return `"${ast.value}"`;
|
|
48747
|
+
case "BOOLEAN":
|
|
48748
|
+
return ast.value ? "TRUE" : "FALSE";
|
|
48749
|
+
case "REFERENCE":
|
|
48750
|
+
return ast.value;
|
|
48751
|
+
case "FUNCALL":
|
|
48752
|
+
const docs = ast.args.map(astToDoc);
|
|
48753
|
+
return wrapInParentheses(concat(docs.map((doc, i) => (i < 1 ? doc : concat([", ", line(), doc])))), ast.value);
|
|
48754
|
+
case "UNARY_OPERATION":
|
|
48755
|
+
const operandDoc = astToDoc(ast.operand);
|
|
48756
|
+
const needParenthesis = ast.postfix
|
|
48757
|
+
? leftOperandNeedsParenthesis(ast)
|
|
48758
|
+
: rightOperandNeedsParenthesis(ast);
|
|
48759
|
+
const finalOperandDoc = needParenthesis ? wrapInParentheses(operandDoc) : operandDoc;
|
|
48760
|
+
return ast.postfix
|
|
48761
|
+
? concat([finalOperandDoc, ast.value])
|
|
48762
|
+
: concat([ast.value, finalOperandDoc]);
|
|
48763
|
+
case "BIN_OPERATION": {
|
|
48764
|
+
const leftDoc = astToDoc(ast.left);
|
|
48765
|
+
const needParenthesisLeftDoc = leftOperandNeedsParenthesis(ast);
|
|
48766
|
+
const finalLeftDoc = needParenthesisLeftDoc ? wrapInParentheses(leftDoc) : leftDoc;
|
|
48767
|
+
const rightDoc = astToDoc(ast.right);
|
|
48768
|
+
const needParenthesisRightDoc = rightOperandNeedsParenthesis(ast);
|
|
48769
|
+
const finalRightDoc = needParenthesisRightDoc ? wrapInParentheses(rightDoc) : rightDoc;
|
|
48770
|
+
const operator = `${ast.value}`;
|
|
48771
|
+
return group(concat([finalLeftDoc, operator, nest(1, concat([line(), finalRightDoc]))]));
|
|
48772
|
+
}
|
|
48773
|
+
case "SYMBOL":
|
|
48774
|
+
return ast.value;
|
|
48775
|
+
case "EMPTY":
|
|
48776
|
+
return "";
|
|
48777
|
+
}
|
|
48778
|
+
}
|
|
48779
|
+
/**
|
|
48780
|
+
* Wraps a `Doc` in parentheses (with optional function name).
|
|
48781
|
+
*/
|
|
48782
|
+
function wrapInParentheses(doc, functionName = undefined) {
|
|
48783
|
+
const docToConcat = ["(", nest(1, concat([line(), doc])), line(), ")"];
|
|
48784
|
+
if (functionName) {
|
|
48785
|
+
docToConcat.unshift(functionName);
|
|
48786
|
+
}
|
|
48787
|
+
return group(concat(docToConcat));
|
|
48788
|
+
}
|
|
48789
|
+
/**
|
|
48790
|
+
* Converts an ast formula to the corresponding string
|
|
48791
|
+
*/
|
|
48792
|
+
function astToFormula(ast) {
|
|
48793
|
+
switch (ast.type) {
|
|
48794
|
+
case "FUNCALL":
|
|
48795
|
+
const args = ast.args.map((arg) => astToFormula(arg));
|
|
48796
|
+
return `${ast.value}(${args.join(",")})`;
|
|
48797
|
+
case "NUMBER":
|
|
48798
|
+
return ast.value.toString();
|
|
48799
|
+
case "REFERENCE":
|
|
48800
|
+
return ast.value;
|
|
48801
|
+
case "STRING":
|
|
48802
|
+
return `"${ast.value}"`;
|
|
48803
|
+
case "BOOLEAN":
|
|
48804
|
+
return ast.value ? "TRUE" : "FALSE";
|
|
48805
|
+
case "UNARY_OPERATION":
|
|
48806
|
+
if (ast.postfix) {
|
|
48807
|
+
const leftOperand = leftOperandNeedsParenthesis(ast)
|
|
48808
|
+
? `(${astToFormula(ast.operand)})`
|
|
48809
|
+
: astToFormula(ast.operand);
|
|
48810
|
+
return leftOperand + ast.value;
|
|
48811
|
+
}
|
|
48812
|
+
const rightOperand = rightOperandNeedsParenthesis(ast)
|
|
48813
|
+
? `(${astToFormula(ast.operand)})`
|
|
48814
|
+
: astToFormula(ast.operand);
|
|
48815
|
+
return ast.value + rightOperand;
|
|
48816
|
+
case "BIN_OPERATION":
|
|
48817
|
+
const leftOperation = leftOperandNeedsParenthesis(ast)
|
|
48818
|
+
? `(${astToFormula(ast.left)})`
|
|
48819
|
+
: astToFormula(ast.left);
|
|
48820
|
+
const rightOperation = rightOperandNeedsParenthesis(ast)
|
|
48821
|
+
? `(${astToFormula(ast.right)})`
|
|
48822
|
+
: astToFormula(ast.right);
|
|
48823
|
+
return leftOperation + ast.value + rightOperation;
|
|
48824
|
+
default:
|
|
48825
|
+
return ast.value;
|
|
48826
|
+
}
|
|
48827
|
+
}
|
|
48828
|
+
function leftOperandNeedsParenthesis(operationAST) {
|
|
48829
|
+
const mainOperator = operationAST.value;
|
|
48830
|
+
const leftOperation = "left" in operationAST ? operationAST.left : operationAST.operand;
|
|
48831
|
+
const leftOperator = leftOperation.value;
|
|
48832
|
+
return (leftOperation.type === "BIN_OPERATION" && OP_PRIORITY[leftOperator] < OP_PRIORITY[mainOperator]);
|
|
48833
|
+
}
|
|
48834
|
+
function rightOperandNeedsParenthesis(operationAST) {
|
|
48835
|
+
const mainOperator = operationAST.value;
|
|
48836
|
+
const rightOperation = "right" in operationAST ? operationAST.right : operationAST.operand;
|
|
48837
|
+
const rightPriority = OP_PRIORITY[rightOperation.value];
|
|
48838
|
+
const mainPriority = OP_PRIORITY[mainOperator];
|
|
48839
|
+
if (rightOperation.type !== "BIN_OPERATION") {
|
|
48840
|
+
return false;
|
|
48841
|
+
}
|
|
48842
|
+
if (rightPriority < mainPriority) {
|
|
48843
|
+
return true;
|
|
48844
|
+
}
|
|
48845
|
+
return rightPriority === mainPriority && !ASSOCIATIVE_OPERATORS.includes(mainOperator);
|
|
48846
|
+
}
|
|
48847
|
+
|
|
48656
48848
|
const CELL_DELETED_MESSAGE = _t("The cell you are trying to edit has been deleted.");
|
|
48657
48849
|
class CellComposerStore extends AbstractComposerStore {
|
|
48658
48850
|
canStopEdition() {
|
|
@@ -48796,7 +48988,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48796
48988
|
const locale = this.getters.getLocale();
|
|
48797
48989
|
const cell = this.getters.getCell(position);
|
|
48798
48990
|
if (cell?.isFormula) {
|
|
48799
|
-
|
|
48991
|
+
const prettifiedContent = cell.compiledFormula.isBadExpression
|
|
48992
|
+
? cell.content
|
|
48993
|
+
: prettify(parseTokens(cell.compiledFormula.tokens), 80);
|
|
48994
|
+
return localizeFormula(prettifiedContent, locale);
|
|
48800
48995
|
}
|
|
48801
48996
|
const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
|
|
48802
48997
|
if (spreader) {
|
|
@@ -60500,6 +60695,42 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60500
60695
|
const supportedPivotPositionalFormulaRegistry = new Registry();
|
|
60501
60696
|
supportedPivotPositionalFormulaRegistry.add("SPREADSHEET", false);
|
|
60502
60697
|
|
|
60698
|
+
class ClickableCellSortIcon extends owl.Component {
|
|
60699
|
+
static template = "o-spreadsheet-ClickableCellSortIcon";
|
|
60700
|
+
static props = {
|
|
60701
|
+
position: Object,
|
|
60702
|
+
sortDirection: String,
|
|
60703
|
+
};
|
|
60704
|
+
hoveredTableStore;
|
|
60705
|
+
setup() {
|
|
60706
|
+
this.hoveredTableStore = useStore(HoveredTableStore);
|
|
60707
|
+
}
|
|
60708
|
+
get style() {
|
|
60709
|
+
const cellStyle = this.env.model.getters.getCellComputedStyle(this.props.position);
|
|
60710
|
+
return cssPropertiesToCss({
|
|
60711
|
+
color: cellStyle.textColor || TEXT_BODY_MUTED,
|
|
60712
|
+
"background-color": this.getBackgroundColor(cellStyle),
|
|
60713
|
+
});
|
|
60714
|
+
}
|
|
60715
|
+
get icon() {
|
|
60716
|
+
switch (this.props.sortDirection) {
|
|
60717
|
+
case "asc":
|
|
60718
|
+
return "fa-sort-asc";
|
|
60719
|
+
case "desc":
|
|
60720
|
+
return "fa-sort-desc";
|
|
60721
|
+
default:
|
|
60722
|
+
return "fa-sort";
|
|
60723
|
+
}
|
|
60724
|
+
}
|
|
60725
|
+
getBackgroundColor(cellStyle) {
|
|
60726
|
+
const overlayColor = this.hoveredTableStore.overlayColors.get(this.props.position);
|
|
60727
|
+
if (overlayColor) {
|
|
60728
|
+
return blendColors(cellStyle.fillColor || "#FFFFFF", overlayColor);
|
|
60729
|
+
}
|
|
60730
|
+
return cellStyle.fillColor || "#FFFFFF";
|
|
60731
|
+
}
|
|
60732
|
+
}
|
|
60733
|
+
|
|
60503
60734
|
class FullScreenChart extends owl.Component {
|
|
60504
60735
|
static template = "o-spreadsheet-FullScreenChart";
|
|
60505
60736
|
static props = {};
|
|
@@ -61794,10 +62025,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
61794
62025
|
*/
|
|
61795
62026
|
getFormulaString(sheetId, tokens, dependencies, useBoundedReference = false) {
|
|
61796
62027
|
if (!dependencies.length) {
|
|
61797
|
-
return concat(tokens.map((token) => token.value));
|
|
62028
|
+
return concat$1(tokens.map((token) => token.value));
|
|
61798
62029
|
}
|
|
61799
62030
|
let rangeIndex = 0;
|
|
61800
|
-
return concat(tokens.map((token) => {
|
|
62031
|
+
return concat$1(tokens.map((token) => {
|
|
61801
62032
|
if (token.type === "REFERENCE") {
|
|
61802
62033
|
const range = dependencies[rangeIndex++];
|
|
61803
62034
|
return this.getters.getRangeString(range, sheetId, { useBoundedReference });
|
|
@@ -62072,11 +62303,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62072
62303
|
};
|
|
62073
62304
|
}
|
|
62074
62305
|
get content() {
|
|
62075
|
-
return concat(this.compiledFormula.tokens.map((token) => token.value));
|
|
62306
|
+
return concat$1(this.compiledFormula.tokens.map((token) => token.value));
|
|
62076
62307
|
}
|
|
62077
62308
|
get contentWithFixedReferences() {
|
|
62078
62309
|
let rangeIndex = 0;
|
|
62079
|
-
return concat(this.compiledFormula.tokens.map((token) => {
|
|
62310
|
+
return concat$1(this.compiledFormula.tokens.map((token) => {
|
|
62080
62311
|
if (token.type === "REFERENCE") {
|
|
62081
62312
|
const index = rangeIndex++;
|
|
62082
62313
|
return this.getRangeString(this.compiledFormula.dependencies[index], this.sheetId, {
|
|
@@ -70856,6 +71087,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
70856
71087
|
static getters = [
|
|
70857
71088
|
"getPivot",
|
|
70858
71089
|
"getFirstPivotFunction",
|
|
71090
|
+
"getPivotCellSortDirection",
|
|
70859
71091
|
"getPivotIdFromPosition",
|
|
70860
71092
|
"getPivotCellFromPosition",
|
|
70861
71093
|
"generateNewCalculatedMeasureName",
|
|
@@ -71076,6 +71308,20 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
71076
71308
|
isPivotUnused(pivotId) {
|
|
71077
71309
|
return this._getUnusedPivots().includes(pivotId);
|
|
71078
71310
|
}
|
|
71311
|
+
getPivotCellSortDirection(position) {
|
|
71312
|
+
const pivotId = this.getters.getPivotIdFromPosition(position);
|
|
71313
|
+
const pivotCell = this.getters.getPivotCellFromPosition(position);
|
|
71314
|
+
if (pivotCell.type === "EMPTY" || pivotCell.type === "HEADER" || !pivotId) {
|
|
71315
|
+
return undefined;
|
|
71316
|
+
}
|
|
71317
|
+
const pivot = this.getters.getPivot(pivotId);
|
|
71318
|
+
const colDomain = domainToColRowDomain(pivot, pivotCell.domain).colDomain;
|
|
71319
|
+
const sortedColumn = pivot.definition.sortedColumn;
|
|
71320
|
+
if (sortedColumn?.measure === pivotCell.measure && deepEquals(sortedColumn.domain, colDomain)) {
|
|
71321
|
+
return sortedColumn.order;
|
|
71322
|
+
}
|
|
71323
|
+
return "none";
|
|
71324
|
+
}
|
|
71079
71325
|
// ---------------------------------------------------------------------
|
|
71080
71326
|
// Private
|
|
71081
71327
|
// ---------------------------------------------------------------------
|
|
@@ -78768,6 +79014,34 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
78768
79014
|
},
|
|
78769
79015
|
sequence: 5,
|
|
78770
79016
|
});
|
|
79017
|
+
clickableCellRegistry.add("dashboard_pivot_sorting", {
|
|
79018
|
+
condition: (position, getters) => {
|
|
79019
|
+
if (!getters.isDashboard()) {
|
|
79020
|
+
return false;
|
|
79021
|
+
}
|
|
79022
|
+
const pivotCell = getters.getPivotCellFromPosition(position);
|
|
79023
|
+
return canSortPivot(getters, position) && pivotCell.type === "MEASURE_HEADER";
|
|
79024
|
+
},
|
|
79025
|
+
execute: (position, env) => {
|
|
79026
|
+
sortPivot(env, position, getNextSortDirection(env.model.getters, position));
|
|
79027
|
+
},
|
|
79028
|
+
component: ClickableCellSortIcon,
|
|
79029
|
+
componentProps: (position, getters) => {
|
|
79030
|
+
return {
|
|
79031
|
+
position,
|
|
79032
|
+
sortDirection: getters.getPivotCellSortDirection(position),
|
|
79033
|
+
};
|
|
79034
|
+
},
|
|
79035
|
+
sequence: 2,
|
|
79036
|
+
});
|
|
79037
|
+
const NEXT_SORT_DIRECTION = {
|
|
79038
|
+
none: "asc",
|
|
79039
|
+
asc: "desc",
|
|
79040
|
+
desc: "none",
|
|
79041
|
+
};
|
|
79042
|
+
function getNextSortDirection(getters, position) {
|
|
79043
|
+
return NEXT_SORT_DIRECTION[getters.getPivotCellSortDirection(position) ?? "none"];
|
|
79044
|
+
}
|
|
78771
79045
|
|
|
78772
79046
|
const inverseCommandRegistry = new Registry()
|
|
78773
79047
|
.add("ADD_COLUMNS_ROWS", inverseAddColumnsRows)
|
|
@@ -80484,6 +80758,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
80484
80758
|
position,
|
|
80485
80759
|
action: item.execute,
|
|
80486
80760
|
title: title || "",
|
|
80761
|
+
component: item.component,
|
|
80762
|
+
componentProps: item.componentProps?.(position, getters) ?? {},
|
|
80487
80763
|
});
|
|
80488
80764
|
}
|
|
80489
80765
|
return cells;
|
|
@@ -81236,7 +81512,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
81236
81512
|
}
|
|
81237
81513
|
}
|
|
81238
81514
|
|
|
81239
|
-
const COMPOSER_MAX_HEIGHT =
|
|
81515
|
+
const COMPOSER_MAX_HEIGHT = 300;
|
|
81240
81516
|
/* svg free of use from https://uxwing.com/formula-fx-icon/ */
|
|
81241
81517
|
const FX_SVG = /*xml*/ `
|
|
81242
81518
|
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 121.8 122.9' width='16' height='16' focusable='false'>
|
|
@@ -82830,6 +83106,27 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82830
83106
|
}
|
|
82831
83107
|
}
|
|
82832
83108
|
|
|
83109
|
+
class ReadonlyTransportFilter {
|
|
83110
|
+
transportService;
|
|
83111
|
+
constructor(transportService) {
|
|
83112
|
+
this.transportService = transportService;
|
|
83113
|
+
}
|
|
83114
|
+
async sendMessage(message) {
|
|
83115
|
+
if (message.type === "CLIENT_JOINED" ||
|
|
83116
|
+
message.type === "CLIENT_LEFT" ||
|
|
83117
|
+
message.type === "CLIENT_MOVED") {
|
|
83118
|
+
this.transportService.sendMessage(message);
|
|
83119
|
+
}
|
|
83120
|
+
// ignore all other messages
|
|
83121
|
+
}
|
|
83122
|
+
onNewMessage(id, callback) {
|
|
83123
|
+
this.transportService.onNewMessage(id, callback);
|
|
83124
|
+
}
|
|
83125
|
+
leave(id) {
|
|
83126
|
+
this.transportService.leave(id);
|
|
83127
|
+
}
|
|
83128
|
+
}
|
|
83129
|
+
|
|
82833
83130
|
function inverseCommand(cmd) {
|
|
82834
83131
|
return inverseCommandRegistry.get(cmd.type)(cmd);
|
|
82835
83132
|
}
|
|
@@ -86922,12 +87219,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
86922
87219
|
name: _t("Anonymous").toString(),
|
|
86923
87220
|
};
|
|
86924
87221
|
const transportService = config.transportService || new LocalTransportService();
|
|
87222
|
+
const isReadonly = config.mode === "readonly" || config.mode === "dashboard";
|
|
86925
87223
|
return {
|
|
86926
87224
|
...config,
|
|
86927
87225
|
mode: config.mode || "normal",
|
|
86928
87226
|
custom: config.custom || {},
|
|
86929
87227
|
external: this.setupExternalConfig(config.external || {}),
|
|
86930
|
-
transportService
|
|
87228
|
+
transportService: isReadonly
|
|
87229
|
+
? new ReadonlyTransportFilter(transportService)
|
|
87230
|
+
: transportService,
|
|
86931
87231
|
client,
|
|
86932
87232
|
moveClient: () => { },
|
|
86933
87233
|
snapshotRequested: false,
|
|
@@ -87340,6 +87640,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
87340
87640
|
ChartPanel,
|
|
87341
87641
|
ChartFigure,
|
|
87342
87642
|
ChartJsComponent,
|
|
87643
|
+
ClickableCellSortIcon,
|
|
87343
87644
|
ZoomableChartJsComponent,
|
|
87344
87645
|
Grid,
|
|
87345
87646
|
GridOverlay,
|
|
@@ -87425,6 +87726,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
87425
87726
|
PIVOT_TABLE_CONFIG,
|
|
87426
87727
|
ChartTerms,
|
|
87427
87728
|
FIGURE_ID_SPLITTER,
|
|
87729
|
+
GRID_ICON_EDGE_LENGTH,
|
|
87730
|
+
GRID_ICON_MARGIN,
|
|
87428
87731
|
};
|
|
87429
87732
|
const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
|
|
87430
87733
|
|
|
@@ -87479,9 +87782,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
87479
87782
|
exports.tokenize = tokenize;
|
|
87480
87783
|
|
|
87481
87784
|
|
|
87482
|
-
__info__.version = "18.5.0-alpha.
|
|
87483
|
-
__info__.date = "2025-08-
|
|
87484
|
-
__info__.hash = "
|
|
87785
|
+
__info__.version = "18.5.0-alpha.12";
|
|
87786
|
+
__info__.date = "2025-08-29T08:05:09.767Z";
|
|
87787
|
+
__info__.hash = "8ee7677";
|
|
87485
87788
|
|
|
87486
87789
|
|
|
87487
87790
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|