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