@odoo/o-spreadsheet 18.5.0-alpha.10 → 18.5.0-alpha.11
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 +322 -122
- package/dist/o-spreadsheet.d.ts +9 -9
- package/dist/o-spreadsheet.esm.js +322 -122
- package/dist/o-spreadsheet.iife.js +322 -122
- package/dist/o-spreadsheet.iife.min.js +404 -402
- package/dist/o_spreadsheet.xml +20 -16
- 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.11
|
|
6
|
+
* @date 2025-08-26T10:14:05.357Z
|
|
7
|
+
* @hash b913e49
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -725,7 +725,7 @@ function batched(callback) {
|
|
|
725
725
|
/*
|
|
726
726
|
* Concatenate an array of strings.
|
|
727
727
|
*/
|
|
728
|
-
function concat(chars) {
|
|
728
|
+
function concat$1(chars) {
|
|
729
729
|
// ~40% faster than chars.join("")
|
|
730
730
|
let output = "";
|
|
731
731
|
for (let i = 0, len = chars.length; i < len; i++) {
|
|
@@ -1197,7 +1197,7 @@ function rgbaStringToHex(color) {
|
|
|
1197
1197
|
if (alphaHex !== 255) {
|
|
1198
1198
|
vals.push(alphaHex);
|
|
1199
1199
|
}
|
|
1200
|
-
return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
|
|
1200
|
+
return "#" + concat$1(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
|
|
1201
1201
|
}
|
|
1202
1202
|
/**
|
|
1203
1203
|
* RGBA to HEX representation (#RRGGBBAA).
|
|
@@ -5111,6 +5111,9 @@ function parseLiteral(content, locale) {
|
|
|
5111
5111
|
if (content === "") {
|
|
5112
5112
|
return null;
|
|
5113
5113
|
}
|
|
5114
|
+
if (content.includes("\n")) {
|
|
5115
|
+
return content;
|
|
5116
|
+
}
|
|
5114
5117
|
if (isNumber(content, DEFAULT_LOCALE)) {
|
|
5115
5118
|
return parseNumber(content, DEFAULT_LOCALE);
|
|
5116
5119
|
}
|
|
@@ -7319,14 +7322,11 @@ function getPasteZones(target, content) {
|
|
|
7319
7322
|
const width = content[0].length, height = content.length;
|
|
7320
7323
|
return target.map((t) => splitZoneForPaste(t, width, height)).flat();
|
|
7321
7324
|
}
|
|
7322
|
-
function parseOSClipboardContent(content
|
|
7325
|
+
function parseOSClipboardContent(content) {
|
|
7323
7326
|
let spreadsheetContent = undefined;
|
|
7324
7327
|
if (content[ClipboardMIMEType.Html]) {
|
|
7325
7328
|
const htmlDocument = new DOMParser().parseFromString(content[ClipboardMIMEType.Html], "text/html");
|
|
7326
|
-
|
|
7327
|
-
.querySelector("div")
|
|
7328
|
-
?.getAttribute("data-osheet-clipboard");
|
|
7329
|
-
spreadsheetContent = oSheetClipboardData && JSON.parse(oSheetClipboardData);
|
|
7329
|
+
spreadsheetContent = getOSheetDataFromHTML(htmlDocument);
|
|
7330
7330
|
}
|
|
7331
7331
|
const textContent = content[ClipboardMIMEType.PlainText] || "";
|
|
7332
7332
|
let imageBlob = undefined;
|
|
@@ -7345,6 +7345,17 @@ function parseOSClipboardContent(content, clipboardId) {
|
|
|
7345
7345
|
};
|
|
7346
7346
|
return osClipboardContent;
|
|
7347
7347
|
}
|
|
7348
|
+
function getOSheetDataFromHTML(htmlDocument) {
|
|
7349
|
+
const attributes = [...htmlDocument.documentElement.attributes];
|
|
7350
|
+
// Check if it's a Microsoft Office clipboard data (it will have some namespaces defined in the root element)
|
|
7351
|
+
if (attributes.some((attr) => attr.value.includes("microsoft"))) {
|
|
7352
|
+
return undefined;
|
|
7353
|
+
}
|
|
7354
|
+
const oSheetClipboardData = htmlDocument
|
|
7355
|
+
.querySelector("div")
|
|
7356
|
+
?.getAttribute("data-osheet-clipboard");
|
|
7357
|
+
return oSheetClipboardData && JSON.parse(oSheetClipboardData);
|
|
7358
|
+
}
|
|
7348
7359
|
/**
|
|
7349
7360
|
* Applies each clipboard handler to paste its corresponding data into the target.
|
|
7350
7361
|
*/
|
|
@@ -18338,7 +18349,6 @@ function rangeTokenize(formula, locale = DEFAULT_LOCALE) {
|
|
|
18338
18349
|
const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
|
|
18339
18350
|
const UNARY_OPERATORS_PREFIX = ["-", "+"];
|
|
18340
18351
|
const UNARY_OPERATORS_POSTFIX = ["%"];
|
|
18341
|
-
const ASSOCIATIVE_OPERATORS = ["*", "+", "&"];
|
|
18342
18352
|
class TokenList {
|
|
18343
18353
|
tokens;
|
|
18344
18354
|
currentIndex = 0;
|
|
@@ -18359,8 +18369,8 @@ class TokenList {
|
|
|
18359
18369
|
}
|
|
18360
18370
|
}
|
|
18361
18371
|
const OP_PRIORITY = {
|
|
18372
|
+
"%": 40,
|
|
18362
18373
|
"^": 30,
|
|
18363
|
-
"%": 30,
|
|
18364
18374
|
"*": 20,
|
|
18365
18375
|
"/": 20,
|
|
18366
18376
|
"+": 15,
|
|
@@ -18641,64 +18651,6 @@ function mapAst(ast, fn) {
|
|
|
18641
18651
|
return ast;
|
|
18642
18652
|
}
|
|
18643
18653
|
}
|
|
18644
|
-
/**
|
|
18645
|
-
* Converts an ast formula to the corresponding string
|
|
18646
|
-
*/
|
|
18647
|
-
function astToFormula(ast) {
|
|
18648
|
-
switch (ast.type) {
|
|
18649
|
-
case "FUNCALL":
|
|
18650
|
-
const args = ast.args.map((arg) => astToFormula(arg));
|
|
18651
|
-
return `${ast.value}(${args.join(",")})`;
|
|
18652
|
-
case "NUMBER":
|
|
18653
|
-
return ast.value.toString();
|
|
18654
|
-
case "REFERENCE":
|
|
18655
|
-
return ast.value;
|
|
18656
|
-
case "STRING":
|
|
18657
|
-
return `"${ast.value}"`;
|
|
18658
|
-
case "BOOLEAN":
|
|
18659
|
-
return ast.value ? "TRUE" : "FALSE";
|
|
18660
|
-
case "UNARY_OPERATION":
|
|
18661
|
-
return ast.postfix
|
|
18662
|
-
? leftOperandToFormula(ast) + ast.value
|
|
18663
|
-
: ast.value + rightOperandToFormula(ast);
|
|
18664
|
-
case "BIN_OPERATION":
|
|
18665
|
-
return leftOperandToFormula(ast) + ast.value + rightOperandToFormula(ast);
|
|
18666
|
-
default:
|
|
18667
|
-
return ast.value;
|
|
18668
|
-
}
|
|
18669
|
-
}
|
|
18670
|
-
/**
|
|
18671
|
-
* Convert the left operand of a binary operation to the corresponding string
|
|
18672
|
-
* and enclose the result inside parenthesis if necessary.
|
|
18673
|
-
*/
|
|
18674
|
-
function leftOperandToFormula(operationAST) {
|
|
18675
|
-
const mainOperator = operationAST.value;
|
|
18676
|
-
const leftOperation = "left" in operationAST ? operationAST.left : operationAST.operand;
|
|
18677
|
-
const leftOperator = leftOperation.value;
|
|
18678
|
-
const needParenthesis = leftOperation.type === "BIN_OPERATION" && OP_PRIORITY[leftOperator] < OP_PRIORITY[mainOperator];
|
|
18679
|
-
return needParenthesis ? `(${astToFormula(leftOperation)})` : astToFormula(leftOperation);
|
|
18680
|
-
}
|
|
18681
|
-
/**
|
|
18682
|
-
* Convert the right operand of a binary or unary operation to the corresponding string
|
|
18683
|
-
* and enclose the result inside parenthesis if necessary.
|
|
18684
|
-
*/
|
|
18685
|
-
function rightOperandToFormula(operationAST) {
|
|
18686
|
-
const mainOperator = operationAST.value;
|
|
18687
|
-
const rightOperation = "right" in operationAST ? operationAST.right : operationAST.operand;
|
|
18688
|
-
const rightPriority = OP_PRIORITY[rightOperation.value];
|
|
18689
|
-
const mainPriority = OP_PRIORITY[mainOperator];
|
|
18690
|
-
let needParenthesis = false;
|
|
18691
|
-
if (rightOperation.type !== "BIN_OPERATION") {
|
|
18692
|
-
needParenthesis = false;
|
|
18693
|
-
}
|
|
18694
|
-
else if (rightPriority < mainPriority) {
|
|
18695
|
-
needParenthesis = true;
|
|
18696
|
-
}
|
|
18697
|
-
else if (rightPriority === mainPriority && !ASSOCIATIVE_OPERATORS.includes(mainOperator)) {
|
|
18698
|
-
needParenthesis = true;
|
|
18699
|
-
}
|
|
18700
|
-
return needParenthesis ? `(${astToFormula(rightOperation)})` : astToFormula(rightOperation);
|
|
18701
|
-
}
|
|
18702
18654
|
|
|
18703
18655
|
/**
|
|
18704
18656
|
* Add the following information on tokens:
|
|
@@ -22197,7 +22149,7 @@ function adaptFormulaStringRanges(defaultSheetId, formula, applyChange) {
|
|
|
22197
22149
|
};
|
|
22198
22150
|
}
|
|
22199
22151
|
}
|
|
22200
|
-
return concat(tokens.map((token) => token.value));
|
|
22152
|
+
return concat$1(tokens.map((token) => token.value));
|
|
22201
22153
|
}
|
|
22202
22154
|
function adaptStringRange(defaultSheetId, sheetXC, applyChange) {
|
|
22203
22155
|
const sheetName = splitReference(sheetXC).sheetName;
|
|
@@ -28282,10 +28234,6 @@ class ComboChart extends AbstractChart {
|
|
|
28282
28234
|
};
|
|
28283
28235
|
}
|
|
28284
28236
|
getDefinitionForExcel() {
|
|
28285
|
-
// Excel does not support aggregating labels
|
|
28286
|
-
if (this.aggregated) {
|
|
28287
|
-
return undefined;
|
|
28288
|
-
}
|
|
28289
28237
|
const { dataSets, labelRange } = this.getCommonDataSetAttributesForExcel(this.labelRange, this.dataSets, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
28290
28238
|
const definition = this.getDefinition();
|
|
28291
28239
|
return {
|
|
@@ -29487,9 +29435,6 @@ class RadarChart extends AbstractChart {
|
|
|
29487
29435
|
};
|
|
29488
29436
|
}
|
|
29489
29437
|
getDefinitionForExcel() {
|
|
29490
|
-
if (this.aggregated) {
|
|
29491
|
-
return undefined;
|
|
29492
|
-
}
|
|
29493
29438
|
const { dataSets, labelRange } = this.getCommonDataSetAttributesForExcel(this.labelRange, this.dataSets, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
29494
29439
|
const definition = this.getDefinition();
|
|
29495
29440
|
return {
|
|
@@ -29637,10 +29582,6 @@ class ScatterChart extends AbstractChart {
|
|
|
29637
29582
|
return new ScatterChart(definition, this.sheetId, this.getters);
|
|
29638
29583
|
}
|
|
29639
29584
|
getDefinitionForExcel() {
|
|
29640
|
-
// Excel does not support aggregating labels
|
|
29641
|
-
if (this.aggregated) {
|
|
29642
|
-
return undefined;
|
|
29643
|
-
}
|
|
29644
29585
|
const dataSets = this.dataSets
|
|
29645
29586
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
29646
29587
|
.filter((ds) => ds.range !== "");
|
|
@@ -30959,7 +30900,7 @@ function escapeXml(strings, ...expressions) {
|
|
|
30959
30900
|
const value = expressions[i] instanceof XMLString ? expressions[i] : xmlEscape(expressions[i]);
|
|
30960
30901
|
str.push(value + strings[i + 1]);
|
|
30961
30902
|
}
|
|
30962
|
-
return new XMLString(concat(str));
|
|
30903
|
+
return new XMLString(concat$1(str));
|
|
30963
30904
|
}
|
|
30964
30905
|
/**
|
|
30965
30906
|
* Removes the escaped namespace of all the xml tags in the string.
|
|
@@ -32045,10 +31986,10 @@ class ChartDashboardMenuStore extends SpreadsheetStore {
|
|
|
32045
31986
|
const item = chartSubtypeRegistry.get(type);
|
|
32046
31987
|
return {
|
|
32047
31988
|
id: item.chartType,
|
|
32048
|
-
label: item.displayName,
|
|
31989
|
+
label: _t("Show as %(chart_type)s chart", { chart_type: item.displayName.toLowerCase() }),
|
|
32049
31990
|
onClick: () => this.updateType(item.chartType),
|
|
32050
|
-
|
|
32051
|
-
|
|
31991
|
+
class: item.chartType === definition.type ? "active" : "",
|
|
31992
|
+
preview: item.preview,
|
|
32052
31993
|
};
|
|
32053
31994
|
});
|
|
32054
31995
|
}
|
|
@@ -32084,18 +32025,6 @@ class ChartDashboardMenuStore extends SpreadsheetStore {
|
|
|
32084
32025
|
sheetId: this.getters.getActiveSheetId(),
|
|
32085
32026
|
});
|
|
32086
32027
|
}
|
|
32087
|
-
getIconClasses(type) {
|
|
32088
|
-
if (type.includes("bar")) {
|
|
32089
|
-
return "fa fa-bar-chart";
|
|
32090
|
-
}
|
|
32091
|
-
if (type.includes("line")) {
|
|
32092
|
-
return "fa fa-line-chart";
|
|
32093
|
-
}
|
|
32094
|
-
if (type.includes("pie")) {
|
|
32095
|
-
return "fa fa-pie-chart";
|
|
32096
|
-
}
|
|
32097
|
-
return "";
|
|
32098
|
-
}
|
|
32099
32028
|
}
|
|
32100
32029
|
|
|
32101
32030
|
class ChartDashboardMenu extends owl.Component {
|
|
@@ -32134,20 +32063,11 @@ class ChartDashboardMenu extends owl.Component {
|
|
|
32134
32063
|
if (definition.type === "scorecard") {
|
|
32135
32064
|
return undefined;
|
|
32136
32065
|
}
|
|
32137
|
-
|
|
32138
|
-
return {
|
|
32139
|
-
id: "fullScreenChart",
|
|
32140
|
-
label: _t("Exit Full Screen"),
|
|
32141
|
-
iconClass: "fa fa-compress",
|
|
32142
|
-
onClick: () => {
|
|
32143
|
-
this.fullScreenFigureStore.toggleFullScreenChart(figureId);
|
|
32144
|
-
},
|
|
32145
|
-
};
|
|
32146
|
-
}
|
|
32066
|
+
const isFullScreen = this.props.chartId === this.fullScreenFigureStore.fullScreenFigure?.id;
|
|
32147
32067
|
return {
|
|
32148
32068
|
id: "fullScreenChart",
|
|
32149
|
-
label: _t("Full Screen"),
|
|
32150
|
-
|
|
32069
|
+
label: isFullScreen ? _t("Exit Full Screen") : _t("Full Screen"),
|
|
32070
|
+
class: `text-muted fa ${isFullScreen ? "fa-compress" : "fa-expand"}`,
|
|
32151
32071
|
onClick: () => {
|
|
32152
32072
|
this.fullScreenFigureStore.toggleFullScreenChart(figureId);
|
|
32153
32073
|
},
|
|
@@ -34329,7 +34249,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
34329
34249
|
if (isFormula(content)) {
|
|
34330
34250
|
const missing = this.getNumberOfMissingParenthesis(this.currentTokens);
|
|
34331
34251
|
if (missing > 0) {
|
|
34332
|
-
content += concat(new Array(missing).fill(")"));
|
|
34252
|
+
content += concat$1(new Array(missing).fill(")"));
|
|
34333
34253
|
}
|
|
34334
34254
|
}
|
|
34335
34255
|
}
|
|
@@ -34381,9 +34301,10 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
34381
34301
|
if (isNewCurrentContent || this.editionMode !== "inactive") {
|
|
34382
34302
|
const locale = this.getters.getLocale();
|
|
34383
34303
|
this.currentTokens = isFormula(text) ? composerTokenize(text, locale) : [];
|
|
34384
|
-
|
|
34304
|
+
const nonSpaceTokensCount = this.currentTokens.filter((token) => token.type !== "SPACE").length;
|
|
34305
|
+
if (nonSpaceTokensCount > 1000) {
|
|
34385
34306
|
if (raise) {
|
|
34386
|
-
this.notificationStore.raiseError(_t("This formula has over
|
|
34307
|
+
this.notificationStore.raiseError(_t("This formula has over 1000 parts. It can't be processed properly, consider splitting it into multiple cells"));
|
|
34387
34308
|
}
|
|
34388
34309
|
}
|
|
34389
34310
|
}
|
|
@@ -34804,6 +34725,8 @@ css /* scss */ `
|
|
|
34804
34725
|
padding-right: 3px;
|
|
34805
34726
|
outline: none;
|
|
34806
34727
|
|
|
34728
|
+
tab-size: 4;
|
|
34729
|
+
|
|
34807
34730
|
p {
|
|
34808
34731
|
margin-bottom: 0px;
|
|
34809
34732
|
|
|
@@ -48654,6 +48577,280 @@ class ClientTag extends owl.Component {
|
|
|
48654
48577
|
}
|
|
48655
48578
|
}
|
|
48656
48579
|
|
|
48580
|
+
const ASSOCIATIVE_OPERATORS = ["*", "+", "&"];
|
|
48581
|
+
/**
|
|
48582
|
+
* Pretty-prints formula ASTs into readable formulas.
|
|
48583
|
+
*
|
|
48584
|
+
* Implements a Wadler-inspired pretty printer:
|
|
48585
|
+
* it converts an AST into a `Doc` structure,
|
|
48586
|
+
* and then chooses between compact (flat) or expanded (with
|
|
48587
|
+
* line breaks and indentation) layouts depending on space.
|
|
48588
|
+
*
|
|
48589
|
+
* References:
|
|
48590
|
+
* - https://lik.ai/blog/how-a-pretty-printer-works/
|
|
48591
|
+
* - Wadler, "A prettier printer": https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf
|
|
48592
|
+
*/
|
|
48593
|
+
function prettify(ast, width = 60) {
|
|
48594
|
+
return "=" + print(astToDoc(ast), width - 1); // width-1 because of the leading '='
|
|
48595
|
+
}
|
|
48596
|
+
/**
|
|
48597
|
+
* A possible line break.
|
|
48598
|
+
* Printed as either space or newline.
|
|
48599
|
+
*/
|
|
48600
|
+
function line() {
|
|
48601
|
+
return { type: "insertLine" };
|
|
48602
|
+
}
|
|
48603
|
+
/**
|
|
48604
|
+
* Increase indentation for a nested block.
|
|
48605
|
+
*/
|
|
48606
|
+
function nest(indentLevel, doc) {
|
|
48607
|
+
return { type: "nest", indentLevel, doc };
|
|
48608
|
+
}
|
|
48609
|
+
/**
|
|
48610
|
+
* Combines multiple docs into a single doc, concatenating them side by side
|
|
48611
|
+
* without any line breaks or indentation.
|
|
48612
|
+
*/
|
|
48613
|
+
function concat(docs) {
|
|
48614
|
+
return { type: "concat", docs };
|
|
48615
|
+
}
|
|
48616
|
+
/**
|
|
48617
|
+
* Marks a document as a unit to be printed "flat" (all on one line)
|
|
48618
|
+
* if it fits within the width, otherwise with line breaks.
|
|
48619
|
+
*/
|
|
48620
|
+
function group(doc) {
|
|
48621
|
+
return chooseBetween(flatten(doc), doc);
|
|
48622
|
+
}
|
|
48623
|
+
/**
|
|
48624
|
+
* Creates a choice between two alternative layouts.
|
|
48625
|
+
* The formatter tries `doc1`; if it does not fit within
|
|
48626
|
+
* the line width, it falls back to `doc2`.
|
|
48627
|
+
*/
|
|
48628
|
+
function chooseBetween(doc1, doc2) {
|
|
48629
|
+
return { type: "chooseBetween", doc1, doc2 };
|
|
48630
|
+
}
|
|
48631
|
+
/**
|
|
48632
|
+
* Flattens a doc into its single-line form.
|
|
48633
|
+
*/
|
|
48634
|
+
function flatten(doc) {
|
|
48635
|
+
if (typeof doc === "string") {
|
|
48636
|
+
return doc;
|
|
48637
|
+
}
|
|
48638
|
+
if (doc.type === "chooseBetween") {
|
|
48639
|
+
// Normally should be "chooseBetween(flatten(doc.doc1), flatten(doc.doc2))",
|
|
48640
|
+
// but this is simplified for performance reasons.
|
|
48641
|
+
return flatten(doc.doc1);
|
|
48642
|
+
}
|
|
48643
|
+
if (doc.type === "concat") {
|
|
48644
|
+
return concat(doc.docs.map(flatten));
|
|
48645
|
+
}
|
|
48646
|
+
if (doc.type === "nest") {
|
|
48647
|
+
return {
|
|
48648
|
+
type: "nest",
|
|
48649
|
+
indentLevel: doc.indentLevel,
|
|
48650
|
+
doc: flatten(doc.doc),
|
|
48651
|
+
};
|
|
48652
|
+
}
|
|
48653
|
+
if (doc.type === "insertLine") {
|
|
48654
|
+
return "";
|
|
48655
|
+
}
|
|
48656
|
+
return doc;
|
|
48657
|
+
}
|
|
48658
|
+
const getIndentationString = memoize(function getIndentationString(indentLevel) {
|
|
48659
|
+
return "\n" + "\t".repeat(indentLevel);
|
|
48660
|
+
});
|
|
48661
|
+
/**
|
|
48662
|
+
* Converts a `Doc` into a string representation that fits within
|
|
48663
|
+
* the specified width.
|
|
48664
|
+
*/
|
|
48665
|
+
function print(doc, width) {
|
|
48666
|
+
return stringify(selectBestLayout(width, doc));
|
|
48667
|
+
}
|
|
48668
|
+
/**
|
|
48669
|
+
* Join all segments of a LinkedString into the final string.
|
|
48670
|
+
*/
|
|
48671
|
+
function stringify(linkedString) {
|
|
48672
|
+
let result = "";
|
|
48673
|
+
while (linkedString) {
|
|
48674
|
+
result += linkedString.subString;
|
|
48675
|
+
linkedString = linkedString.next;
|
|
48676
|
+
}
|
|
48677
|
+
return result;
|
|
48678
|
+
}
|
|
48679
|
+
/**
|
|
48680
|
+
* Layout selection for a `Doc` that fits within the given width.
|
|
48681
|
+
*/
|
|
48682
|
+
function selectBestLayout(width, doc) {
|
|
48683
|
+
const head = {
|
|
48684
|
+
indentLevel: 0,
|
|
48685
|
+
doc,
|
|
48686
|
+
next: null,
|
|
48687
|
+
};
|
|
48688
|
+
return _selectBestLayout(width, 0, head);
|
|
48689
|
+
}
|
|
48690
|
+
function _selectBestLayout(width, currentIndentLevel, head) {
|
|
48691
|
+
if (head === null) {
|
|
48692
|
+
return null;
|
|
48693
|
+
}
|
|
48694
|
+
const { indentLevel, doc, next } = head;
|
|
48695
|
+
if (typeof doc === "string") {
|
|
48696
|
+
return {
|
|
48697
|
+
subString: doc,
|
|
48698
|
+
next: _selectBestLayout(width, currentIndentLevel + doc.length, next),
|
|
48699
|
+
};
|
|
48700
|
+
}
|
|
48701
|
+
if (doc.type === "concat") {
|
|
48702
|
+
let newHead = next;
|
|
48703
|
+
for (let i = doc.docs.length - 1; i >= 0; i--) {
|
|
48704
|
+
newHead = { indentLevel, doc: doc.docs[i], next: newHead };
|
|
48705
|
+
}
|
|
48706
|
+
return _selectBestLayout(width, currentIndentLevel, newHead);
|
|
48707
|
+
}
|
|
48708
|
+
if (doc.type === "nest") {
|
|
48709
|
+
return _selectBestLayout(width, currentIndentLevel, {
|
|
48710
|
+
indentLevel: indentLevel + doc.indentLevel,
|
|
48711
|
+
doc: doc.doc,
|
|
48712
|
+
next,
|
|
48713
|
+
});
|
|
48714
|
+
}
|
|
48715
|
+
if (doc.type === "insertLine") {
|
|
48716
|
+
return {
|
|
48717
|
+
subString: getIndentationString(indentLevel),
|
|
48718
|
+
next: _selectBestLayout(width, indentLevel, next),
|
|
48719
|
+
};
|
|
48720
|
+
}
|
|
48721
|
+
if (doc.type === "chooseBetween") {
|
|
48722
|
+
const head1 = { indentLevel, doc: doc.doc1, next };
|
|
48723
|
+
const possibleLinkedString = _selectBestLayout(width, currentIndentLevel, head1);
|
|
48724
|
+
if (fits(width - currentIndentLevel, possibleLinkedString)) {
|
|
48725
|
+
return possibleLinkedString;
|
|
48726
|
+
}
|
|
48727
|
+
const head2 = { indentLevel, doc: doc.doc2, next };
|
|
48728
|
+
return _selectBestLayout(width, currentIndentLevel, head2);
|
|
48729
|
+
}
|
|
48730
|
+
return null;
|
|
48731
|
+
}
|
|
48732
|
+
/**
|
|
48733
|
+
* Check if a layout fits on a single line within width.
|
|
48734
|
+
*/
|
|
48735
|
+
function fits(width, linkedString) {
|
|
48736
|
+
while (linkedString) {
|
|
48737
|
+
if (linkedString.subString[0] === "\n") {
|
|
48738
|
+
return true;
|
|
48739
|
+
}
|
|
48740
|
+
width -= linkedString.subString.length;
|
|
48741
|
+
if (width < 0)
|
|
48742
|
+
return false;
|
|
48743
|
+
linkedString = linkedString.next;
|
|
48744
|
+
}
|
|
48745
|
+
return true;
|
|
48746
|
+
}
|
|
48747
|
+
function astToDoc(ast) {
|
|
48748
|
+
switch (ast.type) {
|
|
48749
|
+
case "NUMBER":
|
|
48750
|
+
return String(ast.value);
|
|
48751
|
+
case "STRING":
|
|
48752
|
+
return `"${ast.value}"`;
|
|
48753
|
+
case "BOOLEAN":
|
|
48754
|
+
return ast.value ? "TRUE" : "FALSE";
|
|
48755
|
+
case "REFERENCE":
|
|
48756
|
+
return ast.value;
|
|
48757
|
+
case "FUNCALL":
|
|
48758
|
+
const docs = ast.args.map(astToDoc);
|
|
48759
|
+
return wrapInParentheses(concat(docs.map((doc, i) => (i < 1 ? doc : concat([", ", line(), doc])))), ast.value);
|
|
48760
|
+
case "UNARY_OPERATION":
|
|
48761
|
+
const operandDoc = astToDoc(ast.operand);
|
|
48762
|
+
const needParenthesis = ast.postfix
|
|
48763
|
+
? leftOperandNeedsParenthesis(ast)
|
|
48764
|
+
: rightOperandNeedsParenthesis(ast);
|
|
48765
|
+
const finalOperandDoc = needParenthesis ? wrapInParentheses(operandDoc) : operandDoc;
|
|
48766
|
+
return ast.postfix
|
|
48767
|
+
? concat([finalOperandDoc, ast.value])
|
|
48768
|
+
: concat([ast.value, finalOperandDoc]);
|
|
48769
|
+
case "BIN_OPERATION": {
|
|
48770
|
+
const leftDoc = astToDoc(ast.left);
|
|
48771
|
+
const needParenthesisLeftDoc = leftOperandNeedsParenthesis(ast);
|
|
48772
|
+
const finalLeftDoc = needParenthesisLeftDoc ? wrapInParentheses(leftDoc) : leftDoc;
|
|
48773
|
+
const rightDoc = astToDoc(ast.right);
|
|
48774
|
+
const needParenthesisRightDoc = rightOperandNeedsParenthesis(ast);
|
|
48775
|
+
const finalRightDoc = needParenthesisRightDoc ? wrapInParentheses(rightDoc) : rightDoc;
|
|
48776
|
+
const operator = `${ast.value}`;
|
|
48777
|
+
return group(concat([finalLeftDoc, operator, nest(1, concat([line(), finalRightDoc]))]));
|
|
48778
|
+
}
|
|
48779
|
+
case "SYMBOL":
|
|
48780
|
+
return ast.value;
|
|
48781
|
+
case "EMPTY":
|
|
48782
|
+
return "";
|
|
48783
|
+
}
|
|
48784
|
+
}
|
|
48785
|
+
/**
|
|
48786
|
+
* Wraps a `Doc` in parentheses (with optional function name).
|
|
48787
|
+
*/
|
|
48788
|
+
function wrapInParentheses(doc, functionName = undefined) {
|
|
48789
|
+
const docToConcat = ["(", nest(1, concat([line(), doc])), line(), ")"];
|
|
48790
|
+
if (functionName) {
|
|
48791
|
+
docToConcat.unshift(functionName);
|
|
48792
|
+
}
|
|
48793
|
+
return group(concat(docToConcat));
|
|
48794
|
+
}
|
|
48795
|
+
/**
|
|
48796
|
+
* Converts an ast formula to the corresponding string
|
|
48797
|
+
*/
|
|
48798
|
+
function astToFormula(ast) {
|
|
48799
|
+
switch (ast.type) {
|
|
48800
|
+
case "FUNCALL":
|
|
48801
|
+
const args = ast.args.map((arg) => astToFormula(arg));
|
|
48802
|
+
return `${ast.value}(${args.join(",")})`;
|
|
48803
|
+
case "NUMBER":
|
|
48804
|
+
return ast.value.toString();
|
|
48805
|
+
case "REFERENCE":
|
|
48806
|
+
return ast.value;
|
|
48807
|
+
case "STRING":
|
|
48808
|
+
return `"${ast.value}"`;
|
|
48809
|
+
case "BOOLEAN":
|
|
48810
|
+
return ast.value ? "TRUE" : "FALSE";
|
|
48811
|
+
case "UNARY_OPERATION":
|
|
48812
|
+
if (ast.postfix) {
|
|
48813
|
+
const leftOperand = leftOperandNeedsParenthesis(ast)
|
|
48814
|
+
? `(${astToFormula(ast.operand)})`
|
|
48815
|
+
: astToFormula(ast.operand);
|
|
48816
|
+
return leftOperand + ast.value;
|
|
48817
|
+
}
|
|
48818
|
+
const rightOperand = rightOperandNeedsParenthesis(ast)
|
|
48819
|
+
? `(${astToFormula(ast.operand)})`
|
|
48820
|
+
: astToFormula(ast.operand);
|
|
48821
|
+
return ast.value + rightOperand;
|
|
48822
|
+
case "BIN_OPERATION":
|
|
48823
|
+
const leftOperation = leftOperandNeedsParenthesis(ast)
|
|
48824
|
+
? `(${astToFormula(ast.left)})`
|
|
48825
|
+
: astToFormula(ast.left);
|
|
48826
|
+
const rightOperation = rightOperandNeedsParenthesis(ast)
|
|
48827
|
+
? `(${astToFormula(ast.right)})`
|
|
48828
|
+
: astToFormula(ast.right);
|
|
48829
|
+
return leftOperation + ast.value + rightOperation;
|
|
48830
|
+
default:
|
|
48831
|
+
return ast.value;
|
|
48832
|
+
}
|
|
48833
|
+
}
|
|
48834
|
+
function leftOperandNeedsParenthesis(operationAST) {
|
|
48835
|
+
const mainOperator = operationAST.value;
|
|
48836
|
+
const leftOperation = "left" in operationAST ? operationAST.left : operationAST.operand;
|
|
48837
|
+
const leftOperator = leftOperation.value;
|
|
48838
|
+
return (leftOperation.type === "BIN_OPERATION" && OP_PRIORITY[leftOperator] < OP_PRIORITY[mainOperator]);
|
|
48839
|
+
}
|
|
48840
|
+
function rightOperandNeedsParenthesis(operationAST) {
|
|
48841
|
+
const mainOperator = operationAST.value;
|
|
48842
|
+
const rightOperation = "right" in operationAST ? operationAST.right : operationAST.operand;
|
|
48843
|
+
const rightPriority = OP_PRIORITY[rightOperation.value];
|
|
48844
|
+
const mainPriority = OP_PRIORITY[mainOperator];
|
|
48845
|
+
if (rightOperation.type !== "BIN_OPERATION") {
|
|
48846
|
+
return false;
|
|
48847
|
+
}
|
|
48848
|
+
if (rightPriority < mainPriority) {
|
|
48849
|
+
return true;
|
|
48850
|
+
}
|
|
48851
|
+
return rightPriority === mainPriority && !ASSOCIATIVE_OPERATORS.includes(mainOperator);
|
|
48852
|
+
}
|
|
48853
|
+
|
|
48657
48854
|
const CELL_DELETED_MESSAGE = _t("The cell you are trying to edit has been deleted.");
|
|
48658
48855
|
class CellComposerStore extends AbstractComposerStore {
|
|
48659
48856
|
canStopEdition() {
|
|
@@ -48797,7 +48994,10 @@ class CellComposerStore extends AbstractComposerStore {
|
|
|
48797
48994
|
const locale = this.getters.getLocale();
|
|
48798
48995
|
const cell = this.getters.getCell(position);
|
|
48799
48996
|
if (cell?.isFormula) {
|
|
48800
|
-
|
|
48997
|
+
const prettifiedContent = cell.compiledFormula.isBadExpression
|
|
48998
|
+
? cell.content
|
|
48999
|
+
: prettify(parseTokens(cell.compiledFormula.tokens), 80);
|
|
49000
|
+
return localizeFormula(prettifiedContent, locale);
|
|
48801
49001
|
}
|
|
48802
49002
|
const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
|
|
48803
49003
|
if (spreader) {
|
|
@@ -61795,10 +61995,10 @@ class CellPlugin extends CorePlugin {
|
|
|
61795
61995
|
*/
|
|
61796
61996
|
getFormulaString(sheetId, tokens, dependencies, useBoundedReference = false) {
|
|
61797
61997
|
if (!dependencies.length) {
|
|
61798
|
-
return concat(tokens.map((token) => token.value));
|
|
61998
|
+
return concat$1(tokens.map((token) => token.value));
|
|
61799
61999
|
}
|
|
61800
62000
|
let rangeIndex = 0;
|
|
61801
|
-
return concat(tokens.map((token) => {
|
|
62001
|
+
return concat$1(tokens.map((token) => {
|
|
61802
62002
|
if (token.type === "REFERENCE") {
|
|
61803
62003
|
const range = dependencies[rangeIndex++];
|
|
61804
62004
|
return this.getters.getRangeString(range, sheetId, { useBoundedReference });
|
|
@@ -62073,11 +62273,11 @@ class FormulaCellWithDependencies {
|
|
|
62073
62273
|
};
|
|
62074
62274
|
}
|
|
62075
62275
|
get content() {
|
|
62076
|
-
return concat(this.compiledFormula.tokens.map((token) => token.value));
|
|
62276
|
+
return concat$1(this.compiledFormula.tokens.map((token) => token.value));
|
|
62077
62277
|
}
|
|
62078
62278
|
get contentWithFixedReferences() {
|
|
62079
62279
|
let rangeIndex = 0;
|
|
62080
|
-
return concat(this.compiledFormula.tokens.map((token) => {
|
|
62280
|
+
return concat$1(this.compiledFormula.tokens.map((token) => {
|
|
62081
62281
|
if (token.type === "REFERENCE") {
|
|
62082
62282
|
const index = rangeIndex++;
|
|
62083
62283
|
return this.getRangeString(this.compiledFormula.dependencies[index], this.sheetId, {
|
|
@@ -81237,7 +81437,7 @@ class SmallBottomBar extends owl.Component {
|
|
|
81237
81437
|
}
|
|
81238
81438
|
}
|
|
81239
81439
|
|
|
81240
|
-
const COMPOSER_MAX_HEIGHT =
|
|
81440
|
+
const COMPOSER_MAX_HEIGHT = 300;
|
|
81241
81441
|
/* svg free of use from https://uxwing.com/formula-fx-icon/ */
|
|
81242
81442
|
const FX_SVG = /*xml*/ `
|
|
81243
81443
|
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 121.8 122.9' width='16' height='16' focusable='false'>
|
|
@@ -87480,6 +87680,6 @@ exports.tokenColors = tokenColors;
|
|
|
87480
87680
|
exports.tokenize = tokenize;
|
|
87481
87681
|
|
|
87482
87682
|
|
|
87483
|
-
__info__.version = "18.5.0-alpha.
|
|
87484
|
-
__info__.date = "2025-08-
|
|
87485
|
-
__info__.hash = "
|
|
87683
|
+
__info__.version = "18.5.0-alpha.11";
|
|
87684
|
+
__info__.date = "2025-08-26T10:14:05.357Z";
|
|
87685
|
+
__info__.hash = "b913e49";
|
package/dist/o-spreadsheet.d.ts
CHANGED
|
@@ -3656,10 +3656,6 @@ declare function convertAstNodes<T extends AST["type"]>(ast: AST, type: T, fn: (
|
|
|
3656
3656
|
type: T;
|
|
3657
3657
|
}>) => AST): AST;
|
|
3658
3658
|
declare function iterateAstNodes(ast: AST): AST[];
|
|
3659
|
-
/**
|
|
3660
|
-
* Converts an ast formula to the corresponding string
|
|
3661
|
-
*/
|
|
3662
|
-
declare function astToFormula(ast: AST): string;
|
|
3663
3659
|
|
|
3664
3660
|
declare function getFunctionsFromTokens(tokens: Token[], functionNames: string[]): {
|
|
3665
3661
|
functionName: string;
|
|
@@ -9714,9 +9710,9 @@ interface Props$R {
|
|
|
9714
9710
|
interface MenuItem {
|
|
9715
9711
|
id: string;
|
|
9716
9712
|
label: string;
|
|
9717
|
-
|
|
9713
|
+
class: string;
|
|
9718
9714
|
onClick: () => void;
|
|
9719
|
-
|
|
9715
|
+
preview?: string;
|
|
9720
9716
|
}
|
|
9721
9717
|
declare class ChartDashboardMenu extends Component<Props$R, SpreadsheetChildEnv> {
|
|
9722
9718
|
static template: string;
|
|
@@ -11413,12 +11409,11 @@ declare class ChartDashboardMenuStore extends SpreadsheetStore {
|
|
|
11413
11409
|
id: "line" | "bar" | "scatter" | "pie" | "radar" | "funnel" | "treemap" | "geo" | "combo" | "waterfall" | "pyramid" | "sunburst" | "scorecard" | "gauge";
|
|
11414
11410
|
label: string;
|
|
11415
11411
|
onClick: () => void;
|
|
11416
|
-
|
|
11417
|
-
|
|
11412
|
+
class: string;
|
|
11413
|
+
preview: string;
|
|
11418
11414
|
}[];
|
|
11419
11415
|
reset(chartId: UID): void;
|
|
11420
11416
|
private updateType;
|
|
11421
|
-
private getIconClasses;
|
|
11422
11417
|
}
|
|
11423
11418
|
|
|
11424
11419
|
declare class FullScreenChart extends Component<{}, SpreadsheetChildEnv> {
|
|
@@ -12859,6 +12854,11 @@ declare class Spreadsheet extends Component<SpreadsheetProps, SpreadsheetChildEn
|
|
|
12859
12854
|
};
|
|
12860
12855
|
}
|
|
12861
12856
|
|
|
12857
|
+
/**
|
|
12858
|
+
* Converts an ast formula to the corresponding string
|
|
12859
|
+
*/
|
|
12860
|
+
declare function astToFormula(ast: AST): string;
|
|
12861
|
+
|
|
12862
12862
|
type SprintfValues = (string | String | number)[] | [{
|
|
12863
12863
|
[key: string]: string | number;
|
|
12864
12864
|
}];
|