@odoo/o-spreadsheet 18.1.20 → 18.1.22
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 +41 -40
- package/dist/o-spreadsheet.esm.js +354 -243
- package/dist/o-spreadsheet.iife.js +354 -243
- package/dist/o-spreadsheet.iife.min.js +380 -380
- 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.1.
|
|
6
|
-
* @date 2025-05-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.1.22
|
|
6
|
+
* @date 2025-05-26T12:35:56.145Z
|
|
7
|
+
* @hash ff4b0ba
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -1607,18 +1607,53 @@
|
|
|
1607
1607
|
let result = 0;
|
|
1608
1608
|
const l = letters.length;
|
|
1609
1609
|
for (let i = 0; i < l; i++) {
|
|
1610
|
-
const
|
|
1611
|
-
const colIndex = charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
|
|
1610
|
+
const colIndex = charToNumber(letters[i]);
|
|
1612
1611
|
result = result * 26 + colIndex;
|
|
1613
1612
|
}
|
|
1614
1613
|
return result - 1;
|
|
1615
1614
|
}
|
|
1615
|
+
function charToNumber(char) {
|
|
1616
|
+
const charCode = char.charCodeAt(0);
|
|
1617
|
+
return charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
|
|
1618
|
+
}
|
|
1616
1619
|
function isCharALetter(char) {
|
|
1617
1620
|
return (char >= "A" && char <= "Z") || (char >= "a" && char <= "z");
|
|
1618
1621
|
}
|
|
1619
1622
|
function isCharADigit(char) {
|
|
1620
1623
|
return char >= "0" && char <= "9";
|
|
1621
1624
|
}
|
|
1625
|
+
// we limit the max column to 3 letters and max row to 7 digits for performance reasons
|
|
1626
|
+
const MAX_COL = lettersToNumber("ZZZ");
|
|
1627
|
+
const MAX_ROW = 9999998;
|
|
1628
|
+
function consumeSpaces(chars) {
|
|
1629
|
+
while (chars.current === " ") {
|
|
1630
|
+
chars.advanceBy(1);
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
function consumeLetters(chars) {
|
|
1634
|
+
if (chars.current === "$")
|
|
1635
|
+
chars.advanceBy(1);
|
|
1636
|
+
if (!chars.current || !isCharALetter(chars.current)) {
|
|
1637
|
+
return -1;
|
|
1638
|
+
}
|
|
1639
|
+
let colCoordinate = 0;
|
|
1640
|
+
while (chars.current && isCharALetter(chars.current)) {
|
|
1641
|
+
colCoordinate = colCoordinate * 26 + charToNumber(chars.shift());
|
|
1642
|
+
}
|
|
1643
|
+
return colCoordinate;
|
|
1644
|
+
}
|
|
1645
|
+
function consumeDigits(chars) {
|
|
1646
|
+
if (chars.current === "$")
|
|
1647
|
+
chars.advanceBy(1);
|
|
1648
|
+
if (!chars.current || !isCharADigit(chars.current)) {
|
|
1649
|
+
return -1;
|
|
1650
|
+
}
|
|
1651
|
+
let num = 0;
|
|
1652
|
+
while (chars.current && isCharADigit(chars.current)) {
|
|
1653
|
+
num = num * 10 + Number(chars.shift());
|
|
1654
|
+
}
|
|
1655
|
+
return num;
|
|
1656
|
+
}
|
|
1622
1657
|
/**
|
|
1623
1658
|
* Convert a "XC" coordinate to cartesian coordinates.
|
|
1624
1659
|
*
|
|
@@ -1629,33 +1664,17 @@
|
|
|
1629
1664
|
* Note: it also accepts lowercase coordinates, but not fixed references
|
|
1630
1665
|
*/
|
|
1631
1666
|
function toCartesian(xc) {
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
// Process letter part
|
|
1637
|
-
if (xc[i] === "$")
|
|
1638
|
-
i++;
|
|
1639
|
-
while (i < xc.length && isCharALetter(xc[i])) {
|
|
1640
|
-
letterPart += xc[i++];
|
|
1641
|
-
}
|
|
1642
|
-
if (letterPart.length === 0 || letterPart.length > 3) {
|
|
1643
|
-
// limit to max 3 letters for performance reasons
|
|
1667
|
+
const chars = new TokenizingChars(xc);
|
|
1668
|
+
consumeSpaces(chars);
|
|
1669
|
+
const letterPart = consumeLetters(chars);
|
|
1670
|
+
if (letterPart === -1 || !chars.current) {
|
|
1644
1671
|
throw new Error(`Invalid cell description: ${xc}`);
|
|
1645
1672
|
}
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
}
|
|
1652
|
-
if (i !== xc.length || numberPart.length === 0 || numberPart.length > 7) {
|
|
1653
|
-
// limit to max 7 numbers for performance reasons
|
|
1654
|
-
throw new Error(`Invalid cell description: ${xc}`);
|
|
1655
|
-
}
|
|
1656
|
-
const col = lettersToNumber(letterPart);
|
|
1657
|
-
const row = Number(numberPart) - 1;
|
|
1658
|
-
if (isNaN(row)) {
|
|
1673
|
+
const num = consumeDigits(chars);
|
|
1674
|
+
consumeSpaces(chars);
|
|
1675
|
+
const col = letterPart - 1;
|
|
1676
|
+
const row = num - 1;
|
|
1677
|
+
if (!chars.isOver() || col > MAX_COL || row > MAX_ROW) {
|
|
1659
1678
|
throw new Error(`Invalid cell description: ${xc}`);
|
|
1660
1679
|
}
|
|
1661
1680
|
return { col, row };
|
|
@@ -2067,67 +2086,6 @@
|
|
|
2067
2086
|
}
|
|
2068
2087
|
}
|
|
2069
2088
|
|
|
2070
|
-
/** Reference of a cell (eg. A1, $B$5) */
|
|
2071
|
-
const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
|
|
2072
|
-
// Same as above, but matches the exact string (nothing before or after)
|
|
2073
|
-
const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
|
|
2074
|
-
/** Reference of a column header (eg. A, AB, $A) */
|
|
2075
|
-
const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
|
|
2076
|
-
/** Reference of a row header (eg. 1, $1) */
|
|
2077
|
-
const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
|
|
2078
|
-
/** Reference of a column (eg. A, $CA, Sheet1!B) */
|
|
2079
|
-
const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
|
|
2080
|
-
/** Reference of a row (eg. 1, 59, Sheet1!9) */
|
|
2081
|
-
const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
|
|
2082
|
-
/** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
|
|
2083
|
-
const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
|
|
2084
|
-
/** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
|
|
2085
|
-
const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
|
|
2086
|
-
/** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
|
|
2087
|
-
const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
|
|
2088
|
-
"(" +
|
|
2089
|
-
[cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
|
|
2090
|
-
")" +
|
|
2091
|
-
/$/.source, "i");
|
|
2092
|
-
/**
|
|
2093
|
-
* Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
|
|
2094
|
-
*/
|
|
2095
|
-
function isColReference(xc) {
|
|
2096
|
-
return colReference.test(xc);
|
|
2097
|
-
}
|
|
2098
|
-
/**
|
|
2099
|
-
* Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
|
|
2100
|
-
*/
|
|
2101
|
-
function isRowReference(xc) {
|
|
2102
|
-
return rowReference.test(xc);
|
|
2103
|
-
}
|
|
2104
|
-
function isColHeader(str) {
|
|
2105
|
-
return colHeader.test(str);
|
|
2106
|
-
}
|
|
2107
|
-
function isRowHeader(str) {
|
|
2108
|
-
return rowHeader.test(str);
|
|
2109
|
-
}
|
|
2110
|
-
/**
|
|
2111
|
-
* Return true if the given xc is the reference of a single cell,
|
|
2112
|
-
* without any specified sheet (e.g. A1)
|
|
2113
|
-
*/
|
|
2114
|
-
function isSingleCellReference(xc) {
|
|
2115
|
-
return singleCellReference.test(xc);
|
|
2116
|
-
}
|
|
2117
|
-
function splitReference(ref) {
|
|
2118
|
-
if (!ref.includes("!")) {
|
|
2119
|
-
return { xc: ref };
|
|
2120
|
-
}
|
|
2121
|
-
const parts = ref.split("!");
|
|
2122
|
-
const xc = parts.pop();
|
|
2123
|
-
const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
|
|
2124
|
-
return { sheetName, xc };
|
|
2125
|
-
}
|
|
2126
|
-
/** Return a reference SheetName!xc from the given arguments */
|
|
2127
|
-
function getFullReference(sheetName, xc) {
|
|
2128
|
-
return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
|
|
2129
|
-
}
|
|
2130
|
-
|
|
2131
2089
|
/**
|
|
2132
2090
|
* Convert from a cartesian reference to a Zone
|
|
2133
2091
|
* The range boundaries will be kept in the same order as the
|
|
@@ -2145,63 +2103,55 @@
|
|
|
2145
2103
|
*
|
|
2146
2104
|
*/
|
|
2147
2105
|
function toZoneWithoutBoundaryChanges(xc) {
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
if (
|
|
2152
|
-
|
|
2153
|
-
}
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
if (xc.includes(":")) {
|
|
2157
|
-
[firstRangePart, secondRangePart] = xc.split(":");
|
|
2158
|
-
firstRangePart = firstRangePart.trim();
|
|
2159
|
-
secondRangePart = secondRangePart.trim();
|
|
2160
|
-
}
|
|
2161
|
-
else {
|
|
2162
|
-
firstRangePart = xc.trim();
|
|
2163
|
-
}
|
|
2106
|
+
const chars = new TokenizingChars(xc);
|
|
2107
|
+
consumeSpaces(chars);
|
|
2108
|
+
const sheetSeparatorIndex = xc.indexOf("!");
|
|
2109
|
+
if (sheetSeparatorIndex !== -1) {
|
|
2110
|
+
chars.advanceBy(sheetSeparatorIndex + 1);
|
|
2111
|
+
}
|
|
2112
|
+
const leftLetters = consumeLetters(chars);
|
|
2113
|
+
const leftNumbers = consumeDigits(chars);
|
|
2164
2114
|
let top, bottom, left, right;
|
|
2165
2115
|
let fullCol = false;
|
|
2166
2116
|
let fullRow = false;
|
|
2167
2117
|
let hasHeader = false;
|
|
2168
|
-
if (
|
|
2169
|
-
left = right =
|
|
2118
|
+
if (leftNumbers === -1) {
|
|
2119
|
+
left = right = leftLetters - 1;
|
|
2170
2120
|
top = bottom = 0;
|
|
2171
2121
|
fullCol = true;
|
|
2172
2122
|
}
|
|
2173
|
-
else if (
|
|
2174
|
-
top = bottom =
|
|
2123
|
+
else if (leftLetters === -1) {
|
|
2124
|
+
top = bottom = leftNumbers - 1;
|
|
2175
2125
|
left = right = 0;
|
|
2176
2126
|
fullRow = true;
|
|
2177
2127
|
}
|
|
2178
2128
|
else {
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
top = bottom = c.row;
|
|
2129
|
+
left = right = leftLetters - 1;
|
|
2130
|
+
top = bottom = leftNumbers - 1;
|
|
2182
2131
|
hasHeader = true;
|
|
2183
2132
|
}
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2133
|
+
consumeSpaces(chars);
|
|
2134
|
+
if (chars.current === ":") {
|
|
2135
|
+
chars.advanceBy(1);
|
|
2136
|
+
consumeSpaces(chars);
|
|
2137
|
+
const rightLetters = consumeLetters(chars);
|
|
2138
|
+
const rightNumbers = consumeDigits(chars);
|
|
2139
|
+
if (rightNumbers === -1) {
|
|
2140
|
+
right = rightLetters - 1;
|
|
2187
2141
|
fullCol = true;
|
|
2188
2142
|
}
|
|
2189
|
-
else if (
|
|
2190
|
-
bottom =
|
|
2143
|
+
else if (rightLetters === -1) {
|
|
2144
|
+
bottom = rightNumbers - 1;
|
|
2191
2145
|
fullRow = true;
|
|
2192
2146
|
}
|
|
2193
2147
|
else {
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
bottom = c.row;
|
|
2148
|
+
right = rightLetters - 1;
|
|
2149
|
+
bottom = rightNumbers - 1;
|
|
2197
2150
|
top = fullCol ? bottom : top;
|
|
2198
2151
|
left = fullRow ? right : left;
|
|
2199
2152
|
hasHeader = true;
|
|
2200
2153
|
}
|
|
2201
2154
|
}
|
|
2202
|
-
if (fullCol && fullRow) {
|
|
2203
|
-
throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
|
|
2204
|
-
}
|
|
2205
2155
|
const zone = {
|
|
2206
2156
|
top,
|
|
2207
2157
|
left,
|
|
@@ -2230,7 +2180,16 @@
|
|
|
2230
2180
|
*/
|
|
2231
2181
|
function toUnboundedZone(xc) {
|
|
2232
2182
|
const zone = toZoneWithoutBoundaryChanges(xc);
|
|
2233
|
-
|
|
2183
|
+
const orderedZone = reorderZone(zone);
|
|
2184
|
+
const bottom = orderedZone.bottom;
|
|
2185
|
+
const right = orderedZone.right;
|
|
2186
|
+
if ((bottom !== undefined && bottom > MAX_ROW) || (right !== undefined && right > MAX_COL)) {
|
|
2187
|
+
throw new Error(`Range string out of bounds: ${xc}`); // limit the size of the zone for performance
|
|
2188
|
+
}
|
|
2189
|
+
if (bottom === undefined && right === undefined) {
|
|
2190
|
+
throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
|
|
2191
|
+
}
|
|
2192
|
+
return orderedZone;
|
|
2234
2193
|
}
|
|
2235
2194
|
/**
|
|
2236
2195
|
* Convert from a cartesian reference to a Zone.
|
|
@@ -4182,6 +4141,113 @@
|
|
|
4182
4141
|
}
|
|
4183
4142
|
return generateMatrix(matrix[0].length, matrix.length, (i, j) => matrix[j][i]);
|
|
4184
4143
|
}
|
|
4144
|
+
/**
|
|
4145
|
+
* Enables a formula function to accept matrix or vector inputs instead of simple value, computing results across multiple dimensions.
|
|
4146
|
+
*
|
|
4147
|
+
* ```
|
|
4148
|
+
* / |‾ ‾| \ |‾ ‾|
|
|
4149
|
+
* | | [A] | | | compute(A, D, E), compute(A, D, F), compute(A, D, G) |
|
|
4150
|
+
* applyVectorization| compute, | [B], D, [E, F, G] | | <=> | compute(B, D, E), compute(B, D, F), compute(B, D, G) |
|
|
4151
|
+
* | | [C] | | | compute(C, D, E), compute(C, D, F), compute(C, D, G) |
|
|
4152
|
+
* \ |_ _| / |_ _|
|
|
4153
|
+
* ```
|
|
4154
|
+
*
|
|
4155
|
+
* By default, all arguments are vectorized. To control which arguments are vectorized,
|
|
4156
|
+
* pass an `acceptToVectorize` boolean array of the same length as `args`:
|
|
4157
|
+
* - `true` enables vectorization for that argument
|
|
4158
|
+
* - `false` disables vectorization for that argument
|
|
4159
|
+
*
|
|
4160
|
+
* For example, with `[true, true, false]` on previous example you get:
|
|
4161
|
+
*
|
|
4162
|
+
* ```
|
|
4163
|
+
* |‾ ‾|
|
|
4164
|
+
* | compute(A, D, [E, F, G]) |
|
|
4165
|
+
* | compute(B, D, [E, F, G]) |
|
|
4166
|
+
* | compute(C, D, [E, F, G]) |
|
|
4167
|
+
* |_ _|
|
|
4168
|
+
* ```
|
|
4169
|
+
*
|
|
4170
|
+
* @remarks
|
|
4171
|
+
* This helper is automatically applied (by default) to **all** `compute` functions
|
|
4172
|
+
* across the various spreadsheet formula modules:
|
|
4173
|
+
* - If an argument is declared **scalar** (not `"range"`), it is vectorized.
|
|
4174
|
+
* - If **all** arguments are declared **ranges**, no vectorization occurs.
|
|
4175
|
+
* - e.g. `SUM(A1:B2)` returns a 1×1 sum over the range.
|
|
4176
|
+
* - e.g. `COS(A1:B2)` over `A1:B2` returns a 2×2 element-wise result.
|
|
4177
|
+
* - For special behaviors (e.g. the `IF` function), you may declare all arguments
|
|
4178
|
+
* as ranges and invoke this helper directly within your `compute` implementation.
|
|
4179
|
+
*/
|
|
4180
|
+
function applyVectorization(formula, args, acceptToVectorize = undefined) {
|
|
4181
|
+
let countVectorizedCol = 1;
|
|
4182
|
+
let countVectorizedRow = 1;
|
|
4183
|
+
let vectorizedColLimit = Infinity;
|
|
4184
|
+
let vectorizedRowLimit = Infinity;
|
|
4185
|
+
let vectorArgsType = undefined;
|
|
4186
|
+
for (let i = 0; i < args.length; i++) {
|
|
4187
|
+
const arg = args[i];
|
|
4188
|
+
if (isMatrix(arg) && (acceptToVectorize === undefined || acceptToVectorize[i])) {
|
|
4189
|
+
const nColumns = arg.length;
|
|
4190
|
+
const nRows = arg[0].length;
|
|
4191
|
+
if (nColumns !== 1 || nRows !== 1) {
|
|
4192
|
+
vectorArgsType ??= new Array(args.length);
|
|
4193
|
+
if (nColumns !== 1 && nRows !== 1) {
|
|
4194
|
+
vectorArgsType[i] = "matrix";
|
|
4195
|
+
countVectorizedCol = Math.max(countVectorizedCol, nColumns);
|
|
4196
|
+
countVectorizedRow = Math.max(countVectorizedRow, nRows);
|
|
4197
|
+
vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
|
|
4198
|
+
vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
|
|
4199
|
+
}
|
|
4200
|
+
else if (nColumns !== 1) {
|
|
4201
|
+
vectorArgsType[i] = "horizontal";
|
|
4202
|
+
countVectorizedCol = Math.max(countVectorizedCol, nColumns);
|
|
4203
|
+
vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
|
|
4204
|
+
}
|
|
4205
|
+
else if (nRows !== 1) {
|
|
4206
|
+
vectorArgsType[i] = "vertical";
|
|
4207
|
+
countVectorizedRow = Math.max(countVectorizedRow, nRows);
|
|
4208
|
+
vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
else {
|
|
4212
|
+
args[i] = arg[0][0];
|
|
4213
|
+
}
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4216
|
+
if (countVectorizedCol === 1 && countVectorizedRow === 1) {
|
|
4217
|
+
// either this function is not vectorized or it ends up with a 1x1 dimension
|
|
4218
|
+
return formula(...args);
|
|
4219
|
+
}
|
|
4220
|
+
const getArgOffset = (i, j) => args.map((arg, index) => {
|
|
4221
|
+
switch (vectorArgsType?.[index]) {
|
|
4222
|
+
case "matrix":
|
|
4223
|
+
return arg[i][j];
|
|
4224
|
+
case "horizontal":
|
|
4225
|
+
return arg[i][0];
|
|
4226
|
+
case "vertical":
|
|
4227
|
+
return arg[0][j];
|
|
4228
|
+
case undefined:
|
|
4229
|
+
return arg;
|
|
4230
|
+
}
|
|
4231
|
+
});
|
|
4232
|
+
return generateMatrix(countVectorizedCol, countVectorizedRow, (col, row) => {
|
|
4233
|
+
if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) {
|
|
4234
|
+
return new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
|
|
4235
|
+
}
|
|
4236
|
+
const singleCellComputeResult = formula(...getArgOffset(col, row));
|
|
4237
|
+
// In the case where the user tries to vectorize arguments of an array formula, we will get an
|
|
4238
|
+
// array for every combination of the vectorized arguments, which will lead to a 3D matrix and
|
|
4239
|
+
// we won't be able to return the values.
|
|
4240
|
+
// In this case, we keep the first element of each spreading part, just as Excel does, and
|
|
4241
|
+
// create an array with these parts.
|
|
4242
|
+
// For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
|
|
4243
|
+
// range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
|
|
4244
|
+
// for the value in A2). In this case, we will simply take the first value of each matrix and
|
|
4245
|
+
// return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
|
|
4246
|
+
return isMatrix(singleCellComputeResult)
|
|
4247
|
+
? singleCellComputeResult[0][0]
|
|
4248
|
+
: singleCellComputeResult;
|
|
4249
|
+
});
|
|
4250
|
+
}
|
|
4185
4251
|
// -----------------------------------------------------------------------------
|
|
4186
4252
|
// CONDITIONAL EXPLORE FUNCTIONS
|
|
4187
4253
|
// -----------------------------------------------------------------------------
|
|
@@ -5966,6 +6032,67 @@
|
|
|
5966
6032
|
return MIN_DELAY + (MAX_DELAY - MIN_DELAY) * Math.exp(-ACCELERATION * (value - 1));
|
|
5967
6033
|
}
|
|
5968
6034
|
|
|
6035
|
+
/** Reference of a cell (eg. A1, $B$5) */
|
|
6036
|
+
const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
|
|
6037
|
+
// Same as above, but matches the exact string (nothing before or after)
|
|
6038
|
+
const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
|
|
6039
|
+
/** Reference of a column header (eg. A, AB, $A) */
|
|
6040
|
+
const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
|
|
6041
|
+
/** Reference of a row header (eg. 1, $1) */
|
|
6042
|
+
const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
|
|
6043
|
+
/** Reference of a column (eg. A, $CA, Sheet1!B) */
|
|
6044
|
+
const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
|
|
6045
|
+
/** Reference of a row (eg. 1, 59, Sheet1!9) */
|
|
6046
|
+
const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
|
|
6047
|
+
/** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
|
|
6048
|
+
const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
|
|
6049
|
+
/** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
|
|
6050
|
+
const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
|
|
6051
|
+
/** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
|
|
6052
|
+
const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
|
|
6053
|
+
"(" +
|
|
6054
|
+
[cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
|
|
6055
|
+
")" +
|
|
6056
|
+
/$/.source, "i");
|
|
6057
|
+
/**
|
|
6058
|
+
* Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
|
|
6059
|
+
*/
|
|
6060
|
+
function isColReference(xc) {
|
|
6061
|
+
return colReference.test(xc);
|
|
6062
|
+
}
|
|
6063
|
+
/**
|
|
6064
|
+
* Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
|
|
6065
|
+
*/
|
|
6066
|
+
function isRowReference(xc) {
|
|
6067
|
+
return rowReference.test(xc);
|
|
6068
|
+
}
|
|
6069
|
+
function isColHeader(str) {
|
|
6070
|
+
return colHeader.test(str);
|
|
6071
|
+
}
|
|
6072
|
+
function isRowHeader(str) {
|
|
6073
|
+
return rowHeader.test(str);
|
|
6074
|
+
}
|
|
6075
|
+
/**
|
|
6076
|
+
* Return true if the given xc is the reference of a single cell,
|
|
6077
|
+
* without any specified sheet (e.g. A1)
|
|
6078
|
+
*/
|
|
6079
|
+
function isSingleCellReference(xc) {
|
|
6080
|
+
return singleCellReference.test(xc);
|
|
6081
|
+
}
|
|
6082
|
+
function splitReference(ref) {
|
|
6083
|
+
if (!ref.includes("!")) {
|
|
6084
|
+
return { xc: ref };
|
|
6085
|
+
}
|
|
6086
|
+
const parts = ref.split("!");
|
|
6087
|
+
const xc = parts.pop();
|
|
6088
|
+
const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
|
|
6089
|
+
return { sheetName, xc };
|
|
6090
|
+
}
|
|
6091
|
+
/** Return a reference SheetName!xc from the given arguments */
|
|
6092
|
+
function getFullReference(sheetName, xc) {
|
|
6093
|
+
return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
|
|
6094
|
+
}
|
|
6095
|
+
|
|
5969
6096
|
class RangeImpl {
|
|
5970
6097
|
getSheetSize;
|
|
5971
6098
|
_zone;
|
|
@@ -7412,14 +7539,20 @@
|
|
|
7412
7539
|
/**
|
|
7413
7540
|
* Return the input if it's a scalar or the first element of the input if it's a matrix.
|
|
7414
7541
|
*/
|
|
7415
|
-
function toScalar(
|
|
7416
|
-
if (!isMatrix(
|
|
7417
|
-
return
|
|
7542
|
+
function toScalar(arg) {
|
|
7543
|
+
if (!isMatrix(arg)) {
|
|
7544
|
+
return arg;
|
|
7418
7545
|
}
|
|
7419
|
-
if (
|
|
7546
|
+
if (!isSingleElementMatrix(arg)) {
|
|
7420
7547
|
throw new EvaluationError(_t("The value should be a scalar or a 1x1 matrix"));
|
|
7421
7548
|
}
|
|
7422
|
-
return
|
|
7549
|
+
return arg[0][0];
|
|
7550
|
+
}
|
|
7551
|
+
function isSingleElementMatrix(matrix) {
|
|
7552
|
+
return matrix.length === 1 && matrix[0].length === 1;
|
|
7553
|
+
}
|
|
7554
|
+
function isMultipleElementMatrix(arg) {
|
|
7555
|
+
return isMatrix(arg) && !isSingleElementMatrix(arg);
|
|
7423
7556
|
}
|
|
7424
7557
|
|
|
7425
7558
|
function assertSameNumberOfElements(...args) {
|
|
@@ -15263,7 +15396,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
15263
15396
|
}
|
|
15264
15397
|
return mode === "row" ? transposeMatrix(result) : result;
|
|
15265
15398
|
},
|
|
15266
|
-
isExported:
|
|
15399
|
+
isExported: false,
|
|
15267
15400
|
};
|
|
15268
15401
|
// -----------------------------------------------------------------------------
|
|
15269
15402
|
// SORT
|
|
@@ -18394,16 +18527,23 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
18394
18527
|
const IF = {
|
|
18395
18528
|
description: _t("Returns value depending on logical expression."),
|
|
18396
18529
|
args: [
|
|
18397
|
-
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.")),
|
|
18398
|
-
arg("value_if_true (any)", _t("The value the function returns if logical_expression is TRUE.")),
|
|
18399
|
-
arg("value_if_false (any, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
|
|
18530
|
+
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.")),
|
|
18531
|
+
arg("value_if_true (any, range)", _t("The value the function returns if logical_expression is TRUE.")),
|
|
18532
|
+
arg("value_if_false (any, range, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
|
|
18400
18533
|
],
|
|
18401
18534
|
compute: function (logicalExpression, valueIfTrue, valueIfFalse) {
|
|
18402
|
-
|
|
18535
|
+
if (isMultipleElementMatrix(logicalExpression)) {
|
|
18536
|
+
return applyVectorization(IF.compute, [logicalExpression, valueIfTrue, valueIfFalse]);
|
|
18537
|
+
}
|
|
18538
|
+
let result = toBoolean(toScalar(logicalExpression)) ? valueIfTrue : valueIfFalse;
|
|
18539
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
18540
|
+
if (!isMultipleElementMatrix(result)) {
|
|
18541
|
+
result = toScalar(result);
|
|
18542
|
+
}
|
|
18403
18543
|
if (result === undefined) {
|
|
18404
18544
|
return { value: "" };
|
|
18405
18545
|
}
|
|
18406
|
-
if (result.value === null) {
|
|
18546
|
+
if (!isMatrix(result) && result.value === null) {
|
|
18407
18547
|
return { ...result, value: "" };
|
|
18408
18548
|
}
|
|
18409
18549
|
return result;
|
|
@@ -18416,15 +18556,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
18416
18556
|
const IFERROR = {
|
|
18417
18557
|
description: _t("Value if it is not an error, otherwise 2nd argument."),
|
|
18418
18558
|
args: [
|
|
18419
|
-
arg("value (any)", _t("The value to return if value itself is not an error.")),
|
|
18420
|
-
arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an error.")),
|
|
18559
|
+
arg("value (any, range)", _t("The value to return if value itself is not an error.")),
|
|
18560
|
+
arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an error.")),
|
|
18421
18561
|
],
|
|
18422
|
-
compute: function (value, valueIfError
|
|
18423
|
-
|
|
18562
|
+
compute: function (value, valueIfError) {
|
|
18563
|
+
if (isMultipleElementMatrix(value)) {
|
|
18564
|
+
return applyVectorization(IFERROR.compute, [value, valueIfError]);
|
|
18565
|
+
}
|
|
18566
|
+
let result = isEvaluationError(toScalar(value)?.value) ? valueIfError : value;
|
|
18567
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
18568
|
+
if (!isMultipleElementMatrix(result)) {
|
|
18569
|
+
result = toScalar(result);
|
|
18570
|
+
}
|
|
18424
18571
|
if (result === undefined) {
|
|
18425
18572
|
return { value: "" };
|
|
18426
18573
|
}
|
|
18427
|
-
if (result.value === null) {
|
|
18574
|
+
if (!isMatrix(result) && result.value === null) {
|
|
18428
18575
|
return { ...result, value: "" };
|
|
18429
18576
|
}
|
|
18430
18577
|
return result;
|
|
@@ -18437,15 +18584,22 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
18437
18584
|
const IFNA = {
|
|
18438
18585
|
description: _t("Value if it is not an #N/A error, otherwise 2nd argument."),
|
|
18439
18586
|
args: [
|
|
18440
|
-
arg("value (any)", _t("The value to return if value itself is not #N/A an error.")),
|
|
18441
|
-
arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
|
|
18587
|
+
arg("value (any, range)", _t("The value to return if value itself is not #N/A an error.")),
|
|
18588
|
+
arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
|
|
18442
18589
|
],
|
|
18443
|
-
compute: function (value, valueIfError
|
|
18444
|
-
|
|
18590
|
+
compute: function (value, valueIfError) {
|
|
18591
|
+
if (isMultipleElementMatrix(value)) {
|
|
18592
|
+
return applyVectorization(IFNA.compute, [value, valueIfError]);
|
|
18593
|
+
}
|
|
18594
|
+
let result = toScalar(value)?.value === CellErrorType.NotAvailable ? valueIfError : value;
|
|
18595
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
18596
|
+
if (!isMultipleElementMatrix(result)) {
|
|
18597
|
+
result = toScalar(result);
|
|
18598
|
+
}
|
|
18445
18599
|
if (result === undefined) {
|
|
18446
18600
|
return { value: "" };
|
|
18447
18601
|
}
|
|
18448
|
-
if (result.value === null) {
|
|
18602
|
+
if (!isMatrix(result) && result.value === null) {
|
|
18449
18603
|
return { ...result, value: "" };
|
|
18450
18604
|
}
|
|
18451
18605
|
return result;
|
|
@@ -18458,23 +18612,31 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
18458
18612
|
const IFS = {
|
|
18459
18613
|
description: _t("Returns a value depending on multiple logical expressions."),
|
|
18460
18614
|
args: [
|
|
18461
|
-
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.")),
|
|
18462
|
-
arg("value1 (any)", _t("The returned value if condition1 is TRUE.")),
|
|
18463
|
-
arg("condition2 (boolean, any, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
|
|
18464
|
-
arg("value2 (any, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
|
|
18615
|
+
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.")),
|
|
18616
|
+
arg("value1 (any, range)", _t("The returned value if condition1 is TRUE.")),
|
|
18617
|
+
arg("condition2 (boolean, any, range, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
|
|
18618
|
+
arg("value2 (any, range, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
|
|
18465
18619
|
],
|
|
18466
18620
|
compute: function (...values) {
|
|
18467
18621
|
assert(() => values.length % 2 === 0, _t("Wrong number of arguments. Expected an even number of arguments."));
|
|
18468
|
-
|
|
18469
|
-
if (
|
|
18470
|
-
|
|
18471
|
-
|
|
18622
|
+
while (values.length > 0) {
|
|
18623
|
+
if (isMultipleElementMatrix(values[0])) {
|
|
18624
|
+
return applyVectorization(IFS.compute, values);
|
|
18625
|
+
}
|
|
18626
|
+
const condition = toBoolean(toScalar(values.shift()));
|
|
18627
|
+
let valueIfTrue = values.shift();
|
|
18628
|
+
if (condition) {
|
|
18629
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
18630
|
+
if (!isMultipleElementMatrix(valueIfTrue)) {
|
|
18631
|
+
valueIfTrue = toScalar(valueIfTrue);
|
|
18632
|
+
}
|
|
18633
|
+
if (valueIfTrue === undefined) {
|
|
18472
18634
|
return { value: "" };
|
|
18473
18635
|
}
|
|
18474
|
-
if (
|
|
18475
|
-
return { ...
|
|
18636
|
+
if (!isMatrix(valueIfTrue) && valueIfTrue.value === null) {
|
|
18637
|
+
return { ...valueIfTrue, value: "" };
|
|
18476
18638
|
}
|
|
18477
|
-
return
|
|
18639
|
+
return valueIfTrue;
|
|
18478
18640
|
}
|
|
18479
18641
|
}
|
|
18480
18642
|
return new EvaluationError(_t("No match."));
|
|
@@ -20136,7 +20298,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20136
20298
|
}
|
|
20137
20299
|
return transposeMatrix([result]);
|
|
20138
20300
|
},
|
|
20139
|
-
isExported:
|
|
20301
|
+
isExported: false,
|
|
20140
20302
|
};
|
|
20141
20303
|
// -----------------------------------------------------------------------------
|
|
20142
20304
|
// SUBSTITUTE
|
|
@@ -20329,86 +20491,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20329
20491
|
functionRegistry.add(name, { isExported: false, ...addDescr });
|
|
20330
20492
|
}
|
|
20331
20493
|
}
|
|
20332
|
-
|
|
20494
|
+
//------------------------------------------------------------------------------
|
|
20495
|
+
// CREATE COMPUTE FUNCTION
|
|
20496
|
+
//------------------------------------------------------------------------------
|
|
20333
20497
|
function createComputeFunction(descr, functionName) {
|
|
20334
20498
|
function vectorizedCompute(...args) {
|
|
20335
|
-
|
|
20336
|
-
let countVectorizableRow = 1;
|
|
20337
|
-
let vectorizableColLimit = Infinity;
|
|
20338
|
-
let vectorizableRowLimit = Infinity;
|
|
20339
|
-
let vectorArgsType = undefined;
|
|
20340
|
-
//#region Compute vectorisation limits
|
|
20499
|
+
const acceptToVectorize = [];
|
|
20341
20500
|
for (let i = 0; i < args.length; i++) {
|
|
20342
20501
|
const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
|
|
20343
20502
|
const arg = args[i];
|
|
20344
|
-
if (isMatrix(arg) && !argDefinition.acceptMatrix) {
|
|
20345
|
-
// if argDefinition does not accept a matrix but arg is still a matrix
|
|
20346
|
-
// --> triggers the arguments vectorization
|
|
20347
|
-
const nColumns = arg.length;
|
|
20348
|
-
const nRows = arg[0].length;
|
|
20349
|
-
if (nColumns !== 1 || nRows !== 1) {
|
|
20350
|
-
vectorArgsType ??= new Array(args.length);
|
|
20351
|
-
if (nColumns !== 1 && nRows !== 1) {
|
|
20352
|
-
vectorArgsType[i] = "matrix";
|
|
20353
|
-
countVectorizableCol = Math.max(countVectorizableCol, nColumns);
|
|
20354
|
-
countVectorizableRow = Math.max(countVectorizableRow, nRows);
|
|
20355
|
-
vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
|
|
20356
|
-
vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
|
|
20357
|
-
}
|
|
20358
|
-
else if (nColumns !== 1) {
|
|
20359
|
-
vectorArgsType[i] = "horizontal";
|
|
20360
|
-
countVectorizableCol = Math.max(countVectorizableCol, nColumns);
|
|
20361
|
-
vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
|
|
20362
|
-
}
|
|
20363
|
-
else if (nRows !== 1) {
|
|
20364
|
-
vectorArgsType[i] = "vertical";
|
|
20365
|
-
countVectorizableRow = Math.max(countVectorizableRow, nRows);
|
|
20366
|
-
vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
|
|
20367
|
-
}
|
|
20368
|
-
}
|
|
20369
|
-
else {
|
|
20370
|
-
args[i] = arg[0][0];
|
|
20371
|
-
}
|
|
20372
|
-
}
|
|
20373
20503
|
if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
|
|
20374
20504
|
throw new BadExpressionError(_t("Function %s expects the parameter '%s' to be reference to a cell or range.", functionName, (i + 1).toString()));
|
|
20375
20505
|
}
|
|
20506
|
+
acceptToVectorize.push(!argDefinition.acceptMatrix);
|
|
20376
20507
|
}
|
|
20377
|
-
|
|
20378
|
-
if (countVectorizableCol === 1 && countVectorizableRow === 1) {
|
|
20379
|
-
// either this function is not vectorized or it ends up with a 1x1 dimension
|
|
20380
|
-
return errorHandlingCompute.apply(this, args);
|
|
20381
|
-
}
|
|
20382
|
-
const getArgOffset = (i, j) => args.map((arg, index) => {
|
|
20383
|
-
switch (vectorArgsType?.[index]) {
|
|
20384
|
-
case "matrix":
|
|
20385
|
-
return arg[i][j];
|
|
20386
|
-
case "horizontal":
|
|
20387
|
-
return arg[i][0];
|
|
20388
|
-
case "vertical":
|
|
20389
|
-
return arg[0][j];
|
|
20390
|
-
case undefined:
|
|
20391
|
-
return arg;
|
|
20392
|
-
}
|
|
20393
|
-
});
|
|
20394
|
-
return generateMatrix(countVectorizableCol, countVectorizableRow, (col, row) => {
|
|
20395
|
-
if (col > vectorizableColLimit - 1 || row > vectorizableRowLimit - 1) {
|
|
20396
|
-
return notAvailableError;
|
|
20397
|
-
}
|
|
20398
|
-
const singleCellComputeResult = errorHandlingCompute.apply(this, getArgOffset(col, row));
|
|
20399
|
-
// In the case where the user tries to vectorize arguments of an array formula, we will get an
|
|
20400
|
-
// array for every combination of the vectorized arguments, which will lead to a 3D matrix and
|
|
20401
|
-
// we won't be able to return the values.
|
|
20402
|
-
// In this case, we keep the first element of each spreading part, just as Excel does, and
|
|
20403
|
-
// create an array with these parts.
|
|
20404
|
-
// For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
|
|
20405
|
-
// range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
|
|
20406
|
-
// for the value in A2). In this case, we will simply take the first value of each matrix and
|
|
20407
|
-
// return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
|
|
20408
|
-
return isMatrix(singleCellComputeResult)
|
|
20409
|
-
? singleCellComputeResult[0][0]
|
|
20410
|
-
: singleCellComputeResult;
|
|
20411
|
-
});
|
|
20508
|
+
return applyVectorization(errorHandlingCompute.bind(this), args, acceptToVectorize);
|
|
20412
20509
|
}
|
|
20413
20510
|
function errorHandlingCompute(...args) {
|
|
20414
20511
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -21253,7 +21350,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21253
21350
|
proposals &&
|
|
21254
21351
|
!["ARG_SEPARATOR", "LEFT_PAREN", "OPERATOR"].includes(tokenAtCursor.type)) {
|
|
21255
21352
|
const filteredProposals = fuzzyLookup(searchTerm, proposals, (p) => p.fuzzySearchKey || p.text);
|
|
21256
|
-
if (!exactMatch || filteredProposals.length
|
|
21353
|
+
if (!exactMatch || filteredProposals.length) {
|
|
21257
21354
|
proposals = filteredProposals;
|
|
21258
21355
|
}
|
|
21259
21356
|
}
|
|
@@ -41345,12 +41442,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
41345
41442
|
return providersDefinitions;
|
|
41346
41443
|
}
|
|
41347
41444
|
getComposerContent() {
|
|
41445
|
+
let content = this._currentContent;
|
|
41348
41446
|
if (this.editionMode === "inactive") {
|
|
41349
41447
|
// References in the content might not be linked to the current active sheet
|
|
41350
41448
|
// We here force the sheet name prefix for all references that are not in
|
|
41351
41449
|
// the current active sheet
|
|
41352
41450
|
const defaultRangeSheetId = this.args().defaultRangeSheetId;
|
|
41353
|
-
|
|
41451
|
+
content = rangeTokenize(this.args().content)
|
|
41354
41452
|
.map((token) => {
|
|
41355
41453
|
if (token.type === "REFERENCE") {
|
|
41356
41454
|
const range = this.getters.getRangeFromSheetXC(defaultRangeSheetId, token.value);
|
|
@@ -41360,7 +41458,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
41360
41458
|
})
|
|
41361
41459
|
.join("");
|
|
41362
41460
|
}
|
|
41363
|
-
return this.
|
|
41461
|
+
return localizeContent(content, this.getters.getLocale());
|
|
41364
41462
|
}
|
|
41365
41463
|
stopEdition() {
|
|
41366
41464
|
this._stopEdition();
|
|
@@ -45106,6 +45204,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45106
45204
|
}
|
|
45107
45205
|
return undefined;
|
|
45108
45206
|
}
|
|
45207
|
+
get isCalculatedMeasureInvalid() {
|
|
45208
|
+
return this.env.model.getters.getMeasureCompiledFormula(this.props.measure).isBadExpression;
|
|
45209
|
+
}
|
|
45109
45210
|
}
|
|
45110
45211
|
|
|
45111
45212
|
css /* scss */ `
|
|
@@ -46116,7 +46217,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46116
46217
|
return dimension.order === "asc" ? -1 : 1;
|
|
46117
46218
|
}
|
|
46118
46219
|
if (dimension.type === "integer" || dimension.type === "datetime") {
|
|
46119
|
-
return dimension.order === "asc"
|
|
46220
|
+
return dimension.order === "asc"
|
|
46221
|
+
? toNumber(a, DEFAULT_LOCALE) - toNumber(b, DEFAULT_LOCALE)
|
|
46222
|
+
: toNumber(b, DEFAULT_LOCALE) - toNumber(a, DEFAULT_LOCALE);
|
|
46120
46223
|
}
|
|
46121
46224
|
return dimension.order === "asc" ? a.localeCompare(b) : b.localeCompare(a);
|
|
46122
46225
|
}
|
|
@@ -48882,8 +48985,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48882
48985
|
if (!spreader) {
|
|
48883
48986
|
return undefined;
|
|
48884
48987
|
}
|
|
48885
|
-
|
|
48886
|
-
return cell?.content;
|
|
48988
|
+
return this.getters.getCellText(spreader, { showFormula: true });
|
|
48887
48989
|
}
|
|
48888
48990
|
get currentEditedCell() {
|
|
48889
48991
|
return {
|
|
@@ -51694,6 +51796,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51694
51796
|
const friction = 0.95;
|
|
51695
51797
|
const verticalScrollFactor = 1;
|
|
51696
51798
|
const horizontalScrollFactor = 1;
|
|
51799
|
+
const resetTimeoutDuration = 100;
|
|
51697
51800
|
function useTouchScroll(ref, updateScroll, canMoveUp) {
|
|
51698
51801
|
let lastX = 0;
|
|
51699
51802
|
let lastY = 0;
|
|
@@ -51701,6 +51804,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51701
51804
|
let velocityY = 0;
|
|
51702
51805
|
let isMouseDown = false;
|
|
51703
51806
|
let lastTime = 0;
|
|
51807
|
+
let resetTimeout = null;
|
|
51704
51808
|
useRefListener(ref, "touchstart", onTouchStart, { capture: false });
|
|
51705
51809
|
useRefListener(ref, "touchmove", onTouchMove, { capture: false });
|
|
51706
51810
|
useRefListener(ref, "touchend", onTouchEnd, { capture: false });
|
|
@@ -51713,6 +51817,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51713
51817
|
function onTouchMove(event) {
|
|
51714
51818
|
if (!isMouseDown)
|
|
51715
51819
|
return;
|
|
51820
|
+
if (resetTimeout) {
|
|
51821
|
+
clearTimeout(resetTimeout);
|
|
51822
|
+
resetTimeout = null;
|
|
51823
|
+
}
|
|
51716
51824
|
const currentTime = Date.now();
|
|
51717
51825
|
const { clientX, clientY } = event.touches[0];
|
|
51718
51826
|
let deltaX = lastX - clientX;
|
|
@@ -51729,6 +51837,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51729
51837
|
}
|
|
51730
51838
|
event.stopPropagation();
|
|
51731
51839
|
}
|
|
51840
|
+
resetTimeout = setTimeout(() => {
|
|
51841
|
+
velocityX = 0;
|
|
51842
|
+
velocityY = 0;
|
|
51843
|
+
}, resetTimeoutDuration);
|
|
51732
51844
|
updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
|
|
51733
51845
|
}
|
|
51734
51846
|
function onTouchEnd(ev) {
|
|
@@ -60478,10 +60590,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60478
60590
|
return this.evaluatedCells.keysForSheet(sheetId);
|
|
60479
60591
|
}
|
|
60480
60592
|
getArrayFormulaSpreadingOn(position) {
|
|
60481
|
-
const
|
|
60482
|
-
|
|
60483
|
-
|
|
60484
|
-
return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
|
|
60593
|
+
const isEmpty = this.getEvaluatedCell(position).type === CellValueType.empty;
|
|
60594
|
+
if (isEmpty) {
|
|
60595
|
+
return undefined;
|
|
60485
60596
|
}
|
|
60486
60597
|
const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
|
|
60487
60598
|
return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
|
|
@@ -76325,9 +76436,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76325
76436
|
exports.tokenize = tokenize;
|
|
76326
76437
|
|
|
76327
76438
|
|
|
76328
|
-
__info__.version = "18.1.
|
|
76329
|
-
__info__.date = "2025-05-
|
|
76330
|
-
__info__.hash = "
|
|
76439
|
+
__info__.version = "18.1.22";
|
|
76440
|
+
__info__.date = "2025-05-26T12:35:56.145Z";
|
|
76441
|
+
__info__.hash = "ff4b0ba";
|
|
76331
76442
|
|
|
76332
76443
|
|
|
76333
76444
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|