@odoo/o-spreadsheet 18.0.28 → 18.0.30
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 +354 -243
- package/dist/o-spreadsheet.d.ts +33 -32
- package/dist/o-spreadsheet.esm.js +354 -243
- package/dist/o-spreadsheet.iife.js +354 -243
- package/dist/o-spreadsheet.iife.min.js +364 -364
- package/dist/o_spreadsheet.xml +6 -5
- 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.0.
|
|
6
|
-
* @date 2025-05-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.0.30
|
|
6
|
+
* @date 2025-05-26T12:35:05.184Z
|
|
7
|
+
* @hash 838c4f7
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -1453,18 +1453,53 @@
|
|
|
1453
1453
|
let result = 0;
|
|
1454
1454
|
const l = letters.length;
|
|
1455
1455
|
for (let i = 0; i < l; i++) {
|
|
1456
|
-
const
|
|
1457
|
-
const colIndex = charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
|
|
1456
|
+
const colIndex = charToNumber(letters[i]);
|
|
1458
1457
|
result = result * 26 + colIndex;
|
|
1459
1458
|
}
|
|
1460
1459
|
return result - 1;
|
|
1461
1460
|
}
|
|
1461
|
+
function charToNumber(char) {
|
|
1462
|
+
const charCode = char.charCodeAt(0);
|
|
1463
|
+
return charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
|
|
1464
|
+
}
|
|
1462
1465
|
function isCharALetter(char) {
|
|
1463
1466
|
return (char >= "A" && char <= "Z") || (char >= "a" && char <= "z");
|
|
1464
1467
|
}
|
|
1465
1468
|
function isCharADigit(char) {
|
|
1466
1469
|
return char >= "0" && char <= "9";
|
|
1467
1470
|
}
|
|
1471
|
+
// we limit the max column to 3 letters and max row to 7 digits for performance reasons
|
|
1472
|
+
const MAX_COL = lettersToNumber("ZZZ");
|
|
1473
|
+
const MAX_ROW = 9999998;
|
|
1474
|
+
function consumeSpaces(chars) {
|
|
1475
|
+
while (chars.current === " ") {
|
|
1476
|
+
chars.advanceBy(1);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
function consumeLetters(chars) {
|
|
1480
|
+
if (chars.current === "$")
|
|
1481
|
+
chars.advanceBy(1);
|
|
1482
|
+
if (!chars.current || !isCharALetter(chars.current)) {
|
|
1483
|
+
return -1;
|
|
1484
|
+
}
|
|
1485
|
+
let colCoordinate = 0;
|
|
1486
|
+
while (chars.current && isCharALetter(chars.current)) {
|
|
1487
|
+
colCoordinate = colCoordinate * 26 + charToNumber(chars.shift());
|
|
1488
|
+
}
|
|
1489
|
+
return colCoordinate;
|
|
1490
|
+
}
|
|
1491
|
+
function consumeDigits(chars) {
|
|
1492
|
+
if (chars.current === "$")
|
|
1493
|
+
chars.advanceBy(1);
|
|
1494
|
+
if (!chars.current || !isCharADigit(chars.current)) {
|
|
1495
|
+
return -1;
|
|
1496
|
+
}
|
|
1497
|
+
let num = 0;
|
|
1498
|
+
while (chars.current && isCharADigit(chars.current)) {
|
|
1499
|
+
num = num * 10 + Number(chars.shift());
|
|
1500
|
+
}
|
|
1501
|
+
return num;
|
|
1502
|
+
}
|
|
1468
1503
|
/**
|
|
1469
1504
|
* Convert a "XC" coordinate to cartesian coordinates.
|
|
1470
1505
|
*
|
|
@@ -1475,33 +1510,17 @@
|
|
|
1475
1510
|
* Note: it also accepts lowercase coordinates, but not fixed references
|
|
1476
1511
|
*/
|
|
1477
1512
|
function toCartesian(xc) {
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
// Process letter part
|
|
1483
|
-
if (xc[i] === "$")
|
|
1484
|
-
i++;
|
|
1485
|
-
while (i < xc.length && isCharALetter(xc[i])) {
|
|
1486
|
-
letterPart += xc[i++];
|
|
1487
|
-
}
|
|
1488
|
-
if (letterPart.length === 0 || letterPart.length > 3) {
|
|
1489
|
-
// limit to max 3 letters for performance reasons
|
|
1513
|
+
const chars = new TokenizingChars(xc);
|
|
1514
|
+
consumeSpaces(chars);
|
|
1515
|
+
const letterPart = consumeLetters(chars);
|
|
1516
|
+
if (letterPart === -1 || !chars.current) {
|
|
1490
1517
|
throw new Error(`Invalid cell description: ${xc}`);
|
|
1491
1518
|
}
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
}
|
|
1498
|
-
if (i !== xc.length || numberPart.length === 0 || numberPart.length > 7) {
|
|
1499
|
-
// limit to max 7 numbers for performance reasons
|
|
1500
|
-
throw new Error(`Invalid cell description: ${xc}`);
|
|
1501
|
-
}
|
|
1502
|
-
const col = lettersToNumber(letterPart);
|
|
1503
|
-
const row = Number(numberPart) - 1;
|
|
1504
|
-
if (isNaN(row)) {
|
|
1519
|
+
const num = consumeDigits(chars);
|
|
1520
|
+
consumeSpaces(chars);
|
|
1521
|
+
const col = letterPart - 1;
|
|
1522
|
+
const row = num - 1;
|
|
1523
|
+
if (!chars.isOver() || col > MAX_COL || row > MAX_ROW) {
|
|
1505
1524
|
throw new Error(`Invalid cell description: ${xc}`);
|
|
1506
1525
|
}
|
|
1507
1526
|
return { col, row };
|
|
@@ -1913,67 +1932,6 @@
|
|
|
1913
1932
|
}
|
|
1914
1933
|
}
|
|
1915
1934
|
|
|
1916
|
-
/** Reference of a cell (eg. A1, $B$5) */
|
|
1917
|
-
const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
|
|
1918
|
-
// Same as above, but matches the exact string (nothing before or after)
|
|
1919
|
-
const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
|
|
1920
|
-
/** Reference of a column header (eg. A, AB, $A) */
|
|
1921
|
-
const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
|
|
1922
|
-
/** Reference of a row header (eg. 1, $1) */
|
|
1923
|
-
const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
|
|
1924
|
-
/** Reference of a column (eg. A, $CA, Sheet1!B) */
|
|
1925
|
-
const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
|
|
1926
|
-
/** Reference of a row (eg. 1, 59, Sheet1!9) */
|
|
1927
|
-
const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
|
|
1928
|
-
/** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
|
|
1929
|
-
const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
|
|
1930
|
-
/** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
|
|
1931
|
-
const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
|
|
1932
|
-
/** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
|
|
1933
|
-
const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
|
|
1934
|
-
"(" +
|
|
1935
|
-
[cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
|
|
1936
|
-
")" +
|
|
1937
|
-
/$/.source, "i");
|
|
1938
|
-
/**
|
|
1939
|
-
* Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
|
|
1940
|
-
*/
|
|
1941
|
-
function isColReference(xc) {
|
|
1942
|
-
return colReference.test(xc);
|
|
1943
|
-
}
|
|
1944
|
-
/**
|
|
1945
|
-
* Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
|
|
1946
|
-
*/
|
|
1947
|
-
function isRowReference(xc) {
|
|
1948
|
-
return rowReference.test(xc);
|
|
1949
|
-
}
|
|
1950
|
-
function isColHeader(str) {
|
|
1951
|
-
return colHeader.test(str);
|
|
1952
|
-
}
|
|
1953
|
-
function isRowHeader(str) {
|
|
1954
|
-
return rowHeader.test(str);
|
|
1955
|
-
}
|
|
1956
|
-
/**
|
|
1957
|
-
* Return true if the given xc is the reference of a single cell,
|
|
1958
|
-
* without any specified sheet (e.g. A1)
|
|
1959
|
-
*/
|
|
1960
|
-
function isSingleCellReference(xc) {
|
|
1961
|
-
return singleCellReference.test(xc);
|
|
1962
|
-
}
|
|
1963
|
-
function splitReference(ref) {
|
|
1964
|
-
if (!ref.includes("!")) {
|
|
1965
|
-
return { xc: ref };
|
|
1966
|
-
}
|
|
1967
|
-
const parts = ref.split("!");
|
|
1968
|
-
const xc = parts.pop();
|
|
1969
|
-
const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
|
|
1970
|
-
return { sheetName, xc };
|
|
1971
|
-
}
|
|
1972
|
-
/** Return a reference SheetName!xc from the given arguments */
|
|
1973
|
-
function getFullReference(sheetName, xc) {
|
|
1974
|
-
return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
|
|
1975
|
-
}
|
|
1976
|
-
|
|
1977
1935
|
/**
|
|
1978
1936
|
* Convert from a cartesian reference to a Zone
|
|
1979
1937
|
* The range boundaries will be kept in the same order as the
|
|
@@ -1991,63 +1949,55 @@
|
|
|
1991
1949
|
*
|
|
1992
1950
|
*/
|
|
1993
1951
|
function toZoneWithoutBoundaryChanges(xc) {
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
if (
|
|
1998
|
-
|
|
1999
|
-
}
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
if (xc.includes(":")) {
|
|
2003
|
-
[firstRangePart, secondRangePart] = xc.split(":");
|
|
2004
|
-
firstRangePart = firstRangePart.trim();
|
|
2005
|
-
secondRangePart = secondRangePart.trim();
|
|
2006
|
-
}
|
|
2007
|
-
else {
|
|
2008
|
-
firstRangePart = xc.trim();
|
|
2009
|
-
}
|
|
1952
|
+
const chars = new TokenizingChars(xc);
|
|
1953
|
+
consumeSpaces(chars);
|
|
1954
|
+
const sheetSeparatorIndex = xc.indexOf("!");
|
|
1955
|
+
if (sheetSeparatorIndex !== -1) {
|
|
1956
|
+
chars.advanceBy(sheetSeparatorIndex + 1);
|
|
1957
|
+
}
|
|
1958
|
+
const leftLetters = consumeLetters(chars);
|
|
1959
|
+
const leftNumbers = consumeDigits(chars);
|
|
2010
1960
|
let top, bottom, left, right;
|
|
2011
1961
|
let fullCol = false;
|
|
2012
1962
|
let fullRow = false;
|
|
2013
1963
|
let hasHeader = false;
|
|
2014
|
-
if (
|
|
2015
|
-
left = right =
|
|
1964
|
+
if (leftNumbers === -1) {
|
|
1965
|
+
left = right = leftLetters - 1;
|
|
2016
1966
|
top = bottom = 0;
|
|
2017
1967
|
fullCol = true;
|
|
2018
1968
|
}
|
|
2019
|
-
else if (
|
|
2020
|
-
top = bottom =
|
|
1969
|
+
else if (leftLetters === -1) {
|
|
1970
|
+
top = bottom = leftNumbers - 1;
|
|
2021
1971
|
left = right = 0;
|
|
2022
1972
|
fullRow = true;
|
|
2023
1973
|
}
|
|
2024
1974
|
else {
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
top = bottom = c.row;
|
|
1975
|
+
left = right = leftLetters - 1;
|
|
1976
|
+
top = bottom = leftNumbers - 1;
|
|
2028
1977
|
hasHeader = true;
|
|
2029
1978
|
}
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
1979
|
+
consumeSpaces(chars);
|
|
1980
|
+
if (chars.current === ":") {
|
|
1981
|
+
chars.advanceBy(1);
|
|
1982
|
+
consumeSpaces(chars);
|
|
1983
|
+
const rightLetters = consumeLetters(chars);
|
|
1984
|
+
const rightNumbers = consumeDigits(chars);
|
|
1985
|
+
if (rightNumbers === -1) {
|
|
1986
|
+
right = rightLetters - 1;
|
|
2033
1987
|
fullCol = true;
|
|
2034
1988
|
}
|
|
2035
|
-
else if (
|
|
2036
|
-
bottom =
|
|
1989
|
+
else if (rightLetters === -1) {
|
|
1990
|
+
bottom = rightNumbers - 1;
|
|
2037
1991
|
fullRow = true;
|
|
2038
1992
|
}
|
|
2039
1993
|
else {
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
bottom = c.row;
|
|
1994
|
+
right = rightLetters - 1;
|
|
1995
|
+
bottom = rightNumbers - 1;
|
|
2043
1996
|
top = fullCol ? bottom : top;
|
|
2044
1997
|
left = fullRow ? right : left;
|
|
2045
1998
|
hasHeader = true;
|
|
2046
1999
|
}
|
|
2047
2000
|
}
|
|
2048
|
-
if (fullCol && fullRow) {
|
|
2049
|
-
throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
|
|
2050
|
-
}
|
|
2051
2001
|
const zone = {
|
|
2052
2002
|
top,
|
|
2053
2003
|
left,
|
|
@@ -2076,7 +2026,16 @@
|
|
|
2076
2026
|
*/
|
|
2077
2027
|
function toUnboundedZone(xc) {
|
|
2078
2028
|
const zone = toZoneWithoutBoundaryChanges(xc);
|
|
2079
|
-
|
|
2029
|
+
const orderedZone = reorderZone(zone);
|
|
2030
|
+
const bottom = orderedZone.bottom;
|
|
2031
|
+
const right = orderedZone.right;
|
|
2032
|
+
if ((bottom !== undefined && bottom > MAX_ROW) || (right !== undefined && right > MAX_COL)) {
|
|
2033
|
+
throw new Error(`Range string out of bounds: ${xc}`); // limit the size of the zone for performance
|
|
2034
|
+
}
|
|
2035
|
+
if (bottom === undefined && right === undefined) {
|
|
2036
|
+
throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
|
|
2037
|
+
}
|
|
2038
|
+
return orderedZone;
|
|
2080
2039
|
}
|
|
2081
2040
|
/**
|
|
2082
2041
|
* Convert from a cartesian reference to a Zone.
|
|
@@ -4013,6 +3972,113 @@
|
|
|
4013
3972
|
}
|
|
4014
3973
|
return generateMatrix(matrix[0].length, matrix.length, (i, j) => matrix[j][i]);
|
|
4015
3974
|
}
|
|
3975
|
+
/**
|
|
3976
|
+
* Enables a formula function to accept matrix or vector inputs instead of simple value, computing results across multiple dimensions.
|
|
3977
|
+
*
|
|
3978
|
+
* ```
|
|
3979
|
+
* / |‾ ‾| \ |‾ ‾|
|
|
3980
|
+
* | | [A] | | | compute(A, D, E), compute(A, D, F), compute(A, D, G) |
|
|
3981
|
+
* applyVectorization| compute, | [B], D, [E, F, G] | | <=> | compute(B, D, E), compute(B, D, F), compute(B, D, G) |
|
|
3982
|
+
* | | [C] | | | compute(C, D, E), compute(C, D, F), compute(C, D, G) |
|
|
3983
|
+
* \ |_ _| / |_ _|
|
|
3984
|
+
* ```
|
|
3985
|
+
*
|
|
3986
|
+
* By default, all arguments are vectorized. To control which arguments are vectorized,
|
|
3987
|
+
* pass an `acceptToVectorize` boolean array of the same length as `args`:
|
|
3988
|
+
* - `true` enables vectorization for that argument
|
|
3989
|
+
* - `false` disables vectorization for that argument
|
|
3990
|
+
*
|
|
3991
|
+
* For example, with `[true, true, false]` on previous example you get:
|
|
3992
|
+
*
|
|
3993
|
+
* ```
|
|
3994
|
+
* |‾ ‾|
|
|
3995
|
+
* | compute(A, D, [E, F, G]) |
|
|
3996
|
+
* | compute(B, D, [E, F, G]) |
|
|
3997
|
+
* | compute(C, D, [E, F, G]) |
|
|
3998
|
+
* |_ _|
|
|
3999
|
+
* ```
|
|
4000
|
+
*
|
|
4001
|
+
* @remarks
|
|
4002
|
+
* This helper is automatically applied (by default) to **all** `compute` functions
|
|
4003
|
+
* across the various spreadsheet formula modules:
|
|
4004
|
+
* - If an argument is declared **scalar** (not `"range"`), it is vectorized.
|
|
4005
|
+
* - If **all** arguments are declared **ranges**, no vectorization occurs.
|
|
4006
|
+
* - e.g. `SUM(A1:B2)` returns a 1×1 sum over the range.
|
|
4007
|
+
* - e.g. `COS(A1:B2)` over `A1:B2` returns a 2×2 element-wise result.
|
|
4008
|
+
* - For special behaviors (e.g. the `IF` function), you may declare all arguments
|
|
4009
|
+
* as ranges and invoke this helper directly within your `compute` implementation.
|
|
4010
|
+
*/
|
|
4011
|
+
function applyVectorization(formula, args, acceptToVectorize = undefined) {
|
|
4012
|
+
let countVectorizedCol = 1;
|
|
4013
|
+
let countVectorizedRow = 1;
|
|
4014
|
+
let vectorizedColLimit = Infinity;
|
|
4015
|
+
let vectorizedRowLimit = Infinity;
|
|
4016
|
+
let vectorArgsType = undefined;
|
|
4017
|
+
for (let i = 0; i < args.length; i++) {
|
|
4018
|
+
const arg = args[i];
|
|
4019
|
+
if (isMatrix(arg) && (acceptToVectorize === undefined || acceptToVectorize[i])) {
|
|
4020
|
+
const nColumns = arg.length;
|
|
4021
|
+
const nRows = arg[0].length;
|
|
4022
|
+
if (nColumns !== 1 || nRows !== 1) {
|
|
4023
|
+
vectorArgsType ??= new Array(args.length);
|
|
4024
|
+
if (nColumns !== 1 && nRows !== 1) {
|
|
4025
|
+
vectorArgsType[i] = "matrix";
|
|
4026
|
+
countVectorizedCol = Math.max(countVectorizedCol, nColumns);
|
|
4027
|
+
countVectorizedRow = Math.max(countVectorizedRow, nRows);
|
|
4028
|
+
vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
|
|
4029
|
+
vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
|
|
4030
|
+
}
|
|
4031
|
+
else if (nColumns !== 1) {
|
|
4032
|
+
vectorArgsType[i] = "horizontal";
|
|
4033
|
+
countVectorizedCol = Math.max(countVectorizedCol, nColumns);
|
|
4034
|
+
vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
|
|
4035
|
+
}
|
|
4036
|
+
else if (nRows !== 1) {
|
|
4037
|
+
vectorArgsType[i] = "vertical";
|
|
4038
|
+
countVectorizedRow = Math.max(countVectorizedRow, nRows);
|
|
4039
|
+
vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
else {
|
|
4043
|
+
args[i] = arg[0][0];
|
|
4044
|
+
}
|
|
4045
|
+
}
|
|
4046
|
+
}
|
|
4047
|
+
if (countVectorizedCol === 1 && countVectorizedRow === 1) {
|
|
4048
|
+
// either this function is not vectorized or it ends up with a 1x1 dimension
|
|
4049
|
+
return formula(...args);
|
|
4050
|
+
}
|
|
4051
|
+
const getArgOffset = (i, j) => args.map((arg, index) => {
|
|
4052
|
+
switch (vectorArgsType?.[index]) {
|
|
4053
|
+
case "matrix":
|
|
4054
|
+
return arg[i][j];
|
|
4055
|
+
case "horizontal":
|
|
4056
|
+
return arg[i][0];
|
|
4057
|
+
case "vertical":
|
|
4058
|
+
return arg[0][j];
|
|
4059
|
+
case undefined:
|
|
4060
|
+
return arg;
|
|
4061
|
+
}
|
|
4062
|
+
});
|
|
4063
|
+
return generateMatrix(countVectorizedCol, countVectorizedRow, (col, row) => {
|
|
4064
|
+
if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) {
|
|
4065
|
+
return new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
|
|
4066
|
+
}
|
|
4067
|
+
const singleCellComputeResult = formula(...getArgOffset(col, row));
|
|
4068
|
+
// In the case where the user tries to vectorize arguments of an array formula, we will get an
|
|
4069
|
+
// array for every combination of the vectorized arguments, which will lead to a 3D matrix and
|
|
4070
|
+
// we won't be able to return the values.
|
|
4071
|
+
// In this case, we keep the first element of each spreading part, just as Excel does, and
|
|
4072
|
+
// create an array with these parts.
|
|
4073
|
+
// For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
|
|
4074
|
+
// range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
|
|
4075
|
+
// for the value in A2). In this case, we will simply take the first value of each matrix and
|
|
4076
|
+
// return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
|
|
4077
|
+
return isMatrix(singleCellComputeResult)
|
|
4078
|
+
? singleCellComputeResult[0][0]
|
|
4079
|
+
: singleCellComputeResult;
|
|
4080
|
+
});
|
|
4081
|
+
}
|
|
4016
4082
|
// -----------------------------------------------------------------------------
|
|
4017
4083
|
// CONDITIONAL EXPLORE FUNCTIONS
|
|
4018
4084
|
// -----------------------------------------------------------------------------
|
|
@@ -5797,6 +5863,67 @@
|
|
|
5797
5863
|
return MIN_DELAY + (MAX_DELAY - MIN_DELAY) * Math.exp(-ACCELERATION * (value - 1));
|
|
5798
5864
|
}
|
|
5799
5865
|
|
|
5866
|
+
/** Reference of a cell (eg. A1, $B$5) */
|
|
5867
|
+
const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
|
|
5868
|
+
// Same as above, but matches the exact string (nothing before or after)
|
|
5869
|
+
const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
|
|
5870
|
+
/** Reference of a column header (eg. A, AB, $A) */
|
|
5871
|
+
const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
|
|
5872
|
+
/** Reference of a row header (eg. 1, $1) */
|
|
5873
|
+
const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
|
|
5874
|
+
/** Reference of a column (eg. A, $CA, Sheet1!B) */
|
|
5875
|
+
const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
|
|
5876
|
+
/** Reference of a row (eg. 1, 59, Sheet1!9) */
|
|
5877
|
+
const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
|
|
5878
|
+
/** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
|
|
5879
|
+
const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
|
|
5880
|
+
/** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
|
|
5881
|
+
const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
|
|
5882
|
+
/** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
|
|
5883
|
+
const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
|
|
5884
|
+
"(" +
|
|
5885
|
+
[cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
|
|
5886
|
+
")" +
|
|
5887
|
+
/$/.source, "i");
|
|
5888
|
+
/**
|
|
5889
|
+
* Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
|
|
5890
|
+
*/
|
|
5891
|
+
function isColReference(xc) {
|
|
5892
|
+
return colReference.test(xc);
|
|
5893
|
+
}
|
|
5894
|
+
/**
|
|
5895
|
+
* Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
|
|
5896
|
+
*/
|
|
5897
|
+
function isRowReference(xc) {
|
|
5898
|
+
return rowReference.test(xc);
|
|
5899
|
+
}
|
|
5900
|
+
function isColHeader(str) {
|
|
5901
|
+
return colHeader.test(str);
|
|
5902
|
+
}
|
|
5903
|
+
function isRowHeader(str) {
|
|
5904
|
+
return rowHeader.test(str);
|
|
5905
|
+
}
|
|
5906
|
+
/**
|
|
5907
|
+
* Return true if the given xc is the reference of a single cell,
|
|
5908
|
+
* without any specified sheet (e.g. A1)
|
|
5909
|
+
*/
|
|
5910
|
+
function isSingleCellReference(xc) {
|
|
5911
|
+
return singleCellReference.test(xc);
|
|
5912
|
+
}
|
|
5913
|
+
function splitReference(ref) {
|
|
5914
|
+
if (!ref.includes("!")) {
|
|
5915
|
+
return { xc: ref };
|
|
5916
|
+
}
|
|
5917
|
+
const parts = ref.split("!");
|
|
5918
|
+
const xc = parts.pop();
|
|
5919
|
+
const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
|
|
5920
|
+
return { sheetName, xc };
|
|
5921
|
+
}
|
|
5922
|
+
/** Return a reference SheetName!xc from the given arguments */
|
|
5923
|
+
function getFullReference(sheetName, xc) {
|
|
5924
|
+
return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
|
|
5925
|
+
}
|
|
5926
|
+
|
|
5800
5927
|
class RangeImpl {
|
|
5801
5928
|
getSheetSize;
|
|
5802
5929
|
_zone;
|
|
@@ -7258,14 +7385,20 @@
|
|
|
7258
7385
|
/**
|
|
7259
7386
|
* Return the input if it's a scalar or the first element of the input if it's a matrix.
|
|
7260
7387
|
*/
|
|
7261
|
-
function toScalar(
|
|
7262
|
-
if (!isMatrix(
|
|
7263
|
-
return
|
|
7388
|
+
function toScalar(arg) {
|
|
7389
|
+
if (!isMatrix(arg)) {
|
|
7390
|
+
return arg;
|
|
7264
7391
|
}
|
|
7265
|
-
if (
|
|
7392
|
+
if (!isSingleElementMatrix(arg)) {
|
|
7266
7393
|
throw new EvaluationError(_t("The value should be a scalar or a 1x1 matrix"));
|
|
7267
7394
|
}
|
|
7268
|
-
return
|
|
7395
|
+
return arg[0][0];
|
|
7396
|
+
}
|
|
7397
|
+
function isSingleElementMatrix(matrix) {
|
|
7398
|
+
return matrix.length === 1 && matrix[0].length === 1;
|
|
7399
|
+
}
|
|
7400
|
+
function isMultipleElementMatrix(arg) {
|
|
7401
|
+
return isMatrix(arg) && !isSingleElementMatrix(arg);
|
|
7269
7402
|
}
|
|
7270
7403
|
|
|
7271
7404
|
function assertSameNumberOfElements(...args) {
|
|
@@ -21466,7 +21599,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21466
21599
|
}
|
|
21467
21600
|
return mode === "row" ? transposeMatrix(result) : result;
|
|
21468
21601
|
},
|
|
21469
|
-
isExported:
|
|
21602
|
+
isExported: false,
|
|
21470
21603
|
};
|
|
21471
21604
|
// -----------------------------------------------------------------------------
|
|
21472
21605
|
// SORT
|
|
@@ -24434,16 +24567,23 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24434
24567
|
const IF = {
|
|
24435
24568
|
description: _t("Returns value depending on logical expression."),
|
|
24436
24569
|
args: [
|
|
24437
|
-
arg("logical_expression (boolean)", _t("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE.")),
|
|
24438
|
-
arg("value_if_true (any)", _t("The value the function returns if logical_expression is TRUE.")),
|
|
24439
|
-
arg("value_if_false (any, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
|
|
24570
|
+
arg("logical_expression (boolean, range<boolean>)", _t("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE.")),
|
|
24571
|
+
arg("value_if_true (any, range)", _t("The value the function returns if logical_expression is TRUE.")),
|
|
24572
|
+
arg("value_if_false (any, range, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
|
|
24440
24573
|
],
|
|
24441
24574
|
compute: function (logicalExpression, valueIfTrue, valueIfFalse) {
|
|
24442
|
-
|
|
24575
|
+
if (isMultipleElementMatrix(logicalExpression)) {
|
|
24576
|
+
return applyVectorization(IF.compute, [logicalExpression, valueIfTrue, valueIfFalse]);
|
|
24577
|
+
}
|
|
24578
|
+
let result = toBoolean(toScalar(logicalExpression)) ? valueIfTrue : valueIfFalse;
|
|
24579
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
24580
|
+
if (!isMultipleElementMatrix(result)) {
|
|
24581
|
+
result = toScalar(result);
|
|
24582
|
+
}
|
|
24443
24583
|
if (result === undefined) {
|
|
24444
24584
|
return { value: "" };
|
|
24445
24585
|
}
|
|
24446
|
-
if (result.value === null) {
|
|
24586
|
+
if (!isMatrix(result) && result.value === null) {
|
|
24447
24587
|
return { ...result, value: "" };
|
|
24448
24588
|
}
|
|
24449
24589
|
return result;
|
|
@@ -24456,15 +24596,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24456
24596
|
const IFERROR = {
|
|
24457
24597
|
description: _t("Value if it is not an error, otherwise 2nd argument."),
|
|
24458
24598
|
args: [
|
|
24459
|
-
arg("value (any)", _t("The value to return if value itself is not an error.")),
|
|
24460
|
-
arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an error.")),
|
|
24599
|
+
arg("value (any, range)", _t("The value to return if value itself is not an error.")),
|
|
24600
|
+
arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an error.")),
|
|
24461
24601
|
],
|
|
24462
|
-
compute: function (value, valueIfError
|
|
24463
|
-
|
|
24602
|
+
compute: function (value, valueIfError) {
|
|
24603
|
+
if (isMultipleElementMatrix(value)) {
|
|
24604
|
+
return applyVectorization(IFERROR.compute, [value, valueIfError]);
|
|
24605
|
+
}
|
|
24606
|
+
let result = isEvaluationError(toScalar(value)?.value) ? valueIfError : value;
|
|
24607
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
24608
|
+
if (!isMultipleElementMatrix(result)) {
|
|
24609
|
+
result = toScalar(result);
|
|
24610
|
+
}
|
|
24464
24611
|
if (result === undefined) {
|
|
24465
24612
|
return { value: "" };
|
|
24466
24613
|
}
|
|
24467
|
-
if (result.value === null) {
|
|
24614
|
+
if (!isMatrix(result) && result.value === null) {
|
|
24468
24615
|
return { ...result, value: "" };
|
|
24469
24616
|
}
|
|
24470
24617
|
return result;
|
|
@@ -24477,15 +24624,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24477
24624
|
const IFNA = {
|
|
24478
24625
|
description: _t("Value if it is not an #N/A error, otherwise 2nd argument."),
|
|
24479
24626
|
args: [
|
|
24480
|
-
arg("value (any)", _t("The value to return if value itself is not #N/A an error.")),
|
|
24481
|
-
arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
|
|
24627
|
+
arg("value (any, range)", _t("The value to return if value itself is not #N/A an error.")),
|
|
24628
|
+
arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
|
|
24482
24629
|
],
|
|
24483
|
-
compute: function (value, valueIfError
|
|
24484
|
-
|
|
24630
|
+
compute: function (value, valueIfError) {
|
|
24631
|
+
if (isMultipleElementMatrix(value)) {
|
|
24632
|
+
return applyVectorization(IFNA.compute, [value, valueIfError]);
|
|
24633
|
+
}
|
|
24634
|
+
let result = toScalar(value)?.value === CellErrorType.NotAvailable ? valueIfError : value;
|
|
24635
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
24636
|
+
if (!isMultipleElementMatrix(result)) {
|
|
24637
|
+
result = toScalar(result);
|
|
24638
|
+
}
|
|
24485
24639
|
if (result === undefined) {
|
|
24486
24640
|
return { value: "" };
|
|
24487
24641
|
}
|
|
24488
|
-
if (result.value === null) {
|
|
24642
|
+
if (!isMatrix(result) && result.value === null) {
|
|
24489
24643
|
return { ...result, value: "" };
|
|
24490
24644
|
}
|
|
24491
24645
|
return result;
|
|
@@ -24498,23 +24652,31 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24498
24652
|
const IFS = {
|
|
24499
24653
|
description: _t("Returns a value depending on multiple logical expressions."),
|
|
24500
24654
|
args: [
|
|
24501
|
-
arg("condition1 (boolean)", _t("The first condition to be evaluated. This can be a boolean, a number, an array, or a reference to any of those.")),
|
|
24502
|
-
arg("value1 (any)", _t("The returned value if condition1 is TRUE.")),
|
|
24503
|
-
arg("condition2 (boolean, any, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
|
|
24504
|
-
arg("value2 (any, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
|
|
24655
|
+
arg("condition1 (boolean, range<boolean>)", _t("The first condition to be evaluated. This can be a boolean, a number, an array, or a reference to any of those.")),
|
|
24656
|
+
arg("value1 (any, range)", _t("The returned value if condition1 is TRUE.")),
|
|
24657
|
+
arg("condition2 (boolean, any, range, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
|
|
24658
|
+
arg("value2 (any, range, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
|
|
24505
24659
|
],
|
|
24506
24660
|
compute: function (...values) {
|
|
24507
24661
|
assert(() => values.length % 2 === 0, _t("Wrong number of arguments. Expected an even number of arguments."));
|
|
24508
|
-
|
|
24509
|
-
if (
|
|
24510
|
-
|
|
24511
|
-
|
|
24662
|
+
while (values.length > 0) {
|
|
24663
|
+
if (isMultipleElementMatrix(values[0])) {
|
|
24664
|
+
return applyVectorization(IFS.compute, values);
|
|
24665
|
+
}
|
|
24666
|
+
const condition = toBoolean(toScalar(values.shift()));
|
|
24667
|
+
let valueIfTrue = values.shift();
|
|
24668
|
+
if (condition) {
|
|
24669
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
24670
|
+
if (!isMultipleElementMatrix(valueIfTrue)) {
|
|
24671
|
+
valueIfTrue = toScalar(valueIfTrue);
|
|
24672
|
+
}
|
|
24673
|
+
if (valueIfTrue === undefined) {
|
|
24512
24674
|
return { value: "" };
|
|
24513
24675
|
}
|
|
24514
|
-
if (
|
|
24515
|
-
return { ...
|
|
24676
|
+
if (!isMatrix(valueIfTrue) && valueIfTrue.value === null) {
|
|
24677
|
+
return { ...valueIfTrue, value: "" };
|
|
24516
24678
|
}
|
|
24517
|
-
return
|
|
24679
|
+
return valueIfTrue;
|
|
24518
24680
|
}
|
|
24519
24681
|
}
|
|
24520
24682
|
return new EvaluationError(_t("No match."));
|
|
@@ -26158,7 +26320,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
26158
26320
|
}
|
|
26159
26321
|
return transposeMatrix([result]);
|
|
26160
26322
|
},
|
|
26161
|
-
isExported:
|
|
26323
|
+
isExported: false,
|
|
26162
26324
|
};
|
|
26163
26325
|
// -----------------------------------------------------------------------------
|
|
26164
26326
|
// SUBSTITUTE
|
|
@@ -26351,86 +26513,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
26351
26513
|
functionRegistry.add(name, { isExported: false, ...addDescr });
|
|
26352
26514
|
}
|
|
26353
26515
|
}
|
|
26354
|
-
|
|
26516
|
+
//------------------------------------------------------------------------------
|
|
26517
|
+
// CREATE COMPUTE FUNCTION
|
|
26518
|
+
//------------------------------------------------------------------------------
|
|
26355
26519
|
function createComputeFunction(descr, functionName) {
|
|
26356
26520
|
function vectorizedCompute(...args) {
|
|
26357
|
-
|
|
26358
|
-
let countVectorizableRow = 1;
|
|
26359
|
-
let vectorizableColLimit = Infinity;
|
|
26360
|
-
let vectorizableRowLimit = Infinity;
|
|
26361
|
-
let vectorArgsType = undefined;
|
|
26362
|
-
//#region Compute vectorisation limits
|
|
26521
|
+
const acceptToVectorize = [];
|
|
26363
26522
|
for (let i = 0; i < args.length; i++) {
|
|
26364
26523
|
const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
|
|
26365
26524
|
const arg = args[i];
|
|
26366
|
-
if (isMatrix(arg) && !argDefinition.acceptMatrix) {
|
|
26367
|
-
// if argDefinition does not accept a matrix but arg is still a matrix
|
|
26368
|
-
// --> triggers the arguments vectorization
|
|
26369
|
-
const nColumns = arg.length;
|
|
26370
|
-
const nRows = arg[0].length;
|
|
26371
|
-
if (nColumns !== 1 || nRows !== 1) {
|
|
26372
|
-
vectorArgsType ??= new Array(args.length);
|
|
26373
|
-
if (nColumns !== 1 && nRows !== 1) {
|
|
26374
|
-
vectorArgsType[i] = "matrix";
|
|
26375
|
-
countVectorizableCol = Math.max(countVectorizableCol, nColumns);
|
|
26376
|
-
countVectorizableRow = Math.max(countVectorizableRow, nRows);
|
|
26377
|
-
vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
|
|
26378
|
-
vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
|
|
26379
|
-
}
|
|
26380
|
-
else if (nColumns !== 1) {
|
|
26381
|
-
vectorArgsType[i] = "horizontal";
|
|
26382
|
-
countVectorizableCol = Math.max(countVectorizableCol, nColumns);
|
|
26383
|
-
vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
|
|
26384
|
-
}
|
|
26385
|
-
else if (nRows !== 1) {
|
|
26386
|
-
vectorArgsType[i] = "vertical";
|
|
26387
|
-
countVectorizableRow = Math.max(countVectorizableRow, nRows);
|
|
26388
|
-
vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
|
|
26389
|
-
}
|
|
26390
|
-
}
|
|
26391
|
-
else {
|
|
26392
|
-
args[i] = arg[0][0];
|
|
26393
|
-
}
|
|
26394
|
-
}
|
|
26395
26525
|
if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
|
|
26396
26526
|
throw new BadExpressionError(_t("Function %s expects the parameter '%s' to be reference to a cell or range.", functionName, (i + 1).toString()));
|
|
26397
26527
|
}
|
|
26528
|
+
acceptToVectorize.push(!argDefinition.acceptMatrix);
|
|
26398
26529
|
}
|
|
26399
|
-
|
|
26400
|
-
if (countVectorizableCol === 1 && countVectorizableRow === 1) {
|
|
26401
|
-
// either this function is not vectorized or it ends up with a 1x1 dimension
|
|
26402
|
-
return errorHandlingCompute.apply(this, args);
|
|
26403
|
-
}
|
|
26404
|
-
const getArgOffset = (i, j) => args.map((arg, index) => {
|
|
26405
|
-
switch (vectorArgsType?.[index]) {
|
|
26406
|
-
case "matrix":
|
|
26407
|
-
return arg[i][j];
|
|
26408
|
-
case "horizontal":
|
|
26409
|
-
return arg[i][0];
|
|
26410
|
-
case "vertical":
|
|
26411
|
-
return arg[0][j];
|
|
26412
|
-
case undefined:
|
|
26413
|
-
return arg;
|
|
26414
|
-
}
|
|
26415
|
-
});
|
|
26416
|
-
return generateMatrix(countVectorizableCol, countVectorizableRow, (col, row) => {
|
|
26417
|
-
if (col > vectorizableColLimit - 1 || row > vectorizableRowLimit - 1) {
|
|
26418
|
-
return notAvailableError;
|
|
26419
|
-
}
|
|
26420
|
-
const singleCellComputeResult = errorHandlingCompute.apply(this, getArgOffset(col, row));
|
|
26421
|
-
// In the case where the user tries to vectorize arguments of an array formula, we will get an
|
|
26422
|
-
// array for every combination of the vectorized arguments, which will lead to a 3D matrix and
|
|
26423
|
-
// we won't be able to return the values.
|
|
26424
|
-
// In this case, we keep the first element of each spreading part, just as Excel does, and
|
|
26425
|
-
// create an array with these parts.
|
|
26426
|
-
// For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
|
|
26427
|
-
// range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
|
|
26428
|
-
// for the value in A2). In this case, we will simply take the first value of each matrix and
|
|
26429
|
-
// return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
|
|
26430
|
-
return isMatrix(singleCellComputeResult)
|
|
26431
|
-
? singleCellComputeResult[0][0]
|
|
26432
|
-
: singleCellComputeResult;
|
|
26433
|
-
});
|
|
26530
|
+
return applyVectorization(errorHandlingCompute.bind(this), args, acceptToVectorize);
|
|
26434
26531
|
}
|
|
26435
26532
|
function errorHandlingCompute(...args) {
|
|
26436
26533
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -39419,7 +39516,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
39419
39516
|
proposals &&
|
|
39420
39517
|
!["ARG_SEPARATOR", "LEFT_PAREN", "OPERATOR"].includes(tokenAtCursor.type)) {
|
|
39421
39518
|
const filteredProposals = fuzzyLookup(searchTerm, proposals, (p) => p.fuzzySearchKey || p.text);
|
|
39422
|
-
if (!exactMatch || filteredProposals.length
|
|
39519
|
+
if (!exactMatch || filteredProposals.length) {
|
|
39423
39520
|
proposals = filteredProposals;
|
|
39424
39521
|
}
|
|
39425
39522
|
}
|
|
@@ -39494,12 +39591,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
39494
39591
|
return providersDefinitions;
|
|
39495
39592
|
}
|
|
39496
39593
|
getComposerContent() {
|
|
39594
|
+
let content = this._currentContent;
|
|
39497
39595
|
if (this.editionMode === "inactive") {
|
|
39498
39596
|
// References in the content might not be linked to the current active sheet
|
|
39499
39597
|
// We here force the sheet name prefix for all references that are not in
|
|
39500
39598
|
// the current active sheet
|
|
39501
39599
|
const defaultRangeSheetId = this.args().defaultRangeSheetId;
|
|
39502
|
-
|
|
39600
|
+
content = rangeTokenize(this.args().content)
|
|
39503
39601
|
.map((token) => {
|
|
39504
39602
|
if (token.type === "REFERENCE") {
|
|
39505
39603
|
const range = this.getters.getRangeFromSheetXC(defaultRangeSheetId, token.value);
|
|
@@ -39509,7 +39607,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
39509
39607
|
})
|
|
39510
39608
|
.join("");
|
|
39511
39609
|
}
|
|
39512
|
-
return this.
|
|
39610
|
+
return localizeContent(content, this.getters.getLocale());
|
|
39513
39611
|
}
|
|
39514
39612
|
stopEdition() {
|
|
39515
39613
|
this._stopEdition();
|
|
@@ -43112,6 +43210,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43112
43210
|
measure: this.props.measure,
|
|
43113
43211
|
});
|
|
43114
43212
|
}
|
|
43213
|
+
get isCalculatedMeasureInvalid() {
|
|
43214
|
+
return this.env.model.getters.getMeasureCompiledFormula(this.props.measure).isBadExpression;
|
|
43215
|
+
}
|
|
43115
43216
|
}
|
|
43116
43217
|
|
|
43117
43218
|
css /* scss */ `
|
|
@@ -44024,7 +44125,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44024
44125
|
return dimension.order === "asc" ? -1 : 1;
|
|
44025
44126
|
}
|
|
44026
44127
|
if (dimension.type === "integer" || dimension.type === "datetime") {
|
|
44027
|
-
return dimension.order === "asc"
|
|
44128
|
+
return dimension.order === "asc"
|
|
44129
|
+
? toNumber(a, DEFAULT_LOCALE) - toNumber(b, DEFAULT_LOCALE)
|
|
44130
|
+
: toNumber(b, DEFAULT_LOCALE) - toNumber(a, DEFAULT_LOCALE);
|
|
44028
44131
|
}
|
|
44029
44132
|
return dimension.order === "asc" ? a.localeCompare(b) : b.localeCompare(a);
|
|
44030
44133
|
}
|
|
@@ -46765,8 +46868,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46765
46868
|
if (!spreader) {
|
|
46766
46869
|
return undefined;
|
|
46767
46870
|
}
|
|
46768
|
-
|
|
46769
|
-
return cell?.content;
|
|
46871
|
+
return this.getters.getCellText(spreader, { showFormula: true });
|
|
46770
46872
|
}
|
|
46771
46873
|
get currentEditedCell() {
|
|
46772
46874
|
return {
|
|
@@ -49569,6 +49671,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49569
49671
|
const friction = 0.95;
|
|
49570
49672
|
const verticalScrollFactor = 1;
|
|
49571
49673
|
const horizontalScrollFactor = 1;
|
|
49674
|
+
const resetTimeoutDuration = 100;
|
|
49572
49675
|
function useTouchScroll(ref, updateScroll, canMoveUp) {
|
|
49573
49676
|
let lastX = 0;
|
|
49574
49677
|
let lastY = 0;
|
|
@@ -49576,6 +49679,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49576
49679
|
let velocityY = 0;
|
|
49577
49680
|
let isMouseDown = false;
|
|
49578
49681
|
let lastTime = 0;
|
|
49682
|
+
let resetTimeout = null;
|
|
49579
49683
|
useRefListener(ref, "touchstart", onTouchStart, { capture: false });
|
|
49580
49684
|
useRefListener(ref, "touchmove", onTouchMove, { capture: false });
|
|
49581
49685
|
useRefListener(ref, "touchend", onTouchEnd, { capture: false });
|
|
@@ -49588,6 +49692,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49588
49692
|
function onTouchMove(event) {
|
|
49589
49693
|
if (!isMouseDown)
|
|
49590
49694
|
return;
|
|
49695
|
+
if (resetTimeout) {
|
|
49696
|
+
clearTimeout(resetTimeout);
|
|
49697
|
+
resetTimeout = null;
|
|
49698
|
+
}
|
|
49591
49699
|
const currentTime = Date.now();
|
|
49592
49700
|
const { clientX, clientY } = event.touches[0];
|
|
49593
49701
|
let deltaX = lastX - clientX;
|
|
@@ -49604,6 +49712,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
49604
49712
|
}
|
|
49605
49713
|
event.stopPropagation();
|
|
49606
49714
|
}
|
|
49715
|
+
resetTimeout = setTimeout(() => {
|
|
49716
|
+
velocityX = 0;
|
|
49717
|
+
velocityY = 0;
|
|
49718
|
+
}, resetTimeoutDuration);
|
|
49607
49719
|
updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
|
|
49608
49720
|
}
|
|
49609
49721
|
function onTouchEnd(ev) {
|
|
@@ -58446,10 +58558,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
58446
58558
|
return this.evaluatedCells.keysForSheet(sheetId);
|
|
58447
58559
|
}
|
|
58448
58560
|
getArrayFormulaSpreadingOn(position) {
|
|
58449
|
-
const
|
|
58450
|
-
|
|
58451
|
-
|
|
58452
|
-
return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
|
|
58561
|
+
const isEmpty = this.getEvaluatedCell(position).type === CellValueType.empty;
|
|
58562
|
+
if (isEmpty) {
|
|
58563
|
+
return undefined;
|
|
58453
58564
|
}
|
|
58454
58565
|
const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
|
|
58455
58566
|
return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
|
|
@@ -74292,9 +74403,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
74292
74403
|
exports.tokenize = tokenize;
|
|
74293
74404
|
|
|
74294
74405
|
|
|
74295
|
-
__info__.version = "18.0.
|
|
74296
|
-
__info__.date = "2025-05-
|
|
74297
|
-
__info__.hash = "
|
|
74406
|
+
__info__.version = "18.0.30";
|
|
74407
|
+
__info__.date = "2025-05-26T12:35:05.184Z";
|
|
74408
|
+
__info__.hash = "838c4f7";
|
|
74298
74409
|
|
|
74299
74410
|
|
|
74300
74411
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|