@odoo/o-spreadsheet 17.4.0-alpha.11 → 17.4.0-alpha.13
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 +756 -279
- package/dist/o-spreadsheet.d.ts +55 -27
- package/dist/o-spreadsheet.esm.js +756 -279
- package/dist/o-spreadsheet.iife.js +756 -279
- package/dist/o-spreadsheet.iife.min.js +345 -345
- package/dist/o_spreadsheet.xml +6 -6
- package/package.json +2 -2
- package/readme.md +2 -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 17.4.0-alpha.
|
|
6
|
-
* @date 2024-07-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.4.0-alpha.13
|
|
6
|
+
* @date 2024-07-11T06:36:58.556Z
|
|
7
|
+
* @hash e0f506b
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -592,7 +592,7 @@ function getAddHeaderStartIndex(position, base) {
|
|
|
592
592
|
/**
|
|
593
593
|
* Compares two objects.
|
|
594
594
|
*/
|
|
595
|
-
function deepEquals(o1, o2
|
|
595
|
+
function deepEquals(o1, o2) {
|
|
596
596
|
if (o1 === o2)
|
|
597
597
|
return true;
|
|
598
598
|
if ((o1 && !o2) || (o2 && !o1))
|
|
@@ -608,17 +608,13 @@ function deepEquals(o1, o2, ignoreFunctions) {
|
|
|
608
608
|
}
|
|
609
609
|
}
|
|
610
610
|
for (const key in o1) {
|
|
611
|
-
|
|
612
|
-
if (typeOfO1Key !== typeof o2[key])
|
|
611
|
+
if (typeof o1[key] !== typeof o2[key])
|
|
613
612
|
return false;
|
|
614
|
-
if (
|
|
615
|
-
if (!deepEquals(o1[key], o2[key]
|
|
613
|
+
if (typeof o1[key] === "object") {
|
|
614
|
+
if (!deepEquals(o1[key], o2[key]))
|
|
616
615
|
return false;
|
|
617
616
|
}
|
|
618
617
|
else {
|
|
619
|
-
if (ignoreFunctions && typeOfO1Key === "function") {
|
|
620
|
-
continue;
|
|
621
|
-
}
|
|
622
618
|
if (o1[key] !== o2[key])
|
|
623
619
|
return false;
|
|
624
620
|
}
|
|
@@ -1805,7 +1801,7 @@ const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSepa
|
|
|
1805
1801
|
});
|
|
1806
1802
|
const getNumberRegex = memoize(function getNumberRegex(locale) {
|
|
1807
1803
|
const decimalSeparator = escapeRegExp(locale.decimalSeparator);
|
|
1808
|
-
const thousandsSeparator = escapeRegExp(locale.thousandsSeparator);
|
|
1804
|
+
const thousandsSeparator = escapeRegExp(locale.thousandsSeparator || "");
|
|
1809
1805
|
const pIntegerAndDecimals = `(?:\\d+(?:${thousandsSeparator}\\d{3,})*(?:${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
|
|
1810
1806
|
const pOnlyDecimals = `(?:${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
|
|
1811
1807
|
const pScientificFormat = "(?:e(?:\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
|
|
@@ -1838,7 +1834,7 @@ function isNumber(value, locale) {
|
|
|
1838
1834
|
return getNumberRegex(locale).test(value.trim());
|
|
1839
1835
|
}
|
|
1840
1836
|
const getInvaluableSymbolsRegexp = memoize(function getInvaluableSymbolsRegexp(locale) {
|
|
1841
|
-
return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator)}]`, "g");
|
|
1837
|
+
return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator || "")}]`, "g");
|
|
1842
1838
|
});
|
|
1843
1839
|
/**
|
|
1844
1840
|
* Convert a string into a number. It assumes that the string actually represents
|
|
@@ -2641,11 +2637,11 @@ function generateMatrix(nColumns, nRows, callback) {
|
|
|
2641
2637
|
}
|
|
2642
2638
|
return returned;
|
|
2643
2639
|
}
|
|
2644
|
-
function matrixMap(matrix,
|
|
2640
|
+
function matrixMap(matrix, callback) {
|
|
2645
2641
|
if (matrix.length === 0) {
|
|
2646
2642
|
return [];
|
|
2647
2643
|
}
|
|
2648
|
-
return generateMatrix(matrix.length, matrix[0].length, (col, row) =>
|
|
2644
|
+
return generateMatrix(matrix.length, matrix[0].length, (col, row) => callback(matrix[col][row]));
|
|
2649
2645
|
}
|
|
2650
2646
|
function matrixForEach(matrix, fn) {
|
|
2651
2647
|
const numberOfCols = matrix.length;
|
|
@@ -2745,6 +2741,9 @@ function getPredicate(descr, locale) {
|
|
|
2745
2741
|
* If the character is a special regular expression character, it is escaped with "\\".
|
|
2746
2742
|
*/
|
|
2747
2743
|
const wildcardToRegExp = memoize(function wildcardToRegExp(operand) {
|
|
2744
|
+
if (operand === "*") {
|
|
2745
|
+
return /.+/;
|
|
2746
|
+
}
|
|
2748
2747
|
let exp = "";
|
|
2749
2748
|
let predecessor = "";
|
|
2750
2749
|
for (let char of operand) {
|
|
@@ -2768,9 +2767,9 @@ const wildcardToRegExp = memoize(function wildcardToRegExp(operand) {
|
|
|
2768
2767
|
}
|
|
2769
2768
|
return new RegExp("^" + exp + "$", "i");
|
|
2770
2769
|
});
|
|
2771
|
-
function evaluatePredicate(value, criterion) {
|
|
2770
|
+
function evaluatePredicate(value = "", criterion) {
|
|
2772
2771
|
const { operator, operand } = criterion;
|
|
2773
|
-
if (
|
|
2772
|
+
if (operand === undefined || value === null || operand === null) {
|
|
2774
2773
|
return false;
|
|
2775
2774
|
}
|
|
2776
2775
|
if (typeof operand === "number" && operator === "=") {
|
|
@@ -5862,19 +5861,22 @@ class TokenizingChars {
|
|
|
5862
5861
|
}
|
|
5863
5862
|
|
|
5864
5863
|
function isValidLocale(locale) {
|
|
5865
|
-
if (!
|
|
5866
|
-
typeof locale
|
|
5867
|
-
typeof locale.
|
|
5868
|
-
typeof locale.code === "string" &&
|
|
5869
|
-
typeof locale.thousandsSeparator === "string" &&
|
|
5870
|
-
typeof locale.decimalSeparator === "string" &&
|
|
5871
|
-
typeof locale.dateFormat === "string" &&
|
|
5872
|
-
typeof locale.timeFormat === "string" &&
|
|
5873
|
-
typeof locale.formulaArgSeparator === "string")) {
|
|
5864
|
+
if (!locale ||
|
|
5865
|
+
typeof locale !== "object" ||
|
|
5866
|
+
!(!locale.thousandsSeparator || typeof locale.thousandsSeparator === "string")) {
|
|
5874
5867
|
return false;
|
|
5875
5868
|
}
|
|
5876
|
-
|
|
5877
|
-
|
|
5869
|
+
for (const property of [
|
|
5870
|
+
"code",
|
|
5871
|
+
"name",
|
|
5872
|
+
"decimalSeparator",
|
|
5873
|
+
"dateFormat",
|
|
5874
|
+
"timeFormat",
|
|
5875
|
+
"formulaArgSeparator",
|
|
5876
|
+
]) {
|
|
5877
|
+
if (!locale[property] || typeof locale[property] !== "string") {
|
|
5878
|
+
return false;
|
|
5879
|
+
}
|
|
5878
5880
|
}
|
|
5879
5881
|
if (locale.formulaArgSeparator === locale.decimalSeparator) {
|
|
5880
5882
|
return false;
|
|
@@ -5972,7 +5974,10 @@ function canonicalizeNumberLiteral(content, locale) {
|
|
|
5972
5974
|
if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
|
|
5973
5975
|
return content;
|
|
5974
5976
|
}
|
|
5975
|
-
|
|
5977
|
+
if (locale.thousandsSeparator) {
|
|
5978
|
+
content = content.replaceAll(locale.thousandsSeparator, "");
|
|
5979
|
+
}
|
|
5980
|
+
return content.replace(locale.decimalSeparator, ".");
|
|
5976
5981
|
}
|
|
5977
5982
|
/**
|
|
5978
5983
|
* Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
|
|
@@ -6324,7 +6329,7 @@ const quarterNumberAdapter = {
|
|
|
6324
6329
|
},
|
|
6325
6330
|
toValueAndFormat(normalizedValue) {
|
|
6326
6331
|
return {
|
|
6327
|
-
value:
|
|
6332
|
+
value: _t("Q%(quarter_number)s", { quarter_number: normalizedValue }),
|
|
6328
6333
|
format: "0",
|
|
6329
6334
|
};
|
|
6330
6335
|
},
|
|
@@ -6454,9 +6459,9 @@ function getMaxObjectId(o) {
|
|
|
6454
6459
|
}
|
|
6455
6460
|
const ALL_PERIODS = {
|
|
6456
6461
|
year: _t("Year"),
|
|
6457
|
-
quarter: _t("Quarter"),
|
|
6458
|
-
month: _t("Month"),
|
|
6459
|
-
week: _t("Week"),
|
|
6462
|
+
quarter: _t("Quarter & Year"),
|
|
6463
|
+
month: _t("Month & Year"),
|
|
6464
|
+
week: _t("Week & Year"),
|
|
6460
6465
|
day: _t("Day"),
|
|
6461
6466
|
quarter_number: _t("Quarter"),
|
|
6462
6467
|
month_number: _t("Month"),
|
|
@@ -6608,7 +6613,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
|
|
|
6608
6613
|
const pivotId = this.getters.getPivotIdFromPosition(position);
|
|
6609
6614
|
const spreader = this.getters.getArrayFormulaSpreadingOn(position);
|
|
6610
6615
|
if (pivotId) {
|
|
6611
|
-
if (!deepEquals(spreader, position) || !isCopyingOneCell) {
|
|
6616
|
+
if (spreader && (!deepEquals(spreader, position) || !isCopyingOneCell)) {
|
|
6612
6617
|
const pivotCell = this.getters.getPivotCellFromPosition(position);
|
|
6613
6618
|
const formulaPivotId = this.getters.getPivotFormulaId(pivotId);
|
|
6614
6619
|
const pivotFormula = createPivotFormula(formulaPivotId, pivotCell);
|
|
@@ -7413,6 +7418,146 @@ function transformRangeData(range, executed) {
|
|
|
7413
7418
|
return undefined;
|
|
7414
7419
|
}
|
|
7415
7420
|
|
|
7421
|
+
var State;
|
|
7422
|
+
(function (State) {
|
|
7423
|
+
/**
|
|
7424
|
+
* Initial state.
|
|
7425
|
+
* Expecting any reference for the left part of a range
|
|
7426
|
+
* e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
|
|
7427
|
+
*/
|
|
7428
|
+
State[State["LeftRef"] = 0] = "LeftRef";
|
|
7429
|
+
/**
|
|
7430
|
+
* Expecting any reference for the right part of a range
|
|
7431
|
+
* e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
|
|
7432
|
+
*/
|
|
7433
|
+
State[State["RightRef"] = 1] = "RightRef";
|
|
7434
|
+
/**
|
|
7435
|
+
* Expecting the separator without any constraint on the right part
|
|
7436
|
+
*/
|
|
7437
|
+
State[State["Separator"] = 2] = "Separator";
|
|
7438
|
+
/**
|
|
7439
|
+
* Expecting the separator for a full column range
|
|
7440
|
+
*/
|
|
7441
|
+
State[State["FullColumnSeparator"] = 3] = "FullColumnSeparator";
|
|
7442
|
+
/**
|
|
7443
|
+
* Expecting the separator for a full row range
|
|
7444
|
+
*/
|
|
7445
|
+
State[State["FullRowSeparator"] = 4] = "FullRowSeparator";
|
|
7446
|
+
/**
|
|
7447
|
+
* Expecting the right part of a full column range
|
|
7448
|
+
* e.g. "1", "A1"
|
|
7449
|
+
*/
|
|
7450
|
+
State[State["RightColumnRef"] = 5] = "RightColumnRef";
|
|
7451
|
+
/**
|
|
7452
|
+
* Expecting the right part of a full row range
|
|
7453
|
+
* e.g. "A", "A1"
|
|
7454
|
+
*/
|
|
7455
|
+
State[State["RightRowRef"] = 6] = "RightRowRef";
|
|
7456
|
+
/**
|
|
7457
|
+
* Final state. A range has been matched
|
|
7458
|
+
*/
|
|
7459
|
+
State[State["Found"] = 7] = "Found";
|
|
7460
|
+
})(State || (State = {}));
|
|
7461
|
+
const goTo = (state, guard = () => true) => [
|
|
7462
|
+
{
|
|
7463
|
+
goTo: state,
|
|
7464
|
+
guard,
|
|
7465
|
+
},
|
|
7466
|
+
];
|
|
7467
|
+
const goToMulti = (state, guard = () => true) => ({
|
|
7468
|
+
goTo: state,
|
|
7469
|
+
guard,
|
|
7470
|
+
});
|
|
7471
|
+
const machine = {
|
|
7472
|
+
[State.LeftRef]: {
|
|
7473
|
+
REFERENCE: goTo(State.Separator),
|
|
7474
|
+
NUMBER: goTo(State.FullRowSeparator),
|
|
7475
|
+
SYMBOL: [
|
|
7476
|
+
goToMulti(State.FullColumnSeparator, (token) => isColReference(token.value)),
|
|
7477
|
+
goToMulti(State.FullRowSeparator, (token) => isRowReference(token.value)),
|
|
7478
|
+
],
|
|
7479
|
+
},
|
|
7480
|
+
[State.FullColumnSeparator]: {
|
|
7481
|
+
SPACE: goTo(State.FullColumnSeparator),
|
|
7482
|
+
OPERATOR: goTo(State.RightColumnRef, (token) => token.value === ":"),
|
|
7483
|
+
},
|
|
7484
|
+
[State.FullRowSeparator]: {
|
|
7485
|
+
SPACE: goTo(State.FullRowSeparator),
|
|
7486
|
+
OPERATOR: goTo(State.RightRowRef, (token) => token.value === ":"),
|
|
7487
|
+
},
|
|
7488
|
+
[State.Separator]: {
|
|
7489
|
+
SPACE: goTo(State.Separator),
|
|
7490
|
+
OPERATOR: goTo(State.RightRef, (token) => token.value === ":"),
|
|
7491
|
+
},
|
|
7492
|
+
[State.RightRef]: {
|
|
7493
|
+
SPACE: goTo(State.RightRef),
|
|
7494
|
+
NUMBER: goTo(State.Found),
|
|
7495
|
+
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
7496
|
+
SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
|
|
7497
|
+
},
|
|
7498
|
+
[State.RightColumnRef]: {
|
|
7499
|
+
SPACE: goTo(State.RightColumnRef),
|
|
7500
|
+
SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
|
|
7501
|
+
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
7502
|
+
},
|
|
7503
|
+
[State.RightRowRef]: {
|
|
7504
|
+
SPACE: goTo(State.RightRowRef),
|
|
7505
|
+
NUMBER: goTo(State.Found),
|
|
7506
|
+
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
7507
|
+
SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
|
|
7508
|
+
},
|
|
7509
|
+
[State.Found]: {},
|
|
7510
|
+
};
|
|
7511
|
+
/**
|
|
7512
|
+
* Check if the list of tokens starts with a sequence of tokens representing
|
|
7513
|
+
* a range.
|
|
7514
|
+
* If a range is found, the sequence is removed from the list and is returned
|
|
7515
|
+
* as a single token.
|
|
7516
|
+
*/
|
|
7517
|
+
function matchReference(tokens) {
|
|
7518
|
+
let head = 0;
|
|
7519
|
+
let transitions = machine[State.LeftRef];
|
|
7520
|
+
let matchedTokens = "";
|
|
7521
|
+
while (transitions !== undefined) {
|
|
7522
|
+
const token = tokens[head++];
|
|
7523
|
+
if (!token) {
|
|
7524
|
+
return null;
|
|
7525
|
+
}
|
|
7526
|
+
const transition = transitions[token.type]?.find((transition) => transition.guard(token));
|
|
7527
|
+
const nextState = transition ? transition.goTo : undefined;
|
|
7528
|
+
switch (nextState) {
|
|
7529
|
+
case undefined:
|
|
7530
|
+
return null;
|
|
7531
|
+
case State.Found:
|
|
7532
|
+
matchedTokens += token.value;
|
|
7533
|
+
tokens.splice(0, head);
|
|
7534
|
+
return {
|
|
7535
|
+
type: "REFERENCE",
|
|
7536
|
+
value: matchedTokens,
|
|
7537
|
+
};
|
|
7538
|
+
default:
|
|
7539
|
+
transitions = machine[nextState];
|
|
7540
|
+
matchedTokens += token.value;
|
|
7541
|
+
break;
|
|
7542
|
+
}
|
|
7543
|
+
}
|
|
7544
|
+
return null;
|
|
7545
|
+
}
|
|
7546
|
+
/**
|
|
7547
|
+
* Take the result of the tokenizer and transform it to be usable in the
|
|
7548
|
+
* manipulations of range
|
|
7549
|
+
*
|
|
7550
|
+
* @param formula
|
|
7551
|
+
*/
|
|
7552
|
+
function rangeTokenize(formula, locale = DEFAULT_LOCALE) {
|
|
7553
|
+
const tokens = tokenize(formula, locale);
|
|
7554
|
+
const result = [];
|
|
7555
|
+
while (tokens.length) {
|
|
7556
|
+
result.push(matchReference(tokens) || tokens.shift());
|
|
7557
|
+
}
|
|
7558
|
+
return result;
|
|
7559
|
+
}
|
|
7560
|
+
|
|
7416
7561
|
const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
|
|
7417
7562
|
const UNARY_OPERATORS_PREFIX = ["-", "+"];
|
|
7418
7563
|
const UNARY_OPERATORS_POSTFIX = ["%"];
|
|
@@ -7561,7 +7706,7 @@ function parseExpression(tokens, parent_priority = 0) {
|
|
|
7561
7706
|
* Parse an expression (as a string) into an AST.
|
|
7562
7707
|
*/
|
|
7563
7708
|
function parse(str) {
|
|
7564
|
-
return parseTokens(
|
|
7709
|
+
return parseTokens(rangeTokenize(str));
|
|
7565
7710
|
}
|
|
7566
7711
|
function parseTokens(tokens) {
|
|
7567
7712
|
tokens = tokens.filter((x) => x.type !== "SPACE");
|
|
@@ -7697,146 +7842,6 @@ function rightOperandToFormula(operationAST) {
|
|
|
7697
7842
|
return needParenthesis ? `(${astToFormula(rightOperation)})` : astToFormula(rightOperation);
|
|
7698
7843
|
}
|
|
7699
7844
|
|
|
7700
|
-
var State;
|
|
7701
|
-
(function (State) {
|
|
7702
|
-
/**
|
|
7703
|
-
* Initial state.
|
|
7704
|
-
* Expecting any reference for the left part of a range
|
|
7705
|
-
* e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
|
|
7706
|
-
*/
|
|
7707
|
-
State[State["LeftRef"] = 0] = "LeftRef";
|
|
7708
|
-
/**
|
|
7709
|
-
* Expecting any reference for the right part of a range
|
|
7710
|
-
* e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
|
|
7711
|
-
*/
|
|
7712
|
-
State[State["RightRef"] = 1] = "RightRef";
|
|
7713
|
-
/**
|
|
7714
|
-
* Expecting the separator without any constraint on the right part
|
|
7715
|
-
*/
|
|
7716
|
-
State[State["Separator"] = 2] = "Separator";
|
|
7717
|
-
/**
|
|
7718
|
-
* Expecting the separator for a full column range
|
|
7719
|
-
*/
|
|
7720
|
-
State[State["FullColumnSeparator"] = 3] = "FullColumnSeparator";
|
|
7721
|
-
/**
|
|
7722
|
-
* Expecting the separator for a full row range
|
|
7723
|
-
*/
|
|
7724
|
-
State[State["FullRowSeparator"] = 4] = "FullRowSeparator";
|
|
7725
|
-
/**
|
|
7726
|
-
* Expecting the right part of a full column range
|
|
7727
|
-
* e.g. "1", "A1"
|
|
7728
|
-
*/
|
|
7729
|
-
State[State["RightColumnRef"] = 5] = "RightColumnRef";
|
|
7730
|
-
/**
|
|
7731
|
-
* Expecting the right part of a full row range
|
|
7732
|
-
* e.g. "A", "A1"
|
|
7733
|
-
*/
|
|
7734
|
-
State[State["RightRowRef"] = 6] = "RightRowRef";
|
|
7735
|
-
/**
|
|
7736
|
-
* Final state. A range has been matched
|
|
7737
|
-
*/
|
|
7738
|
-
State[State["Found"] = 7] = "Found";
|
|
7739
|
-
})(State || (State = {}));
|
|
7740
|
-
const goTo = (state, guard = () => true) => [
|
|
7741
|
-
{
|
|
7742
|
-
goTo: state,
|
|
7743
|
-
guard,
|
|
7744
|
-
},
|
|
7745
|
-
];
|
|
7746
|
-
const goToMulti = (state, guard = () => true) => ({
|
|
7747
|
-
goTo: state,
|
|
7748
|
-
guard,
|
|
7749
|
-
});
|
|
7750
|
-
const machine = {
|
|
7751
|
-
[State.LeftRef]: {
|
|
7752
|
-
REFERENCE: goTo(State.Separator),
|
|
7753
|
-
NUMBER: goTo(State.FullRowSeparator),
|
|
7754
|
-
SYMBOL: [
|
|
7755
|
-
goToMulti(State.FullColumnSeparator, (token) => isColReference(token.value)),
|
|
7756
|
-
goToMulti(State.FullRowSeparator, (token) => isRowReference(token.value)),
|
|
7757
|
-
],
|
|
7758
|
-
},
|
|
7759
|
-
[State.FullColumnSeparator]: {
|
|
7760
|
-
SPACE: goTo(State.FullColumnSeparator),
|
|
7761
|
-
OPERATOR: goTo(State.RightColumnRef, (token) => token.value === ":"),
|
|
7762
|
-
},
|
|
7763
|
-
[State.FullRowSeparator]: {
|
|
7764
|
-
SPACE: goTo(State.FullRowSeparator),
|
|
7765
|
-
OPERATOR: goTo(State.RightRowRef, (token) => token.value === ":"),
|
|
7766
|
-
},
|
|
7767
|
-
[State.Separator]: {
|
|
7768
|
-
SPACE: goTo(State.Separator),
|
|
7769
|
-
OPERATOR: goTo(State.RightRef, (token) => token.value === ":"),
|
|
7770
|
-
},
|
|
7771
|
-
[State.RightRef]: {
|
|
7772
|
-
SPACE: goTo(State.RightRef),
|
|
7773
|
-
NUMBER: goTo(State.Found),
|
|
7774
|
-
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
7775
|
-
SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
|
|
7776
|
-
},
|
|
7777
|
-
[State.RightColumnRef]: {
|
|
7778
|
-
SPACE: goTo(State.RightColumnRef),
|
|
7779
|
-
SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
|
|
7780
|
-
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
7781
|
-
},
|
|
7782
|
-
[State.RightRowRef]: {
|
|
7783
|
-
SPACE: goTo(State.RightRowRef),
|
|
7784
|
-
NUMBER: goTo(State.Found),
|
|
7785
|
-
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
7786
|
-
SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
|
|
7787
|
-
},
|
|
7788
|
-
[State.Found]: {},
|
|
7789
|
-
};
|
|
7790
|
-
/**
|
|
7791
|
-
* Check if the list of tokens starts with a sequence of tokens representing
|
|
7792
|
-
* a range.
|
|
7793
|
-
* If a range is found, the sequence is removed from the list and is returned
|
|
7794
|
-
* as a single token.
|
|
7795
|
-
*/
|
|
7796
|
-
function matchReference(tokens) {
|
|
7797
|
-
let head = 0;
|
|
7798
|
-
let transitions = machine[State.LeftRef];
|
|
7799
|
-
let matchedTokens = "";
|
|
7800
|
-
while (transitions !== undefined) {
|
|
7801
|
-
const token = tokens[head++];
|
|
7802
|
-
if (!token) {
|
|
7803
|
-
return null;
|
|
7804
|
-
}
|
|
7805
|
-
const transition = transitions[token.type]?.find((transition) => transition.guard(token));
|
|
7806
|
-
const nextState = transition ? transition.goTo : undefined;
|
|
7807
|
-
switch (nextState) {
|
|
7808
|
-
case undefined:
|
|
7809
|
-
return null;
|
|
7810
|
-
case State.Found:
|
|
7811
|
-
matchedTokens += token.value;
|
|
7812
|
-
tokens.splice(0, head);
|
|
7813
|
-
return {
|
|
7814
|
-
type: "REFERENCE",
|
|
7815
|
-
value: matchedTokens,
|
|
7816
|
-
};
|
|
7817
|
-
default:
|
|
7818
|
-
transitions = machine[nextState];
|
|
7819
|
-
matchedTokens += token.value;
|
|
7820
|
-
break;
|
|
7821
|
-
}
|
|
7822
|
-
}
|
|
7823
|
-
return null;
|
|
7824
|
-
}
|
|
7825
|
-
/**
|
|
7826
|
-
* Take the result of the tokenizer and transform it to be usable in the
|
|
7827
|
-
* manipulations of range
|
|
7828
|
-
*
|
|
7829
|
-
* @param formula
|
|
7830
|
-
*/
|
|
7831
|
-
function rangeTokenize(formula, locale = DEFAULT_LOCALE) {
|
|
7832
|
-
const tokens = tokenize(formula, locale);
|
|
7833
|
-
const result = [];
|
|
7834
|
-
while (tokens.length) {
|
|
7835
|
-
result.push(matchReference(tokens) || tokens.shift());
|
|
7836
|
-
}
|
|
7837
|
-
return result;
|
|
7838
|
-
}
|
|
7839
|
-
|
|
7840
7845
|
/**
|
|
7841
7846
|
* Add the following information on tokens:
|
|
7842
7847
|
* - length
|
|
@@ -8067,8 +8072,8 @@ function detectLink(value) {
|
|
|
8067
8072
|
|
|
8068
8073
|
function evaluateLiteral(literalCell, localeFormat) {
|
|
8069
8074
|
const value = localeFormat.format === PLAIN_TEXT_FORMAT ? literalCell.content : literalCell.parsedValue;
|
|
8070
|
-
const
|
|
8071
|
-
return createEvaluatedCell(
|
|
8075
|
+
const functionResult = { value, format: localeFormat.format };
|
|
8076
|
+
return createEvaluatedCell(functionResult, localeFormat.locale);
|
|
8072
8077
|
}
|
|
8073
8078
|
function parseLiteral(content, locale) {
|
|
8074
8079
|
if (content.startsWith("=")) {
|
|
@@ -8089,13 +8094,13 @@ function parseLiteral(content, locale) {
|
|
|
8089
8094
|
}
|
|
8090
8095
|
return content;
|
|
8091
8096
|
}
|
|
8092
|
-
function createEvaluatedCell(
|
|
8093
|
-
const link = detectLink(
|
|
8097
|
+
function createEvaluatedCell(functionResult, locale = DEFAULT_LOCALE, cell) {
|
|
8098
|
+
const link = detectLink(functionResult.value);
|
|
8094
8099
|
if (!link) {
|
|
8095
|
-
return _createEvaluatedCell(
|
|
8100
|
+
return _createEvaluatedCell(functionResult, locale, cell);
|
|
8096
8101
|
}
|
|
8097
8102
|
const value = parseLiteral(link.label, locale);
|
|
8098
|
-
const format =
|
|
8103
|
+
const format = functionResult.format ||
|
|
8099
8104
|
(typeof value === "number"
|
|
8100
8105
|
? detectDateFormat(link.label, locale) || detectNumberFormat(link.label)
|
|
8101
8106
|
: undefined);
|
|
@@ -8108,8 +8113,8 @@ function createEvaluatedCell(fPayload, locale = DEFAULT_LOCALE, cell) {
|
|
|
8108
8113
|
link,
|
|
8109
8114
|
};
|
|
8110
8115
|
}
|
|
8111
|
-
function _createEvaluatedCell(
|
|
8112
|
-
let { value, format, message } =
|
|
8116
|
+
function _createEvaluatedCell(functionResult, locale, cell) {
|
|
8117
|
+
let { value, format, message } = functionResult;
|
|
8113
8118
|
format = cell?.format || format;
|
|
8114
8119
|
const formattedValue = formatValue(value, { format, locale });
|
|
8115
8120
|
if (isEvaluationError(value)) {
|
|
@@ -10296,7 +10301,6 @@ function getNextNonEmptyBar(bars, startIndex) {
|
|
|
10296
10301
|
return bars.find((bar, i) => i > startIndex && bar.height !== 0);
|
|
10297
10302
|
}
|
|
10298
10303
|
|
|
10299
|
-
// @ts-ignore
|
|
10300
10304
|
window.Chart?.register(waterfallLinesPlugin);
|
|
10301
10305
|
class ChartJsComponent extends owl.Component {
|
|
10302
10306
|
static template = "o-spreadsheet-ChartJsComponent";
|
|
@@ -10329,7 +10333,7 @@ class ChartJsComponent extends owl.Component {
|
|
|
10329
10333
|
owl.onWillUnmount(() => this.chart?.destroy());
|
|
10330
10334
|
owl.useEffect(() => {
|
|
10331
10335
|
const runtime = this.chartRuntime;
|
|
10332
|
-
if (
|
|
10336
|
+
if (runtime !== this.currentRuntime) {
|
|
10333
10337
|
if (runtime.chartJsConfig.type !== this.currentRuntime.chartJsConfig.type) {
|
|
10334
10338
|
this.chart?.destroy();
|
|
10335
10339
|
this.createChart(deepCopy(runtime.chartJsConfig));
|
|
@@ -10344,7 +10348,6 @@ class ChartJsComponent extends owl.Component {
|
|
|
10344
10348
|
createChart(chartData) {
|
|
10345
10349
|
const canvas = this.canvas.el;
|
|
10346
10350
|
const ctx = canvas.getContext("2d");
|
|
10347
|
-
// @ts-ignore
|
|
10348
10351
|
this.chart = new window.Chart(ctx, chartData);
|
|
10349
10352
|
}
|
|
10350
10353
|
updateChartJs(chartRuntime) {
|
|
@@ -19096,7 +19099,7 @@ const PIVOT = {
|
|
|
19096
19099
|
arg("include_column_titles (boolean, default=TRUE)", _t("Whether to include the column titles or not.")),
|
|
19097
19100
|
arg("column_count (number, optional)", _t("number of columns")),
|
|
19098
19101
|
],
|
|
19099
|
-
compute: function (pivotFormulaId, rowCount = { value:
|
|
19102
|
+
compute: function (pivotFormulaId, rowCount = { value: 10000 }, includeTotal = { value: true }, includeColumnHeaders = { value: true }, columnCount = { value: Number.MAX_VALUE }) {
|
|
19100
19103
|
const _pivotFormulaId = toString(pivotFormulaId);
|
|
19101
19104
|
const _rowCount = toNumber(rowCount, this.locale);
|
|
19102
19105
|
if (_rowCount < 0) {
|
|
@@ -19520,6 +19523,320 @@ var operators = /*#__PURE__*/Object.freeze({
|
|
|
19520
19523
|
UPLUS: UPLUS
|
|
19521
19524
|
});
|
|
19522
19525
|
|
|
19526
|
+
const transformFromFactor = (factor) => ({
|
|
19527
|
+
transform: (x) => x * factor,
|
|
19528
|
+
inverseTransform: (x) => x / factor,
|
|
19529
|
+
});
|
|
19530
|
+
const standard = { transform: (x) => x, inverseTransform: (x) => x };
|
|
19531
|
+
const ANG2M = 1e-10;
|
|
19532
|
+
const IN2M = 0.0254;
|
|
19533
|
+
const PICAPT2M = IN2M / 72;
|
|
19534
|
+
const FT2M = 0.3048;
|
|
19535
|
+
const YD2M = 0.9144;
|
|
19536
|
+
const MI2M = 1609.34;
|
|
19537
|
+
const NMI2M = 1852;
|
|
19538
|
+
const LY2M = 9.46073047258e15;
|
|
19539
|
+
const UNITS = {
|
|
19540
|
+
// WEIGHT UNITs : Standard = gramme
|
|
19541
|
+
g: { ...standard, category: "weight" },
|
|
19542
|
+
u: { ...transformFromFactor(1.66053e-24), category: "weight" },
|
|
19543
|
+
grain: { ...transformFromFactor(0.0647989), category: "weight" },
|
|
19544
|
+
ozm: { ...transformFromFactor(28.3495), category: "weight" },
|
|
19545
|
+
lbm: { ...transformFromFactor(453.592), category: "weight" },
|
|
19546
|
+
stone: { ...transformFromFactor(6350.29), category: "weight" },
|
|
19547
|
+
sg: { ...transformFromFactor(14593.90294), category: "weight" },
|
|
19548
|
+
cwt: { ...transformFromFactor(45359.237), category: "weight" },
|
|
19549
|
+
uk_cwt: { ...transformFromFactor(50802.3), category: "weight" },
|
|
19550
|
+
ton: { ...transformFromFactor(907184.74), category: "weight" },
|
|
19551
|
+
uk_ton: { ...transformFromFactor(1016046.9), category: "weight" },
|
|
19552
|
+
// DISTANCE UNITS : Standard = meter
|
|
19553
|
+
m: { ...standard, category: "distance" },
|
|
19554
|
+
km: { ...transformFromFactor(1000), category: "distance" },
|
|
19555
|
+
ang: { ...transformFromFactor(ANG2M), category: "distance" },
|
|
19556
|
+
Picapt: { ...transformFromFactor(PICAPT2M), category: "distance" },
|
|
19557
|
+
pica: { ...transformFromFactor(IN2M / 6), category: "distance" },
|
|
19558
|
+
in: { ...transformFromFactor(IN2M), category: "distance" },
|
|
19559
|
+
ft: { ...transformFromFactor(FT2M), category: "distance" },
|
|
19560
|
+
yd: { ...transformFromFactor(YD2M), category: "distance" },
|
|
19561
|
+
ell: { ...transformFromFactor(1.143), category: "distance" },
|
|
19562
|
+
mi: { ...transformFromFactor(MI2M), category: "distance" },
|
|
19563
|
+
survey_mi: { ...transformFromFactor(1609.34), category: "distance" },
|
|
19564
|
+
Nmi: { ...transformFromFactor(NMI2M), category: "distance" },
|
|
19565
|
+
ly: { ...transformFromFactor(LY2M), category: "distance" },
|
|
19566
|
+
parsec: { ...transformFromFactor(3.0856775814914e16), category: "distance" },
|
|
19567
|
+
// TIME UNITS : Standard = second
|
|
19568
|
+
sec: { ...standard, category: "time" },
|
|
19569
|
+
min: { ...transformFromFactor(60), category: "time" },
|
|
19570
|
+
hr: { ...transformFromFactor(3600), category: "time" },
|
|
19571
|
+
day: { ...transformFromFactor(86400), category: "time" },
|
|
19572
|
+
yr: { ...transformFromFactor(31556952), category: "time" },
|
|
19573
|
+
// PRESSURE UNITS : Standard = Pascal
|
|
19574
|
+
Pa: { ...standard, category: "pressure" },
|
|
19575
|
+
bar: { ...transformFromFactor(100000), category: "pressure" },
|
|
19576
|
+
mmHg: { ...transformFromFactor(133.322), category: "pressure" },
|
|
19577
|
+
Torr: { ...transformFromFactor(133.322), category: "pressure" },
|
|
19578
|
+
psi: { ...transformFromFactor(6894.76), category: "pressure" },
|
|
19579
|
+
atm: { ...transformFromFactor(101325), category: "pressure" },
|
|
19580
|
+
// FORCE UNITS : Standard = Newton
|
|
19581
|
+
N: { ...standard, category: "force" },
|
|
19582
|
+
dyn: { ...transformFromFactor(1e-5), category: "force" },
|
|
19583
|
+
pond: { ...transformFromFactor(0.00980665), category: "force" },
|
|
19584
|
+
lbf: { ...transformFromFactor(4.44822), category: "force" },
|
|
19585
|
+
// ENERGY UNITS : Standard = Joule
|
|
19586
|
+
J: { ...standard, category: "energy" },
|
|
19587
|
+
eV: { ...transformFromFactor(1.60218e-19), category: "energy" },
|
|
19588
|
+
e: { ...transformFromFactor(1e-7), category: "energy" },
|
|
19589
|
+
flb: { ...transformFromFactor(1.3558179483), category: "energy" },
|
|
19590
|
+
c: { ...transformFromFactor(4.184), category: "energy" },
|
|
19591
|
+
cal: { ...transformFromFactor(4.1868), category: "energy" },
|
|
19592
|
+
BTU: { ...transformFromFactor(1055.06), category: "energy" },
|
|
19593
|
+
Wh: { ...transformFromFactor(3600), category: "energy" },
|
|
19594
|
+
HPh: { ...transformFromFactor(2684520), category: "energy" },
|
|
19595
|
+
// POWER UNITS : Standard = Watt
|
|
19596
|
+
W: { ...standard, category: "power" },
|
|
19597
|
+
PS: { ...transformFromFactor(735.499), category: "power" },
|
|
19598
|
+
HP: { ...transformFromFactor(745.7), category: "power" },
|
|
19599
|
+
// MAGNETISM UNITS : Standard = Tesla
|
|
19600
|
+
T: { ...standard, category: "magnetism" },
|
|
19601
|
+
ga: { ...transformFromFactor(1e-4), category: "magnetism" },
|
|
19602
|
+
// TEMPERATURE UNITS : Standard = Kelvin
|
|
19603
|
+
K: { ...standard, category: "temperature" },
|
|
19604
|
+
C: {
|
|
19605
|
+
transform: (T) => T + 273.15,
|
|
19606
|
+
inverseTransform: (T) => T - 273.15,
|
|
19607
|
+
category: "temperature",
|
|
19608
|
+
},
|
|
19609
|
+
F: {
|
|
19610
|
+
transform: (T) => ((T - 32) * 5) / 9 + 273.15,
|
|
19611
|
+
inverseTransform: (T) => ((T - 273.15) * 9) / 5 + 32,
|
|
19612
|
+
category: "temperature",
|
|
19613
|
+
},
|
|
19614
|
+
Rank: { ...transformFromFactor(5 / 9), category: "temperature" },
|
|
19615
|
+
Reau: {
|
|
19616
|
+
transform: (T) => T * 1.25 + 273.15,
|
|
19617
|
+
inverseTransform: (T) => (T - 273.15) / 1.25,
|
|
19618
|
+
category: "temperature",
|
|
19619
|
+
},
|
|
19620
|
+
// VOLUME UNITS : Standard = cubic meter
|
|
19621
|
+
"m^3": { ...standard, category: "volume", order: 3 },
|
|
19622
|
+
"ang^3": { ...transformFromFactor(Math.pow(ANG2M, 3)), category: "volume", order: 3 },
|
|
19623
|
+
"Picapt^3": { ...transformFromFactor(Math.pow(PICAPT2M, 3)), category: "volume", order: 3 },
|
|
19624
|
+
tsp: { ...transformFromFactor(4.92892e-6), category: "volume" },
|
|
19625
|
+
tspm: { ...transformFromFactor(5e-6), category: "volume" },
|
|
19626
|
+
tbs: { ...transformFromFactor(1.4786764825785619e-5), category: "volume" },
|
|
19627
|
+
"in^3": { ...transformFromFactor(Math.pow(IN2M, 3)), category: "volume", order: 3 },
|
|
19628
|
+
oz: { ...transformFromFactor(2.95735295625e-5), category: "volume" },
|
|
19629
|
+
cup: { ...transformFromFactor(0.000237), category: "volume" },
|
|
19630
|
+
pt: { ...transformFromFactor(0.0004731765), category: "volume" },
|
|
19631
|
+
uk_pt: { ...transformFromFactor(0.000568261), category: "volume" },
|
|
19632
|
+
qt: { ...transformFromFactor(0.0009463529), category: "volume" },
|
|
19633
|
+
l: { ...transformFromFactor(1e-3), category: "volume" },
|
|
19634
|
+
uk_qt: { ...transformFromFactor(0.0011365225), category: "volume" },
|
|
19635
|
+
gal: { ...transformFromFactor(0.0037854118), category: "volume" },
|
|
19636
|
+
uk_gal: { ...transformFromFactor(0.00454609), category: "volume" },
|
|
19637
|
+
"ft^3": { ...transformFromFactor(Math.pow(FT2M, 3)), category: "volume", order: 3 },
|
|
19638
|
+
bushel: { ...transformFromFactor(0.0352390704), category: "volume" },
|
|
19639
|
+
barrel: { ...transformFromFactor(0.158987295), category: "volume" },
|
|
19640
|
+
"yd^3": { ...transformFromFactor(Math.pow(YD2M, 3)), category: "volume", order: 3 },
|
|
19641
|
+
MTON: { ...transformFromFactor(1.13267386368), category: "volume" },
|
|
19642
|
+
GRT: { ...transformFromFactor(2.83168), category: "volume" },
|
|
19643
|
+
"mi^3": { ...transformFromFactor(Math.pow(MI2M, 3)), category: "volume", order: 3 },
|
|
19644
|
+
"Nmi^3": { ...transformFromFactor(Math.pow(NMI2M, 3)), category: "volume", order: 3 },
|
|
19645
|
+
"ly^3": { ...transformFromFactor(Math.pow(LY2M, 3)), category: "volume", order: 3 },
|
|
19646
|
+
// AREA UNITS : Standard = square meter
|
|
19647
|
+
"m^2": { ...standard, category: "area", order: 2 },
|
|
19648
|
+
"ang^2": { ...transformFromFactor(Math.pow(ANG2M, 2)), category: "area", order: 2 },
|
|
19649
|
+
"Picapt^2": { ...transformFromFactor(Math.pow(PICAPT2M, 2)), category: "area", order: 2 },
|
|
19650
|
+
"in^2": { ...transformFromFactor(Math.pow(IN2M, 2)), category: "area", order: 2 },
|
|
19651
|
+
"ft^2": { ...transformFromFactor(Math.pow(FT2M, 2)), category: "area", order: 2 },
|
|
19652
|
+
"yd^2": { ...transformFromFactor(Math.pow(YD2M, 2)), category: "area", order: 2 },
|
|
19653
|
+
ar: { ...transformFromFactor(100), category: "area" },
|
|
19654
|
+
Morgen: { ...transformFromFactor(2500), category: "area" },
|
|
19655
|
+
uk_acre: { ...transformFromFactor(4046.8564224), category: "area" },
|
|
19656
|
+
us_acre: { ...transformFromFactor(4046.8726098743), category: "area" },
|
|
19657
|
+
ha: { ...transformFromFactor(1e4), category: "area" },
|
|
19658
|
+
"mi^2": { ...transformFromFactor(Math.pow(MI2M, 2)), category: "area", order: 2 },
|
|
19659
|
+
"Nmi^2": { ...transformFromFactor(Math.pow(NMI2M, 2)), category: "area", order: 2 },
|
|
19660
|
+
"ly^2": { ...transformFromFactor(Math.pow(LY2M, 2)), category: "area", order: 2 },
|
|
19661
|
+
// INFORMATION UNITS : Standard = bit
|
|
19662
|
+
bit: { ...standard, category: "information" },
|
|
19663
|
+
byte: { ...transformFromFactor(8), category: "information" },
|
|
19664
|
+
// SPEED UNITS : Standard = m/s
|
|
19665
|
+
"m/s": { ...standard, category: "speed" },
|
|
19666
|
+
"m/hr": { ...transformFromFactor(1 / 3600), category: "speed" },
|
|
19667
|
+
"km/hr": { ...transformFromFactor(1 / 3.6), category: "speed" },
|
|
19668
|
+
mph: { ...transformFromFactor(0.44704), category: "speed" },
|
|
19669
|
+
kn: { ...transformFromFactor(0.5144444444), category: "speed" },
|
|
19670
|
+
admkn: { ...transformFromFactor(0.5147733333), category: "speed" },
|
|
19671
|
+
};
|
|
19672
|
+
const UNITS_ALIASES = {
|
|
19673
|
+
shweight: "cwt",
|
|
19674
|
+
lcwt: "uk_cwt",
|
|
19675
|
+
hweight: "uk_cwt",
|
|
19676
|
+
LTON: "uk_ton",
|
|
19677
|
+
brton: "uk_ton",
|
|
19678
|
+
pc: "parsec",
|
|
19679
|
+
Pica: "Picapt",
|
|
19680
|
+
d: "day",
|
|
19681
|
+
mn: "min",
|
|
19682
|
+
s: "sec",
|
|
19683
|
+
p: "Pa",
|
|
19684
|
+
at: "atm",
|
|
19685
|
+
dy: "dyn",
|
|
19686
|
+
ev: "eV",
|
|
19687
|
+
hh: "HPh",
|
|
19688
|
+
wh: "Wh",
|
|
19689
|
+
btu: "BTU",
|
|
19690
|
+
h: "HP",
|
|
19691
|
+
cel: "C",
|
|
19692
|
+
fah: "F",
|
|
19693
|
+
kel: "K",
|
|
19694
|
+
us_pt: "pt",
|
|
19695
|
+
L: "l",
|
|
19696
|
+
lt: "l",
|
|
19697
|
+
ang3: "ang^3",
|
|
19698
|
+
ft3: "ft^3",
|
|
19699
|
+
in3: "in^3",
|
|
19700
|
+
ly3: "ly^3",
|
|
19701
|
+
m3: "m^3",
|
|
19702
|
+
mi3: "mi^3",
|
|
19703
|
+
yd3: "yd^3",
|
|
19704
|
+
Nmi3: "Nmi^3",
|
|
19705
|
+
Picapt3: "Picapt^3",
|
|
19706
|
+
"Pica^3": "Picapt^3",
|
|
19707
|
+
Pica3: "Picapt^3",
|
|
19708
|
+
regton: "GRT",
|
|
19709
|
+
ang2: "ang^2",
|
|
19710
|
+
ft2: "ft^2",
|
|
19711
|
+
in2: "in^2",
|
|
19712
|
+
ly2: "ly^2",
|
|
19713
|
+
m2: "m^2",
|
|
19714
|
+
mi2: "mi^2",
|
|
19715
|
+
Nmi2: "Nmi^2",
|
|
19716
|
+
Picapt2: "Picapt^2",
|
|
19717
|
+
"Pica^2": "Picapt^2",
|
|
19718
|
+
Pica2: "Picapt^2",
|
|
19719
|
+
yd2: "yd^2",
|
|
19720
|
+
"m/h": "m/hr",
|
|
19721
|
+
"m/sec": "m/s",
|
|
19722
|
+
};
|
|
19723
|
+
const UNIT_PREFIXES = {
|
|
19724
|
+
"": 1,
|
|
19725
|
+
Y: 1e24,
|
|
19726
|
+
Z: 1e21,
|
|
19727
|
+
E: 1e18,
|
|
19728
|
+
P: 1e15,
|
|
19729
|
+
T: 1e12,
|
|
19730
|
+
G: 1e9,
|
|
19731
|
+
M: 1e6,
|
|
19732
|
+
k: 1e3,
|
|
19733
|
+
h: 1e2,
|
|
19734
|
+
da: 1e1,
|
|
19735
|
+
e: 1e1,
|
|
19736
|
+
d: 1e-1,
|
|
19737
|
+
c: 1e-2,
|
|
19738
|
+
m: 1e-3,
|
|
19739
|
+
u: 1e-6,
|
|
19740
|
+
n: 1e-9,
|
|
19741
|
+
p: 1e-12,
|
|
19742
|
+
f: 1e-15,
|
|
19743
|
+
a: 1e-18,
|
|
19744
|
+
z: 1e-21,
|
|
19745
|
+
y: 1e-21,
|
|
19746
|
+
Yi: Math.pow(2, 80),
|
|
19747
|
+
Zi: Math.pow(2, 70),
|
|
19748
|
+
Ei: Math.pow(2, 60),
|
|
19749
|
+
Pi: Math.pow(2, 50),
|
|
19750
|
+
Ti: Math.pow(2, 40),
|
|
19751
|
+
Gi: Math.pow(2, 30),
|
|
19752
|
+
Mi: Math.pow(2, 20),
|
|
19753
|
+
ki: Math.pow(2, 10),
|
|
19754
|
+
};
|
|
19755
|
+
const TRANSLATED_CATEGORIES = {
|
|
19756
|
+
weight: _t("Weight"),
|
|
19757
|
+
distance: _t("Distance"),
|
|
19758
|
+
time: _t("Time"),
|
|
19759
|
+
pressure: _t("Pressure"),
|
|
19760
|
+
force: _t("Force"),
|
|
19761
|
+
energy: _t("Energy"),
|
|
19762
|
+
power: _t("Power"),
|
|
19763
|
+
magnetism: _t("Magnetism"),
|
|
19764
|
+
temperature: _t("Temperature"),
|
|
19765
|
+
volume: _t("Volume"),
|
|
19766
|
+
area: _t("Area"),
|
|
19767
|
+
information: _t("Information"),
|
|
19768
|
+
speed: _t("Speed"),
|
|
19769
|
+
};
|
|
19770
|
+
function getTranslatedCategory(key) {
|
|
19771
|
+
return TRANSLATED_CATEGORIES[key] ?? "";
|
|
19772
|
+
}
|
|
19773
|
+
function getTransformation(key) {
|
|
19774
|
+
for (const [prefix, value] of Object.entries(UNIT_PREFIXES)) {
|
|
19775
|
+
if (prefix && !key.startsWith(prefix))
|
|
19776
|
+
continue;
|
|
19777
|
+
const _key = key.slice(prefix.length);
|
|
19778
|
+
let conversion = UNITS[_key];
|
|
19779
|
+
if (!conversion && UNITS_ALIASES[_key]) {
|
|
19780
|
+
conversion = UNITS[UNITS_ALIASES[_key]];
|
|
19781
|
+
}
|
|
19782
|
+
if (conversion) {
|
|
19783
|
+
return {
|
|
19784
|
+
...conversion,
|
|
19785
|
+
factor: conversion.order ? Math.pow(value, conversion.order) : value,
|
|
19786
|
+
};
|
|
19787
|
+
}
|
|
19788
|
+
}
|
|
19789
|
+
return;
|
|
19790
|
+
}
|
|
19791
|
+
|
|
19792
|
+
// -----------------------------------------------------------------------------
|
|
19793
|
+
// CONVERT
|
|
19794
|
+
// -----------------------------------------------------------------------------
|
|
19795
|
+
const CONVERT = {
|
|
19796
|
+
description: _t("Converts a numeric value to a different unit of measure."),
|
|
19797
|
+
args: [
|
|
19798
|
+
arg("value (number)", _t("the numeric value in start_unit to convert to end_unit")),
|
|
19799
|
+
arg("start_unit (string)", _t("The starting unit, the unit currently assigned to value")),
|
|
19800
|
+
arg("end_unit (string)", _t("The unit of measure into which to convert value")),
|
|
19801
|
+
],
|
|
19802
|
+
compute: function (value, startUnit, endUnit) {
|
|
19803
|
+
const _value = toNumber(value, this.locale);
|
|
19804
|
+
const _startUnit = toString(startUnit);
|
|
19805
|
+
const _endUnit = toString(endUnit);
|
|
19806
|
+
const startConversion = getTransformation(_startUnit);
|
|
19807
|
+
const endConversion = getTransformation(_endUnit);
|
|
19808
|
+
if (!startConversion) {
|
|
19809
|
+
return {
|
|
19810
|
+
value: CellErrorType.GenericError,
|
|
19811
|
+
message: _t("Invalid units of measure ('%s')", _startUnit),
|
|
19812
|
+
};
|
|
19813
|
+
}
|
|
19814
|
+
if (!endConversion) {
|
|
19815
|
+
return {
|
|
19816
|
+
value: CellErrorType.GenericError,
|
|
19817
|
+
message: _t("Invalid units of measure ('%s')", _endUnit),
|
|
19818
|
+
};
|
|
19819
|
+
}
|
|
19820
|
+
if (startConversion.category !== endConversion.category) {
|
|
19821
|
+
return {
|
|
19822
|
+
value: CellErrorType.GenericError,
|
|
19823
|
+
message: _t("Incompatible units of measure ('%s' vs '%s')", getTranslatedCategory(startConversion.category), getTranslatedCategory(endConversion.category)),
|
|
19824
|
+
};
|
|
19825
|
+
}
|
|
19826
|
+
return {
|
|
19827
|
+
value: endConversion.inverseTransform(startConversion.factor * startConversion.transform(_value)) /
|
|
19828
|
+
endConversion.factor,
|
|
19829
|
+
format: value?.format,
|
|
19830
|
+
};
|
|
19831
|
+
},
|
|
19832
|
+
isExported: true,
|
|
19833
|
+
};
|
|
19834
|
+
|
|
19835
|
+
var parser = /*#__PURE__*/Object.freeze({
|
|
19836
|
+
__proto__: null,
|
|
19837
|
+
CONVERT: CONVERT
|
|
19838
|
+
});
|
|
19839
|
+
|
|
19523
19840
|
const DEFAULT_STARTING_AT = 1;
|
|
19524
19841
|
/** Regex matching all the words in a string */
|
|
19525
19842
|
const wordRegex = /[A-Za-zÀ-ÖØ-öø-ÿ]+/g;
|
|
@@ -19937,6 +20254,7 @@ const categories = [
|
|
|
19937
20254
|
{ name: _t("Text"), functions: text },
|
|
19938
20255
|
{ name: _t("Engineering"), functions: engineering },
|
|
19939
20256
|
{ name: _t("Web"), functions: web },
|
|
20257
|
+
{ name: _t("Parser"), functions: parser },
|
|
19940
20258
|
];
|
|
19941
20259
|
const functionNameRegex = /^[A-Z0-9\_\.]+$/;
|
|
19942
20260
|
class FunctionRegistry extends Registry {
|
|
@@ -19948,41 +20266,127 @@ class FunctionRegistry extends Registry {
|
|
|
19948
20266
|
}
|
|
19949
20267
|
const descr = addMetaInfoFromArg(addDescr);
|
|
19950
20268
|
validateArguments(descr.args);
|
|
19951
|
-
this.mapping[name] =
|
|
20269
|
+
this.mapping[name] = createComputeFunction(descr, name);
|
|
19952
20270
|
super.add(name, descr);
|
|
19953
20271
|
return this;
|
|
19954
20272
|
}
|
|
19955
20273
|
}
|
|
19956
|
-
|
|
19957
|
-
|
|
20274
|
+
const functionRegistry = new FunctionRegistry();
|
|
20275
|
+
for (let category of categories) {
|
|
20276
|
+
const fns = category.functions;
|
|
20277
|
+
for (let name in fns) {
|
|
20278
|
+
const addDescr = fns[name];
|
|
20279
|
+
addDescr.category = addDescr.category || category.name;
|
|
20280
|
+
name = name.replace(/_/g, ".");
|
|
20281
|
+
functionRegistry.add(name, { isExported: false, ...addDescr });
|
|
20282
|
+
}
|
|
20283
|
+
}
|
|
20284
|
+
const notAvailableError = new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
|
|
20285
|
+
function createComputeFunction(descr, functionName) {
|
|
20286
|
+
function runtimeCompute(...args) {
|
|
20287
|
+
try {
|
|
20288
|
+
return vectorizedCompute.apply(this, args);
|
|
20289
|
+
}
|
|
20290
|
+
catch (e) {
|
|
20291
|
+
return handleError(e, functionName);
|
|
20292
|
+
}
|
|
20293
|
+
}
|
|
20294
|
+
function vectorizedCompute(...args) {
|
|
20295
|
+
let countVectorizableCol = 1;
|
|
20296
|
+
let countVectorizableRow = 1;
|
|
20297
|
+
let vectorizableColLimit = Infinity;
|
|
20298
|
+
let vectorizableRowLimit = Infinity;
|
|
20299
|
+
let vectorArgsType = undefined;
|
|
20300
|
+
//#region Compute vectorisation limits
|
|
19958
20301
|
for (let i = 0; i < args.length; i++) {
|
|
19959
20302
|
const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
|
|
19960
20303
|
const arg = args[i];
|
|
19961
20304
|
if (isMatrix(arg) && !argDefinition.acceptMatrix) {
|
|
19962
|
-
if
|
|
19963
|
-
|
|
20305
|
+
// if argDefinition does not accept a matrix but arg is still a matrix
|
|
20306
|
+
// --> triggers the arguments vectorization
|
|
20307
|
+
const nColumns = arg.length;
|
|
20308
|
+
const nRows = arg[0].length;
|
|
20309
|
+
if (nColumns !== 1 || nRows !== 1) {
|
|
20310
|
+
vectorArgsType ??= new Array(args.length);
|
|
20311
|
+
if (nColumns !== 1 && nRows !== 1) {
|
|
20312
|
+
vectorArgsType[i] = "matrix";
|
|
20313
|
+
countVectorizableCol = Math.max(countVectorizableCol, nColumns);
|
|
20314
|
+
countVectorizableRow = Math.max(countVectorizableRow, nRows);
|
|
20315
|
+
vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
|
|
20316
|
+
vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
|
|
20317
|
+
}
|
|
20318
|
+
else if (nColumns !== 1) {
|
|
20319
|
+
vectorArgsType[i] = "horizontal";
|
|
20320
|
+
countVectorizableCol = Math.max(countVectorizableCol, nColumns);
|
|
20321
|
+
vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
|
|
20322
|
+
}
|
|
20323
|
+
else if (nRows !== 1) {
|
|
20324
|
+
vectorArgsType[i] = "vertical";
|
|
20325
|
+
countVectorizableRow = Math.max(countVectorizableRow, nRows);
|
|
20326
|
+
vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
|
|
20327
|
+
}
|
|
20328
|
+
}
|
|
20329
|
+
else {
|
|
20330
|
+
args[i] = arg[0][0];
|
|
19964
20331
|
}
|
|
19965
|
-
args[i] = arg[0][0];
|
|
19966
20332
|
}
|
|
19967
20333
|
if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
|
|
19968
20334
|
throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
|
|
19969
20335
|
}
|
|
19970
20336
|
}
|
|
19971
|
-
|
|
20337
|
+
//#endregion
|
|
20338
|
+
if (countVectorizableCol === 1 && countVectorizableRow === 1) {
|
|
20339
|
+
// either this function is not vectorized or it ends up with a 1x1 dimension
|
|
20340
|
+
return computeFunctionToObject.apply(this, args);
|
|
20341
|
+
}
|
|
20342
|
+
const getArgOffset = (i, j) => args.map((arg, index) => {
|
|
20343
|
+
switch (vectorArgsType?.[index]) {
|
|
20344
|
+
case "matrix":
|
|
20345
|
+
return arg[i][j];
|
|
20346
|
+
case "horizontal":
|
|
20347
|
+
return arg[i][0];
|
|
20348
|
+
case "vertical":
|
|
20349
|
+
return arg[0][j];
|
|
20350
|
+
case undefined:
|
|
20351
|
+
return arg;
|
|
20352
|
+
}
|
|
20353
|
+
});
|
|
20354
|
+
return generateMatrix(countVectorizableCol, countVectorizableRow, (col, row) => {
|
|
20355
|
+
if (col > vectorizableColLimit - 1 || row > vectorizableRowLimit - 1) {
|
|
20356
|
+
return notAvailableError;
|
|
20357
|
+
}
|
|
20358
|
+
const singleCellComputeResult = computeFunctionToObject.apply(this, getArgOffset(col, row));
|
|
20359
|
+
// In the case where the user tries to vectorize arguments of an array formula, we will get an
|
|
20360
|
+
// array for every combination of the vectorized arguments, which will lead to a 3D matrix and
|
|
20361
|
+
// we won't be able to return the values.
|
|
20362
|
+
// In this case, we keep the first element of each spreading part, just as Excel does, and
|
|
20363
|
+
// create an array with these parts.
|
|
20364
|
+
// For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
|
|
20365
|
+
// range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
|
|
20366
|
+
// for the value in A2). In this case, we will simply take the first value of each matrix and
|
|
20367
|
+
// return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
|
|
20368
|
+
return isMatrix(singleCellComputeResult)
|
|
20369
|
+
? singleCellComputeResult[0][0]
|
|
20370
|
+
: singleCellComputeResult;
|
|
20371
|
+
});
|
|
19972
20372
|
}
|
|
19973
|
-
|
|
19974
|
-
|
|
19975
|
-
|
|
19976
|
-
|
|
19977
|
-
|
|
19978
|
-
|
|
20373
|
+
function computeFunctionToObject(...args) {
|
|
20374
|
+
const result = descr.compute.apply(this, args);
|
|
20375
|
+
if (!isMatrix(result)) {
|
|
20376
|
+
if (typeof result === "object" && result !== null && "value" in result) {
|
|
20377
|
+
replaceFunctionNamePlaceholder(result, functionName);
|
|
20378
|
+
return result;
|
|
20379
|
+
}
|
|
20380
|
+
return { value: result };
|
|
19979
20381
|
}
|
|
19980
|
-
|
|
19981
|
-
|
|
20382
|
+
if (typeof result[0][0] === "object" && result[0][0] !== null && "value" in result[0][0]) {
|
|
20383
|
+
matrixForEach(result, (result) => replaceFunctionNamePlaceholder(result, functionName));
|
|
20384
|
+
return result;
|
|
19982
20385
|
}
|
|
19983
|
-
|
|
20386
|
+
return matrixMap(result, (row) => ({ value: row }));
|
|
20387
|
+
}
|
|
20388
|
+
return runtimeCompute;
|
|
19984
20389
|
}
|
|
19985
|
-
const implementationErrorMessage = _t("An unexpected error occurred. Submit a support ticket at odoo.com/help.");
|
|
19986
20390
|
function handleError(e, functionName) {
|
|
19987
20391
|
// the error could be an user error (instance of EvaluationError)
|
|
19988
20392
|
// or a javascript error (instance of Error)
|
|
@@ -20001,42 +20405,16 @@ function hasStringValue(obj) {
|
|
|
20001
20405
|
return (obj?.value !== undefined &&
|
|
20002
20406
|
typeof obj.value === "string");
|
|
20003
20407
|
}
|
|
20004
|
-
function
|
|
20005
|
-
return (obj?.message !== undefined &&
|
|
20006
|
-
typeof obj.message === "string");
|
|
20007
|
-
}
|
|
20008
|
-
function addResultHandling(compute, functionName) {
|
|
20009
|
-
return function computeWithResultHandling(...args) {
|
|
20010
|
-
const result = compute.apply(this, args);
|
|
20011
|
-
if (!isMatrix(result)) {
|
|
20012
|
-
if (typeof result === "object" && result !== null && "value" in result) {
|
|
20013
|
-
replaceFunctionNamePlaceholder(result, functionName);
|
|
20014
|
-
return result;
|
|
20015
|
-
}
|
|
20016
|
-
return { value: result };
|
|
20017
|
-
}
|
|
20018
|
-
if (typeof result[0][0] === "object" && result[0][0] !== null && "value" in result[0][0]) {
|
|
20019
|
-
matrixForEach(result, (result) => replaceFunctionNamePlaceholder(result, functionName));
|
|
20020
|
-
return result;
|
|
20021
|
-
}
|
|
20022
|
-
return matrixMap(result, (row) => ({ value: row }));
|
|
20023
|
-
};
|
|
20024
|
-
}
|
|
20025
|
-
function replaceFunctionNamePlaceholder(fPayload, functionName) {
|
|
20408
|
+
function replaceFunctionNamePlaceholder(functionResult, functionName) {
|
|
20026
20409
|
// for performance reasons: change in place and only if needed
|
|
20027
|
-
if (
|
|
20028
|
-
|
|
20410
|
+
if (functionResult.message?.includes("[[FUNCTION_NAME]]")) {
|
|
20411
|
+
functionResult.message = functionResult.message.replace("[[FUNCTION_NAME]]", functionName);
|
|
20029
20412
|
}
|
|
20030
20413
|
}
|
|
20031
|
-
const
|
|
20032
|
-
|
|
20033
|
-
|
|
20034
|
-
|
|
20035
|
-
const addDescr = fns[name];
|
|
20036
|
-
addDescr.category = addDescr.category || category.name;
|
|
20037
|
-
name = name.replace(/_/g, ".");
|
|
20038
|
-
functionRegistry.add(name, { isExported: false, ...addDescr });
|
|
20039
|
-
}
|
|
20414
|
+
const implementationErrorMessage = _t("An unexpected error occurred. Submit a support ticket at odoo.com/help.");
|
|
20415
|
+
function hasStringMessage(obj) {
|
|
20416
|
+
return (obj?.message !== undefined &&
|
|
20417
|
+
typeof obj.message === "string");
|
|
20040
20418
|
}
|
|
20041
20419
|
|
|
20042
20420
|
autoCompleteProviders.add("functions", {
|
|
@@ -21485,6 +21863,7 @@ function indentCode(code) {
|
|
|
21485
21863
|
|
|
21486
21864
|
const functions$1 = functionRegistry.content;
|
|
21487
21865
|
const OPERATOR_MAP = {
|
|
21866
|
+
// export for test
|
|
21488
21867
|
"=": "EQ",
|
|
21489
21868
|
"+": "ADD",
|
|
21490
21869
|
"-": "MINUS",
|
|
@@ -21499,6 +21878,7 @@ const OPERATOR_MAP = {
|
|
|
21499
21878
|
"&": "CONCATENATE",
|
|
21500
21879
|
};
|
|
21501
21880
|
const UNARY_OPERATOR_MAP = {
|
|
21881
|
+
// export for test
|
|
21502
21882
|
"-": "UMINUS",
|
|
21503
21883
|
"+": "UPLUS",
|
|
21504
21884
|
"%": "UNARY.PERCENT",
|
|
@@ -22787,8 +23167,7 @@ function truncateLabel(label) {
|
|
|
22787
23167
|
/**
|
|
22788
23168
|
* Get a default chart js configuration
|
|
22789
23169
|
*/
|
|
22790
|
-
function getDefaultChartJsRuntime(chart, labels, fontColor,
|
|
22791
|
-
const { format, locale, truncateLabels, horizontalChart } = args;
|
|
23170
|
+
function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, truncateLabels = true, horizontalChart, }) {
|
|
22792
23171
|
const chartTitle = chart.title.text ? chart.title : { ...chart.title, content: "" };
|
|
22793
23172
|
const options = {
|
|
22794
23173
|
// https://www.chartjs.org/docs/latest/general/responsive.html
|
|
@@ -22964,7 +23343,6 @@ function chartToImage(runtime, figure, type) {
|
|
|
22964
23343
|
if ("chartJsConfig" in runtime) {
|
|
22965
23344
|
const config = deepCopy(runtime.chartJsConfig);
|
|
22966
23345
|
config.plugins = [backgroundColorChartJSPlugin];
|
|
22967
|
-
// @ts-ignore
|
|
22968
23346
|
const chart = new window.Chart(canvas, config);
|
|
22969
23347
|
const imgContent = chart.toBase64Image();
|
|
22970
23348
|
chart.destroy();
|
|
@@ -23885,13 +24263,11 @@ function canBeLinearChart(labelRange, getters) {
|
|
|
23885
24263
|
}
|
|
23886
24264
|
let missingTimeAdapterAlreadyWarned = false;
|
|
23887
24265
|
function isLuxonTimeAdapterInstalled() {
|
|
23888
|
-
// @ts-ignore
|
|
23889
24266
|
if (!window.Chart) {
|
|
23890
24267
|
return false;
|
|
23891
24268
|
}
|
|
23892
24269
|
// @ts-ignore
|
|
23893
24270
|
const adapter = new window.Chart._adapters._date({});
|
|
23894
|
-
// @ts-ignore
|
|
23895
24271
|
const isInstalled = adapter._id === "luxon";
|
|
23896
24272
|
if (!isInstalled && !missingTimeAdapterAlreadyWarned) {
|
|
23897
24273
|
missingTimeAdapterAlreadyWarned = true;
|
|
@@ -23908,9 +24284,7 @@ function getLineOrScatterConfiguration(chart, labels, options) {
|
|
|
23908
24284
|
generateLabels(chart) {
|
|
23909
24285
|
// color the legend labels with the dataset color, without any transparency
|
|
23910
24286
|
const { data } = chart;
|
|
23911
|
-
|
|
23912
|
-
const labels = window.Chart.defaults.plugins.legend.labels
|
|
23913
|
-
.generateLabels(chart);
|
|
24287
|
+
const labels = window.Chart.defaults.plugins.legend.labels.generateLabels(chart);
|
|
23914
24288
|
for (const [index, label] of labels.entries()) {
|
|
23915
24289
|
label.fillStyle = data.datasets[index].borderColor;
|
|
23916
24290
|
}
|
|
@@ -24027,10 +24401,6 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
24027
24401
|
const colors = new ColorGenerator();
|
|
24028
24402
|
const definition = chart.getDefinition();
|
|
24029
24403
|
for (let [index, { label, data }] of dataSetsValues.entries()) {
|
|
24030
|
-
if (["linear", "time"].includes(axisType)) {
|
|
24031
|
-
// Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
|
|
24032
|
-
data = data.map((y, index) => ({ x: labels[index] || undefined, y }));
|
|
24033
|
-
}
|
|
24034
24404
|
const color = colors.next();
|
|
24035
24405
|
let backgroundRGBA = colorToRGBA(color);
|
|
24036
24406
|
if (areaChart) {
|
|
@@ -24046,6 +24416,10 @@ function createLineOrScatterChartRuntime(chart, getters) {
|
|
|
24046
24416
|
return value;
|
|
24047
24417
|
});
|
|
24048
24418
|
}
|
|
24419
|
+
if (["linear", "time"].includes(axisType)) {
|
|
24420
|
+
// Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
|
|
24421
|
+
data = data.map((y, index) => ({ x: labels[index] || undefined, y }));
|
|
24422
|
+
}
|
|
24049
24423
|
const backgroundColor = rgbaToHex(backgroundRGBA);
|
|
24050
24424
|
const dataset = {
|
|
24051
24425
|
label,
|
|
@@ -33152,21 +33526,25 @@ function useHoveredElement(ref) {
|
|
|
33152
33526
|
|
|
33153
33527
|
function useHighlightsOnHover(ref, highlightProvider) {
|
|
33154
33528
|
const hoverState = useHoveredElement(ref);
|
|
33155
|
-
const stores = useStoreProvider();
|
|
33156
33529
|
useHighlights({
|
|
33157
33530
|
get highlights() {
|
|
33158
33531
|
return hoverState.hovered ? highlightProvider.highlights : [];
|
|
33159
33532
|
},
|
|
33160
33533
|
});
|
|
33161
|
-
owl.useEffect(() => {
|
|
33162
|
-
stores.trigger("store-updated");
|
|
33163
|
-
}, () => [hoverState.hovered]);
|
|
33164
33534
|
}
|
|
33165
33535
|
function useHighlights(highlightProvider) {
|
|
33536
|
+
const stores = useStoreProvider();
|
|
33166
33537
|
const store = useLocalStore(HighlightStore);
|
|
33167
33538
|
owl.onMounted(() => {
|
|
33168
33539
|
store.register(highlightProvider);
|
|
33169
33540
|
});
|
|
33541
|
+
let currentHighlights = highlightProvider.highlights;
|
|
33542
|
+
owl.useEffect((highlights) => {
|
|
33543
|
+
if (!deepEquals(highlights, currentHighlights)) {
|
|
33544
|
+
currentHighlights = highlights;
|
|
33545
|
+
stores.trigger("store-updated");
|
|
33546
|
+
}
|
|
33547
|
+
}, () => [highlightProvider.highlights]);
|
|
33170
33548
|
}
|
|
33171
33549
|
|
|
33172
33550
|
css /* scss */ `
|
|
@@ -34638,6 +35016,8 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
34638
35016
|
isSearchDirty = false;
|
|
34639
35017
|
initialShowFormulaState;
|
|
34640
35018
|
preserveSelectedMatchIndex = false;
|
|
35019
|
+
irreplaceableMatchCount = 0;
|
|
35020
|
+
notificationStore = this.get(NotificationStore);
|
|
34641
35021
|
// fixme: why do we make selectedMatchIndex on top of a selected
|
|
34642
35022
|
// property in the matches?
|
|
34643
35023
|
selectedMatchIndex = null;
|
|
@@ -34714,6 +35094,11 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
34714
35094
|
for (const match of cmd.matches) {
|
|
34715
35095
|
this.replaceMatch(match, cmd.searchString, cmd.replaceWith, cmd.searchOptions);
|
|
34716
35096
|
}
|
|
35097
|
+
if (this.irreplaceableMatchCount > 0) {
|
|
35098
|
+
this.showReplaceWarningMessage(cmd.matches.length, this.irreplaceableMatchCount);
|
|
35099
|
+
}
|
|
35100
|
+
this.irreplaceableMatchCount = 0;
|
|
35101
|
+
break;
|
|
34717
35102
|
}
|
|
34718
35103
|
}
|
|
34719
35104
|
finalize() {
|
|
@@ -34895,12 +35280,36 @@ class FindAndReplaceStore extends SpreadsheetStore {
|
|
|
34895
35280
|
searchOptions: this.searchOptions,
|
|
34896
35281
|
});
|
|
34897
35282
|
}
|
|
35283
|
+
/**
|
|
35284
|
+
* Show a warning message based on the number of matches replaced and irreplaceable.
|
|
35285
|
+
*/
|
|
35286
|
+
showReplaceWarningMessage(totalMatches, irreplaceableMatches) {
|
|
35287
|
+
const replaceableMatches = totalMatches - irreplaceableMatches;
|
|
35288
|
+
if (replaceableMatches === 0) {
|
|
35289
|
+
this.notificationStore.notifyUser({
|
|
35290
|
+
type: "warning",
|
|
35291
|
+
sticky: false,
|
|
35292
|
+
text: _t("Match(es) cannot be replaced as they are part of a formula."),
|
|
35293
|
+
});
|
|
35294
|
+
}
|
|
35295
|
+
else {
|
|
35296
|
+
this.notificationStore.notifyUser({
|
|
35297
|
+
type: "warning",
|
|
35298
|
+
sticky: false,
|
|
35299
|
+
text: _t("%(replaceable_count)s match(es) replaced. %(irreplaceable_count)s match(es) cannot be replaced as they are part of a formula.", {
|
|
35300
|
+
replaceable_count: replaceableMatches,
|
|
35301
|
+
irreplaceable_count: irreplaceableMatches,
|
|
35302
|
+
}),
|
|
35303
|
+
});
|
|
35304
|
+
}
|
|
35305
|
+
}
|
|
34898
35306
|
replaceMatch(selectedMatch, searchString, replaceWith, searchOptions) {
|
|
34899
35307
|
const cell = this.getters.getCell(selectedMatch);
|
|
34900
35308
|
if (!cell?.content) {
|
|
34901
35309
|
return;
|
|
34902
35310
|
}
|
|
34903
35311
|
if (cell?.isFormula && !searchOptions.searchFormulas) {
|
|
35312
|
+
this.irreplaceableMatchCount++;
|
|
34904
35313
|
return;
|
|
34905
35314
|
}
|
|
34906
35315
|
const searchRegex = getSearchRegex(searchString, searchOptions);
|
|
@@ -36966,7 +37375,13 @@ class SettingsPanel extends owl.Component {
|
|
|
36966
37375
|
}
|
|
36967
37376
|
async loadLocales() {
|
|
36968
37377
|
this.loadedLocales = (await this.env.loadLocales())
|
|
36969
|
-
.filter(
|
|
37378
|
+
.filter((locale) => {
|
|
37379
|
+
const isValid = isValidLocale(locale);
|
|
37380
|
+
if (!isValid) {
|
|
37381
|
+
console.warn(`Invalid locale: ${locale["code"]} ${locale}`);
|
|
37382
|
+
}
|
|
37383
|
+
return isValid;
|
|
37384
|
+
})
|
|
36970
37385
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
36971
37386
|
}
|
|
36972
37387
|
get numberFormatPreview() {
|
|
@@ -38025,6 +38440,9 @@ class TopBarComponentRegistry extends Registry {
|
|
|
38025
38440
|
const component = { ...value, id: this.uuidGenerator.uuidv4() };
|
|
38026
38441
|
return super.add(name, component);
|
|
38027
38442
|
}
|
|
38443
|
+
getAllOrdered() {
|
|
38444
|
+
return this.getAll().sort((a, b) => a.sequence - b.sequence);
|
|
38445
|
+
}
|
|
38028
38446
|
}
|
|
38029
38447
|
const topbarComponentRegistry = new TopBarComponentRegistry();
|
|
38030
38448
|
|
|
@@ -42135,6 +42553,7 @@ class Grid extends owl.Component {
|
|
|
42135
42553
|
return;
|
|
42136
42554
|
}
|
|
42137
42555
|
if (clipboardData.types.indexOf(ClipboardMIMEType.PlainText) > -1) {
|
|
42556
|
+
ev.preventDefault();
|
|
42138
42557
|
const content = clipboardData.getData(ClipboardMIMEType.PlainText);
|
|
42139
42558
|
const target = this.env.model.getters.getSelectedZones();
|
|
42140
42559
|
const clipboardString = this.env.model.getters.getClipboardTextContent();
|
|
@@ -45719,7 +46138,7 @@ function getRelationFile(file, xmls) {
|
|
|
45719
46138
|
return relsFile;
|
|
45720
46139
|
}
|
|
45721
46140
|
|
|
45722
|
-
const EXCEL_IMPORT_VERSION =
|
|
46141
|
+
const EXCEL_IMPORT_VERSION = 17;
|
|
45723
46142
|
class XlsxReader {
|
|
45724
46143
|
warningManager;
|
|
45725
46144
|
xmls;
|
|
@@ -45851,7 +46270,7 @@ function normalizeV9(formula) {
|
|
|
45851
46270
|
* a breaking change is made in the way the state is handled, and an upgrade
|
|
45852
46271
|
* function should be defined
|
|
45853
46272
|
*/
|
|
45854
|
-
const CURRENT_VERSION =
|
|
46273
|
+
const CURRENT_VERSION = 17;
|
|
45855
46274
|
const INITIAL_SHEET_ID = "Sheet1";
|
|
45856
46275
|
/**
|
|
45857
46276
|
* This function tries to load anything that could look like a valid
|
|
@@ -46798,6 +47217,21 @@ class BordersPlugin extends CorePlugin {
|
|
|
46798
47217
|
return [];
|
|
46799
47218
|
return Object.keys(sheetBorders).map((index) => parseInt(index, 10));
|
|
46800
47219
|
}
|
|
47220
|
+
/**
|
|
47221
|
+
* Get all the rows which contains at least a border
|
|
47222
|
+
*/
|
|
47223
|
+
getRowsWithBorders(sheetId) {
|
|
47224
|
+
const sheetBorders = this.borders[sheetId]?.filter(isDefined);
|
|
47225
|
+
if (!sheetBorders)
|
|
47226
|
+
return [];
|
|
47227
|
+
const rowsWithBorders = new Set();
|
|
47228
|
+
for (const rowBorders of sheetBorders) {
|
|
47229
|
+
for (const rowBorder in rowBorders) {
|
|
47230
|
+
rowsWithBorders.add(parseInt(rowBorder, 10));
|
|
47231
|
+
}
|
|
47232
|
+
}
|
|
47233
|
+
return Array.from(rowsWithBorders);
|
|
47234
|
+
}
|
|
46801
47235
|
/**
|
|
46802
47236
|
* Get the range of all the rows in the sheet
|
|
46803
47237
|
*/
|
|
@@ -46847,7 +47281,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
46847
47281
|
destructive: false,
|
|
46848
47282
|
});
|
|
46849
47283
|
}
|
|
46850
|
-
this.
|
|
47284
|
+
this.getRowsWithBorders(sheetId)
|
|
46851
47285
|
.filter((row) => row >= start)
|
|
46852
47286
|
.sort((a, b) => (delta < 0 ? a - b : b - a)) // start by the end when moving up
|
|
46853
47287
|
.forEach((row) => {
|
|
@@ -49173,10 +49607,12 @@ class MergePlugin extends CorePlugin {
|
|
|
49173
49607
|
if (!sheetMap)
|
|
49174
49608
|
return [];
|
|
49175
49609
|
const mergeIds = new Set();
|
|
49176
|
-
for (
|
|
49177
|
-
|
|
49178
|
-
|
|
49179
|
-
|
|
49610
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
49611
|
+
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
49612
|
+
const mergeId = sheetMap[col]?.[row];
|
|
49613
|
+
if (mergeId) {
|
|
49614
|
+
mergeIds.add(mergeId);
|
|
49615
|
+
}
|
|
49180
49616
|
}
|
|
49181
49617
|
}
|
|
49182
49618
|
return Array.from(mergeIds)
|
|
@@ -53044,7 +53480,13 @@ class FormulaDependencyGraph {
|
|
|
53044
53480
|
const queue = Array.from(ranges).reverse();
|
|
53045
53481
|
while (queue.length > 0) {
|
|
53046
53482
|
const range = queue.pop();
|
|
53047
|
-
|
|
53483
|
+
const zone = range.zone;
|
|
53484
|
+
const sheetId = range.sheetId;
|
|
53485
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
53486
|
+
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
53487
|
+
visited.add({ sheetId, col, row });
|
|
53488
|
+
}
|
|
53489
|
+
}
|
|
53048
53490
|
const impactedPositions = this.rTree.search(range).map((dep) => dep.data);
|
|
53049
53491
|
const nextInQueue = {};
|
|
53050
53492
|
for (const position of impactedPositions) {
|
|
@@ -53060,7 +53502,16 @@ class FormulaDependencyGraph {
|
|
|
53060
53502
|
queue.push(...zones.map((zone) => ({ sheetId, zone })));
|
|
53061
53503
|
}
|
|
53062
53504
|
}
|
|
53063
|
-
|
|
53505
|
+
// remove initial ranges
|
|
53506
|
+
for (const range of ranges) {
|
|
53507
|
+
const zone = range.zone;
|
|
53508
|
+
const sheetId = range.sheetId;
|
|
53509
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
53510
|
+
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
53511
|
+
visited.delete({ sheetId, col, row });
|
|
53512
|
+
}
|
|
53513
|
+
}
|
|
53514
|
+
}
|
|
53064
53515
|
return visited;
|
|
53065
53516
|
}
|
|
53066
53517
|
}
|
|
@@ -53191,7 +53642,7 @@ class PositionSet {
|
|
|
53191
53642
|
return this.sheets[position.sheetId].getValue(position) === 1;
|
|
53192
53643
|
}
|
|
53193
53644
|
clear() {
|
|
53194
|
-
const insertions = this
|
|
53645
|
+
const insertions = [...this];
|
|
53195
53646
|
this.insertions = [];
|
|
53196
53647
|
for (const sheetId in this.sheets) {
|
|
53197
53648
|
this.sheets[sheetId].clear();
|
|
@@ -53535,6 +53986,7 @@ class Evaluator {
|
|
|
53535
53986
|
}
|
|
53536
53987
|
finally {
|
|
53537
53988
|
this.cellsBeingComputed.delete(cellId);
|
|
53989
|
+
this.nextPositionsToUpdate.delete(position);
|
|
53538
53990
|
}
|
|
53539
53991
|
}
|
|
53540
53992
|
computeAndSave(position) {
|
|
@@ -53561,8 +54013,33 @@ class Evaluator {
|
|
|
53561
54013
|
forEachSpreadPositionInMatrix(nbColumns, nbRows,
|
|
53562
54014
|
// thanks to the isMatrix check above, we know that formulaReturn is MatrixFunctionReturn
|
|
53563
54015
|
this.spreadValues(formulaPosition, formulaReturn));
|
|
54016
|
+
this.invalidatePositionsDependingOnSpread(formulaPosition, nbColumns, nbRows);
|
|
53564
54017
|
return createEvaluatedCell(nullValueToZeroValue(formulaReturn[0][0]), this.getters.getLocale(), cellData);
|
|
53565
54018
|
}
|
|
54019
|
+
invalidatePositionsDependingOnSpread(arrayFormulaPosition, nbColumns, nbRows) {
|
|
54020
|
+
// the result matrix is split in 2 zones to exclude the array formula position
|
|
54021
|
+
const top = arrayFormulaPosition.row;
|
|
54022
|
+
const left = arrayFormulaPosition.col;
|
|
54023
|
+
const bottom = top + nbRows - 1;
|
|
54024
|
+
const leftColumnZone = {
|
|
54025
|
+
top: top + 1,
|
|
54026
|
+
bottom,
|
|
54027
|
+
left,
|
|
54028
|
+
right: left,
|
|
54029
|
+
};
|
|
54030
|
+
const rightPartZone = {
|
|
54031
|
+
top,
|
|
54032
|
+
bottom,
|
|
54033
|
+
left: left + 1,
|
|
54034
|
+
right: left + nbColumns - 1,
|
|
54035
|
+
};
|
|
54036
|
+
const sheetId = arrayFormulaPosition.sheetId;
|
|
54037
|
+
const invalidatedPositions = this.formulaDependencies().getCellsDependingOn([
|
|
54038
|
+
{ sheetId, zone: rightPartZone },
|
|
54039
|
+
{ sheetId, zone: leftColumnZone },
|
|
54040
|
+
]);
|
|
54041
|
+
this.nextPositionsToUpdate.addMany(invalidatedPositions);
|
|
54042
|
+
}
|
|
53566
54043
|
assertSheetHasEnoughSpaceToSpreadFormulaResult({ sheetId, col, row }, matrixResult) {
|
|
53567
54044
|
const numberOfCols = this.getters.getNumberCols(sheetId);
|
|
53568
54045
|
const numberOfRows = this.getters.getNumberRows(sheetId);
|
|
@@ -53593,14 +54070,15 @@ class Evaluator {
|
|
|
53593
54070
|
}
|
|
53594
54071
|
updateSpreadRelation({ sheetId, col, row, }) {
|
|
53595
54072
|
const arrayFormulaPosition = { sheetId, col, row };
|
|
53596
|
-
|
|
54073
|
+
const updateSpreadRelation = (i, j) => {
|
|
53597
54074
|
const position = { sheetId, col: i + col, row: j + row };
|
|
53598
54075
|
this.spreadingRelations.addRelation({ resultPosition: position, arrayFormulaPosition });
|
|
53599
54076
|
};
|
|
54077
|
+
return updateSpreadRelation;
|
|
53600
54078
|
}
|
|
53601
54079
|
checkCollision(formulaPosition) {
|
|
53602
54080
|
const { sheetId, col, row } = formulaPosition;
|
|
53603
|
-
|
|
54081
|
+
const checkCollision = (i, j) => {
|
|
53604
54082
|
const position = { sheetId: sheetId, col: i + col, row: j + row };
|
|
53605
54083
|
const rawCell = this.getters.getCell(position);
|
|
53606
54084
|
if (rawCell?.content ||
|
|
@@ -53610,17 +54088,16 @@ class Evaluator {
|
|
|
53610
54088
|
}
|
|
53611
54089
|
this.blockedArrayFormulas.delete(formulaPosition);
|
|
53612
54090
|
};
|
|
54091
|
+
return checkCollision;
|
|
53613
54092
|
}
|
|
53614
54093
|
spreadValues({ sheetId, col, row }, matrixResult) {
|
|
53615
|
-
|
|
54094
|
+
const spreadValues = (i, j) => {
|
|
53616
54095
|
const position = { sheetId, col: i + col, row: j + row };
|
|
53617
54096
|
const cell = this.getters.getCell(position);
|
|
53618
54097
|
const evaluatedCell = createEvaluatedCell(nullValueToZeroValue(matrixResult[i][j]), this.getters.getLocale(), cell);
|
|
53619
54098
|
this.evaluatedCells.set(position, evaluatedCell);
|
|
53620
|
-
// check if formula dependencies present in the spread zone
|
|
53621
|
-
// if so, they need to be recomputed
|
|
53622
|
-
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([position]));
|
|
53623
54099
|
};
|
|
54100
|
+
return spreadValues;
|
|
53624
54101
|
}
|
|
53625
54102
|
invalidateSpreading(position) {
|
|
53626
54103
|
if (!this.spreadingRelations.isArrayFormula(position)) {
|
|
@@ -53675,12 +54152,12 @@ function forEachSpreadPositionInMatrix(nbColumns, nbRows, callback) {
|
|
|
53675
54152
|
* rather than appearing empty. This indicates that the
|
|
53676
54153
|
* cell is the result of a non-empty content.
|
|
53677
54154
|
*/
|
|
53678
|
-
function nullValueToZeroValue(
|
|
53679
|
-
if (
|
|
53680
|
-
// '
|
|
53681
|
-
return { ...
|
|
54155
|
+
function nullValueToZeroValue(functionResult) {
|
|
54156
|
+
if (functionResult.value === null || functionResult.value === undefined) {
|
|
54157
|
+
// 'functionResult.value === undefined' is supposed to never happen, it's a safety net for javascript use
|
|
54158
|
+
return { ...functionResult, value: 0 };
|
|
53682
54159
|
}
|
|
53683
|
-
return
|
|
54160
|
+
return functionResult;
|
|
53684
54161
|
}
|
|
53685
54162
|
function updateEvalContextAndExecute(compiledFormula, compilationParams, sheetId, cellId) {
|
|
53686
54163
|
compilationParams.evalContext.__originCellXC = lazy(() => {
|
|
@@ -63140,7 +63617,7 @@ class TopBar extends owl.Component {
|
|
|
63140
63617
|
}
|
|
63141
63618
|
get topbarComponents() {
|
|
63142
63619
|
return topbarComponentRegistry
|
|
63143
|
-
.
|
|
63620
|
+
.getAllOrdered()
|
|
63144
63621
|
.filter((item) => !item.isVisible || item.isVisible(this.env));
|
|
63145
63622
|
}
|
|
63146
63623
|
onExternalClick(ev) {
|
|
@@ -67771,6 +68248,6 @@ exports.tokenColors = tokenColors;
|
|
|
67771
68248
|
exports.tokenize = tokenize;
|
|
67772
68249
|
|
|
67773
68250
|
|
|
67774
|
-
__info__.version = "17.4.0-alpha.
|
|
67775
|
-
__info__.date = "2024-07-
|
|
67776
|
-
__info__.hash = "
|
|
68251
|
+
__info__.version = "17.4.0-alpha.13";
|
|
68252
|
+
__info__.date = "2024-07-11T06:36:58.556Z";
|
|
68253
|
+
__info__.hash = "e0f506b";
|